Merge "drivers: lmh-dcvsh: Add debug support"
diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt
index d534246..01e865d 100644
--- a/Documentation/DMA-attributes.txt
+++ b/Documentation/DMA-attributes.txt
@@ -182,6 +182,11 @@
 
 When passed to a DMA map call the DMA_ATTR_FORCE_COHERENT DMA
 attribute can be used to force a buffer to be mapped as IO coherent.
+
+When the DMA_ATTR_FORCE_COHERENT attribute is set during a map call ensure
+that it is also set during for the matching unmap call to ensure that the
+correct cache maintenance is carried out.
+
 This DMA attribute is only currently supported for arm64 stage 1 IOMMU
 mappings.
 
@@ -193,5 +198,10 @@
 coherent.
 The DMA_ATTR_FORCE_NON_COHERENT DMA attribute overrides the buffer IO
 coherency configuration set by making the device IO coherent.
+
+When the DMA_ATTR_FORCE_NON_COHERENT attribute is set during a map call
+ensure that it is also set during for the matching unmap call to ensure
+that the correct cache maintenance is carried out.
+
 This DMA attribute is only currently supported for arm64 stage 1 IOMMU
 mappings.
diff --git a/Documentation/arm/msm/remote_debug_drv.txt b/Documentation/arm/msm/remote_debug_drv.txt
new file mode 100644
index 0000000..13a35f4
--- /dev/null
+++ b/Documentation/arm/msm/remote_debug_drv.txt
@@ -0,0 +1,468 @@
+Introduction
+============
+
+The goal of this debug feature is to provide a reliable, responsive,
+accurate and secure debug capability to developers interested in
+debugging MSM subsystem processor images without the use of a hardware
+debugger.
+
+The Debug Agent along with the Remote Debug Driver implements a shared
+memory based transport mechanism that allows for a debugger (ex. GDB)
+running on a host PC to communicate with a remote stub running on
+peripheral subsystems such as the ADSP, MODEM etc.
+
+The diagram below depicts end to end the components involved to
+support remote debugging:
+
+
+:               :
+:    HOST (PC)  :  MSM
+:  ,--------,   :   ,-------,
+:  |        |   :   | Debug |                         ,--------,
+:  |Debugger|<--:-->| Agent |                         | Remote |
+:  |        |   :   |  App  |                  +----->| Debug  |
+:  `--------`   :   |-------|    ,--------,    |      | Stub   |
+:               :   | Remote|    |        |<---+      `--------`
+:               :   | Debug |<-->|--------|
+:               :   | Driver|    |        |<---+      ,--------,
+:               :   `-------`    `--------`    |      | Remote |
+:               :       LA         Shared      +----->| Debug  |
+:               :                  Memory             | Stub   |
+:               :                                     `--------`
+:               :                               Peripheral Subsystems
+:               :                                 (ADSP, MODEM, ...)
+
+
+Debugger:       Debugger application running on the host PC that
+                communicates with the remote stub.
+                Examples: GDB, LLDB
+
+Debug Agent:    Software that runs on the Linux Android platform
+                that provides connectivity from the MSM to the
+                host PC. This involves two portions:
+                1) User mode Debug Agent application that discovers
+                processes running on the subsystems and creates
+                TCP/IP sockets for the host to connect to. In addition
+                to this, it creates an info (or meta) port that
+                users can connect to discover the various
+                processes and their corresponding debug ports.
+
+Remote Debug    A character based driver that the Debug
+Driver:         Agent uses to transport the payload received from the
+                host to the debug stub running on the subsystem
+                processor over shared memory and vice versa.
+
+Shared Memory:  Shared memory from the SMEM pool that is accessible
+                from the Applications Processor (AP) and the
+                subsystem processors.
+
+Remote Debug    Privileged code that runs in the kernels of the
+Stub:           subsystem processors that receives debug commands
+                from the debugger running on the host and
+                acts on these commands. These commands include reading
+                and writing to registers and memory belonging to the
+                subsystem's address space, setting breakpoints,
+                single stepping etc.
+
+Hardware description
+====================
+
+The Remote Debug Driver interfaces with the Remote Debug stubs
+running on the subsystem processors and does not drive or
+manage any hardware resources.
+
+Software description
+====================
+
+The debugger and the remote stubs use Remote Serial Protocol (RSP)
+to communicate with each other. This is widely used protocol by both
+software and hardware debuggers. RSP is an ASCII based protocol
+and used when it is not possible to run GDB server on the target under
+debug.
+
+The Debug Agent application along with the Remote Debug Driver
+is responsible for establishing a bi-directional connection from
+the debugger application running on the host to the remote debug
+stub running on a subsystem. The Debug Agent establishes connectivity
+to the host PC via TCP/IP sockets.
+
+This feature uses ADB port forwarding to establish connectivity
+between the debugger running on the host and the target under debug.
+
+Please note the Debug Agent does not expose HLOS memory to the
+remote subsystem processors.
+
+Design
+======
+
+Here is the overall flow:
+
+1) When the Debug Agent application starts up, it opens up a shared memory
+based transport channel to the various subsystem processor images.
+
+2) The Debug Agent application sends messages across to the remote stubs
+to discover the various processes that are running on the subsystem and
+creates debug sockets for each of them.
+
+3) Whenever a process running on a subsystem exits, the Debug Agent
+is notified by the stub so that the debug port and other resources
+can be reclaimed.
+
+4) The Debug Agent uses the services of the Remote Debug Driver to
+transport payload from the host debugger to the remote stub and vice versa.
+
+5) Communication between the Remote Debug Driver and the Remote Debug stub
+running on the subsystem processor is done over shared memory (see figure).
+SMEM services are used to allocate the shared memory that will
+be readable and writeable by the AP and the subsystem image under debug.
+
+A separate SMEM allocation takes place for each subsystem processor
+involved in remote debugging. The remote stub running on each of the
+subsystems allocates a SMEM buffer using a unique identifier so that both
+the AP and subsystem get the same physical block of memory. It should be
+noted that subsystem images can be restarted at any time.
+However, when a subsystem comes back up, its stub uses the same unique
+SMEM identifier to allocate the SMEM block. This would not result in a
+new allocation rather the same block of memory in the first bootup instance
+is provided back to the stub running on the subsystem.
+
+An 8KB chunk of shared memory is allocated and used for communication
+per subsystem. For multi-process capable subsystems, 16KB chunk of shared
+memory is allocated to allow for simultaneous debugging of more than one
+process running on a single subsystem.
+
+The shared memory is used as a circular ring buffer in each direction.
+Thus we have a bi-directional shared memory channel between the AP
+and a subsystem. We call this SMQ. Each memory channel contains a header,
+data and a control mechanism that is used to synchronize read and write
+of data between the AP and the remote subsystem.
+
+Overall SMQ memory view:
+:
+:    +------------------------------------------------+
+:    | SMEM buffer                                    |
+:    |-----------------------+------------------------|
+:    |Producer: LA           | Producer: Remote       |
+:    |Consumer: Remote       |           subsystem    |
+:    |          subsystem    | Consumer: LA           |
+:    |                       |                        |
+:    |               Producer|                Consumer|
+:    +-----------------------+------------------------+
+:    |                       |
+:    |                       |
+:    |                       +--------------------------------------+
+:    |                                                              |
+:    |                                                              |
+:    v                                                              v
+:    +--------------------------------------------------------------+
+:    |   Header  |       Data      |            Control             |
+:    +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+:    |           | b | b | b |     | S  |n |n |     | S |n |n |     |
+:    |  Producer | l | l | l |     | M  |o |o |     | M |o |o |     |
+:    |    Ver    | o | o | o |     | Q  |d |d |     | Q |d |d |     |
+:    |-----------| c | c | c | ... |    |e |e | ... |   |e |e | ... |
+:    |           | k | k | k |     | O  |  |  |     | I |  |  |     |
+:    |  Consumer |   |   |   |     | u  |0 |1 |     | n |0 |1 |     |
+:    |    Ver    | 0 | 1 | 2 |     | t  |  |  |     |   |  |  |     |
+:    +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+:                                       |           |
+:                                       +           |
+:                                                   |
+:                          +------------------------+
+:                          |
+:                          v
+:                        +----+----+----+----+
+:                        | SMQ Nodes         |
+:                        |----|----|----|----|
+:                 Node # |  0 |  1 |  2 | ...|
+:                        |----|----|----|----|
+: Starting Block Index # |  0 |  3 |  8 | ...|
+:                        |----|----|----|----|
+:            # of blocks |  3 |  5 |  1 | ...|
+:                        +----+----+----+----+
+:
+
+Header: Contains version numbers for software compatibility to ensure
+that both producers and consumers on the AP and subsystems know how to
+read from and write to the queue.
+Both the producer and consumer versions are 1.
+:     +---------+-------------------+
+:     | Size    | Field             |
+:     +---------+-------------------+
+:     | 1 byte  | Producer Version  |
+:     +---------+-------------------+
+:     | 1 byte  | Consumer Version  |
+:     +---------+-------------------+
+
+
+Data: The data portion contains multiple blocks [0..N] of a fixed size.
+The block size SM_BLOCKSIZE is fixed to 128 bytes for header version #1.
+Payload sent from the debug agent app is split (if necessary) and placed
+in these blocks. The first data block is placed at the next 8 byte aligned
+address after the header.
+
+The number of blocks for a given SMEM allocation is derived as follows:
+  Number of Blocks = ((Total Size - Alignment - Size of Header
+                      - Size of SMQIn - Size of SMQOut)/(SM_BLOCKSIZE))
+
+The producer maintains a private block map of each of these blocks to
+determine which of these blocks in the queue is available and which are free.
+
+Control:
+The control portion contains a list of nodes [0..N] where N is number
+of available data blocks. Each node identifies the data
+block indexes that contain a particular debug message to be transferred,
+and the number of blocks it took to hold the contents of the message.
+
+Each node has the following structure:
+:     +---------+-------------------+
+:     | Size    | Field             |
+:     +---------+-------------------+
+:     | 2 bytes |Staring Block Index|
+:     +---------+-------------------+
+:     | 2 bytes |Number of Blocks   |
+:     +---------+-------------------+
+
+The producer and the consumer update different parts of the control channel
+(SMQOut / SMQIn) respectively. Each of these control data structures contains
+information about the last node that was written / read, and the actual nodes
+that were written/read.
+
+SMQOut Structure (R/W by producer, R by consumer):
+:     +---------+-------------------+
+:     | Size    | Field             |
+:     +---------+-------------------+
+:     | 4 bytes | Magic Init Number |
+:     +---------+-------------------+
+:     | 4 bytes | Reset             |
+:     +---------+-------------------+
+:     | 4 bytes | Last Sent Index   |
+:     +---------+-------------------+
+:     | 4 bytes | Index Free Read   |
+:     +---------+-------------------+
+
+SMQIn Structure (R/W by consumer, R by producer):
+:     +---------+-------------------+
+:     | Size    | Field             |
+:     +---------+-------------------+
+:     | 4 bytes | Magic Init Number |
+:     +---------+-------------------+
+:     | 4 bytes | Reset ACK         |
+:     +---------+-------------------+
+:     | 4 bytes | Last Read Index   |
+:     +---------+-------------------+
+:     | 4 bytes | Index Free Write  |
+:     +---------+-------------------+
+
+Magic Init Number:
+Both SMQ Out and SMQ In initialize this field with a predefined magic
+number so as to make sure that both the consumer and producer blocks
+have fully initialized and have valid data in the shared memory control area.
+  Producer Magic #: 0xFF00FF01
+  Consumer Magic #: 0xFF00FF02
+
+SMQ Out's Last Sent Index and Index Free Read:
+  Only a producer can write to these indexes and they are updated whenever
+  there is new payload to be inserted into the SMQ in order to be sent to a
+  consumer.
+
+  The number of blocks required for the SMQ allocation is determined as:
+   (payload size + SM_BLOCKSIZE - 1) / SM_BLOCKSIZE
+
+  The private block map is searched for a large enough continuous set of blocks
+  and the user data is copied into the data blocks.
+
+  The starting index of the free block(s) is updated in the SMQOut's Last Sent
+  Index. This update keeps track of which index was last written to and the
+  producer uses it to determine where the the next allocation could be done.
+
+  Every allocation, a producer updates the Index Free Read from its
+  collaborating consumer's Index Free Write field (if they are unequal).
+  This index value indicates that the consumer has read all blocks associated
+  with allocation on the SMQ and that the producer can reuse these blocks for
+  subsquent allocations since this is a circular queue.
+
+  At cold boot and restart, these indexes are initialized to zero and all
+  blocks are marked as available for allocation.
+
+SMQ In's Last Read Index and Index Free Write:
+  These indexes are written to only by a consumer and are updated whenever
+  there is new payload to be read from the SMQ. The Last Read Index keeps
+  track of which index was last read by the consumer and using this, it
+  determines where the next read should be done.
+  After completing a read, Last Read Index is incremented to the
+  next block index. A consumer updates Index Free Write to the starting
+  index of an allocation whenever it has completed processing the blocks.
+  This is an optimization that can be used to prevent an additional copy
+  of data from the queue into a client's data buffer and the data in the queue
+  itself can be used.
+  Once Index Free Write is updated, the collaborating producer (on the next
+  data allocation) reads the updated Index Free Write value and it then
+  updates its corresponding SMQ Out's Index Free Read and marks the blocks
+  associated with that index as available for allocation. At cold boot and
+  restart, these indexes are initialized to zero.
+
+SMQ Out Reset# and SMQ In Reset ACK #:
+  Since subsystems can restart at anytime, the data blocks and control channel
+  can be in an inconsistent state when a producer or consumer comes up.
+  We use Reset and Reset ACK to manage this. At cold boot, the producer
+  initializes the Reset# to a known number ex. 1. Every other reset that the
+  producer undergoes, the Reset#1 is simply incremented by 1. All the producer
+  indexes are reset.
+  When the producer notifies the consumer of data availability, the consumer
+  reads the producers Reset # and copies that into its SMQ In Reset ACK#
+  field when they differ. When that occurs, the consumer resets its
+  indexes to 0.
+
+6) Asynchronous notifications between a producer and consumer are
+done using the SMP2P service which is interrupt based.
+
+Power Management
+================
+
+None
+
+SMP/multi-core
+==============
+
+The driver uses completion to wake up the Debug Agent client threads.
+
+Security
+========
+
+From the perspective of the subsystem, the AP is untrusted. The remote
+stubs consult the secure debug fuses to determine whether or not the
+remote debugging will be enabled at the subsystem.
+
+If the hardware debug fuses indicate that debugging is disabled, the
+remote stubs will not be functional on the subsystem. Writes to the
+queue will only be done if the driver sees that the remote stub has been
+initialized on the subsystem.
+
+Therefore even if any untrusted software running on the AP requests
+the services of the Remote Debug Driver and inject RSP messages
+into the shared memory buffer, these RSP messages will be discarded and
+an appropriate error code will be sent up to the invoking application.
+
+Performance
+===========
+
+During operation, the Remote Debug Driver copies RSP messages
+asynchronously sent from the host debugger to the remote stub and vice
+versa. The debug messages are ASCII based and relatively short
+(<25 bytes) and may once in a while go up to a maximum 700 bytes
+depending on the command the user requested. Thus we do not
+anticipate any major performance impact. Moreover, in a typical
+functional debug scenario performance should not be a concern.
+
+Interface
+=========
+
+The Remote Debug Driver is a character based device that manages
+a piece of shared memory that is used as a bi-directional
+single producer/consumer circular queue using a next fit allocator.
+Every subsystem, has its own shared memory buffer that is managed
+like a separate device.
+
+The driver distinguishes each subsystem processor's buffer by
+registering a node with a different minor number.
+
+For each subsystem that is supported, the driver exposes a user space
+interface through the following node:
+    - /dev/rdbg-<subsystem>
+    Ex. /dev/rdbg-adsp (for the ADSP subsystem)
+
+The standard open(), close(), read() and write() API set is
+implemented.
+
+The open() syscall will fail if a subsystem is not present or supported
+by the driver or a shared memory buffer cannot be allocated for the
+AP - subsystem communication. It will also fail if the subsytem has
+not initialized the queue on its side. Here are the error codes returned
+in case a call to open() fails:
+ENODEV - memory was not yet allocated for the device
+EEXIST - device is already opened
+ENOMEM - SMEM allocation failed
+ECOMM - Subsytem queue is not yet setup
+ENOMEM - Failure to initialize SMQ
+
+read() is a blocking call that will return with the number of bytes written
+by the subsystem whenever the subsystem sends it some payload. Here are the
+error codes returned in case a call to read() fails:
+EINVAL - Invalid input
+ENODEV - Device has not been opened yet
+ERESTARTSYS - call to wait_for_completion_interruptible is interrupted
+ENODATA - call to smq_receive failed
+
+write() attempts to send user mode payload out to the subsystem. It can fail
+if the SMQ is full. The number of bytes written is returned back to the user.
+Here are the error codes returned in case a call to write() fails:
+EINVAL - Invalid input
+ECOMM - SMQ send failed
+
+In the close() syscall, the control information state of the SMQ is
+initialized to zero thereby preventing any further communication between
+the AP and the subsystem. Here is the error code returned in case
+a call to close() fails:
+ENODEV - device wasn't opened/initialized
+
+The Remote Debug driver uses SMP2P for bi-directional AP to subsystem
+notification. Notifications are sent to indicate that there are new
+debug messages available for processing. Each subsystem that is
+supported will need to add a device tree entry per the usage
+specification of SMP2P driver.
+
+In case the remote stub becomes non operational or the security configuration
+on the subsystem does not permit debugging, any messages put in the SMQ will
+not be responded to. It is the responsibility of the Debug Agent app and the
+host debugger application such as GDB to timeout and notify the user of the
+non availability of remote debugging.
+
+Driver parameters
+=================
+
+None
+
+Config options
+==============
+
+The driver is configured with a device tree entry to map an SMP2P entry
+to the device. The SMP2P entry name used is "rdbg". Please see
+kernel\Documentation\arm\msm\msm_smp2p.txt for information about the
+device tree entry required to configure SMP2P.
+
+The driver uses the SMEM allocation type SMEM_LC_DEBUGGER to allocate memory
+for the queue that is used to share data with the subsystems.
+
+Dependencies
+============
+
+The Debug Agent driver requires services of SMEM to
+allocate shared memory buffers.
+
+SMP2P is used as a bi-directional notification
+mechanism between the AP and a subsystem processor.
+
+User space utilities
+====================
+
+This driver is meant to be used in conjunction with the user mode
+Remote Debug Agent application.
+
+Other
+=====
+
+None
+
+Known issues
+============
+For targets with an external subsystem, we cannot use
+shared memory for communication and would have to use the prevailing
+transport mechanisms that exists between the AP and the external subsystem.
+
+This driver cannot be leveraged for such targets.
+
+To do
+=====
+
+None
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index 592fcef..d4a352b 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -159,6 +159,23 @@
 
 	* qcom,inst-id: must be present. QMI instance id for remote ETMs.
 
+* Optional properties for funnels:
+
+	* qcom,duplicate-funnel: boolean, indicates its a duplicate of an
+	  existing funnel. Funnel devices are now capable of supporting
+	  multiple-input and multiple-output configuration with in built
+	  hardware filtering for TPDM devices. Each set of input-output
+	  combination is treated as independent funnel device.
+	  funnel-base-dummy and funnel-base-real reg-names must be specified
+	  when this property is enabled.
+
+	* reg-names: funnel-base-dummy: dummy register space used by a
+	  duplicate funnel. Should be a valid register address space that
+	  no other device is using.
+
+	* reg-names: funnel-base-real: actual register space for the
+	  duplicate funnel.
+
 Example:
 
 1. Sinks
diff --git a/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt b/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt
new file mode 100644
index 0000000..e63d09b
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/heap-sharing.txt
@@ -0,0 +1,44 @@
+* Memory Share Driver (MEMSHARE)
+
+The Memshare driver implements a Kernel QMI service on the
+LA-APSS, which is responsible for providing contiguous physical
+memory to MPSS for use cases when the modem requires additional
+memory (e.g. GPS).
+
+Required properties for Memshare
+
+-Root Node-
+
+- compatible:	Must be "qcom,memshare"
+
+Required properties for child nodes:
+
+- compatible:	Must be "qcom,memshare-peripheral"
+
+- qcom,peripheral-size:	Indicates the size (in bytes) required for that child.
+
+- qcom,client-id:	Indicates the client id of the child node.
+
+- label:	Indicates the peripheral information for the node. Should be one of
+  the following:
+  - modem	/* Represent Modem Peripheral */
+  - adsp	/* Represent ADSP Peripheral */
+  - wcnss	/* Represent WCNSS Peripheral */
+
+Optional properties for child nodes:
+
+- qcom,allocate-boot-time:	Indicates whether clients needs boot time memory allocation.
+
+Example:
+
+qcom,memshare {
+	compatible = "qcom,memshare";
+
+	qcom,client_1 {
+		compatible = "qcom,memshare-peripheral";
+		qcom,peripheral-size = <0x200000>;
+		qcom,client-id = <0>;
+		qcom,allocate-boot-time;
+		label = "modem";
+	};
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index ae476d0..797dbcc 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -28,9 +28,6 @@
 	- qcom,default-level: The default low power level that a cluster is
 	programmed. The SPM of the corresponding device is configured at this
 	low power mode by default.
-	- qcom,cpu: List of CPU phandles to identify the CPUs associated with
-	this cluster. This property is required if and only if the cluster
-	node contains a qcom,pm-cpu node.
 
 	qcom,pm-cluster contains qcom,pm-cluster-level nodes which identify
 	the various low power modes that the cluster can enter. The
@@ -103,9 +100,13 @@
 					power collapse (PC)
 
 [Node bindings for qcom,pm-cpu]
-qcom,pm-cpu contains the low power modes that a cpu could enter. Currently it
-doesn't have any required properties and is a container for
-qcom,pm-cpu-levels.
+qcom,pm-cpu contains the low power modes that a cpu could enter and the CPUs
+that share the parameters.It contains the following properties.
+	- qcom,cpu: List of CPU phandles to identify the CPUs associated with
+	this cluster.
+	- qcom,pm-cpu-levels: The different low power modes that a CPU could
+	enter. The following section explains the required properties of this
+	node.
 
 [Node bindings for qcom,pm-cpu-levels]
  Required properties:
@@ -184,7 +185,6 @@
 			label = "a53";
 			qcom,spm-device-names = "l2";
 			qcom,default-level=<0>;
-			qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>;
 
 			qcom,pm-cluster-level@0{
 				reg = <0>;
@@ -210,6 +210,7 @@
 			qcom,pm-cpu {
 				#address-cells = <1>;
 				#size-cells = <0>;
+				qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>;
 				qcom,pm-cpu-level@0 {
 					reg = <0>;
 					qcom,spm-cpu-mode = "wfi";
@@ -255,7 +256,6 @@
 			label = "a57";
 			qcom,spm-device-names = "l2";
 			qcom,default-level=<0>;
-			qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>;
 
 			qcom,pm-cluster-level@0{
 				reg = <0>;
@@ -281,6 +281,7 @@
 			qcom,pm-cpu {
 				#address-cells = <1>;
 				#size-cells = <0>;
+				qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>;
 				qcom,pm-cpu-level@0 {
 					reg = <0>;
 					qcom,spm-cpu-mode = "wfi";
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt
index 6bf6a57..8aeaf77 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt
@@ -121,6 +121,20 @@
 			cannot connect to either directly or via any number of
 			intermediate nodes.
 qcom,agg-ports:		The number of aggregation ports on the bus.
+qcom,node-qos-bcms:	Optional property to target specific BCMs to toggle during QoS configuration,
+			this is to ensure QoS register space is clocked and accessible. Array is
+			defined as follows: BCM node ID, VoteX, VoteY. The vectors must be defined in
+			sets of the three values aforementioned.
+qcom,prio:		Default fixed priority for bus master.
+qcom,qos-lim-params:	Array containing QoS limiter configurations defined as: Bandwidth, Saturation.
+			Must define "qcom,qos-lim-en" for these settings to take effect.
+qcom,qos-lim-en:	Boolean to enable limiter settings, default is disabled.
+qcom,qos-reg-params:	Array containing QoS regulator configurations defined as: Low Priority, High
+			Priority, Bandwidth, Saturation. Must define "qcom,qos-reg-regmode" for these
+			settings to take effect.
+qcom,qos-reg-mode:	Array containing QoS regulator mode enablement: Read Enable, Write Enable,
+			default is disabled.
+qcom,forwarding:	Boolean indicate Urgent Forwarding enablement.
 
 The following properties are optional as collecting data via coresight might
 and are present on child nodes that represent NOC devices. The documentation
@@ -172,6 +186,12 @@
 				<&clock_gcc clk_q1_clk>;
 			q0-clk-supply = <&gdsc_q0_clk>;
 		};
+		qcom,node-qos-bcms = <0x7011 0 1>;
+		qcom,prio = 1;
+		qcom,qos-lim-params = <1000 1000>;
+		qcom,qos-lim-en:
+		qcom,qos-reg-params = <1 2 1000 1000>;
+		qcom,qos-reg-mode = <1 1>;
         };
 
         mm_int_bimc: mm-int-bimc {
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt b/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt
index 0a5c0b3..5fb3e65 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_qmp.txt
@@ -13,6 +13,7 @@
 - qcom,irq-mask : the bitmask to trigger an interrupt.
 - interrupt : the receiving interrupt line.
 - mbox-desc-offset : offset of mailbox descriptor from start of the msgram.
+- priority : the priority of this mailbox compared to other mailboxes.
 - #mbox-cells: Common mailbox binding property to identify the number of cells
 		required for the mailbox specifier, should be 1.
 
@@ -33,6 +34,7 @@
 		qcom,irq-mask = <0x1>;
 		interrupt = <0 389 1>;
 		mbox-desc-offset = <0x100>;
+		priority = <1>;
 		mbox-offset = <0x500>;
 		mbox-size = <0x400>;
 		#mbox-cells = <1>;
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
index 50488b4..628b2aa 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
@@ -81,6 +81,10 @@
 -qcom,fg-cnt : The value of fine grained counter of activity monitor
 	        block.
 
+compatible devices:
+		qcom,sdm845-llcc,
+		qcom,sdm670-llcc
+
 Example:
 
 	qcom,llcc@01300000 {
diff --git a/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt
new file mode 100644
index 0000000..ce2d8bd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rdbg-smp2p.txt
@@ -0,0 +1,17 @@
+Qualcomm Technologies, Inc. Remote Debugger (RDBG) driver
+
+Required properties:
+-compatible : Should be one of
+	To communicate with modem
+		qcom,smp2pgpio_client_rdbg_2_in (inbound)
+		qcom,smp2pgpio_client_rdbg_2_out (outbound)
+	To communicate with modem
+		qcom,smp2pgpio_client_rdbg_1_in (inbound)
+		qcom,smp2pgpio_client_rdbg_1_out (outbound)
+-gpios : the relevant gpio pins of the entry.
+
+Example:
+	qcom,smp2pgpio_client_rdbg_2_in {
+		compatible = "qcom,smp2pgpio_client_rdbg_2_in";
+		gpios = <&smp2pgpio_rdbg_2_in 0 0>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/qcom,camcc.txt b/Documentation/devicetree/bindings/clock/qcom,camcc.txt
index dc93b35..313e50f 100644
--- a/Documentation/devicetree/bindings/clock/qcom,camcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,camcc.txt
@@ -2,7 +2,7 @@
 ----------------------------------------------------
 
 Required properties :
-- compatible : shall contain "qcom,cam_cc-sdm845"
+- compatible : shall contain "qcom,cam_cc-sdm845" or "qcom,cam_cc-sdm845-v2"
 - reg : shall contain base register location and length
 - reg-names: names of registers listed in the same order as in
 	     the reg property.
diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt
index 92828e0..87af0f6 100644
--- a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt
@@ -2,7 +2,7 @@
 ----------------------------------------------------
 
 Required properties :
-- compatible : shall contain "qcom,dispcc-sdm845".
+- compatible : shall contain "qcom,dispcc-sdm845" or "qcom,dispcc-sdm845-v2".
 - reg : shall contain base register location and length.
 - reg-names: names of registers listed in the same order as in
 	     the reg property.
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index d95aa59..c280b92 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -17,6 +17,7 @@
 			"qcom,gcc-msm8996"
 			"qcom,gcc-mdm9615"
 			"qcom,gcc-sdm845"
+			"qcom,gcc-sdm845-v2"
 			"qcom,debugcc-sdm845"
 
 - reg : shall contain base register location and length
diff --git a/Documentation/devicetree/bindings/clock/qcom,videocc.txt b/Documentation/devicetree/bindings/clock/qcom,videocc.txt
index 5dc109d..6bd0f0b 100644
--- a/Documentation/devicetree/bindings/clock/qcom,videocc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,videocc.txt
@@ -2,12 +2,13 @@
 ----------------------------------------------------
 
 Required properties :
-- compatible : shall contain "qcom,video_cc-sdm845"
-- reg : shall contain base register location and length
+- compatible : shall contain "qcom,video_cc-sdm845" or
+	       "qcom,video_cc-sdm845-v2".
+- reg : shall contain base register location and length.
 - reg-names: names of registers listed in the same order as in
 	     the reg property.
-- #clock-cells : shall contain 1
-- #reset-cells : shall contain 1
+- #clock-cells : shall contain 1.
+- #reset-cells : shall contain 1.
 
 Optional properties :
 - vdd_<rail>-supply: The logic rail supply.
diff --git a/Documentation/devicetree/bindings/devfreq/devfreq-simple-dev.txt b/Documentation/devicetree/bindings/devfreq/devfreq-simple-dev.txt
index d00ebd8..5f66bbf 100644
--- a/Documentation/devicetree/bindings/devfreq/devfreq-simple-dev.txt
+++ b/Documentation/devicetree/bindings/devfreq/devfreq-simple-dev.txt
@@ -9,12 +9,12 @@
 - compatible:		Must be "devfreq-simple-dev"
 - clock-names:		Must be "devfreq_clk"
 - clocks:		Must refer to the clock that's fed to the device.
-- freq-tbl-khz:		A list of usable frequencies (in KHz) for the device
-			clock.
 Optional properties:
 - polling-ms:	Polling interval for the device in milliseconds. Default: 50
 - governor:	Initial governor to user for the device. Default: "performance"
 - qcom,prepare-clk:	Prepare the device clock during initialization.
+- freq-tbl-khz:		A list of usable frequencies (in kHz) for the device
+			clock.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/display/msm/sde-rsc.txt b/Documentation/devicetree/bindings/display/msm/sde-rsc.txt
index 7e54fdd..55d18cf 100644
--- a/Documentation/devicetree/bindings/display/msm/sde-rsc.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde-rsc.txt
@@ -29,6 +29,10 @@
 Bus Scaling Subnodes:
 - qcom,sde-data-bus:		Property to provide Bus scaling for data bus access for
 				sde blocks.
+- qcom,sde-llcc-bus:		Property to provide Bus scaling for data bus access for
+				mnoc to llcc.
+- qcom,sde-ebi-bus:		Property to provide Bus scaling for data bus access for
+				llcc to ebi.
 
 Bus Scaling Data:
 - qcom,msm-bus,name:		String property describing client name.
@@ -69,4 +73,24 @@
 		          <22 512 0 6400000>, <23 512 0 6400000>,
 		          <22 512 0 6400000>, <23 512 0 6400000>;
 		};
+		qcom,sde-llcc-bus {
+			qcom,msm-bus,name = "sde_rsc_llcc";
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-cases = <3>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+			    <20001 20513 0 0>,
+			    <20001 20513 0 6400000>,
+			    <20001 20513 0 6400000>;
+		};
+		qcom,sde-ebi-bus {
+			qcom,msm-bus,name = "sde_rsc_ebi";
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-cases = <3>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+			    <20000 20512 0 0>,
+			    <20000 20512 0 6400000>,
+			    <20000 20512 0 6400000>;
+		};
 	};
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt
index 5cf2cb8..863a169 100644
--- a/Documentation/devicetree/bindings/display/msm/sde.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde.txt
@@ -322,12 +322,29 @@
 - qcom,sde-cdp-setting:		Array of 2 cell property, with a format of
 				<read enable, write enable> for cdp use cases in
 				order of <real_time>, and <non_real_time>.
+- qcom,sde-inline-rot-xin:	An integer array of xin-ids related to inline
+				rotation.
+- qcom,sde-inline-rot-xin-type:	A string array indicating the type of xin,
+				namely sspp or wb. Number of entries should match
+				the number of xin-ids defined in
+				property: qcom,sde-inline-rot-xin
+- qcom,sde-inline-rot-clk-ctrl:	Array of offsets describing clk control
+				offsets for dynamic clock gating. 1st value
+				in the array represents offset of the control
+				register. 2nd value represents bit offset within
+				control register. Number of offsets defined should
+				match the number of xin-ids defined in
+				property: qcom,sde-inline-rot-xin
 
 Bus Scaling Subnodes:
 - qcom,sde-reg-bus:		Property to provide Bus scaling for register access for
 				mdss blocks.
 - qcom,sde-data-bus:		Property to provide Bus scaling for data bus access for
 				mdss blocks.
+- qcom,sde-llcc-bus:		Property to provide Bus scaling for data bus access for
+				mnoc to llcc.
+- qcom,sde-ebi-bus:		Property to provide Bus scaling for data bus access for
+				llcc to ebi.
 
 - qcom,sde-inline-rotator:	A 2 cell property, with format of (rotator phandle,
 				instance id), of inline rotator device.
@@ -593,6 +610,9 @@
     };
 
     qcom,sde-inline-rotator = <&mdss_rotator 0>;
+    qcom,sde-inline-rot-xin = <10 11>;
+    qcom,sde-inline-rot-xin-type = "sspp", "wb";
+    qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>;
 
     qcom,platform-supply-entries {
        #address-cells = <1>;
@@ -622,6 +642,24 @@
             <22 512 0 6400000>, <23 512 0 6400000>,
                 <25 512 0 6400000>;
     };
+    qcom,sde-llcc-bus {
+        qcom,msm-bus,name = "mdss_sde_llcc";
+        qcom,msm-bus,num-cases = <3>;
+        qcom,msm-bus,num-paths = <1>;
+        qcom,msm-bus,vectors-KBps =
+            <132 770 0 0>,
+            <132 770 0 6400000>,
+            <132 770 0 6400000>;
+    };
+    qcom,sde-ebi-bus {
+        qcom,msm-bus,name = "mdss_sde_ebi";
+        qcom,msm-bus,num-cases = <3>;
+        qcom,msm-bus,num-paths = <1>;
+        qcom,msm-bus,vectors-KBps =
+            <129 512 0 0>,
+            <129 512 0 6400000>,
+            <129 512 0 6400000>;
+    };
 
     qcom,sde-reg-bus {
         /* Reg Bus Scale Settings */
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 1394fd3..375eaf2 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -74,6 +74,14 @@
                   address size faults are due to a fundamental programming
                   error from which we don't care about recovering anyways.
 
+- qcom,skip-init : Disable resetting configuration for all context banks
+                  during device reset.  This is useful for targets where
+                  some context banks are dedicated to other execution
+                  environments outside of Linux and those other EEs are
+                  programming their own stream match tables, SCTLR, etc.
+                  Without setting this option we will trample on their
+                  configuration.
+
 - qcom,dynamic  : Allow dynamic domains to be attached. This is only
 		  useful if the upstream hardware is capable of switching
 		  between multiple domains within a single context bank.
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
new file mode 100644
index 0000000..b7ce662
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
@@ -0,0 +1,257 @@
+Qualcomm Technologies, Inc. Haptics driver
+
+QPNP (Qualcomm Technologies, Inc. Plug N Play) Haptics is a peripheral on some
+QTI PMICs. It can be interfaced with the host processor via SPMI or I2C bus.
+
+Haptics peripheral can support different actuators or vibrators,
+1. Eccentric Rotation Mass (ERM)
+2. Linear Resonant Actuator (LRA)
+
+Also, it can support multiple modes of operation: Direct, Buffer, PWM or Audio.
+
+Haptics device is described under a single level of node.
+
+Properties:
+
+- compatible
+  Usage:      required
+  Value type: <string>
+  Definition: "qcom,qpnp-haptics".
+
+- reg
+  Usage:      required
+  Value type: <u32>
+  Definition: Base address of haptics peripheral.
+
+- interrupts
+  Usage:      required
+  Value type: <prop-encoded-array>
+  Definition: Peripheral interrupt specifier.
+
+- interrupt-names
+  Usage:      required
+  Value type: <stringlist>
+  Definition: Interrupt names.  This list must match up 1-to-1 with the
+		interrupts specified in the 'interrupts' property. Currently
+		supported interrupts are short-circuit and play.
+
+- qcom,pmic-revid
+  Usage:      required
+  Value type: <phandle>
+  Definition: Should specify the phandle of PMIC's revid module. This is used to
+		identify the PMIC subtype.
+
+- qcom,pmic-misc
+  Usage:      optional
+  Value type: <phandle>
+  Definition: Should specify the phandle of PMIC's misc module. This is used to
+		read the clock trim error register under MISC peripheral.
+
+- qcom,misc-clk-trim-error-reg
+  Usage:      optional
+  Value type: <u32>
+  Definition: Register offset in MISC peripheral to read the clock trim error.
+		If this is specified, then qcom,pmic-misc should be specified.
+
+- qcom,actuator-type
+  Usage:      optional
+  Value type: <u32>
+  Definition: Allowed values are 0 for LRA and 1 for ERM. If this is not
+		specified, then LRA type will be used by default.
+
+- qcom,play-mode
+  Usage:      optional
+  Value type: <string>
+  Definition: Allowed values are: "direct", "buffer", "pwm", "auto". If not
+		specified for LRA actuator, auto mode will be selected by
+		default.
+
+- qcom,wave-shape
+  Usage:      optional
+  Value type: <string>
+  Definition: Wave shape to be played. Allowed values: "sine" or "square".
+		Default value is "square".
+
+- qcom,wave-play-rate-us
+  Usage:      optional
+  Value type: <u32>
+  Definition: Wave sample duration in microseconds. This should match with
+		the frequency the vibrator supports.
+		Allowed values are: 0 to 20475. Default value is 5715.
+
+- qcom,max-play-time-us
+  Usage:      optional
+  Value type: <u32>
+  Definition: Maximum play time supported in microseconds. Default value is
+		15000.
+
+- qcom,vmax-mv
+  Usage:      optional
+  Value type: <u32>
+  Definition: Maximum output voltage in millivolts. Value specified here will
+		be rounded off to the closest multiple of 116 mV.
+		Allowed values: 0 to 3596. Default value is 3596.
+
+- qcom,ilim-ma
+  Usage:      optional
+  Value type: <u32>
+  Definition: Output current limit in mA. Allowed values: 400 or 800. Default
+		value is 400.
+
+- qcom,en-brake
+  Usage:      optional
+  Value type: <empty>
+  Definition: Enables internal reverse braking.
+
+- qcom,brake-pattern
+  Usage:      optional
+  Value type: <prop-encoded-array>
+  Definition: Brake pattern to be applied. If specified, should be having
+		4 elements. Allowed values for each element are:
+		0, 1: Vmax/4, 2: Vmax/2, 3: Vmax.
+
+- qcom,sc-dbc-cycles
+  Usage:      optional
+  Value type: <u32>
+  Definition: Short circuit debounce cycles for internal PWM.
+		Allowed values: 0, 8, 16 or 32.
+
+Following properties are specific only to LRA vibrators.
+
+- qcom,lra-auto-res-mode
+  Usage:      optional
+  Value type: <string>
+  Definition: Auto resonance method. Allowed values are:
+		For pmi8998 and chips earlier,
+		"none" : No auto resonance
+		"zxd" : Zero crossing detection method
+		"qwd" : Quarter wave drive method
+		"max-qwd" : Maximum QWD
+		"zxd-eop" : ZXD + End of Pattern
+		For pm660,
+		"zxd" : Zero crossing detection method
+		"qwd" : Quarter wave drive method
+
+- qcom,lra-high-z
+  Usage:      optional
+  Value type: <string>
+  Definition: High Z configuration for auto resonance. Allowed values are:
+		"none", "opt1", "opt2" and "opt3".
+		For pm660, "opt0" is valid value for 1 LRA period.
+
+- qcom,lra-res-cal-period
+  Usage:      optional
+  Value type: <u32>
+  Definition: Auto resonance calibration period. Allowed values are:
+		For pmi8998 and chips earlier: 4, 8, 16, and 32.
+		For pm660: 4, 8, 16, 32, 64, 128 and 256.
+
+- qcom,lra-qwd-drive-duration
+  Usage:      optional
+  Value type: <u32>
+  Definition: LRA drive duration in QWD mode. Applies only for pm660 currently.
+		Allowed values are: 0 and 1, for 1/4 and 3/8 LRA period.
+		respectively.
+
+- qcom,lra-calibrate-at-eop
+  Usage:      optional
+  Value type: <u32>
+  Definition: Enables calibration at end of pattern. Applies only for pm660
+		currently. Allowed values are: 0 and 1.
+
+- qcom,auto-res-err-recovery-hw
+  Usage:      optional
+  Value type: <empty>
+  Definition: Enables Hardware auto resonance error recovery. Applies only for
+		pm660 currently.
+
+- qcom,drive-period-code-max-variation-pct
+  Usage:      optional
+  Value type: <u32>
+  Definition: Maximum allowed variation of LRA drive period code in percentage
+		above which RATE_CFG registers will not be updated by SW when
+		auto resonance is enabled and auto resonance error correction
+		algorithm is running. If not specified, default value is 25%.
+
+- qcom,drive-period-code-min-variation-pct
+  Usage:      optional
+  Value type: <u32>
+  Definition: Minimum allowed variation of LRA drive period code in percentage
+		below which RATE_CFG registers will not be updated by SW when
+		auto resonance is enabled and auto resonance error correction
+		algorithm is running. If not specified, default value is 25%.
+
+Following properties are applicable only when "qcom,play-mode" is set to
+"buffer".
+
+- qcom,wave-rep-cnt
+  Usage:      optional
+  Value type: <u32>
+  Definition: Repetition count for wave form.
+		Allowed values are: 1, 2, 4, 8, 16, 32, 64 and 128. Default
+		value is 1.
+
+- qcom,wave-samp-rep-cnt
+  Usage:      optional
+  Value type: <u32>
+  Definition: Repetition count for each sample of wave form. Allowed values
+		are: 1, 2, 4 and 8. Default value is 1.
+
+- qcom,wave-samples
+  Usage:      optional
+  Value type: <prop-encoded-array>
+  Definition: Wave samples in an array of 8 elements. Each element takes the
+		following representation, bit 0: unused, bits[5:1] : amplitude,
+		bit 6: overdrive, bit 7: sign. Default sample value is 0x3E.
+
+Following properties are applicable only when "qcom,play-mode" is set to
+"pwm".
+
+- pwms
+  Usage:      required, if "qcom,play-mode" is set to "pwm".
+  Value type: <phandle>
+  Definition: PWM device that is feeding its output to Haptics.
+
+- qcom,period-us
+  Usage:      required, if "qcom,play-mode" is set to "pwm".
+  Value type: <u32>
+  Definition: PWM period in us.
+
+- qcom,duty-us
+  Usage:      required, if "qcom,play-mode" is set to "pwm".
+  Value type: <u32>
+  Definition: PWM duty cycle in us.
+
+- qcom,ext-pwm-freq-khz
+  Usage:      optional
+  Value type: <u32>
+  Definition: Frequency for external PWM in KHz.
+		Allowed values are: 25, 50, 75 and 100.
+
+- qcom,ext-pwm-dtest-line
+  Usage:      optional
+  Value type: <u32>
+  Definition: DTEST line which is used for external PWM.
+
+Example:
+	qcom,haptics@c000 {
+		compatible = "qcom,qpnp-haptics";
+		reg = <0xc000 0x100>;
+		interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_RISING>,
+			     <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+		interrupt-names = "hap-sc-irq", "hap-play-irq";
+		qcom,pmic-revid = <&pmi8998_revid>;
+		qcom,pmic-misc = <&pmi8998_misc>;
+		qcom,misc-clk-trim-error-reg = <0xf3>;
+		qcom,actuator-type = <0>;
+		qcom,play-mode = "direct";
+		qcom,vmax-mv = <3200>;
+		qcom,ilim-ma = <800>;
+		qcom,sc-dbc-cycles = <8>;
+		qcom,wave-play-rate-us = <6667>;
+		qcom,en-brake;
+		qcom,brake-pattern = <0x3 0x0 0x0 0x0>;
+		qcom,lra-high-z = "opt1";
+		qcom,lra-auto-res-mode = "qwd";
+		qcom,lra-res-cal-period = <4>;
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index 53f419c..d61606a 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -6,20 +6,11 @@
 Required properties:
 - compatible : one of:
 	- "qcom,msm-vidc"
-- qcom,max-hw-load: The maximum load the hardware can support expressed in units
-  of macroblocks per second. The load is a reflection of hardware capability
-  rather than a performance guarantee. Performance is guaranteed only up to
-  advertised capability of the chipset.
-- qcom,max-hq-mbs-per-frame : Max no of mbs per frame beyond which
-    "High Quality" encoding is not supported.
-- qcom,max-hq-frames-per-sec : Max no of frames per second beyond which
-    "High Quality" encoding is not supported.
+        - "qcom,sdm845-vidc" : Invokes driver specific data for SDM845.
 
 Optional properties:
 - reg : offset and length of the register set for the device.
 - interrupts : should contain the vidc interrupt.
-- qcom,platform-version : mask and shift of the platform version bits
-    in efuse register.
 - qcom,reg-presets : list of offset-value pairs for registers to be written.
   The offsets are from the base offset specified in 'reg'. This is mainly
   used for QoS, VBIF, etc. presets for video.
@@ -64,20 +55,9 @@
        macro block in low power mode.
        the required frequency to get the final frequency, the factor is
        represented in Q16 format.
-- qcom,sw-power-collapse = A bool indicating if video hardware core can be
-  power collapsed in idle state.
-- qcom,never-unload-fw = A bool indicating if video firmware should be not be
-  unloaded after all active sessions have closed.  Once a new session starts up
-  after this, the firmware will be ready to go.  This should be set on platforms
-  that desire low-latency video startup and don't mind "leakage" of some memory.
 - qcom,use-non-secure-pil = A bool indicating which type of pil to use to load
   the fw.
 - qcom,fw-bias = The address at which venus fw is loaded (manually).
-- qcom,enable-thermal-mitigation = A bool to enable thermal mitigation when
-  thermal run away occurs.
-- qcom,hfi-version = The hfi packetization version supported by venus firmware.
-  If hfi version is not specified, then packetization type will default to
-  legacy.
 - qcom,vidc-iommu-domains = node containing individual domain nodes, each with:
      - a unique domain name for the domain node (e.g vidc,domain-ns)
      - qcom,vidc-domain-phandle: phandle for the domain as defined in
@@ -97,13 +77,6 @@
            internal persist = 0x200
            internal persist1 = 0x400
            internal cmd queue = 0x800
-- qcom,pm-qos-latency-us = The latency used to vote for QOS power manager. This
-value is typically max(latencies of every cluster at all power levels) + 1
-- qcom,max-secure-instances = An int containing max number of concurrent secure
-  instances supported, accounting for venus and system wide limitations like
-  memory, performance etc.
-- qcom,debug-timeout = A bool indicating that FW errors such as SYS_ERROR,
-  SESSION_ERROR and timeouts will be treated as Fatal.
 - cache-slice-names = An array of supported cache slice names by llcc
 - cache-slices = An array of supported cache slice ids corresponding
   to cache-slice-names by llcc
@@ -171,25 +144,16 @@
 		venus-supply = <&gdsc>;
 		venus-core0-supply = <&gdsc1>;
 		venus-core1-supply = <&gdsc2>;
-		qcom,hfi-version = "3xx";
 		qcom,reg-presets = <0x80004 0x1>,
 			<0x80178 0x00001FFF>;
 		qcom,qdss-presets = <0xFC307000 0x1000>,
 			<0xFC322000 0x1000>;
-		qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
-		qcom,never-unload-fw;
 		clock-names = "foo_clk", "bar_clk", "baz_clk";
 		qcom,clock-configs = <0x3 0x1 0x0>;
-		qcom,sw-power-collapse;
 		qcom,buffer-type-tz-usage-table = <0x1 0x1>,
 						<0x1fe 0x2>;
-		qcom,enable-thermal-mitigation;
-		qcom,use-non-secure-pil;
-		qcom,use_dynamic_bw_update;
 		qcom,fw-bias = <0xe000000>;
 		qcom,allowed-clock-rates = <200000000 300000000 400000000>;
-		qcom,max-hq-mbs-per-frame = <8160>;
-		qcom,max-hq-frames-per-sec = <60>;
 		msm_vidc_cb1: msm_vidc_cb1 {
 			compatible = "qcom,msm-vidc,context-bank";
 			label = "venus_ns";
diff --git a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
new file mode 100644
index 0000000..094dc25
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
@@ -0,0 +1,74 @@
+Qualcomm Technologies, Inc. Parallel Interface controller (QPIC) for NAND devices
+
+Required properties:
+- compatible : "qcom,msm-nand".
+- reg : should specify QPIC NANDc and BAM physical address range.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should specify QPIC/BAM interrupt numbers.
+- interrupt-names : should specify relevant names to each interrupts property
+  defined.
+- qcom,reg-adjustment-offset : Specify the base adjustment offset value for the
+  version registers
+
+MTD flash partition layout for NAND devices -
+
+Each partition is represented as a sub-node of the qcom,mtd-partitions device.
+Each node's name represents the name of the corresponding partition.
+
+This is now completely optional as the partition information is avaialble from
+bootloader.
+
+Optional properties:
+- reg : boot_cfg. This is needed only on the targets where both NAND and eMMC
+  devices are supported. On eMMC based builds, NAND cannot be enabled by
+  default due to the absence of some of its required resources.
+- reg : The partition offset and size
+- label : The label / name for this partition.
+- read-only: This parameter, if present, indicates that this partition
+  should only be mounted read-only.
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+below optional properties:
+	- qcom,msm-bus,name
+	- qcom,msm-bus,num-cases
+	- qcom,msm-bus,active-only
+	- qcom,msm-bus,num-paths
+	- qcom,msm-bus,vectors-KBps
+
+Examples:
+
+	qcom,nand@f9af0000 {
+		compatible = "qcom,msm-nand";
+		reg = <0xf9af0000 0x1000>,
+		      <0xf9ac4000 0x8000>,
+		      <0x5e02c 0x4>;
+		reg-names = "nand_phys",
+			    "bam_phys",
+			    "boot_cfg";
+		qcom,reg-adjustment-offset = <0x4000>;
+
+		interrupts = <0 279 0>;
+		interrupt-names = "bam_irq";
+
+		qcom,msm-bus,name = "qpic_nand";
+		qcom,msm-bus,num-cases = <1>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps = <91 512 0 0>,
+	};
+
+       qcom,mtd-partitions {
+	       #address-cells = <1>;
+	       #size-cells = <1>;
+               partition@0 {
+                       label = "boot";
+                       reg = <0x0 0x1000>;
+		       read-only;
+               };
+               partition@20000 {
+                       label = "userdata";
+                       reg = <0x20000 0x1000>;
+               };
+               partition@40000 {
+                       label = "system";
+                       reg = <0x40000 0x1000>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt
new file mode 100644
index 0000000..1398309
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt
@@ -0,0 +1,82 @@
+* TSPP ( QTI Transport Stream Packet Processor )
+
+Hardware driver for QTI TSIF 12seg wrapper core, which consists of a TSPP, a
+BAM (Bus access manager, used for DMA) and two TSIF inputs.
+
+The TSPP driver is responsible for:
+ - TSPP/TSIF hardware configuration (using SPS driver to configure BAM hardware)
+ - TSIF GPIO/Clocks configuration
+ - Memory resource management
+ - Handling TSIF/TSPP interrupts and BAM events
+ - TSPP Power management
+
+Required properties:
+- compatible : Should be "qcom,msm_tspp"
+- reg : Specifies the base physical addresses and sizes of TSIF, TSPP & BAM registers.
+- reg-names : Specifies the register names of TSIF, TSPP & BAM base registers.
+- interrupts : Specifies the interrupts associated with TSIF 12 seg core.
+- interrupt-names: Specifies interrupt names for TSIF, TSPP & BAM interrupts.
+- clock-names: Specifies the clock names used for interface & reference clocks.
+- clocks: GCC_TSIF_AHB_CLK clock for interface clock & GCC_TSIF_REF_CLK clock for reference clock.
+- qcom, msm_bus,name: Should be "tsif"
+- qcom, msm_bus,num_cases: Depends on the use cases for bus scaling
+- qcom, msm_bus,num_paths: The paths for source and destination ports
+- qcom, msm_bus,vectors: Vectors for bus topology.
+- pinctrl-names: Names for the TSIF mode configuration to specify which TSIF interface is active.
+
+Optional properties:
+  - qcom,lpass-timer-tts : Indicates to add time stamps to TS packets from LPASS timer.
+                           bydefault time stamps will be added from TFIS internal counter.
+
+Example:
+
+        tspp: msm_tspp@0x8880000 {
+                compatible = "qcom,msm_tspp";
+                reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */
+                      <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */
+                      <0x088a9000 0x1000>, /* MSM_TSPP_PHYS  */
+                      <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */
+                reg-names = "MSM_TSIF0_PHYS",
+                        "MSM_TSIF1_PHYS",
+                        "MSM_TSPP_PHYS",
+                        "MSM_TSPP_BAM_PHYS";
+                interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */
+                        <0 119 0>, /* TSIF0_IRQ */
+                        <0 120 0>, /* TSIF1_IRQ */
+                        <0 122 0>; /* TSIF_BAM_IRQ */
+                interrupt-names = "TSIF_TSPP_IRQ",
+                        "TSIF0_IRQ",
+                        "TSIF1_IRQ",
+                        "TSIF_BAM_IRQ";
+
+                clock-names = "iface_clk", "ref_clk";
+                clocks = <&clock_gcc GCC_TSIF_AHB_CLK>,
+                        <&clock_gcc GCC_TSIF_REF_CLK>;
+
+                qcom,msm-bus,name = "tsif";
+                qcom,msm-bus,num-cases = <2>;
+                qcom,msm-bus,num-paths = <1>;
+                qcom,msm-bus,vectors-KBps =
+                                <82 512 0 0>, /* No vote */
+                                <82 512 12288 24576>;
+                                /* Max. bandwidth, 2xTSIF, each max of 96Mbps */
+
+                pinctrl-names = "disabled",
+                        "tsif0-mode1", "tsif0-mode2",
+                        "tsif1-mode1", "tsif1-mode2",
+                        "dual-tsif-mode1", "dual-tsif-mode2";
+
+                pinctrl-0 = <>;                         /* disabled */
+                pinctrl-1 = <&tsif0_signals_active>;    /* tsif0-mode1 */
+                pinctrl-2 = <&tsif0_signals_active
+                        &tsif0_sync_active>;            /* tsif0-mode2 */
+                pinctrl-3 = <&tsif1_signals_active>;    /* tsif1-mode1 */
+                pinctrl-4 = <&tsif1_signals_active
+                        &tsif1_sync_active>;            /* tsif1-mode2 */
+                pinctrl-5 = <&tsif0_signals_active
+                        &tsif1_signals_active>;         /* dual-tsif-mode1 */
+                pinctrl-6 = <&tsif0_signals_active
+                        &tsif0_sync_active
+                        &tsif1_signals_active
+                        &tsif1_sync_active>;            /* dual-tsif-mode2 */
+        };
diff --git a/Documentation/devicetree/bindings/scheduler/energy.txt b/Documentation/devicetree/bindings/scheduler/energy.txt
new file mode 100644
index 0000000..3c7121c
--- /dev/null
+++ b/Documentation/devicetree/bindings/scheduler/energy.txt
@@ -0,0 +1,13 @@
+* Scheduler Energy Driver
+
+Scheduler Energy Driver updates capacities in the scheduler group energy array.
+The array contains power cost at each CPU operating points so energy aware
+scheduler (EAS) can utilize it for task placement.
+
+Required properties:
+- compatible:		Must be "sched-energy"
+
+Example:
+	energy-costs {
+		compatible = "sched-energy";
+	}
diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
index 95cc85a..7711b8b 100644
--- a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
+++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
@@ -65,6 +65,17 @@
 		 and follow appropriate steps to ensure communication on the bus
 		 can be resumed after subsytem restart. By default slimbus driver
 		 register with ADSP subsystem.
+ - qcom,iommu-s1-bypass: Boolean flag to bypass IOMMU stage 1 translation.
+
+Optional subnodes:
+qcom,iommu_slim_ctrl_cb : Child node representing the Slimbus controller
+                          context bank.
+
+Subnode Required properties:
+- compatible : Must be "qcom,slim-ctrl-cb";
+- iommus : A list of phandle and IOMMU specifier pairs that
+           describe the IOMMU master interfaces of the device.
+
 Example:
 	slim@fe12f000 {
 		cell-index = <1>;
@@ -78,4 +89,9 @@
 		qcom,rxreg-access;
 		qcom,apps-ch-pipes = <0x60000000>;
 		qcom,ea-pc = <0x30>;
+
+		iommu_slim_ctrl_cb: qcom,iommu_slim_ctrl_cb {
+			compatible = "qcom,iommu-slim-ctrl-cb";
+			iommus = <&apps_smmu 0x1 0x0>;
+		};
 	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 3a09b28..c116e42 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -186,6 +186,12 @@
  - qcom,msm-pcm-loopback-low-latency : Flag indicating whether
    the device node is of type low latency.
 
+* msm-transcode-loopback
+
+Required properties:
+
+ - compatible : "qcom,msm-transcode-loopback"
+
 * msm-dai-q6
 
 [First Level Nodes]
@@ -347,6 +353,8 @@
  - clocks:                                  phandle reference to the parent
                                             clock.
 
+ - qcom,mclk-clk-reg:                       Indicate the register address for mclk.
+
 * audio_slimslave
 
 Required properties:
@@ -1149,12 +1157,9 @@
 				When clock rate is set to zero,
 				then external clock is assumed.
 
- [Second Level Nodes]
-
-Required properties:
-
- - compatible : "qcom,msm-dai-q6-tdm"
- - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID.
+ - qcom,msm-cpudai-tdm-clk-internal: Clock Source.
+				0 - EBIT clock from clk tree
+				1 - IBIT clock from clk tree
 
  - qcom,msm-cpudai-tdm-sync-mode: Synchronization setting.
 				0 - Short sync bit mode
@@ -1179,6 +1184,13 @@
 				1 - 1 bit clock cycle
 				2 - 2 bit clock cycle
 
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-tdm"
+ - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID.
+
  - qcom,msm-cpudai-tdm-data-align: Indicate how data is packed
 				within the slot. For example, 32 slot width in case of
 				sample bit width is 24.
@@ -1213,17 +1225,18 @@
 		qcom,msm-cpudai-tdm-group-num-ports = <1>;
 		qcom,msm-cpudai-tdm-group-port-id = <36912>;
 		qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <0>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <0>;
+		qcom,msm-cpudai-tdm-data-delay = <0>;
 		pinctrl-names = "default", "sleep";
 		pinctrl-0 = <&quat_tdm_active &quat_tdm_dout_active>;
 		pinctrl-1 = <&quat_tdm_sleep &quat_tdm_dout_sleep>;
 		dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36912>;
-			qcom,msm-cpudai-tdm-sync-mode = <0>;
-			qcom,msm-cpudai-tdm-sync-src = <1>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <0>;
-			qcom,msm-cpudai-tdm-data-delay = <0>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 			qcom,msm-cpudai-tdm-header-start-offset = <0>;
 			qcom,msm-cpudai-tdm-header-width = <2>;
@@ -2298,14 +2311,15 @@
 		qcom,tasha-mclk-clk-freq = <9600000>;
 		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
 				<&loopback>, <&compress>, <&hostless>,
-				<&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>;
+				<&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+				<&trans_loopback>;
 		asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
 				"msm-pcm-dsp.2", "msm-voip-dsp",
 				"msm-pcm-voice", "msm-pcm-loopback",
 				"msm-compress-dsp", "msm-pcm-hostless",
 				"msm-pcm-afe", "msm-lsm-client",
 				"msm-pcm-routing", "msm-cpe-lsm",
-				"msm-compr-dsp";
+				"msm-compr-dsp","msm-transcode-loopback";
 		asoc-cpu = <&dai_hdmi>,
 				<&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
 				<&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
diff --git a/Documentation/devicetree/bindings/thermal/qti-rpmh-reg-cdev.txt b/Documentation/devicetree/bindings/thermal/qti-rpmh-reg-cdev.txt
new file mode 100644
index 0000000..b7734ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qti-rpmh-reg-cdev.txt
@@ -0,0 +1,44 @@
+RPMh regulator cooling device.
+
+The RPMh regulator cooling device, will be used to place a voltage floor
+restriction on a rail. This cooling device will use a QMP AOP mail box to send
+the message to apply and clear voltage floor restriction.
+
+The cooling device node should be a child of the regulator devicetree node,
+which it is trying to place the floor restriction.
+
+Properties:
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: shall be "qcom,rpmh-reg-cdev"
+
+- qcom,reg-resource-name:
+	Usage: required
+	Value type: <string>
+	Definition: The regulator resource name to be used for communicating
+			with RPMh. This value should be any of the below
+			resource name,
+			cx -> For CX rail,
+			mx -> For MX rail,
+			ebi -> For EBI rail.
+
+- mboxes:
+	Usage: required
+	Value type: <phandle>
+	Definition: A phandle to the QMP AOP mail box, that needs to be used
+			for sending the floor restriction message.
+
+- #cooling-cells: Must be 2. Please refer to
+			<devicetree/bindings/thermal/thermal.txt> for more
+			details.
+
+Example:
+
+	vdd_cx: rpmh-cx-regulator-cdev {
+		compatible = "qcom,rpmh-reg-cdev";
+		mboxes = <&qmp_aop 0>;
+		qcom,reg-resource-name = "cx";
+		#cooling-cells = <2>;
+	};
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 958194b..4901fa0 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -70,6 +70,7 @@
 			  2: 38.4 MHz
 			  3: 52 MHz
 			  Defaults to 26 MHz if not specified.
+- extcon:       phandle to external connector (Refer Documentation/devicetree/bindings/extcon/extcon-gpio.txt for more details).
 
 Note: If above properties are not defined it can be assumed that the supply
 regulators or clocks are always on.
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt
index e508a4f..a9480be 100644
--- a/Documentation/devicetree/bindings/usb/msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/msm-phy.txt
@@ -1,5 +1,39 @@
 MSM USB PHY transceivers
 
+HSUSB PHY
+
+Required properties:
+ - compatible: Should be "qcom,usb-hsphy-snps-femto"
+ - reg: Address and length of the register set for the device
+   Required regs are:
+	"hsusb_phy_base" : the base register for the PHY
+ - <supply-name>-supply: phandle to the regulator device tree node
+   Required "supply-name" examples are:
+	"vdd" : vdd supply for HSPHY digital circuit operation
+	"vdda18" : 1.8v supply for HSPHY
+	"vdda33" : 3.3v supply for HSPHY
+ - clocks: a list of phandles to the PHY clocks. Use as per
+   Documentation/devicetree/bindings/clock/clock-bindings.txt
+ - clock-names: Names of the clocks in 1-1 correspondence with the "clocks"
+   property. "ref_clk_src" is a mandatory clock.
+ - qcom,vdd-voltage-level: This property must be a list of three integer
+   values (no, min, max) where each value represents either a voltage in
+   microvolts or a value corresponding to voltage corner
+ - resets: reset specifier pair consists of phandle for the reset controller
+   and reset lines used by this controller.
+ - reset-names: reset signal name strings sorted in the same order as the resets
+   property.
+
+Example:
+	hsphy@f9200000 {
+		compatible = "qcom,usb-hsphy-snps-femto";
+		reg = <0xff1000 0x400>;
+		vdd-supply = <&pm8841_s2_corner>;
+		vdda18-supply = <&pm8941_l6>;
+		vdda33-supply = <&pm8941_l24>;
+		qcom,vdd-voltage-level = <0 872000 872000>;
+	};
+
 SSUSB-QMP PHY
 
 Required properties:
@@ -140,6 +174,7 @@
  - qcom,hold-reset: Indicates that hold QUSB PHY into reset state.
  - qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided.
  - qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0
+ - qcom,phy-auto-resume-offset: Provides phy auto-resume register offset.
 
 Example:
 	qusb_phy: qusb@f9b39000 {
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index bc66690..4bb75aa 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -7,7 +7,6 @@
 	"core_base" : usb controller register set
 - interrupts: IRQ lines used by this controller
 - interrupt-names : Interrupt resource entries are :
-	"hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM.
 	"pwr_event_irq" : Interrupt to controller for asynchronous events in LPM.
 	Used for SS-USB power events.
  - clocks: a list of phandles to the controller clocks. Use as per
@@ -36,6 +35,12 @@
 - interrupt-names : Optional interrupt resource entries are:
     "pmic_id_irq" : Interrupt from PMIC for external ID pin notification.
     "ss_phy_irq"  : Interrupt from super speed phy for wake up notification.
+    "hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM.
+    "dp_hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM
+    going through PDC. (use qcom,use-pdc-interrupts property)
+    "dm_hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM
+    going through PDC. (use qcom,use-pdc-interrupts property)
+
  - clocks: a list of phandles to the controller clocks. Use as per
    Documentation/devicetree/bindings/clock/clock-bindings.txt
  - clock-names: Names of the clocks in 1-1 correspondence with the "clocks"
@@ -57,6 +62,8 @@
 - qcom,core-clk-rate: If present, indicates clock frequency to be set for USB master clock.
 - qcom,core-clk-rate-hs: If present, indicates min core clock frequency required to support
   hs speed.
+- qcom,use-pdc-interrupts: It present, it configures provided PDC IRQ with required
+  configuration for wakeup functionality.
 - extcon: phandles to external connector devices. First phandle should point to
 	  external connector, which provide "USB" cable events, the second
 	  should point to external connector device, which provide "USB-HOST"
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 0f0fc7d..9d2908d 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -858,6 +858,11 @@
 
 	Default: Empty
 
+reserved_port_bind - BOOLEAN
+	If set, allows explicit bind requests to applications requesting
+	any port within the range of ip_local_reserved_ports.
+	Default: 1
+
 ip_nonlocal_bind - BOOLEAN
 	If set, allows processes to bind() to non-local IP addresses,
 	which can be quite useful - but may break some applications.
diff --git a/Makefile b/Makefile
index 29030c6..9e428c5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 31
+SUBLEVEL = 32
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
index fc4ff37..b3103cd 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
@@ -36,3 +36,35 @@
 &gdsc_pcie {
 	compatible = "regulator-fixed";
 };
+
+&usb {
+	/delete-property/ qcom,usb-dbm;
+	qcom,charging-disabled;
+	dwc3@a600000 {
+		usb-phy = <&usb2_phy>, <&usb_nop_phy>;
+		maximum-speed = "high-speed";
+	};
+};
+
+&usb2_phy {
+	reg = <0xff1000 0x1000>,
+	      <0x0a60cd00 0x40>;
+	reg-names = "hsusb_phy_base",
+		"emu_phy_base";
+	qcom,emu-init-seq = <0x19 0x404
+			     0x20 0x414
+			     0x79 0x410
+			     0x00 0x418
+			     0x99 0x404
+			     0x04 0x408
+			     0xd9 0x404>;
+
+	qcom,emu-dcm-reset-seq = <0x100000 0x20
+				  0x0 0x20
+				  0x1e0 0x20
+				  0x5 0x14>;
+};
+
+&usb3_qmp_phy {
+	status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
new file mode 100644
index 0000000..be2b63e
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/clock/qcom,gcc-sdxpoorwills.h>
+
+&soc {
+	/* USB port for DWC3 controller */
+	usb: ssusb@a600000 {
+		compatible = "qcom,dwc-usb3-msm";
+		reg = <0x0a600000 0xf8c00>;
+		reg-names = "core_base";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		interrupts = <0 131 0>, <0 130 0>, <0 59 0>;
+		interrupt-names = "hs_phy_irq", "pwr_event_irq", "ss_phy_irq";
+
+		USB3_GDSC-supply = <&gdsc_usb30>;
+		qcom,usb-dbm = <&dbm_1p5>;
+		qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
+		qcom,num-gsi-evt-buffs = <0x3>;
+
+		clocks = <&clock_gcc GCC_USB30_MASTER_CLK>,
+			 <&clock_gcc GCC_SYS_NOC_USB3_CLK>,
+			 <&clock_gcc GCC_USB30_MOCK_UTMI_CLK>,
+			 <&clock_gcc GCC_USB30_SLEEP_CLK>,
+			 <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+			 <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>;
+
+		clock-names = "core_clk", "iface_clk", "utmi_clk", "sleep_clk",
+				"cfg_ahb_clk", "xo";
+
+		qcom,core-clk-rate = <133333333>;
+		qcom,core-clk-rate-hs = <66666667>;
+
+		resets = <&clock_gcc GCC_USB30_BCR>;
+		reset-names = "core_reset";
+
+		dwc3@a600000 {
+			compatible = "snps,dwc3";
+			reg = <0x0a600000 0xcd00>;
+			interrupt-parent = <&intc>;
+			interrupts = <0 133 0>;
+			usb-phy = <&usb2_phy>, <&usb3_qmp_phy>;
+			tx-fifo-resize;
+			linux,sysdev_is_parent;
+			snps,disable-clk-gating;
+			snps,has-lpm-erratum;
+			snps,hird-threshold = /bits/ 8 <0x10>;
+		};
+	};
+
+	/* USB port for High Speed PHY */
+	usb2_phy: hsphy@ff1000 {
+		compatible = "qcom,usb-hsphy-snps-femto";
+		reg = <0xff1000 0x400>;
+		reg-names = "hsusb_phy_base";
+
+		vdd-supply = <&pmxpoorwills_l4>;
+		vdda18-supply = <&pmxpoorwills_l5>;
+		vdda33-supply = <&pmxpoorwills_l10>;
+		qcom,vdd-voltage-level = <0 872000 872000>;
+		clocks = <&clock_rpmh RPMH_CXO_CLK>,
+			 <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
+		clock-names = "ref_clk_src", "cfg_ahb_clk";
+
+		resets = <&clock_gcc GCC_QUSB2PHY_BCR>;
+		reset-names = "phy_reset";
+	};
+
+	dbm_1p5: dbm@a6f8000 {
+		compatible = "qcom,usb-dbm-1p5";
+		reg = <0xa6f8000 0x400>;
+		qcom,reset-ep-after-lpm-resume;
+	};
+
+	usb_nop_phy: usb_nop_phy {
+		compatible = "usb-nop-xceiv";
+	};
+
+	/* USB port for Super Speed PHY */
+	usb3_qmp_phy: ssphy@ff0000 {
+		compatible = "qcom,usb-ssphy-qmp-v2";
+		reg = <0xff0000 0x1000>;
+		reg-names = "qmp_phy_base";
+
+		vdd-supply = <&pmxpoorwills_l4>;
+		core-supply = <&pmxpoorwills_l1>;
+		qcom,vdd-voltage-level = <0 872000 872000>;
+		qcom,vbus-valid-override;
+		qcom,qmp-phy-init-seq =
+		/* <reg_offset, value, delay> */
+			<0x048 0x07 0x00 /* QSERDES_COM_PLL_IVCO */
+			 0x080 0x14 0x00 /* QSERDES_COM_SYSCLK_EN_SEL */
+			 0x034 0x04 0x00 /* QSERDES_COM_BIAS_EN_CLKBUFLR_EN */
+			 0x138 0x30 0x00 /* QSERDES_COM_CLK_SELECT */
+			 0x03c 0x02 0x00 /* QSERDES_COM_SYS_CLK_CTRL */
+			 0x08c 0x08 0x00 /* QSERDES_COM_RESETSM_CNTRL2 */
+			 0x15c 0x06 0x00 /* QSERDES_COM_CMN_CONFIG */
+			 0x164 0x01 0x00 /* QSERDES_COM_SVS_MODE_CLK_SEL */
+			 0x13c 0x80 0x00 /* QSERDES_COM_HSCLK_SEL */
+			 0x0b0 0x82 0x00 /* QSERDES_COM_DEC_START_MODE0 */
+			 0x0b8 0xab 0x00 /* QSERDES_COM_DIV_FRAC_START1_MODE0 */
+			 0x0bc 0xea 0x00 /* QSERDES_COM_DIV_FRAC_START2_MODE0 */
+			 0x0c0 0x02 0x00 /* QSERDES_COM_DIV_FRAC_START3_MODE0 */
+			 0x060 0x06 0x00 /* QSERDES_COM_CP_CTRL_MODE0 */
+			 0x068 0x16 0x00 /* QSERDES_COM_PLL_RCTRL_MODE0 */
+			 0x070 0x36 0x00 /* QSERDES_COM_PLL_CCTRL_MODE0 */
+			 0x0dc 0x00 0x00 /* QSERDES_COM_INTEGLOOP_GAIN1_MODE0 */
+			 0x0d8 0x3f 0x00 /* QSERDES_COM_INTEGLOOP_GAIN0_MODE0 */
+			 0x0f8 0x01 0x00 /* QSERDES_COM_VCO_TUNE2_MODE0 */
+			 0x0f4 0xc9 0x00 /* QSERDES_COM_VCO_TUNE1_MODE0 */
+			 0x148 0x0a 0x00 /* QSERDES_COM_CORECLK_DIV_MODE0 */
+			 0x0a0 0x00 0x00 /* QSERDES_COM_LOCK_CMP3_MODE0 */
+			 0x09c 0x34 0x00 /* QSERDES_COM_LOCK_CMP2_MODE0 */
+			 0x098 0x15 0x00 /* QSERDES_COM_LOCK_CMP1_MODE0 */
+			 0x090 0x04 0x00 /* QSERDES_COM_LOCK_CMP_EN */
+			 0x154 0x00 0x00 /* QSERDES_COM_CORE_CLK_EN */
+			 0x094 0x00 0x00 /* QSERDES_COM_LOCK_CMP_CFG */
+			 0x0f0 0x00 0x00 /* QSERDES_COM_VCO_TUNE_MAP */
+			 0x040 0x0a 0x00 /* QSERDES_COM_SYSCLK_BUF_ENABLE */
+			 0x0d0 0x80 0x00 /* QSERDES_COM_INTEGLOOP_INITVAL */
+			 0x010 0x01 0x00 /* QSERDES_COM_SSC_EN_CENTER */
+			 0x01c 0x31 0x00 /* QSERDES_COM_SSC_PER1 */
+			 0x020 0x01 0x00 /* QSERDES_COM_SSC_PER2 */
+			 0x014 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER1 */
+			 0x018 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER2 */
+			 0x024 0x85 0x00 /* QSERDES_COM_SSC_STEP_SIZE1 */
+			 0x028 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE2 */
+			 0x4c0 0x0c 0x00 /* QSERDES_RX_VGA_CAL_CNTRL2 */
+			 0x564 0x50 0x00 /* QSERDES_RX_RX_MODE_00 */
+			 0x430 0x0b 0x00 /* QSERDES_RX_UCDR_FASTLOCK_FO_GAIN */
+			 0x4d4 0x0e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 */
+			 0x4d8 0x4e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 */
+			 0x4dc 0x18 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 */
+			 0x4f8 0x77 0x00 /* RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 */
+			 0x4fc 0x80 0x00 /* RX_RX_OFFSET_ADAPTOR_CNTRL2 */
+			 0x504 0x03 0x00 /* QSERDES_RX_SIGDET_CNTRL */
+			 0x50c 0x1c 0x00 /* QSERDES_RX_SIGDET_DEGLITCH_CNTRL */
+			 0x434 0x75 0x00 /* RX_UCDR_SO_SATURATION_AND_ENABLE */
+			 0x444 0x80 0x00 /* QSERDES_RX_UCDR_PI_CONTROLS */
+			 0x408 0x0a 0x00 /* QSERDES_RX_UCDR_FO_GAIN */
+			 0x40c 0x06 0x00 /* QSERDES_RX_UCDR_SO_GAIN */
+			 0x500 0x00 0x00 /* QSERDES_RX_SIGDET_ENABLES */
+			 0x260 0x10 0x00 /* QSERDES_TX_HIGHZ_DRVR_EN */
+			 0x2a4 0x12 0x00 /* QSERDES_TX_RCV_DETECT_LVL_2 */
+			 0x28c 0xc6 0x00 /* QSERDES_TX_LANE_MODE_1 */
+			 0x248 0x09 0x00 /* TX_RES_CODE_LANE_OFFSET_RX */
+			 0x244 0x0d 0x00 /* TX_RES_CODE_LANE_OFFSET_TX */
+			 0x8c8 0x83 0x00 /* USB3_UNI_PCS_FLL_CNTRL2 */
+			 0x8cc 0x09 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_L */
+			 0x8d0 0xa2 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_H_TOL */
+			 0x8d4 0x40 0x00 /* USB3_UNI_PCS_FLL_MAN_CODE */
+			 0x8c4 0x02 0x00 /* USB3_UNI_PCS_FLL_CNTRL1 */
+			 0x864 0x1b 0x00 /* USB3_UNI_PCS_POWER_STATE_CONFIG2 */
+			 0x80c 0x9f 0x00 /* USB3_UNI_PCS_TXMGN_V0 */
+			 0x810 0x9f 0x00 /* USB3_UNI_PCS_TXMGN_V1 */
+			 0x814 0xb5 0x00 /* USB3_UNI_PCS_TXMGN_V2 */
+			 0x818 0x4c 0x00 /* USB3_UNI_PCS_TXMGN_V3 */
+			 0x81c 0x64 0x00 /* USB3_UNI_PCS_TXMGN_V4 */
+			 0x820 0x6a 0x00 /* USB3_UNI_PCS_TXMGN_LS */
+			 0x824 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V0 */
+			 0x828 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V0 */
+			 0x82c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V1 */
+			 0x830 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V1 */
+			 0x834 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V2 */
+			 0x838 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V2 */
+			 0x83c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V3 */
+			 0x840 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V3 */
+			 0x844 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V4 */
+			 0x848 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V4 */
+			 0x84c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_LS */
+			 0x850 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_LS */
+			 0x85c 0x02 0x00 /* USB3_UNI_PCS_RATE_SLEW_CNTRL */
+			 0x8a0 0x04 0x00 /* PCS_PWRUP_RESET_DLY_TIME_AUXCLK */
+			 0x88c 0x44 0x00 /* USB3_UNI_PCS_TSYNC_RSYNC_TIME */
+			 0x880 0xd1 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG1 */
+			 0x884 0x1f 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG2 */
+			 0x888 0x47 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG3 */
+			 0x870 0xe7 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_L */
+			 0x874 0x03 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_H */
+			 0x878 0x40 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_U3_L */
+			 0x87c 0x00 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_U3_H */
+			 0x9d8 0xba 0x00 /* USB3_UNI_PCS_RX_SIGDET_LVL */
+			 0x8b8 0x75 0x00 /* RXEQTRAINING_WAIT_TIME */
+			 0x8b0 0x86 0x00 /* PCS_LFPS_TX_ECSTART_EQTLOCK */
+			 0x8bc 0x13 0x00 /* PCS_RXEQTRAINING_RUN_TIME */
+			 0xa0c 0x21 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG1 */
+			 0xa10 0x60 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG2 */
+			 0xffffffff 0xffffffff 0x00>;
+
+		qcom,qmp-phy-reg-offset =
+				<0x974 /* USB3_UNI_PCS_PCS_STATUS */
+				 0x8d8 /* USB3_UNI_PCS_AUTONOMOUS_MODE_CTRL */
+				 0x8dc /* USB3_UNI_PCS_LFPS_RXTERM_IRQ_CLEAR */
+				 0x804 /* USB3_UNI_PCS_POWER_DOWN_CONTROL */
+				 0x800 /* USB3_UNI_PCS_SW_RESET */
+				 0x808>; /* USB3_UNI_PCS_START_CONTROL */
+
+		clocks = <&clock_gcc GCC_USB3_PHY_AUX_CLK>,
+			 <&clock_gcc GCC_USB3_PHY_PIPE_CLK>,
+			 <&clock_rpmh RPMH_CXO_CLK>,
+			 <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
+
+		clock-names = "aux_clk", "pipe_clk", "ref_clk_src",
+				"cfg_ahb_clk";
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 961adc9..a2a3231 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -180,6 +180,38 @@
 		reg = <0x00137004 0x4>;
 		status = "ok";
 	};
+
+	qcom,msm-imem@8600000 {
+		compatible = "qcom,msm-imem";
+		reg = <0x8600000 0x1000>; /* Address and size of IMEM */
+		ranges = <0x0 0x8600000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		mem_dump_table@10 {
+			compatible = "qcom,msm-imem-mem_dump_table";
+			reg = <0x10 8>;
+		};
+
+		restart_reason@65c {
+			compatible = "qcom,msm-imem-restart_reason";
+			reg = <0x65c 4>;
+		};
+
+		boot_stats@6b0 {
+			compatible = "qcom,msm-imem-boot_stats";
+			reg = <0x6b0 32>;
+		};
+	};
+
+	restart@4ab000 {
+		compatible = "qcom,pshold";
+		reg = <0x4ab000 0x4>,
+			<0x193d100 0x4>;
+		reg-names = "pshold-base", "tcsr-boot-misc-detect";
+	};
+
 };
 
 #include "sdxpoorwills-regulator.dtsi"
+#include "sdxpoorwills-usb.dtsi"
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index 40289a8..c2252c0 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -156,6 +156,7 @@
 CONFIG_MTD_TESTS=m
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
+CONFIG_MTD_MSM_QPIC_NAND=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -174,8 +175,6 @@
 # CONFIG_NET_VENDOR_INTEL is not set
 CONFIG_KS8851=y
 # CONFIG_NET_VENDOR_MICROCHIP is not set
-CONFIG_ECM_IPA=y
-CONFIG_RNDIS_IPA=y
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_SEEQ is not set
 # CONFIG_NET_VENDOR_SMSC is not set
@@ -207,6 +206,8 @@
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_THERMAL=y
 CONFIG_REGULATOR=y
@@ -240,11 +241,20 @@
 CONFIG_USB_STORAGE_KARMA=y
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_MSM=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_HSUSB_PHY=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_GSI=y
 CONFIG_MMC=y
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
@@ -258,6 +268,8 @@
 CONFIG_STAGING=y
 CONFIG_GSI=y
 CONFIG_IPA3=y
+CONFIG_ECM_IPA=y
+CONFIG_RNDIS_IPA=y
 CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index d91f5f6..e8fa052 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -148,6 +148,7 @@
 CONFIG_MTD_TESTS=m
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
+CONFIG_MTD_MSM_QPIC_NAND=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -166,8 +167,6 @@
 # CONFIG_NET_VENDOR_INTEL is not set
 CONFIG_KS8851=y
 # CONFIG_NET_VENDOR_MICROCHIP is not set
-CONFIG_ECM_IPA=y
-CONFIG_RNDIS_IPA=y
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_SEEQ is not set
 # CONFIG_NET_VENDOR_SMSC is not set
@@ -200,6 +199,8 @@
 CONFIG_SLIMBUS=y
 CONFIG_PINCTRL_SDXPOORWILLS=y
 CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_THERMAL=y
 CONFIG_MSM_CDC_PINCTRL=y
@@ -236,11 +237,21 @@
 CONFIG_USB_STORAGE_KARMA=y
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_MSM=y
 CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_HSUSB_PHY=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_GSI=y
 CONFIG_MMC=y
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
@@ -253,6 +264,8 @@
 CONFIG_STAGING=y
 CONFIG_GSI=y
 CONFIG_IPA3=y
+CONFIG_ECM_IPA=y
+CONFIG_RNDIS_IPA=y
 CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
index d060641..9edea10 100644
--- a/arch/arm/include/asm/topology.h
+++ b/arch/arm/include/asm/topology.h
@@ -24,6 +24,7 @@
 void init_cpu_topology(void);
 void store_cpu_topology(unsigned int cpuid);
 const struct cpumask *cpu_coregroup_mask(int cpu);
+unsigned long arch_get_cpu_efficiency(int cpu);
 
 #ifdef CONFIG_CPU_FREQ
 #define arch_scale_freq_capacity cpufreq_scale_freq_capacity
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index fab57d3..877f461 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -81,7 +81,7 @@
 extern void init_default_cache_policy(unsigned long);
 extern void paging_init(const struct machine_desc *desc);
 extern void early_paging_init(const struct machine_desc *);
-extern void sanity_check_meminfo(void);
+extern void adjust_lowmem_bounds(void);
 extern enum reboot_mode reboot_mode;
 extern void setup_dma_zone(const struct machine_desc *desc);
 
@@ -1104,8 +1104,14 @@
 	setup_dma_zone(mdesc);
 	xen_early_init();
 	efi_init();
-	sanity_check_meminfo();
+	/*
+	 * Make sure the calculation for lowmem/highmem is set appropriately
+	 * before reserving/allocating any mmeory
+	 */
+	adjust_lowmem_bounds();
 	arm_memblock_init(mdesc);
+	/* Memory may have been removed so recalculate the bounds. */
+	adjust_lowmem_bounds();
 
 	early_ioremap_reset();
 
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
index 92b7237..fe76010 100644
--- a/arch/arm/kernel/stacktrace.c
+++ b/arch/arm/kernel/stacktrace.c
@@ -170,6 +170,7 @@
 {
 	__save_stack_trace(tsk, trace, 1);
 }
+EXPORT_SYMBOL(save_stack_trace_tsk);
 
 void save_stack_trace(struct stack_trace *trace)
 {
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index bd884da..2b6c530 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -196,6 +196,14 @@
 	return 0;
 }
 
+static DEFINE_PER_CPU(unsigned long, cpu_efficiency) = SCHED_CAPACITY_SCALE;
+
+unsigned long arch_get_cpu_efficiency(int cpu)
+{
+	return per_cpu(cpu_efficiency, cpu);
+}
+EXPORT_SYMBOL(arch_get_cpu_efficiency);
+
 #ifdef CONFIG_OF
 struct cpu_efficiency {
 	const char *compatible;
@@ -272,6 +280,7 @@
 	for_each_possible_cpu(cpu) {
 		const u32 *rate;
 		int len;
+		u32 efficiency;
 
 		/* too early to use cpu->of_node */
 		cn = of_get_cpu_node(cpu, NULL);
@@ -280,12 +289,26 @@
 			continue;
 		}
 
-		for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++)
-			if (of_device_is_compatible(cn, cpu_eff->compatible))
-				break;
+		/*
+		 * The CPU efficiency value passed from the device tree
+		 * overrides the value defined in the table_efficiency[]
+		 */
+		if (of_property_read_u32(cn, "efficiency", &efficiency) < 0) {
 
-		if (cpu_eff->compatible == NULL)
-			continue;
+			for (cpu_eff = table_efficiency;
+					cpu_eff->compatible; cpu_eff++)
+
+				if (of_device_is_compatible(cn,
+						cpu_eff->compatible))
+					break;
+
+			if (cpu_eff->compatible == NULL)
+				continue;
+
+			efficiency = cpu_eff->efficiency;
+		}
+
+		per_cpu(cpu_efficiency, cpu) = efficiency;
 
 		rate = of_get_property(cn, "clock-frequency", &len);
 		if (!rate || len != 4) {
@@ -294,7 +317,7 @@
 			continue;
 		}
 
-		capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency;
+		capacity = ((be32_to_cpup(rate)) >> 20) * efficiency;
 
 		/* Save min capacity of the system */
 		if (capacity < min_capacity)
diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S
index bf89c91..bd0ee7f 100644
--- a/arch/arm/kvm/init.S
+++ b/arch/arm/kvm/init.S
@@ -95,7 +95,6 @@
 	@  - Write permission implies XN: disabled
 	@  - Instruction cache: enabled
 	@  - Data/Unified cache: enabled
-	@  - Memory alignment checks: enabled
 	@  - MMU: enabled (this code must be run from an identity mapping)
 	mrc	p15, 4, r0, c1, c0, 0	@ HSCR
 	ldr	r2, =HSCTLR_MASK
@@ -103,8 +102,8 @@
 	mrc	p15, 0, r1, c1, c0, 0	@ SCTLR
 	ldr	r2, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C)
 	and	r1, r1, r2
- ARM(	ldr	r2, =(HSCTLR_M | HSCTLR_A)			)
- THUMB(	ldr	r2, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE)		)
+ ARM(	ldr	r2, =(HSCTLR_M)					)
+ THUMB(	ldr	r2, =(HSCTLR_M | HSCTLR_TE)			)
 	orr	r1, r1, r2
 	orr	r0, r0, r1
 	mcr	p15, 4, r0, c1, c0, 0	@ HSCR
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 2fd5c13..332ce3b 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -872,6 +872,9 @@
 	pmd_t *pmd;
 
 	pud = stage2_get_pud(kvm, cache, addr);
+	if (!pud)
+		return NULL;
+
 	if (stage2_pud_none(*pud)) {
 		if (!cache)
 			return NULL;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4001dd1..5cbfd9f 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1152,13 +1152,12 @@
 
 phys_addr_t arm_lowmem_limit __initdata = 0;
 
-void __init sanity_check_meminfo(void)
+void __init adjust_lowmem_bounds(void)
 {
 	phys_addr_t memblock_limit = 0;
-	int highmem = 0;
 	u64 vmalloc_limit;
 	struct memblock_region *reg;
-	bool should_use_highmem = false;
+	phys_addr_t lowmem_limit = 0;
 
 	/*
 	 * Let's use our own (unoptimized) equivalent of __pa() that is
@@ -1172,43 +1171,18 @@
 	for_each_memblock(memory, reg) {
 		phys_addr_t block_start = reg->base;
 		phys_addr_t block_end = reg->base + reg->size;
-		phys_addr_t size_limit = reg->size;
 
-		if (reg->base >= vmalloc_limit)
-			highmem = 1;
-		else
-			size_limit = vmalloc_limit - reg->base;
-
-
-		if (!IS_ENABLED(CONFIG_HIGHMEM) || cache_is_vipt_aliasing()) {
-
-			if (highmem) {
-				pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
-					  &block_start, &block_end);
-				memblock_remove(reg->base, reg->size);
-				should_use_highmem = true;
-				continue;
-			}
-
-			if (reg->size > size_limit) {
-				phys_addr_t overlap_size = reg->size - size_limit;
-
-				pr_notice("Truncating RAM at %pa-%pa",
-					  &block_start, &block_end);
-				block_end = vmalloc_limit;
-				pr_cont(" to -%pa", &block_end);
-				memblock_remove(vmalloc_limit, overlap_size);
-				should_use_highmem = true;
-			}
-		}
-
-		if (!highmem) {
-			if (block_end > arm_lowmem_limit) {
-				if (reg->size > size_limit)
-					arm_lowmem_limit = vmalloc_limit;
-				else
-					arm_lowmem_limit = block_end;
-			}
+		if (reg->base < vmalloc_limit) {
+			if (block_end > lowmem_limit)
+				/*
+				 * Compare as u64 to ensure vmalloc_limit does
+				 * not get truncated. block_end should always
+				 * fit in phys_addr_t so there should be no
+				 * issue with assignment.
+				 */
+				lowmem_limit = min_t(u64,
+							 vmalloc_limit,
+							 block_end);
 
 			/*
 			 * Find the first non-pmd-aligned page, and point
@@ -1227,14 +1201,13 @@
 				if (!IS_ALIGNED(block_start, PMD_SIZE))
 					memblock_limit = block_start;
 				else if (!IS_ALIGNED(block_end, PMD_SIZE))
-					memblock_limit = arm_lowmem_limit;
+					memblock_limit = lowmem_limit;
 			}
 
 		}
 	}
 
-	if (should_use_highmem)
-		pr_notice("Consider using a HIGHMEM enabled kernel.\n");
+	arm_lowmem_limit = lowmem_limit;
 
 	high_memory = __va(arm_lowmem_limit - 1) + 1;
 
@@ -1248,6 +1221,18 @@
 	if (!memblock_limit)
 		memblock_limit = arm_lowmem_limit;
 
+	if (!IS_ENABLED(CONFIG_HIGHMEM) || cache_is_vipt_aliasing()) {
+		if (memblock_end_of_DRAM() > arm_lowmem_limit) {
+			phys_addr_t end = memblock_end_of_DRAM();
+
+			pr_notice("Ignoring RAM at %pa-%pa\n",
+				  &memblock_limit, &end);
+			pr_notice("Consider using a HIGHMEM enabled kernel.\n");
+
+			memblock_remove(memblock_limit, end - memblock_limit);
+		}
+	}
+
 	memblock_set_current_limit(memblock_limit);
 }
 
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 2740967..13a25d6 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -85,7 +85,7 @@
 }
 
 /* MPU initialisation functions */
-void __init sanity_check_meminfo_mpu(void)
+void __init adjust_lowmem_bounds_mpu(void)
 {
 	phys_addr_t phys_offset = PHYS_OFFSET;
 	phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size;
@@ -274,7 +274,7 @@
 	}
 }
 #else
-static void sanity_check_meminfo_mpu(void) {}
+static void adjust_lowmem_bounds_mpu(void) {}
 static void __init mpu_setup(void) {}
 #endif /* CONFIG_ARM_MPU */
 
@@ -295,10 +295,10 @@
 #endif
 }
 
-void __init sanity_check_meminfo(void)
+void __init adjust_lowmem_bounds(void)
 {
 	phys_addr_t end;
-	sanity_check_meminfo_mpu();
+	adjust_lowmem_bounds_mpu();
 	end = memblock_end_of_DRAM();
 	high_memory = __va(end - 1) + 1;
 	memblock_set_current_limit(end);
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 7ad029a..3c8eaf8 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -10,6 +10,7 @@
 	sdm845-v2-mtp.dtb \
 	sdm845-v2-cdp.dtb \
 	sdm845-qrd.dtb \
+	sdm845-v2-qrd.dtb \
 	sdm845-4k-panel-mtp.dtb \
 	sdm845-4k-panel-cdp.dtb \
 	sdm845-4k-panel-qrd.dtb
@@ -17,10 +18,12 @@
 ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
 	dtbo-$(CONFIG_ARCH_SDM845) += \
 		sdm845-cdp-overlay.dtbo \
-		sdm845-mtp-overlay.dtbo
+		sdm845-mtp-overlay.dtbo \
+		sdm845-qrd-overlay.dtbo
 
 sdm845-cdp-overlay.dtbo-base := sdm845.dtb
 sdm845-mtp-overlay.dtbo-base := sdm845.dtb
+sdm845-qrd-overlay.dtbo-base := sdm845.dtb
 endif
 
 dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi
index aa52083..c2b054a 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi
@@ -50,6 +50,7 @@
 			15 01 00 00 00 00 02 ff f0
 			15 01 00 00 00 00 02 92 01
 			15 01 00 00 00 00 02 ff 10
+			15 01 00 00 00 00 02 35 00 /* enable TE generation */
 			05 01 00 00 28 00 01 29];
 		qcom,mdss-dsi-off-command = [
 			05 01 00 00 10 00 01 28
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
index 061f1d9..6534cdc 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
@@ -40,7 +40,7 @@
 		qcom,mdss-dsi-lane-3-state;
 		qcom,mdss-dsi-dma-trigger = "trigger_sw";
 		qcom,mdss-dsi-mdp-trigger = "none";
-		qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>;
+		qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>;
 		qcom,mdss-dsi-te-pin-select = <1>;
 		qcom,mdss-dsi-wr-mem-start = <0x2c>;
 		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi
new file mode 100644
index 0000000..8e5d854
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi
@@ -0,0 +1,316 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/msm/msm-bus-ids.h>
+
+&soc {
+	kgsl_smmu: arm,smmu-kgsl@5040000 {
+		status = "ok";
+		compatible = "qcom,smmu-v2";
+		reg = <0x5040000 0x10000>;
+		#iommu-cells = <1>;
+		qcom,dynamic;
+		qcom,use-3-lvl-tables;
+		#global-interrupts = <2>;
+		qcom,regulator-names = "vdd";
+		vdd-supply = <&gpu_cx_gdsc>;
+		interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 364 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 365 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 366 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 367 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 368 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 369 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 370 IRQ_TYPE_EDGE_RISING>,
+				<GIC_SPI 371 IRQ_TYPE_EDGE_RISING>;
+		clock-names = "gcc_ddrss_gpu_axi_clk",
+				"gcc_gpu_memnoc_gfx_clk",
+				"gpu_cc_ahb_clk",
+				"gpu_cc_cx_gmu_clk";
+		clocks = <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+			<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+			<&clock_gpucc GPU_CC_AHB_CLK>,
+			<&clock_gpucc GPU_CC_CX_GMU_CLK>;
+		attach-impl-defs =
+				<0x6000 0x2378>,
+				<0x6060 0x1055>,
+				<0x678c 0x8>,
+				<0x6794 0x28>,
+				<0x6800 0x6>,
+				<0x6900 0x3ff>,
+				<0x6924 0x204>,
+				<0x6928 0x11000>,
+				<0x6930 0x800>,
+				<0x6960 0xffffffff>,
+				<0x6b64 0x1a5551>,
+				<0x6b68 0x9a82a382>;
+	};
+
+	apps_smmu: apps-smmu@0x15000000 {
+		compatible = "qcom,qsmmu-v500";
+		reg = <0x15000000 0x80000>,
+			<0x150c2000 0x18>;
+		reg-names = "base", "tcu-base";
+		#iommu-cells = <2>;
+		qcom,skip-init;
+		qcom,use-3-lvl-tables;
+		#global-interrupts = <1>;
+		#size-cells = <1>;
+		#address-cells = <1>;
+		ranges;
+		interrupts =	<GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 186 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>;
+		qcom,msm-bus,name = "apps_smmu";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<MSM_BUS_MASTER_GNOC_SNOC>,
+			<MSM_BUS_SLAVE_IMEM_CFG>,
+			<0 0>,
+			<MSM_BUS_MASTER_GNOC_SNOC>,
+			<MSM_BUS_SLAVE_IMEM_CFG>,
+			<0 1000>;
+
+		anoc_1_tbu: anoc_1_tbu@0x150c5000 {
+			compatible = "qcom,qsmmuv500-tbu";
+			reg = <0x150c5000 0x1000>,
+				<0x150c2200 0x8>;
+			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x0 0x400>;
+			qcom,regulator-names = "vdd";
+			vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu1_gdsc>;
+			qcom,msm-bus,name = "apps_smmu";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<MSM_BUS_MASTER_GNOC_SNOC>,
+				<MSM_BUS_SLAVE_IMEM_CFG>,
+				<0 0>,
+				<MSM_BUS_MASTER_GNOC_SNOC>,
+				<MSM_BUS_SLAVE_IMEM_CFG>,
+				<0 1000>;
+		};
+
+		anoc_2_tbu: anoc_2_tbu@0x150c9000 {
+			compatible = "qcom,qsmmuv500-tbu";
+			reg = <0x150c9000 0x1000>,
+				<0x150c2208 0x8>;
+			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x400 0x400>;
+			qcom,regulator-names = "vdd";
+			vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu2_gdsc>;
+			qcom,msm-bus,name = "apps_smmu";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<MSM_BUS_MASTER_GNOC_SNOC>,
+				<MSM_BUS_SLAVE_IMEM_CFG>,
+				<0 0>,
+				<MSM_BUS_MASTER_GNOC_SNOC>,
+				<MSM_BUS_SLAVE_IMEM_CFG>,
+				<0 1000>;
+		};
+
+		mnoc_hf_0_tbu: mnoc_hf_0_tbu@0x150cd000 {
+			compatible = "qcom,qsmmuv500-tbu";
+			reg = <0x150cd000 0x1000>,
+				<0x150c2210 0x8>;
+			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x800 0x400>;
+			qcom,regulator-names = "vdd";
+			vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc>;
+			qcom,msm-bus,name = "mnoc_hf_0_tbu";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<MSM_BUS_MASTER_MDP_PORT0>,
+				<MSM_BUS_SLAVE_MNOC_HF_MEM_NOC>,
+				<0 0>,
+				<MSM_BUS_MASTER_MDP_PORT0>,
+				<MSM_BUS_SLAVE_MNOC_HF_MEM_NOC>,
+				<0 1000>;
+		};
+
+		mnoc_hf_1_tbu: mnoc_hf_1_tbu@0x150d1000 {
+			compatible = "qcom,qsmmuv500-tbu";
+			reg = <0x150d1000 0x1000>,
+				<0x150c2218 0x8>;
+			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0xc00 0x400>;
+			qcom,regulator-names = "vdd";
+			vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc>;
+			qcom,msm-bus,name = "mnoc_hf_1_tbu";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<MSM_BUS_MASTER_MDP_PORT0>,
+				<MSM_BUS_SLAVE_MNOC_HF_MEM_NOC>,
+				<0 0>,
+				<MSM_BUS_MASTER_MDP_PORT0>,
+				<MSM_BUS_SLAVE_MNOC_HF_MEM_NOC>,
+				<0 1000>;
+		};
+
+		mnoc_sf_0_tbu: mnoc_sf_0_tbu@0x150d5000 {
+			compatible = "qcom,qsmmuv500-tbu";
+			reg = <0x150d5000 0x1000>,
+				<0x150c2220 0x8>;
+			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x1000 0x400>;
+			qcom,regulator-names = "vdd";
+			vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>;
+			qcom,msm-bus,name = "mnoc_sf_0_tbu";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<MSM_BUS_MASTER_CAMNOC_SF>,
+				<MSM_BUS_SLAVE_MNOC_SF_MEM_NOC>,
+				<0 0>,
+				<MSM_BUS_MASTER_CAMNOC_SF>,
+				<MSM_BUS_SLAVE_MNOC_SF_MEM_NOC>,
+				<0 1000>;
+		};
+
+		compute_dsp_tbu: compute_dsp_tbu@0x150d9000 {
+			compatible = "qcom,qsmmuv500-tbu";
+			reg = <0x150d9000 0x1000>,
+				<0x150c2228 0x8>;
+			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x1400 0x400>;
+			/* No GDSC */
+			qcom,msm-bus,name = "apps_smmu";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<MSM_BUS_MASTER_GNOC_SNOC>,
+				<MSM_BUS_SLAVE_IMEM_CFG>,
+				<0 0>,
+				<MSM_BUS_MASTER_GNOC_SNOC>,
+				<MSM_BUS_SLAVE_IMEM_CFG>,
+				<0 1000>;
+		};
+
+		adsp_tbu: adsp_tbu@0x150dd000 {
+			compatible = "qcom,qsmmuv500-tbu";
+			reg = <0x150dd000 0x1000>,
+				<0x150c2230 0x8>;
+			reg-names = "base", "status-reg";
+			qcom,stream-id-range = <0x1800 0x400>;
+			qcom,regulator-names = "vdd";
+			vdd-supply = <&hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc>;
+			qcom,msm-bus,name = "apps_smmu";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<MSM_BUS_MASTER_GNOC_SNOC>,
+				<MSM_BUS_SLAVE_IMEM_CFG>,
+				<0 0>,
+				<MSM_BUS_MASTER_GNOC_SNOC>,
+				<MSM_BUS_SLAVE_IMEM_CFG>,
+				<0 1000>;
+		};
+
+	};
+
+	kgsl_iommu_test_device {
+		compatible = "iommu-debug-test";
+		/*
+		 * 0x7 isn't a valid sid, but should pass the sid sanity check.
+		 * We just need _something_ here to get this node recognized by
+		 * the SMMU driver. Our test uses ATOS, which doesn't use SIDs
+		 * anyways, so using a dummy value is ok.
+		 */
+		iommus = <&kgsl_smmu 0x7>;
+	};
+
+	apps_iommu_test_device {
+		compatible = "iommu-debug-test";
+		/*
+		 * This SID belongs to QUP1-GSI. We can't use a fake SID for
+		 * the apps_smmu device.
+		 */
+		iommus = <&apps_smmu 0x16 0x0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 0c2ae5f..1a2ca5b 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -63,6 +63,7 @@
 			<0x150c2000 0x20>;
 		reg-names = "base", "tcu-base";
 		#iommu-cells = <2>;
+		qcom,skip-init;
 		qcom,use-3-lvl-tables;
 		#global-interrupts = <1>;
 		#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
index 655f447..bc0b118 100644
--- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -377,14 +377,15 @@
 		qcom,msm-cpudai-tdm-group-num-ports = <1>;
 		qcom,msm-cpudai-tdm-group-port-id = <36864>;
 		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
 		dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36864>;
-			qcom,msm-cpudai-tdm-sync-mode = <1>;
-			qcom,msm-cpudai-tdm-sync-src = <1>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <1>;
-			qcom,msm-cpudai-tdm-data-delay = <1>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
@@ -395,14 +396,15 @@
 		qcom,msm-cpudai-tdm-group-num-ports = <1>;
 		qcom,msm-cpudai-tdm-group-port-id = <36865>;
 		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
 		dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36865>;
-			qcom,msm-cpudai-tdm-sync-mode = <1>;
-			qcom,msm-cpudai-tdm-sync-src = <1>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <1>;
-			qcom,msm-cpudai-tdm-data-delay = <1>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
@@ -413,14 +415,15 @@
 		qcom,msm-cpudai-tdm-group-num-ports = <1>;
 		qcom,msm-cpudai-tdm-group-port-id = <36880>;
 		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
 		dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36880>;
-			qcom,msm-cpudai-tdm-sync-mode = <1>;
-			qcom,msm-cpudai-tdm-sync-src = <1>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <1>;
-			qcom,msm-cpudai-tdm-data-delay = <1>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
@@ -431,14 +434,15 @@
 		qcom,msm-cpudai-tdm-group-num-ports = <1>;
 		qcom,msm-cpudai-tdm-group-port-id = <36881>;
 		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
 		dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36881>;
-			qcom,msm-cpudai-tdm-sync-mode = <1>;
-			qcom,msm-cpudai-tdm-sync-src = <1>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <1>;
-			qcom,msm-cpudai-tdm-data-delay = <1>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
@@ -449,14 +453,15 @@
 		qcom,msm-cpudai-tdm-group-num-ports = <1>;
 		qcom,msm-cpudai-tdm-group-port-id = <36896>;
 		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
 		dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36896>;
-			qcom,msm-cpudai-tdm-sync-mode = <1>;
-			qcom,msm-cpudai-tdm-sync-src = <1>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <1>;
-			qcom,msm-cpudai-tdm-data-delay = <1>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
@@ -467,14 +472,15 @@
 		qcom,msm-cpudai-tdm-group-num-ports = <1>;
 		qcom,msm-cpudai-tdm-group-port-id = <36897 >;
 		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
 		dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36897 >;
-			qcom,msm-cpudai-tdm-sync-mode = <1>;
-			qcom,msm-cpudai-tdm-sync-src = <1>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <1>;
-			qcom,msm-cpudai-tdm-data-delay = <1>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
@@ -485,14 +491,15 @@
 		qcom,msm-cpudai-tdm-group-num-ports = <1>;
 		qcom,msm-cpudai-tdm-group-port-id = <36912>;
 		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
 		dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36912>;
-			qcom,msm-cpudai-tdm-sync-mode = <1>;
-			qcom,msm-cpudai-tdm-sync-src = <1>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <1>;
-			qcom,msm-cpudai-tdm-data-delay = <1>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
@@ -503,14 +510,15 @@
 		qcom,msm-cpudai-tdm-group-num-ports = <1>;
 		qcom,msm-cpudai-tdm-group-port-id = <36913 >;
 		qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+		qcom,msm-cpudai-tdm-clk-internal = <1>;
+		qcom,msm-cpudai-tdm-sync-mode = <1>;
+		qcom,msm-cpudai-tdm-sync-src = <1>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <1>;
+		qcom,msm-cpudai-tdm-data-delay = <1>;
 		dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36913 >;
-			qcom,msm-cpudai-tdm-sync-mode = <1>;
-			qcom,msm-cpudai-tdm-sync-src = <1>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <1>;
-			qcom,msm-cpudai-tdm-data-delay = <1>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi
new file mode 100644
index 0000000..2b8f22e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi
@@ -0,0 +1,75 @@
+/* Copyright (c) 2017, 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.
+ */
+
+&soc {
+	smp2pgpio_rdbg_2_in: qcom,smp2pgpio-rdbg-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "rdbg";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_client_rdbg_2_in {
+		compatible = "qcom,smp2pgpio_client_rdbg_2_in";
+		gpios = <&smp2pgpio_rdbg_2_in 0 0>;
+	};
+
+	smp2pgpio_rdbg_2_out: qcom,smp2pgpio-rdbg-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "rdbg";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_client_rdbg_2_out {
+		compatible = "qcom,smp2pgpio_client_rdbg_2_out";
+		gpios = <&smp2pgpio_rdbg_2_out 0 0>;
+	};
+
+	smp2pgpio_rdbg_1_in: qcom,smp2pgpio-rdbg-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "rdbg";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_client_rdbg_1_in {
+		compatible = "qcom,smp2pgpio_client_rdbg_1_in";
+		gpios = <&smp2pgpio_rdbg_1_in 0 0>;
+	};
+
+	smp2pgpio_rdbg_1_out: qcom,smp2pgpio-rdbg-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "rdbg";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_client_rdbg_1_out {
+		compatible = "qcom,smp2pgpio_client_rdbg_1_out";
+		gpios = <&smp2pgpio_rdbg_1_out 0 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
new file mode 100644
index 0000000..4abf260
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -0,0 +1,633 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+&spmi_bus {
+	qcom,pm660@0 {
+		compatible ="qcom,spmi-pmic";
+		reg = <0x0 SPMI_USID>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		pm660_revid: qcom,revid@100 {
+			compatible = "qcom,qpnp-revid";
+			reg = <0x100 0x100>;
+			qcom,fab-id-valid;
+		};
+
+		pm660_misc: qcom,misc@900 {
+			compatible = "qcom,qpnp-misc";
+			reg = <0x900 0x100>;
+		};
+
+		qcom,power-on@800 {
+			compatible = "qcom,qpnp-power-on";
+			reg = <0x800 0x100>;
+			interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>,
+				     <0x0 0x8 0x1 IRQ_TYPE_NONE>,
+				     <0x0 0x8 0x4 IRQ_TYPE_NONE>,
+				     <0x0 0x8 0x5 IRQ_TYPE_NONE>;
+			interrupt-names = "kpdpwr", "resin",
+					"resin-bark", "kpdpwr-resin-bark";
+			qcom,pon-dbc-delay = <15625>;
+			qcom,kpdpwr-sw-debounce;
+			qcom,system-reset;
+			qcom,store-hard-reset-reason;
+
+			qcom,pon_1 {
+				qcom,pon-type = <0>;
+				qcom,pull-up = <1>;
+				linux,code = <116>;
+			};
+
+			qcom,pon_2 {
+				qcom,pon-type = <1>;
+				qcom,pull-up = <1>;
+				linux,code = <114>;
+			};
+		};
+
+		qcom,temp-alarm@2400 {
+			compatible = "qcom,qpnp-temp-alarm";
+			reg = <0x2400 0x100>;
+			interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
+			label = "pm660_tz";
+			qcom,channel-num = <6>;
+			qcom,temp_alarm-vadc = <&pm660_vadc>;
+		};
+
+		pm660_gpios: gpios {
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm660-gpio";
+
+			gpio@c000 {
+				reg = <0xc000 0x100>;
+				qcom,pin-num = <1>;
+				status = "disabled";
+			};
+
+			gpio@c100 {
+				reg = <0xc100 0x100>;
+				qcom,pin-num = <2>;
+				status = "disabled";
+			};
+
+			gpio@c200 {
+				reg = <0xc200 0x100>;
+				qcom,pin-num = <3>;
+				status = "disabled";
+			};
+
+			gpio@c300 {
+				reg = <0xc300 0x100>;
+				qcom,pin-num = <4>;
+				status = "disabled";
+			};
+
+			gpio@c400 {
+				reg = <0xc400 0x100>;
+				qcom,pin-num = <5>;
+				status = "disabled";
+			};
+
+			gpio@c500 {
+				reg = <0xc500 0x100>;
+				qcom,pin-num = <6>;
+				status = "disabled";
+			};
+
+			gpio@c600 {
+				reg = <0xc600 0x100>;
+				qcom,pin-num = <7>;
+				status = "disabled";
+			};
+
+			gpio@c700 {
+				reg = <0xc700 0x100>;
+				qcom,pin-num = <8>;
+				status = "disabled";
+			};
+
+			gpio@c800 {
+				reg = <0xc800 0x100>;
+				qcom,pin-num = <9>;
+				status = "disabled";
+			};
+
+			gpio@c900 {
+				reg = <0xc900 0x100>;
+				qcom,pin-num = <10>;
+				status = "disabled";
+			};
+
+			gpio@ca00 {
+				reg = <0xca00 0x100>;
+				qcom,pin-num = <11>;
+				status = "disabled";
+			};
+
+			gpio@cb00 {
+				reg = <0xcb00 0x100>;
+				qcom,pin-num = <12>;
+				status = "disabled";
+			};
+
+			gpio@cc00 {
+				reg = <0xcc00 0x100>;
+				qcom,pin-num = <13>;
+				status = "disabled";
+			};
+		};
+
+		pm660_coincell: qcom,coincell@2800 {
+			compatible = "qcom,qpnp-coincell";
+			reg = <0x2800 0x100>;
+		};
+
+		pm660_rtc: qcom,pm660_rtc {
+			compatible = "qcom,qpnp-rtc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			qcom,qpnp-rtc-write = <0>;
+			qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+			qcom,pm660_rtc_rw@6000 {
+				reg = <0x6000 0x100>;
+			};
+			qcom,pm660_rtc_alarm@6100 {
+				reg = <0x6100 0x100>;
+				interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
+			};
+		};
+
+		pm660_vadc: vadc@3100 {
+			compatible = "qcom,qpnp-vadc-hc";
+			reg = <0x3100 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "eoc-int-en-set";
+			qcom,adc-bit-resolution = <15>;
+			qcom,adc-vdd-reference = <1875>;
+
+			chan@6 {
+				label = "die_temp";
+				reg = <6>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <3>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@0 {
+				label = "ref_gnd";
+				reg = <0>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@1 {
+				label = "ref_1250v";
+				reg = <1>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@83 {
+				label = "vph_pwr";
+				reg = <0x83>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@85 {
+				label = "vcoin";
+				reg = <0x85>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@4c {
+				label = "xo_therm";
+				reg = <0x4c>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <4>;
+				qcom,hw-settle-time = <2>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@4d {
+				label = "msm_therm";
+				reg = <0x4d>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <2>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@51 {
+				label = "quiet_therm";
+				reg = <0x51>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <2>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@4e {
+				label = "emmc_therm";
+				reg = <0x4e>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <2>;
+				qcom,fast-avg-setup = <0>;
+				qcom,vadc-thermal-node;
+			};
+
+			chan@4f {
+				label = "pa_therm0";
+				reg = <0x4f>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <2>;
+				qcom,fast-avg-setup = <0>;
+				qcom,vadc-thermal-node;
+			};
+
+			chan@1d {
+				label = "drax_temp";
+				reg = <0x1d>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <3>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+		};
+
+		pm660_charger: qcom,qpnp-smb2 {
+			compatible = "qcom,qpnp-smb2";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qcom,pmic-revid = <&pm660_revid>;
+
+			io-channels = <&pm660_rradc 8>,
+				      <&pm660_rradc 10>,
+				      <&pm660_rradc 3>,
+				      <&pm660_rradc 4>;
+			io-channel-names = "charger_temp",
+					   "charger_temp_max",
+					   "usbin_i",
+					   "usbin_v";
+
+			qcom,wipower-max-uw = <5000000>;
+
+			/* Enable after the qusb_phy0 device node is added */
+			/* dpdm-supply = <&qusb_phy0>; */
+
+			qcom,thermal-mitigation
+					= <3000000 2500000 2000000 1500000
+						1000000 500000>;
+
+			qcom,chgr@1000 {
+				reg = <0x1000 0x100>;
+				interrupts =
+					<0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "chg-error",
+						  "chg-state-change",
+						  "step-chg-state-change",
+						  "step-chg-soc-update-fail",
+						  "step-chg-soc-update-request";
+			};
+
+			qcom,otg@1100 {
+				reg = <0x1100 0x100>;
+				interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
+
+				interrupt-names = "otg-fail",
+						  "otg-overcurrent",
+						  "otg-oc-dis-sw-sts",
+						  "testmode-change-detect";
+			};
+
+			qcom,bat-if@1200 {
+				reg = <0x1200 0x100>;
+				interrupts =
+					<0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
+
+				interrupt-names = "bat-temp",
+						  "bat-ocp",
+						  "bat-ov",
+						  "bat-low",
+						  "bat-therm-or-id-missing",
+						  "bat-terminal-missing";
+			};
+
+			qcom,usb-chgpth@1300 {
+				reg = <0x1300 0x100>;
+				interrupts =
+					<0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "usbin-collapse",
+						  "usbin-lt-3p6v",
+						  "usbin-uv",
+						  "usbin-ov",
+						  "usbin-plugin",
+						  "usbin-src-change",
+						  "usbin-icl-change",
+						  "type-c-change";
+			};
+
+			qcom,dc-chgpth@1400 {
+				reg = <0x1400 0x100>;
+				interrupts =
+					<0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "dcin-collapse",
+						  "dcin-lt-3p6v",
+						  "dcin-uv",
+						  "dcin-ov",
+						  "dcin-plugin",
+						  "div2-en-dg",
+						  "dcin-icl-change";
+			};
+
+			qcom,chgr-misc@1600 {
+				reg = <0x1600 0x100>;
+				interrupts =
+					<0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+					<0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+				interrupt-names = "wdog-snarl",
+						  "wdog-bark",
+						  "aicl-fail",
+						  "aicl-done",
+						  "high-duty-cycle",
+						  "input-current-limiting",
+						  "temperature-change",
+						  "switcher-power-ok";
+			};
+		};
+
+		pm660_pdphy: qcom,usb-pdphy@1700 {
+			compatible = "qcom,qpnp-pdphy";
+			reg = <0x1700 0x100>;
+			vdd-pdphy-supply = <&pm660l_l7>;
+			vbus-supply = <&smb2_vbus>;
+			vconn-supply = <&smb2_vconn>;
+			interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x17 0x3 IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x17 0x4 IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x17 0x5 IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x17 0x6 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "sig-tx",
+					  "sig-rx",
+					  "msg-tx",
+					  "msg-rx",
+					  "msg-tx-failed",
+					  "msg-tx-discarded",
+					  "msg-rx-discarded";
+
+			qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */
+						 <9000 3000>; /* 9V @ 3A */
+		};
+
+		pm660_adc_tm: vadc@3400 {
+			compatible = "qcom,qpnp-adc-tm-hc";
+			reg = <0x3400 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "eoc-int-en-set";
+			qcom,adc-bit-resolution = <15>;
+			qcom,adc-vdd-reference = <1875>;
+			qcom,adc_tm-vadc = <&pm660_vadc>;
+			qcom,decimation = <0>;
+			qcom,fast-avg-setup = <0>;
+
+			chan@83 {
+				label = "vph_pwr";
+				reg = <0x83>;
+				qcom,pre-div-channel-scaling = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,btm-channel-number = <0x60>;
+			};
+
+			chan@4d {
+				label = "msm_therm";
+				reg = <0x4d>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <2>;
+				qcom,btm-channel-number = <0x68>;
+				qcom,thermal-node;
+			};
+
+			chan@51 {
+				label = "quiet_therm";
+				reg = <0x51>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <2>;
+				qcom,btm-channel-number = <0x70>;
+				qcom,thermal-node;
+			};
+
+			chan@4c {
+				label = "xo_therm";
+				reg = <0x4c>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <4>;
+				qcom,hw-settle-time = <2>;
+				qcom,btm-channel-number = <0x78>;
+				qcom,thermal-node;
+			};
+		};
+
+		pm660_rradc: rradc@4500 {
+			compatible = "qcom,rradc";
+			reg = <0x4500 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#io-channel-cells = <1>;
+			qcom,pmic-revid = <&pm660_revid>;
+		};
+
+		pm660_fg: qpnp,fg {
+			compatible = "qcom,fg-gen3";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			qcom,pmic-revid = <&pm660_revid>;
+			io-channels = <&pm660_rradc 0>,
+				      <&pm660_rradc 7>;
+			io-channel-names = "rradc_batt_id",
+					   "rradc_die_temp";
+			qcom,rradc-base = <0x4500>;
+			qcom,fg-esr-timer-awake = <96 96>;
+			qcom,fg-esr-timer-asleep = <256 256>;
+			qcom,fg-esr-timer-charging = <0 96>;
+			qcom,cycle-counter-en;
+			status = "okay";
+
+			qcom,fg-batt-soc@4000 {
+				status = "okay";
+				reg = <0x4000 0x100>;
+				interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x40 0x2
+							IRQ_TYPE_EDGE_RISING>,
+					     <0x0 0x40 0x3
+							IRQ_TYPE_EDGE_RISING>,
+					     <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x40 0x5
+							IRQ_TYPE_EDGE_RISING>,
+					     <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
+				interrupt-names = "soc-update",
+						  "soc-ready",
+						  "bsoc-delta",
+						  "msoc-delta",
+						  "msoc-low",
+						  "msoc-empty",
+						  "msoc-high",
+						  "msoc-full";
+			};
+
+			qcom,fg-batt-info@4100 {
+				status = "okay";
+				reg = <0x4100 0x100>;
+				interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
+				interrupt-names = "vbatt-pred-delta",
+						  "vbatt-low",
+						  "esr-delta",
+						  "batt-missing",
+						  "batt-temp-delta";
+			};
+
+			qcom,fg-memif@4400 {
+				status = "okay";
+				reg = <0x4400 0x100>;
+				interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
+					     <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
+				interrupt-names = "ima-rdy",
+						  "mem-xcp",
+						  "dma-grant";
+			};
+		};
+
+		bcl@4200 {
+			compatible = "qcom,msm-bcl-lmh";
+			reg = <0x4200 0xff>,
+				<0x4300 0xff>;
+			reg-names = "fg_user_adc",
+					"fg_lmh";
+			interrupts = <0x0 0x42 0x0 IRQ_TYPE_NONE>,
+					<0x0 0x42 0x2 IRQ_TYPE_NONE>;
+			interrupt-names = "bcl-high-ibat-int",
+					"bcl-low-vbat-int";
+			qcom,vbat-polling-delay-ms = <100>;
+			qcom,ibat-polling-delay-ms = <100>;
+		};
+	};
+
+	qcom,pm660@1 {
+		compatible ="qcom,spmi-pmic";
+		reg = <0x1 SPMI_USID>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pm660a.dtsi b/arch/arm64/boot/dts/qcom/pm660a.dtsi
new file mode 100644
index 0000000..bfe1b5a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm660a.dtsi
@@ -0,0 +1,29 @@
+/* Copyright (c) 2016-2017, 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.
+ */
+
+/* Disable WLED */
+&pm660l_wled {
+	status = "disabled";
+};
+
+/* disable LCDB */
+&pm660l_lcdb {
+	status = "disabled";
+};
+
+&pm660a_oledb {
+	status = "okay";
+};
+
+&pm660a_labibb {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi
new file mode 100644
index 0000000..0f18ba5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi
@@ -0,0 +1,470 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/msm/power-on.h>
+
+&spmi_bus {
+	qcom,pm660l@2 {
+		compatible = "qcom,spmi-pmic";
+		reg = <0x2 SPMI_USID>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		pm660l_revid: qcom,revid@100 {
+			compatible = "qcom,qpnp-revid";
+			reg = <0x100 0x100>;
+		};
+
+		pm660l_pbs: qcom,pbs@7300 {
+			compatible = "qcom,qpnp-pbs";
+			reg = <0x7300 0x100>;
+		};
+
+		qcom,power-on@800 {
+			compatible = "qcom,qpnp-power-on";
+			reg = <0x800 0x100>;
+			qcom,secondary-pon-reset;
+			qcom,hard-reset-poweroff-type =
+				<PON_POWER_OFF_SHUTDOWN>;
+		};
+
+		qcom,temp-alarm@2400 {
+			compatible = "qcom,qpnp-temp-alarm";
+			reg = <0x2400 0x100>;
+			interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
+			label = "pm660l_tz";
+		};
+
+		pm660l_gpios: gpios {
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm660l-gpio";
+
+			gpio@c000 {
+				reg = <0xc000 0x100>;
+				qcom,pin-num = <1>;
+				status = "disabled";
+			};
+
+			gpio@c100 {
+				reg = <0xc100 0x100>;
+				qcom,pin-num = <2>;
+				status = "disabled";
+			};
+
+			gpio@c200 {
+				reg = <0xc200 0x100>;
+				qcom,pin-num = <3>;
+				status = "disabled";
+			};
+
+			gpio@c300 {
+				reg = <0xc300 0x100>;
+				qcom,pin-num = <4>;
+				status = "disabled";
+			};
+
+			gpio@c400 {
+				reg = <0xc400 0x100>;
+				qcom,pin-num = <5>;
+				status = "disabled";
+			};
+
+			gpio@c500 {
+				reg = <0xc500 0x100>;
+				qcom,pin-num = <6>;
+				status = "disabled";
+			};
+
+			gpio@c600 {
+				reg = <0xc600 0x100>;
+				qcom,pin-num = <7>;
+				status = "disabled";
+			};
+
+			gpio@c700 {
+				reg = <0xc700 0x100>;
+				qcom,pin-num = <8>;
+				status = "disabled";
+			};
+
+			gpio@c800 {
+				reg = <0xc800 0x100>;
+				qcom,pin-num = <9>;
+				status = "disabled";
+			};
+
+			gpio@c900 {
+				reg = <0xc900 0x100>;
+				qcom,pin-num = <10>;
+				status = "disabled";
+			};
+
+			gpio@ca00 {
+				reg = <0xca00 0x100>;
+				qcom,pin-num = <11>;
+				status = "disabled";
+			};
+
+			gpio@cb00 {
+				reg = <0xcb00 0x100>;
+				qcom,pin-num = <12>;
+				status = "disabled";
+			};
+
+		};
+	};
+
+	pm660l_3: qcom,pm660l@3 {
+		compatible ="qcom,spmi-pmic";
+		reg = <0x3 SPMI_USID>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		pm660l_pwm_1: pwm@b100 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb100 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base",
+					"qpnp-lpg-lut-base";
+			qcom,channel-id = <1>;
+			qcom,lpg-lut-size = <0x7e>;
+			qcom,supported-sizes = <6>, <9>;
+			qcom,ramp-index = <0>;
+			#pwm-cells = <2>;
+		};
+
+		pm660l_pwm_2: pwm@b200 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb200 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base",
+					 "qpnp-lpg-lut-base";
+			qcom,channel-id = <2>;
+			qcom,lpg-lut-size = <0x7e>;
+			qcom,supported-sizes = <6>, <9>;
+			qcom,ramp-index = <1>;
+			#pwm-cells = <2>;
+		};
+
+		pm660l_pwm_3: pwm@b300 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb300 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base",
+					 "qpnp-lpg-lut-base";
+			qcom,channel-id = <3>;
+			qcom,lpg-lut-size = <0x7e>;
+			qcom,supported-sizes = <6>, <9>;
+			qcom,ramp-index = <2>;
+			#pwm-cells = <2>;
+			qcom,period = <6000000>;
+
+			qcom,lpg {
+				label = "lpg";
+				cell-index = <0>;
+				qcom,duty-percents =
+					<0x01 0x0a 0x14 0x1e 0x28 0x32 0x3c
+					0x46 0x50 0x5a 0x64
+					0x64 0x5a 0x50 0x46 0x3c 0x32 0x28 0x1e
+					0x14 0x0a 0x01>;
+			};
+		};
+
+		pm660l_pwm_4: pwm@b400 {
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xb400 0x100>,
+			      <0xb042 0x7e>;
+			reg-names = "qpnp-lpg-channel-base",
+					 "qpnp-lpg-lut-base";
+			qcom,channel-id = <4>;
+			qcom,lpg-lut-size = <0x7e>;
+			qcom,supported-sizes = <6>, <9>;
+			qcom,ramp-index = <3>;
+			#pwm-cells = <2>;
+			status = "disabled";
+		};
+
+		qcom,leds@d000 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xd000 0x100>;
+			label = "rgb";
+
+			red_led: qcom,rgb_0 {
+				label = "rgb";
+				qcom,id = <3>;
+				qcom,mode = "pwm";
+				pwms = <&pm660l_pwm_3 0 0>;
+				qcom,pwm-us = <1000>;
+				qcom,max-current = <12>;
+				qcom,default-state = "off";
+				linux,name = "red";
+				qcom,start-idx = <0>;
+				qcom,idx-len = <22>;
+				qcom,duty-pcts =
+					[01 0a 14 1e 28 32 3c 46 50 5a 64
+					64 5a 50 46 3c 32 28 1e 14 0a 01];
+				qcom,use-blink;
+			};
+
+			green_led: qcom,rgb_1 {
+				label = "rgb";
+				qcom,id = <4>;
+				qcom,mode = "pwm";
+				pwms = <&pm660l_pwm_2 0 0>;
+				qcom,pwm-us = <1000>;
+				qcom,max-current = <12>;
+				qcom,default-state = "off";
+				linux,name = "green";
+			};
+
+			blue_led: qcom,rgb_2 {
+				label = "rgb";
+				qcom,id = <5>;
+				qcom,mode = "pwm";
+				pwms = <&pm660l_pwm_1 0 0>;
+				qcom,pwm-us = <1000>;
+				qcom,max-current = <12>;
+				qcom,default-state = "off";
+				linux,name = "blue";
+			};
+		};
+
+		pm660l_wled: qcom,leds@d800 {
+			compatible = "qcom,qpnp-wled";
+			reg = <0xd800 0x100>,
+				<0xd900 0x100>;
+			reg-names = "qpnp-wled-ctrl-base",
+					"qpnp-wled-sink-base";
+			interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "ovp-irq", "sc-irq";
+			linux,name = "wled";
+			linux,default-trigger = "bkl-trigger";
+			qcom,fdbk-output = "auto";
+			qcom,vref-uv = <127500>;
+			qcom,switch-freq-khz = <800>;
+			qcom,ovp-mv = <29600>;
+			qcom,ilim-ma = <970>;
+			qcom,boost-duty-ns = <26>;
+			qcom,mod-freq-khz = <9600>;
+			qcom,dim-mode = "hybrid";
+			qcom,hyb-thres = <625>;
+			qcom,sync-dly-us = <800>;
+			qcom,fs-curr-ua = <25000>;
+			qcom,cons-sync-write-delay-us = <1000>;
+			qcom,led-strings-list = [00 01 02];
+			qcom,en-ext-pfet-sc-pro;
+			qcom,loop-auto-gm-en;
+			qcom,pmic-revid = <&pm660l_revid>;
+			status = "ok";
+		};
+
+		flash_led: qcom,leds@d300 {
+			compatible = "qcom,qpnp-flash-led-v2";
+			reg = <0xd300 0x100>;
+			label = "flash";
+			interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x3 0xd3 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x3 0xd3 0x4 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "led-fault-irq",
+					"all-ramp-down-done-irq",
+					"all-ramp-up-done-irq";
+			qcom,hdrm-auto-mode;
+			qcom,short-circuit-det;
+			qcom,open-circuit-det;
+			qcom,vph-droop-det;
+			qcom,thermal-derate-en;
+			qcom,thermal-derate-current = <200 500 1000>;
+			qcom,isc-delay = <192>;
+			qcom,pmic-revid = <&pm660l_revid>;
+
+			pm660l_flash0: qcom,flash_0 {
+				label = "flash";
+				qcom,led-name = "led:flash_0";
+				qcom,max-current = <1500>;
+				qcom,default-led-trigger = "flash0_trigger";
+				qcom,id = <0>;
+				qcom,current-ma = <1000>;
+				qcom,duration-ms = <1280>;
+				qcom,ires-ua = <12500>;
+				qcom,hdrm-voltage-mv = <325>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pm660l_flash1: qcom,flash_1 {
+				label = "flash";
+				qcom,led-name = "led:flash_1";
+				qcom,max-current = <1500>;
+				qcom,default-led-trigger = "flash1_trigger";
+				qcom,id = <1>;
+				qcom,current-ma = <1000>;
+				qcom,duration-ms = <1280>;
+				qcom,ires-ua = <12500>;
+				qcom,hdrm-voltage-mv = <325>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pm660l_flash2: qcom,flash_2 {
+				label = "flash";
+				qcom,led-name = "led:flash_2";
+				qcom,max-current = <750>;
+				qcom,default-led-trigger = "flash2_trigger";
+				qcom,id = <2>;
+				qcom,current-ma = <500>;
+				qcom,duration-ms = <1280>;
+				qcom,ires-ua = <12500>;
+				qcom,hdrm-voltage-mv = <325>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pm660l_torch0: qcom,torch_0 {
+				label = "torch";
+				qcom,led-name = "led:torch_0";
+				qcom,max-current = <500>;
+				qcom,default-led-trigger = "torch0_trigger";
+				qcom,id = <0>;
+				qcom,current-ma = <300>;
+				qcom,ires-ua = <12500>;
+				qcom,hdrm-voltage-mv = <325>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pm660l_torch1: qcom,torch_1 {
+				label = "torch";
+				qcom,led-name = "led:torch_1";
+				qcom,max-current = <500>;
+				qcom,default-led-trigger = "torch1_trigger";
+				qcom,id = <1>;
+				qcom,current-ma = <300>;
+				qcom,ires-ua = <12500>;
+				qcom,hdrm-voltage-mv = <325>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pm660l_torch2: qcom,torch_2 {
+				label = "torch";
+				qcom,led-name = "led:torch_2";
+				qcom,max-current = <500>;
+				qcom,default-led-trigger = "torch2_trigger";
+				qcom,id = <2>;
+				qcom,current-ma = <300>;
+				qcom,ires-ua = <12500>;
+				qcom,hdrm-voltage-mv = <325>;
+				qcom,hdrm-vol-hi-lo-win-mv = <100>;
+			};
+
+			pm660l_switch0: qcom,led_switch_0 {
+				label = "switch";
+				qcom,led-name = "led:switch_0";
+				qcom,led-mask = <3>;
+				qcom,default-led-trigger = "switch0_trigger";
+			};
+
+			pm660l_switch1: qcom,led_switch_1 {
+				label = "switch";
+				qcom,led-name = "led:switch_1";
+				qcom,led-mask = <4>;
+				qcom,default-led-trigger = "switch1_trigger";
+			};
+		};
+
+		pm660l_lcdb: qpnp-lcdb@ec00 {
+			compatible = "qcom,qpnp-lcdb-regulator";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xec00 0x100>;
+			interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "sc-irq";
+
+			qcom,pmic-revid = <&pm660l_revid>;
+
+			lcdb_ldo_vreg: ldo {
+				label = "ldo";
+				regulator-name = "lcdb_ldo";
+				regulator-min-microvolt = <4000000>;
+				regulator-max-microvolt = <6000000>;
+			};
+
+			lcdb_ncp_vreg: ncp {
+				label = "ncp";
+				regulator-name = "lcdb_ncp";
+				regulator-min-microvolt = <4000000>;
+				regulator-max-microvolt = <6000000>;
+			};
+		};
+
+		pm660a_oledb: qpnp-oledb@e000 {
+		       compatible = "qcom,qpnp-oledb-regulator";
+		       #address-cells = <1>;
+		       #size-cells = <1>;
+		       qcom,pmic-revid = <&pm660l_revid>;
+		       reg = <0xe000 0x100>;
+		       qcom,pbs-client = <&pm660l_pbs>;
+
+		       label = "oledb";
+		       regulator-name = "regulator-oledb";
+		       regulator-min-microvolt = <5000000>;
+		       regulator-max-microvolt = <8100000>;
+
+		       qcom,swire-control;
+		       qcom,ext-pin-control;
+		       status = "disabled";
+		};
+
+		pm660a_labibb: qpnp-labibb-regulator {
+			compatible = "qcom,qpnp-labibb-regulator";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			qcom,pmic-revid = <&pm660l_revid>;
+			qcom,swire-control;
+			status = "disabled";
+
+			ibb_regulator: qcom,ibb@dc00 {
+				reg = <0xdc00 0x100>;
+				reg-names = "ibb_reg";
+				regulator-name = "ibb_reg";
+
+				regulator-min-microvolt = <4000000>;
+				regulator-max-microvolt = <6300000>;
+
+				qcom,qpnp-ibb-min-voltage = <1400000>;
+				qcom,qpnp-ibb-step-size = <100000>;
+				qcom,qpnp-ibb-slew-rate = <2000000>;
+				qcom,qpnp-ibb-init-voltage = <4000000>;
+				qcom,qpnp-ibb-init-amoled-voltage = <4000000>;
+			};
+
+			lab_regulator: qcom,lab@de00 {
+				reg = <0xde00 0x100>;
+				reg-names = "lab";
+				regulator-name = "lab_reg";
+
+				regulator-min-microvolt = <4600000>;
+				regulator-max-microvolt = <6100000>;
+
+				qcom,qpnp-lab-min-voltage = <4600000>;
+				qcom,qpnp-lab-step-size = <100000>;
+				qcom,qpnp-lab-slew-rate = <5000>;
+				qcom,qpnp-lab-init-voltage = <4600000>;
+				qcom,qpnp-lab-init-amoled-voltage = <4600000>;
+
+				qcom,notify-lab-vreg-ok-sts;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 660dac5..71eee1f 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -26,16 +26,22 @@
 			qcom,fab-id-valid;
 		};
 
+		pmi8998_misc: qcom,misc@900 {
+			compatible = "qcom,qpnp-misc";
+			reg = <0x900 0x100>;
+		};
+
 		qcom,power-on@800 {
 			compatible = "qcom,qpnp-power-on";
 			reg = <0x800 0x100>;
 		};
 
 		pmi8998_tz: qcom,temp-alarm@2400 {
-			compatible = "qcom,qpnp-temp-alarm";
+			compatible = "qcom,spmi-temp-alarm";
 			reg = <0x2400 0x100>;
 			interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
-			label = "pmi8998_tz";
+			io-channels = <&pmi8998_rradc 7>;
+			io-channel-names = "thermal";
 			#thermal-sensor-cells = <0>;
 		};
 
@@ -671,6 +677,28 @@
 				qcom,default-led-trigger = "switch1_trigger";
 			};
 		};
+
+		pmi8998_haptics: qcom,haptics@c000 {
+			compatible = "qcom,qpnp-haptics";
+			reg = <0xc000 0x100>;
+			interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "hap-sc-irq", "hap-play-irq";
+			qcom,pmic-revid = <&pmi8998_revid>;
+			qcom,pmic-misc = <&pmi8998_misc>;
+			qcom,misc-clk-trim-error-reg = <0xf3>;
+			qcom,actuator-type = <0>;
+			qcom,play-mode = "direct";
+			qcom,vmax-mv = <3200>;
+			qcom,ilim-ma = <800>;
+			qcom,sc-dbc-cycles = <8>;
+			qcom,wave-play-rate-us = <6667>;
+			qcom,en-brake;
+			qcom,lra-high-z = "opt1";
+			qcom,lra-auto-res-mode = "qwd";
+			qcom,lra-res-cal-period = <4>;
+			status = "disabled";
+		};
 	};
 };
 
@@ -720,19 +748,27 @@
 		cooling-maps {
 			vbat_cpu4 {
 				trip = <&low_vbat>;
-				cooling-device = <&CPU4 22 22>;
+				cooling-device =
+					<&CPU4 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
 			};
 			vbat_cpu5 {
 				trip = <&low_vbat>;
-				cooling-device = <&CPU5 22 22>;
+				cooling-device =
+					<&CPU5 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
 			};
 			vbat_map6 {
 				trip = <&low_vbat>;
-				cooling-device = <&CPU6 22 22>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
 			};
 			vbat_map7 {
 				trip = <&low_vbat>;
-				cooling-device = <&CPU7 22 22>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
 			};
 		};
 	};
@@ -783,19 +819,27 @@
 		cooling-maps {
 			soc_cpu4 {
 				trip = <&low_soc>;
-				cooling-device = <&CPU4 22 22>;
+				cooling-device =
+					<&CPU4 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
 			};
 			soc_cpu5 {
 				trip = <&low_soc>;
-				cooling-device = <&CPU5 22 22>;
+				cooling-device =
+					<&CPU5 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
 			};
 			soc_map6 {
 				trip = <&low_soc>;
-				cooling-device = <&CPU6 22 22>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
 			};
 			soc_map7 {
 				trip = <&low_soc>;
-				cooling-device = <&CPU7 22 22>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
 			};
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
index 09ce9d2..86e2948 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
@@ -19,5 +19,1103 @@
 		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
+
+		/* QUPv3 South SE mappings */
+		/* SE 0 pin mappings */
+		qupv3_se0_i2c_pins: qupv3_se0_i2c_pins {
+			qupv3_se0_i2c_active: qupv3_se0_i2c_active {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "qup0";
+				};
+
+				config {
+					pins = "gpio0", "gpio1";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio0", "gpio1";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se0_spi_pins: qupv3_se0_spi_pins {
+			qupv3_se0_spi_active: qupv3_se0_spi_active {
+				mux {
+					pins = "gpio0", "gpio1", "gpio2",
+								"gpio3";
+					function = "qup0";
+				};
+
+				config {
+					pins = "gpio0", "gpio1", "gpio2",
+								"gpio3";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se0_spi_sleep: qupv3_se0_spi_sleep {
+				mux {
+					pins = "gpio0", "gpio1", "gpio2",
+								"gpio3";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio0", "gpio1", "gpio2",
+								"gpio3";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 1 pin mappings */
+		qupv3_se1_i2c_pins: qupv3_se1_i2c_pins {
+			qupv3_se1_i2c_active: qupv3_se1_i2c_active {
+				mux {
+					pins = "gpio17", "gpio18";
+					function = "qup1";
+				};
+
+				config {
+					pins = "gpio17", "gpio18";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep {
+				mux {
+					pins = "gpio17", "gpio18";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio17", "gpio18";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se1_spi_pins: qupv3_se1_spi_pins {
+			qupv3_se1_spi_active: qupv3_se1_spi_active {
+				mux {
+					pins = "gpio17", "gpio18", "gpio19",
+								"gpio20";
+					function = "qup1";
+				};
+
+				config {
+					pins = "gpio17", "gpio18", "gpio19",
+								"gpio20";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se1_spi_sleep: qupv3_se1_spi_sleep {
+				mux {
+					pins = "gpio17", "gpio18", "gpio19",
+								"gpio20";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio17", "gpio18", "gpio19",
+								"gpio20";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 2 pin mappings */
+		qupv3_se2_i2c_pins: qupv3_se2_i2c_pins {
+			qupv3_se2_i2c_active: qupv3_se2_i2c_active {
+				mux {
+					pins = "gpio27", "gpio28";
+					function = "qup2";
+				};
+
+				config {
+					pins = "gpio27", "gpio28";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep {
+				mux {
+					pins = "gpio27", "gpio28";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio27", "gpio28";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se2_spi_pins: qupv3_se2_spi_pins {
+			qupv3_se2_spi_active: qupv3_se2_spi_active {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29",
+								"gpio30";
+					function = "qup2";
+				};
+
+				config {
+					pins = "gpio27", "gpio28", "gpio29",
+								"gpio30";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se2_spi_sleep: qupv3_se2_spi_sleep {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29",
+								"gpio30";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio27", "gpio28", "gpio29",
+								"gpio30";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 3 pin mappings */
+		qupv3_se3_i2c_pins: qupv3_se3_i2c_pins {
+			qupv3_se3_i2c_active: qupv3_se3_i2c_active {
+				mux {
+					pins = "gpio41", "gpio42";
+					function = "qup3";
+				};
+
+				config {
+					pins = "gpio41", "gpio42";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se3_i2c_sleep: qupv3_se3_i2c_sleep {
+				mux {
+					pins = "gpio41", "gpio42";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio41", "gpio42";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se3_spi_pins: qupv3_se3_spi_pins {
+			qupv3_se3_spi_active: qupv3_se3_spi_active {
+				mux {
+					pins = "gpio41", "gpio42", "gpio43",
+								"gpio44";
+					function = "qup3";
+				};
+
+				config {
+					pins = "gpio41", "gpio42", "gpio43",
+								"gpio44";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se3_spi_sleep: qupv3_se3_spi_sleep {
+				mux {
+					pins = "gpio41", "gpio42", "gpio43",
+								"gpio44";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio41", "gpio42", "gpio43",
+								"gpio44";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 4 pin mappings */
+		qupv3_se4_i2c_pins: qupv3_se4_i2c_pins {
+			qupv3_se4_i2c_active: qupv3_se4_i2c_active {
+				mux {
+					pins = "gpio89", "gpio90";
+					function = "qup4";
+				};
+
+				config {
+					pins = "gpio89", "gpio90";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se4_i2c_sleep: qupv3_se4_i2c_sleep {
+				mux {
+					pins = "gpio89", "gpio90";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio89", "gpio90";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se4_spi_pins: qupv3_se4_spi_pins {
+			qupv3_se4_spi_active: qupv3_se4_spi_active {
+				mux {
+					pins = "gpio89", "gpio90", "gpio91",
+								"gpio92";
+					function = "qup4";
+				};
+
+				config {
+					pins = "gpio89", "gpio90", "gpio91",
+								"gpio92";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se4_spi_sleep: qupv3_se4_spi_sleep {
+				mux {
+					pins = "gpio89", "gpio90", "gpio91",
+								"gpio92";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio89", "gpio90", "gpio91",
+								"gpio92";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 5 pin mappings */
+		qupv3_se5_i2c_pins: qupv3_se5_i2c_pins {
+			qupv3_se5_i2c_active: qupv3_se5_i2c_active {
+				mux {
+					pins = "gpio85", "gpio86";
+					function = "qup5";
+				};
+
+				config {
+					pins = "gpio85", "gpio86";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep {
+				mux {
+					pins = "gpio85", "gpio86";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio85", "gpio86";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se5_spi_pins: qupv3_se5_spi_pins {
+			qupv3_se5_spi_active: qupv3_se5_spi_active {
+				mux {
+					pins = "gpio85", "gpio86", "gpio87",
+								"gpio88";
+					function = "qup5";
+				};
+
+				config {
+					pins = "gpio85", "gpio86", "gpio87",
+								"gpio88";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se5_spi_sleep: qupv3_se5_spi_sleep {
+				mux {
+					pins = "gpio85", "gpio86", "gpio87",
+								"gpio88";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio85", "gpio86", "gpio87",
+								"gpio88";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 6 pin mappings */
+		qupv3_se6_i2c_pins: qupv3_se6_i2c_pins {
+			qupv3_se6_i2c_active: qupv3_se6_i2c_active {
+				mux {
+					pins = "gpio45", "gpio46";
+					function = "qup6";
+				};
+
+				config {
+					pins = "gpio45", "gpio46";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep {
+				mux {
+					pins = "gpio45", "gpio46";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio45", "gpio46";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se6_4uart_pins: qupv3_se6_4uart_pins {
+			qupv3_se6_4uart_active: qupv3_se6_4uart_active {
+				mux {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					function = "qup6";
+				};
+
+				config {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se6_4uart_sleep: qupv3_se6_4uart_sleep {
+				mux {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		qupv3_se6_spi_pins: qupv3_se6_spi_pins {
+			qupv3_se6_spi_active: qupv3_se6_spi_active {
+				mux {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					function = "qup6";
+				};
+
+				config {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se6_spi_sleep: qupv3_se6_spi_sleep {
+				mux {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio45", "gpio46", "gpio47",
+								"gpio48";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 7 pin mappings */
+		qupv3_se7_i2c_pins: qupv3_se7_i2c_pins {
+			qupv3_se7_i2c_active: qupv3_se7_i2c_active {
+				mux {
+					pins = "gpio93", "gpio94";
+					function = "qup7";
+				};
+
+				config {
+					pins = "gpio93", "gpio94";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep {
+				mux {
+					pins = "gpio93", "gpio94";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio93", "gpio94";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se7_4uart_pins: qupv3_se7_4uart_pins {
+			qupv3_se7_4uart_active: qupv3_se7_4uart_active {
+				mux {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					function = "qup7";
+				};
+
+				config {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se7_4uart_sleep: qupv3_se7_4uart_sleep {
+				mux {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		qupv3_se7_spi_pins: qupv3_se7_spi_pins {
+			qupv3_se7_spi_active: qupv3_se7_spi_active {
+				mux {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					function = "qup7";
+				};
+
+				config {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se7_spi_sleep: qupv3_se7_spi_sleep {
+				mux {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio93", "gpio94", "gpio95",
+								"gpio96";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* QUPv3 North instances */
+		/* SE 8 pin mappings */
+		qupv3_se8_i2c_pins: qupv3_se8_i2c_pins {
+			qupv3_se8_i2c_active: qupv3_se8_i2c_active {
+				mux {
+					pins = "gpio65", "gpio66";
+					function = "qup8";
+				};
+
+				config {
+					pins = "gpio65", "gpio66";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se8_i2c_sleep: qupv3_se8_i2c_sleep {
+				mux {
+					pins = "gpio65", "gpio66";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65", "gpio66";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se8_spi_pins: qupv3_se8_spi_pins {
+			qupv3_se8_spi_active: qupv3_se8_spi_active {
+				mux {
+					pins = "gpio65", "gpio66", "gpio67",
+								"gpio68";
+					function = "qup8";
+				};
+
+				config {
+					pins = "gpio65", "gpio66", "gpio67",
+								"gpio68";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se8_spi_sleep: qupv3_se8_spi_sleep {
+				mux {
+					pins = "gpio65", "gpio66", "gpio67",
+								"gpio68";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65", "gpio66", "gpio67",
+								"gpio68";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 9 pin mappings */
+		qupv3_se9_i2c_pins: qupv3_se9_i2c_pins {
+			qupv3_se9_i2c_active: qupv3_se9_i2c_active {
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "qup9";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se9_i2c_sleep: qupv3_se9_i2c_sleep {
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se9_2uart_pins: qupv3_se9_2uart_pins {
+			qupv3_se9_2uart_active: qupv3_se9_2uart_active {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "qup9";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se9_2uart_sleep: qupv3_se9_2uart_sleep {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		qupv3_se9_spi_pins: qupv3_se9_spi_pins {
+			qupv3_se9_spi_active: qupv3_se9_spi_active {
+				mux {
+					pins = "gpio4", "gpio5", "gpio6",
+								"gpio7";
+					function = "qup9";
+				};
+
+				config {
+					pins = "gpio4", "gpio5", "gpio6",
+								"gpio7";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se9_spi_sleep: qupv3_se9_spi_sleep {
+				mux {
+					pins = "gpio4", "gpio5", "gpio6",
+								"gpio7";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio4", "gpio5", "gpio6",
+								"gpio7";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 10 pin mappings */
+		qupv3_se10_i2c_pins: qupv3_se10_i2c_pins {
+			qupv3_se10_i2c_active: qupv3_se10_i2c_active {
+				mux {
+					pins = "gpio55", "gpio56";
+					function = "qup10";
+				};
+
+				config {
+					pins = "gpio55", "gpio56";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se10_i2c_sleep: qupv3_se10_i2c_sleep {
+				mux {
+					pins = "gpio55", "gpio56";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio55", "gpio56";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se10_2uart_pins: qupv3_se10_2uart_pins {
+			qupv3_se10_2uart_active: qupv3_se10_2uart_active {
+				mux {
+					pins = "gpio53", "gpio54";
+					function = "qup10";
+				};
+
+				config {
+					pins = "gpio53", "gpio54";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se10_2uart_sleep: qupv3_se10_2uart_sleep {
+				mux {
+					pins = "gpio53", "gpio54";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio53", "gpio54";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		qupv3_se10_spi_pins: qupv3_se10_spi_pins {
+			qupv3_se10_spi_active: qupv3_se10_spi_active {
+				mux {
+					pins = "gpio53", "gpio54", "gpio55",
+								"gpio56";
+					function = "qup10";
+				};
+
+				config {
+					pins = "gpio53", "gpio54", "gpio55",
+								"gpio56";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se10_spi_sleep: qupv3_se10_spi_sleep {
+				mux {
+					pins = "gpio53", "gpio54", "gpio55",
+								"gpio56";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio53", "gpio54", "gpio55",
+								"gpio56";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 11 pin mappings */
+		qupv3_se11_i2c_pins: qupv3_se11_i2c_pins {
+			qupv3_se11_i2c_active: qupv3_se11_i2c_active {
+				mux {
+					pins = "gpio31", "gpio32";
+					function = "qup11";
+				};
+
+				config {
+					pins = "gpio31", "gpio32";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se11_i2c_sleep: qupv3_se11_i2c_sleep {
+				mux {
+					pins = "gpio31", "gpio32";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio31", "gpio32";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se11_spi_pins: qupv3_se11_spi_pins {
+			qupv3_se11_spi_active: qupv3_se11_spi_active {
+				mux {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					function = "qup11";
+				};
+
+				config {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se11_spi_sleep: qupv3_se11_spi_sleep {
+				mux {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 12 pin mappings */
+		qupv3_se12_i2c_pins: qupv3_se12_i2c_pins {
+			qupv3_se12_i2c_active: qupv3_se12_i2c_active {
+				mux {
+					pins = "gpio49", "gpio50";
+					function = "qup12";
+				};
+
+				config {
+					pins = "gpio49", "gpio50";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se12_i2c_sleep: qupv3_se12_i2c_sleep {
+				mux {
+					pins = "gpio49", "gpio50";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio49", "gpio50";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se12_spi_pins: qupv3_se12_spi_pins {
+			qupv3_se12_spi_active: qupv3_se12_spi_active {
+				mux {
+					pins = "gpio49", "gpio50", "gpio51",
+								"gpio52";
+					function = "qup12";
+				};
+
+				config {
+					pins = "gpio49", "gpio50", "gpio51",
+								"gpio52";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se12_spi_sleep: qupv3_se12_spi_sleep {
+				mux {
+					pins = "gpio49", "gpio50", "gpio51",
+								"gpio52";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio49", "gpio50", "gpio51",
+								"gpio52";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 13 pin mappings */
+		qupv3_se13_i2c_pins: qupv3_se13_i2c_pins {
+			qupv3_se13_i2c_active: qupv3_se13_i2c_active {
+				mux {
+					pins = "gpio105", "gpio106";
+					function = "qup13";
+				};
+
+				config {
+					pins = "gpio105", "gpio106";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se13_i2c_sleep: qupv3_se13_i2c_sleep {
+				mux {
+					pins = "gpio105", "gpio106";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio105", "gpio106";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se13_spi_pins: qupv3_se13_spi_pins {
+			qupv3_se13_spi_active: qupv3_se13_spi_active {
+				mux {
+					pins = "gpio105", "gpio106", "gpio107",
+								"gpio108";
+					function = "qup13";
+				};
+
+				config {
+					pins = "gpio105", "gpio106", "gpio107",
+								"gpio108";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se13_spi_sleep: qupv3_se13_spi_sleep {
+				mux {
+					pins = "gpio105", "gpio106", "gpio107",
+								"gpio108";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio105", "gpio106", "gpio107",
+								"gpio108";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 14 pin mappings */
+		qupv3_se14_i2c_pins: qupv3_se14_i2c_pins {
+			qupv3_se14_i2c_active: qupv3_se14_i2c_active {
+				mux {
+					pins = "gpio33", "gpio34";
+					function = "qup14";
+				};
+
+				config {
+					pins = "gpio33", "gpio34";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se14_i2c_sleep: qupv3_se14_i2c_sleep {
+				mux {
+					pins = "gpio33", "gpio34";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio33", "gpio34";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se14_spi_pins: qupv3_se14_spi_pins {
+			qupv3_se14_spi_active: qupv3_se14_spi_active {
+				mux {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					function = "qup14";
+				};
+
+				config {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se14_spi_sleep: qupv3_se14_spi_sleep {
+				mux {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio31", "gpio32", "gpio33",
+								"gpio34";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
+
+		/* SE 15 pin mappings */
+		qupv3_se15_i2c_pins: qupv3_se15_i2c_pins {
+			qupv3_se15_i2c_active: qupv3_se15_i2c_active {
+				mux {
+					pins = "gpio81", "gpio82";
+					function = "qup15";
+				};
+
+				config {
+					pins = "gpio81", "gpio82";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se15_i2c_sleep: qupv3_se15_i2c_sleep {
+				mux {
+					pins = "gpio81", "gpio82";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio81", "gpio82";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		qupv3_se15_spi_pins: qupv3_se15_spi_pins {
+			qupv3_se15_spi_active: qupv3_se15_spi_active {
+				mux {
+					pins = "gpio81", "gpio82", "gpio83",
+								"gpio84";
+					function = "qup15";
+				};
+
+				config {
+					pins = "gpio81", "gpio82", "gpio83",
+								"gpio84";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+
+			qupv3_se15_spi_sleep: qupv3_se15_spi_sleep {
+				mux {
+					pins = "gpio81", "gpio82", "gpio83",
+								"gpio84";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio81", "gpio82", "gpio83",
+								"gpio84";
+					drive-strength = <6>;
+					bias-disable;
+				};
+			};
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi
new file mode 100644
index 0000000..0fb455f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-qupv3.dtsi
@@ -0,0 +1,699 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/msm-bus-ids.h>
+
+&soc {
+	/* QUPv3 South instances */
+	qupv3_0: qcom,qupv3_0_geni_se@8c0000 {
+		compatible = "qcom,qupv3-geni-se";
+		reg = <0x8c0000 0x6000>;
+		qcom,bus-mas-id = <MSM_BUS_MASTER_BLSP_1>;
+		qcom,bus-slv-id = <MSM_BUS_SLAVE_EBI_CH0>;
+		qcom,iommu-s1-bypass;
+
+		iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb {
+			compatible = "qcom,qupv3-geni-se-cb";
+			iommus = <&apps_smmu 0x003 0x0>;
+		};
+	};
+
+	/*
+	 * HS UART instances. HS UART usecases can be supported on these
+	 * instances only.
+	 */
+	qupv3_se6_4uart: qcom,qup_uart@0x898000 {
+		compatible = "qcom,msm-geni-serial-hs", "qcom,msm-geni-uart";
+		reg = <0x898000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se6_4uart_active>;
+		pinctrl-1 = <&qupv3_se6_4uart_sleep>;
+		interrupts-extended = <&intc GIC_SPI 607 0>,
+				<&tlmm 48 0>;
+		status = "disabled";
+		qcom,wakeup-byte = <0xFD>;
+		qcom,wrapper-core = <&qupv3_0>;
+	};
+
+	qupv3_se7_4uart: qcom,qup_uart@0x89c000 {
+		compatible = "qcom,msm-geni-serial-hs", "qcom,msm-geni-uart";
+		reg = <0x89c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se7_4uart_active>;
+		pinctrl-1 = <&qupv3_se7_4uart_sleep>;
+		interrupts-extended = <&intc GIC_SPI 608 0>,
+				<&tlmm 96 0>;
+		status = "disabled";
+		qcom,wakeup-byte = <0xFD>;
+		qcom,wrapper-core = <&qupv3_0>;
+	};
+
+	/* I2C */
+	qupv3_se0_i2c: i2c@880000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x880000 0x4000>;
+		interrupts = <GIC_SPI 601 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se0_i2c_active>;
+		pinctrl-1 = <&qupv3_se0_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se1_i2c: i2c@884000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x884000 0x4000>;
+		interrupts = <GIC_SPI 602 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se1_i2c_active>;
+		pinctrl-1 = <&qupv3_se1_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se2_i2c: i2c@888000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x888000 0x4000>;
+		interrupts = <GIC_SPI 603 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se2_i2c_active>;
+		pinctrl-1 = <&qupv3_se2_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se3_i2c: i2c@88c000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x88c000 0x4000>;
+		interrupts = <GIC_SPI 604 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se3_i2c_active>;
+		pinctrl-1 = <&qupv3_se3_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se4_i2c: i2c@890000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x890000 0x4000>;
+		interrupts = <GIC_SPI 605 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se4_i2c_active>;
+		pinctrl-1 = <&qupv3_se4_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se5_i2c: i2c@894000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x894000 0x4000>;
+		interrupts = <GIC_SPI 606 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se5_i2c_active>;
+		pinctrl-1 = <&qupv3_se5_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se6_i2c: i2c@898000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x898000 0x4000>;
+		interrupts = <GIC_SPI 607 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se6_i2c_active>;
+		pinctrl-1 = <&qupv3_se6_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se7_i2c: i2c@89c000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0x89c000 0x4000>;
+		interrupts = <GIC_SPI 608 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se7_i2c_active>;
+		pinctrl-1 = <&qupv3_se7_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	/* SPI */
+	qupv3_se0_spi: spi@880000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x880000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se0_spi_active>;
+		pinctrl-1 = <&qupv3_se0_spi_sleep>;
+		interrupts = <GIC_SPI 601 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se1_spi: spi@884000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x884000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se1_spi_active>;
+		pinctrl-1 = <&qupv3_se1_spi_sleep>;
+		interrupts = <GIC_SPI 602 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se2_spi: spi@888000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x888000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se2_spi_active>;
+		pinctrl-1 = <&qupv3_se2_spi_sleep>;
+		interrupts = <GIC_SPI 603 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se3_spi: spi@88c000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x88c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se3_spi_active>;
+		pinctrl-1 = <&qupv3_se3_spi_sleep>;
+		interrupts = <GIC_SPI 604 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se4_spi: spi@890000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x890000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se4_spi_active>;
+		pinctrl-1 = <&qupv3_se4_spi_sleep>;
+		interrupts = <GIC_SPI 605 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se5_spi: spi@894000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x894000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se5_spi_active>;
+		pinctrl-1 = <&qupv3_se5_spi_sleep>;
+		interrupts = <GIC_SPI 606 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se6_spi: spi@898000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x898000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se6_spi_active>;
+		pinctrl-1 = <&qupv3_se6_spi_sleep>;
+		interrupts = <GIC_SPI 607 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	qupv3_se7_spi: spi@89c000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x89c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se7_spi_active>;
+		pinctrl-1 = <&qupv3_se7_spi_sleep>;
+		interrupts = <GIC_SPI 608 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_0>;
+		status = "disabled";
+	};
+
+	/* QUPv3 North Instances */
+	qupv3_1: qcom,qupv3_1_geni_se@ac0000 {
+		compatible = "qcom,qupv3-geni-se";
+		reg = <0xac0000 0x6000>;
+		qcom,bus-mas-id = <MSM_BUS_MASTER_BLSP_2>;
+		qcom,bus-slv-id = <MSM_BUS_SLAVE_EBI_CH0>;
+		qcom,iommu-s1-bypass;
+
+		iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb {
+			compatible = "qcom,qupv3-geni-se-cb";
+			iommus = <&apps_smmu 0x6c3 0x0>;
+		};
+	};
+
+	/* 2-wire UART */
+
+	/* Debug UART Instance for CDP/MTP platform */
+	qupv3_se9_2uart: qcom,qup_uart@0xa84000 {
+		compatible = "qcom,msm-geni-console", "qcom,msm-geni-uart";
+		reg = <0xa84000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se9_2uart_active>;
+		pinctrl-1 = <&qupv3_se9_2uart_sleep>;
+		interrupts = <GIC_SPI 354 0>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	/* Debug UART Instance for RUMI platform */
+	qupv3_se10_2uart: qcom,qup_uart@0xa88000 {
+		compatible = "qcom,msm-geni-console", "qcom,msm-geni-uart";
+		reg = <0xa88000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se10_2uart_active>;
+		pinctrl-1 = <&qupv3_se10_2uart_sleep>;
+		interrupts = <GIC_SPI 355 0>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	/* I2C */
+	qupv3_se8_i2c: i2c@a80000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa80000 0x4000>;
+		interrupts = <GIC_SPI 353 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se8_i2c_active>;
+		pinctrl-1 = <&qupv3_se8_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se9_i2c: i2c@a84000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa84000 0x4000>;
+		interrupts = <GIC_SPI 354 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se9_i2c_active>;
+		pinctrl-1 = <&qupv3_se9_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se10_i2c: i2c@a88000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa88000 0x4000>;
+		interrupts = <GIC_SPI 355 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se10_i2c_active>;
+		pinctrl-1 = <&qupv3_se10_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se11_i2c: i2c@a8c000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa8c000 0x4000>;
+		interrupts = <GIC_SPI 356 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se11_i2c_active>;
+		pinctrl-1 = <&qupv3_se11_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se12_i2c: i2c@a90000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa90000 0x4000>;
+		interrupts = <GIC_SPI 357 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se12_i2c_active>;
+		pinctrl-1 = <&qupv3_se12_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se13_i2c: i2c@a94000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa94000 0x4000>;
+		interrupts = <GIC_SPI 358 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se13_i2c_active>;
+		pinctrl-1 = <&qupv3_se13_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se14_i2c: i2c@a98000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa98000 0x4000>;
+		interrupts = <GIC_SPI 359 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se14_i2c_active>;
+		pinctrl-1 = <&qupv3_se14_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se15_i2c: i2c@a9c000 {
+		compatible = "qcom,i2c-geni";
+		reg = <0xa9c000 0x4000>;
+		interrupts = <GIC_SPI 360 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se15_i2c_active>;
+		pinctrl-1 = <&qupv3_se15_i2c_sleep>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	/* SPI */
+	qupv3_se8_spi: spi@a80000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa80000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se8_spi_active>;
+		pinctrl-1 = <&qupv3_se8_spi_sleep>;
+		interrupts = <GIC_SPI 353 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se9_spi: spi@a84000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa84000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se9_spi_active>;
+		pinctrl-1 = <&qupv3_se9_spi_sleep>;
+		interrupts = <GIC_SPI 354 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se10_spi: spi@a88000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa88000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se10_spi_active>;
+		pinctrl-1 = <&qupv3_se10_spi_sleep>;
+		interrupts = <GIC_SPI 355 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se11_spi: spi@a8c000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa8c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se11_spi_active>;
+		pinctrl-1 = <&qupv3_se11_spi_sleep>;
+		interrupts = <GIC_SPI 356 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se12_spi: spi@a90000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa90000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se12_spi_active>;
+		pinctrl-1 = <&qupv3_se12_spi_sleep>;
+		interrupts = <GIC_SPI 357 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se13_spi: spi@a94000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa94000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se13_spi_active>;
+		pinctrl-1 = <&qupv3_se13_spi_sleep>;
+		interrupts = <GIC_SPI 358 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se14_spi: spi@a98000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa98000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se14_spi_active>;
+		pinctrl-1 = <&qupv3_se14_spi_sleep>;
+		interrupts = <GIC_SPI 359 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+
+	qupv3_se15_spi: spi@a9c000 {
+		compatible = "qcom,spi-geni";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xa9c000 0x4000>;
+		reg-names = "se_phys";
+		clock-names = "se-clk", "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&qupv3_se15_spi_active>;
+		pinctrl-1 = <&qupv3_se15_spi_sleep>;
+		interrupts = <GIC_SPI 360 0>;
+		spi-max-frequency = <50000000>;
+		qcom,wrapper-core = <&qupv3_1>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
new file mode 100644
index 0000000..b0c436f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -0,0 +1,373 @@
+/* Copyright (c) 2017, 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  PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+/* Stub regulators */
+
+/ {
+	pm660_s4: regulator-pm660-s4 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_s4";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <2040000>;
+		regulator-max-microvolt = <2040000>;
+	};
+
+	/* pm660 S5 - VDD_MODEM supply */
+	pm660_s5_level: regulator-pm660-s5 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_s5_level";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	pm660_s6: regulator-pm660-s6 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_s6";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <1352000>;
+		regulator-max-microvolt = <1352000>;
+	};
+
+	/* pm660l S1 - VDD_MX supply */
+	pm660l_s1_level: regulator-pm660l-s1 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_s1_level";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	pm660l_s1_floor_level: regulator-pm660l-s1-floor-level {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_s1_floor_level";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	pm660l_s1_level_ao: regulator-pm660l-s1-level-ao {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_s1_level_ao";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	/* pm660l S2 - VDD_GFX supply */
+	pm660l_s2_level: regulator-pm660l-s2 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_s2_level";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	/* pm660l S3 + S4 - VDD_CX supply */
+	pm660l_s3_level: regulator-pm660l-s3-level {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_s3_level";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	pm660l_s3_floor_level: regulator-pm660l-s3-floor-level {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_s3_floor_level";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	pm660l_s3_level_ao: regulator-pm660l-s3-level-ao {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_s3_level_ao";
+		qcom,hpm-min-load = <100000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	pm660_l1: regulator-pm660-l1 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l1";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1250000>;
+	};
+
+	pm660_l2: regulator-pm660-l2 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l2";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1000000>;
+	};
+
+	pm660_l3: regulator-pm660-l3 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l3";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1000000>;
+	};
+
+	pm660_l5: regulator-pm660-l5 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l5";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <800000>;
+		regulator-max-microvolt = <800000>;
+	};
+
+	pm660_l6: regulator-pm660-l6 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l6";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1304000>;
+		regulator-max-microvolt = <1304000>;
+	};
+
+	pm660_l7: regulator-pm660-l7 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l7";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+	};
+
+	pm660_l8: regulator-pm660-l8 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l8";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm660_l9: regulator-pm660-l9 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l9";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm660_l10: regulator-pm660-l10 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l10";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm660_l11: regulator-pm660-l11 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l11";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm660_l12: regulator-pm660-l12 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l12";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm660_l13: regulator-pm660-l13 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l13";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm660_l14: regulator-pm660-l14 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l14";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	pm660_l15: regulator-pm660-l15 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l15";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	pm660_l16: regulator-pm660-l16 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l16";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2700000>;
+		regulator-max-microvolt = <2700000>;
+	};
+
+	pm660_l17: regulator-pm660-l17 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l17";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2950000>;
+	};
+
+	pm660_l19: regulator-pm660-l19 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660_l19";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <3312000>;
+		regulator-max-microvolt = <3312000>;
+	};
+
+	pm660l_l1: regulator-pm660l-l1 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l1";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <880000>;
+		regulator-max-microvolt = <900000>;
+	};
+
+	pm660l_l2: regulator-pm660l-l2 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l2";
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <2960000>;
+	};
+
+	pm660l_l3: regulator-pm660l-l3 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l3";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2850000>;
+		regulator-max-microvolt = <3008000>;
+	};
+
+	pm660l_l4: regulator-pm660l-l4 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l4";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2960000>;
+		regulator-max-microvolt = <2960000>;
+	};
+
+	pm660l_l5: regulator-pm660l-l5 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l5";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <2960000>;
+		regulator-max-microvolt = <2960000>;
+	};
+
+	pm660l_l6: regulator-pm660l-l6 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l6";
+		qcom,hpm-min-load = <5000>;
+		regulator-min-microvolt = <3008000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	pm660l_l7: regulator-pm660l-l7 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l7";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <3088000>;
+		regulator-max-microvolt = <3100000>;
+	};
+
+	pm660l_l8: regulator-pm660l-l8 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l8";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3312000>;
+	};
+
+	/* pm660l L9 = VDD_LPI_CX supply */
+	pm660l_l9_level: regulator-pm660l-l9-level {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l9_level";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	pm660l_l9_floor_level: regulator-pm660l-l9-floor-level {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l9_floor_level";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	/* pm660l L10 = VDD_LPI_MX supply */
+	pm660l_l10_level: regulator-pm660l-l10-level {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l10_level";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	pm660l_l10_floor_level: regulator-pm660l-l10-floor-level {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_l10_floor_level";
+		qcom,hpm-min-load = <10000>;
+		regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+		regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+	};
+
+	pm660l_bob: regulator-pm660l-bob {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "pm660l_bob";
+		regulator-min-microvolt = <3312000>;
+		regulator-max-microvolt = <3312000>;
+	};
+
+	apc0_pwrcl_vreg: regulator-pwrcl {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "apc0_pwrcl_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <7>;
+	};
+
+	apc0_l3_vreg: regulator-l3 {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "apc0_l3_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <7>;
+	};
+
+	apc1_perfcl_vreg: regulator-perfcl {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "apc1_perfcl_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <7>;
+	};
+};
+
+&pm660_charger {
+	smb2_vbus: qcom,smb2-vbus {
+		regulator-name = "smb2-vbus";
+	};
+
+	smb2_vconn: qcom,smb2-vconn {
+		regulator-name = "smb2-vconn";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
index 6ea92ee..17b90c7 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
@@ -9,3 +9,71 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+
+/{
+	aliases {
+		serial0 = &qupv3_se10_2uart;
+		serial1 = &qupv3_se9_2uart;
+		spi0 = &qupv3_se8_spi;
+		i2c0 = &qupv3_se10_i2c;
+		i2c1 = &qupv3_se3_i2c;
+		hsuart0 = &qupv3_se6_4uart;
+	};
+
+};
+
+&qupv3_se9_2uart {
+	status = "disabled";
+};
+
+&qupv3_se8_spi {
+	status = "disabled";
+};
+
+&qupv3_se10_2uart {
+	status = "ok";
+};
+
+&qupv3_se3_i2c {
+	status = "disabled";
+};
+
+&qupv3_se10_i2c {
+	status = "disabled";
+};
+
+&qupv3_se6_4uart {
+	status = "disabled";
+};
+
+&ufsphy_mem {
+	compatible = "qcom,ufs-phy-qrbtc-sdm845";
+
+	vdda-phy-supply = <&pm660l_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm660_l1>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_mem {
+	limit-tx-hs-gear = <1>;
+	limit-rx-hs-gear = <1>;
+	scsi-cmd-timeout = <300000>;
+
+	vdd-hba-supply = <&ufs_phy_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm660l_l4>;
+	vccq2-supply = <&pm660_l8>;
+	vcc-max-microamp = <600000>;
+	vccq2-max-microamp = <600000>;
+
+	qcom,vddp-ref-clk-supply = <&pm660_l1>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	qcom,disable-lpm;
+	rpm-level = <0>;
+	spm-level = <0>;
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
new file mode 100644
index 0000000..4ab0839
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-smp2p.dtsi
@@ -0,0 +1,179 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&soc {
+	qcom,smp2p-modem@1799000c {
+		compatible = "qcom,smp2p";
+		reg = <0x1799000c 0x4>;
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <GIC_SPI 451 IRQ_TYPE_EDGE_RISING>;
+	};
+
+	qcom,smp2p-adsp@1799000c {
+		compatible = "qcom,smp2p";
+		reg = <0x1799000c 0x4>;
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x200>;
+		interrupts = <GIC_SPI 157 IRQ_TYPE_EDGE_RISING>;
+	};
+
+	qcom,smp2p-cdsp@1799000c {
+		compatible = "qcom,smp2p";
+		reg = <0x1799000c 0x4>;
+		qcom,remote-pid = <5>;
+		qcom,irq-bitmask = <0x40>;
+		interrupts = <GIC_SPI 576 IRQ_TYPE_EDGE_RISING>;
+	};
+
+
+	smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+		gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+		gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	smp2pgpio_sleepstate_2_out: qcom,smp2pgpio-sleepstate-gpio-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "sleepstate";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio-sleepstate-2-out {
+		compatible = "qcom,smp2pgpio-sleepstate-out";
+		gpios = <&smp2pgpio_sleepstate_2_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_5_in: qcom,smp2pgpio-smp2p-5-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <5>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_5_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_5_in";
+		gpios = <&smp2pgpio_smp2p_5_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_5_out: qcom,smp2pgpio-smp2p-5-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <5>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_5_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_5_out";
+		gpios = <&smp2pgpio_smp2p_5_out 0 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 7bef48d..5392df0 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -12,6 +12,14 @@
 
 #include "skeleton64.dtsi"
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,gpucc-sdm845.h>
+#include <dt-bindings/clock/qcom,videocc-sdm845.h>
+#include <dt-bindings/clock/qcom,cpucc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM670";
@@ -19,7 +27,9 @@
 	qcom,msm-id = <336 0x0>;
 	interrupt-parent = <&intc>;
 
-	aliases { };
+	aliases {
+		ufshc1 = &ufshc_mem; /* Embedded UFS slot */
+	};
 
 	cpus {
 		#address-cells = <2>;
@@ -307,37 +317,37 @@
 		pil_cdsp_mem: cdsp_regions@93300000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x93300000 0 0x600000>;
+			reg = <0 0x93300000 0 0x800000>;
 		};
 
-		pil_mba_mem: pil_mba_region@0x93900000 {
+		pil_mba_mem: pil_mba_region@0x93b00000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x93900000 0 0x200000>;
+			reg = <0 0x93b00000 0 0x200000>;
 		};
 
-		pil_adsp_mem: pil_adsp_region@93b00000 {
+		pil_adsp_mem: pil_adsp_region@93d00000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x93b00000 0 0x1e00000>;
+			reg = <0 0x93d00000 0 0x1e00000>;
 		};
 
-		pil_ipa_fw_mem: pil_ipa_fw_region@95900000 {
+		pil_ipa_fw_mem: pil_ipa_fw_region@95b00000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x95900000 0 0x10000>;
+			reg = <0 0x95b00000 0 0x10000>;
 		};
 
-		pil_ipa_gsi_mem: pil_ipa_gsi_region@95910000 {
+		pil_ipa_gsi_mem: pil_ipa_gsi_region@95b10000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x95910000 0 0x5000>;
+			reg = <0 0x95b10000 0 0x5000>;
 		};
 
-		pil_gpu_mem: pil_gpu_region@95915000 {
+		pil_gpu_mem: pil_gpu_region@95b15000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x95915000 0 0x1000>;
+			reg = <0 0x95b15000 0 0x1000>;
 		};
 
 		adsp_mem: adsp_region {
@@ -386,6 +396,10 @@
 
 #include "sdm670-ion.dtsi"
 
+#include "sdm670-smp2p.dtsi"
+
+#include "sdm670-qupv3.dtsi"
+
 &soc {
 	#address-cells = <1>;
 	#size-cells = <1>;
@@ -412,6 +426,11 @@
 		clock-frequency = <19200000>;
 	};
 
+	qcom,sps {
+		compatible = "qcom,msm_sps_4k";
+		qcom,pipe-attr-ee;
+	};
+
 	timer@0x17c90000{
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -478,6 +497,54 @@
 		reg-names = "pshold-base", "tcsr-boot-misc-detect";
 	};
 
+	clock_rpmh: qcom,rpmhclk {
+		compatible = "qcom,dummycc";
+		clock-output-names = "rpmh_clocks";
+		#clock-cells = <1>;
+	};
+
+	clock_gcc: qcom,gcc@100000 {
+		compatible = "qcom,dummycc";
+		clock-output-names = "gcc_clocks";
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	clock_videocc: qcom,videocc@ab00000 {
+		compatible = "qcom,dummycc";
+		clock-output-names = "videocc_clocks";
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	clock_camcc: qcom,camcc@ad00000 {
+		compatible = "qcom,dummycc";
+		clock-output-names = "camcc_clocks";
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	clock_dispcc: qcom,dispcc@af00000 {
+		compatible = "qcom,dummycc";
+		clock-output-names = "dispcc_clocks";
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	clock_gpucc: qcom,gpucc@5090000 {
+		compatible = "qcom,dummycc";
+		clock-output-names = "gpucc_clocks";
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	clock_gfx: qcom,gfxcc@5090000  {
+		compatible = "qcom,dummycc";
+		clock-output-names = "gfxcc_clocks";
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
 	clock_cpucc: qcom,cpucc {
 		compatible = "qcom,dummycc";
 		clock-output-names = "cpucc_clocks";
@@ -595,6 +662,14 @@
 			qcom,dump-node = <&L1_D_700>;
 			qcom,dump-id = <0x87>;
 		};
+		qcom,llcc1_d_cache {
+			qcom,dump-node = <&LLCC_1>;
+			qcom,dump-id = <0x140>;
+		};
+		qcom,llcc2_d_cache {
+			qcom,dump-node = <&LLCC_2>;
+			qcom,dump-id = <0x141>;
+		};
 	};
 
 	kryo3xx-erp {
@@ -610,6 +685,225 @@
 				  "l3-scu-faultirq";
 	};
 
+	qcom,ipc-spinlock@1f40000 {
+		compatible = "qcom,ipc-spinlock-sfpb";
+		reg = <0x1f40000 0x8000>;
+		qcom,num-locks = <8>;
+	};
+
+	qcom,smem@86000000 {
+		compatible = "qcom,smem";
+		reg = <0x86000000 0x200000>,
+			<0x17911008 0x4>,
+			<0x778000 0x7000>,
+			<0x1fd4000 0x8>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1",
+			"smem_targ_info_reg";
+		qcom,mpu-enabled;
+	};
+
+	qmp_aop: mailbox@1799000c {
+		compatible = "qcom,qmp-mbox";
+		label = "aop";
+		reg = <0xc300000 0x100000>,
+			<0x1799000c 0x4>;
+		reg-names = "msgram", "irq-reg-base";
+		qcom,irq-mask = <0x1>;
+		interrupts = <0 389 1>;
+		mbox-desc-offset = <0x0>;
+		#mbox-cells = <1>;
+	};
+
+	qcom,glink-smem-native-xprt-modem@86000000 {
+		compatible = "qcom,glink-smem-native-xprt";
+		reg = <0x86000000 0x200000>,
+			<0x1799000c 0x4>;
+		reg-names = "smem", "irq-reg-base";
+		qcom,irq-mask = <0x1000>;
+		interrupts = <GIC_SPI 449 IRQ_TYPE_EDGE_RISING>;
+		label = "mpss";
+	};
+
+	qcom,glink-smem-native-xprt-adsp@86000000 {
+		compatible = "qcom,glink-smem-native-xprt";
+		reg = <0x86000000 0x200000>,
+			<0x1799000c 0x4>;
+		reg-names = "smem", "irq-reg-base";
+		qcom,irq-mask = <0x100>;
+		interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
+		label = "lpass";
+		qcom,qos-config = <&glink_qos_adsp>;
+		qcom,ramp-time = <0xaf>;
+	};
+
+	glink_qos_adsp: qcom,glink-qos-config-adsp {
+		compatible = "qcom,glink-qos-config";
+		qcom,flow-info = <0x3c 0x0>,
+				<0x3c 0x0>,
+				<0x3c 0x0>,
+				<0x3c 0x0>;
+		qcom,mtu-size = <0x800>;
+		qcom,tput-stats-cycle = <0xa>;
+	};
+
+	glink_spi_xprt_wdsp: qcom,glink-spi-xprt-wdsp {
+		compatible = "qcom,glink-spi-xprt";
+		label = "wdsp";
+		qcom,remote-fifo-config = <&glink_fifo_wdsp>;
+		qcom,qos-config = <&glink_qos_wdsp>;
+		qcom,ramp-time = <0x10>,
+				     <0x20>,
+				     <0x30>,
+				     <0x40>;
+	};
+
+	glink_fifo_wdsp: qcom,glink-fifo-config-wdsp {
+		compatible = "qcom,glink-fifo-config";
+		qcom,out-read-idx-reg = <0x12000>;
+		qcom,out-write-idx-reg = <0x12004>;
+		qcom,in-read-idx-reg = <0x1200C>;
+		qcom,in-write-idx-reg = <0x12010>;
+	};
+
+	glink_qos_wdsp: qcom,glink-qos-config-wdsp {
+		compatible = "qcom,glink-qos-config";
+		qcom,flow-info = <0x80 0x0>,
+				 <0x70 0x1>,
+				 <0x60 0x2>,
+				 <0x50 0x3>;
+		qcom,mtu-size = <0x800>;
+		qcom,tput-stats-cycle = <0xa>;
+	};
+
+	qcom,glink-smem-native-xprt-cdsp@86000000 {
+		compatible = "qcom,glink-smem-native-xprt";
+		reg = <0x86000000 0x200000>,
+			<0x1799000c 0x4>;
+		reg-names = "smem", "irq-reg-base";
+		qcom,irq-mask = <0x10>;
+		interrupts = <GIC_SPI 574 IRQ_TYPE_EDGE_RISING>;
+		label = "cdsp";
+	};
+
+	glink_mpss: qcom,glink-ssr-modem {
+		compatible = "qcom,glink_ssr";
+		label = "modem";
+		qcom,edge = "mpss";
+		qcom,notify-edges = <&glink_lpass>, <&glink_cdsp>;
+		qcom,xprt = "smem";
+	};
+
+	glink_lpass: qcom,glink-ssr-adsp {
+		compatible = "qcom,glink_ssr";
+		label = "adsp";
+		qcom,edge = "lpass";
+		qcom,notify-edges = <&glink_mpss>, <&glink_cdsp>;
+		qcom,xprt = "smem";
+	};
+
+	glink_cdsp: qcom,glink-ssr-cdsp {
+		compatible = "qcom,glink_ssr";
+		label = "cdsp";
+		qcom,edge = "cdsp";
+		qcom,notify-edges = <&glink_mpss>, <&glink_lpass>;
+		qcom,xprt = "smem";
+	};
+
+	qcom,ipc_router {
+		compatible = "qcom,ipc_router";
+		qcom,node-id = <1>;
+	};
+
+	qcom,ipc_router_modem_xprt {
+		compatible = "qcom,ipc_router_glink_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "mpss";
+		qcom,glink-xprt = "smem";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+
+	qcom,ipc_router_q6_xprt {
+		compatible = "qcom,ipc_router_glink_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "lpass";
+		qcom,glink-xprt = "smem";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+
+	qcom,ipc_router_cdsp_xprt {
+		compatible = "qcom,ipc_router_glink_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "cdsp";
+		qcom,glink-xprt = "smem";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+
+	qcom,glink_pkt {
+		compatible = "qcom,glinkpkt";
+
+		qcom,glinkpkt-at-mdm0 {
+			qcom,glinkpkt-transport = "smem";
+			qcom,glinkpkt-edge = "mpss";
+			qcom,glinkpkt-ch-name = "DS";
+			qcom,glinkpkt-dev-name = "at_mdm0";
+		};
+
+		qcom,glinkpkt-loopback_cntl {
+			qcom,glinkpkt-transport = "lloop";
+			qcom,glinkpkt-edge = "local";
+			qcom,glinkpkt-ch-name = "LOCAL_LOOPBACK_CLNT";
+			qcom,glinkpkt-dev-name = "glink_pkt_loopback_ctrl";
+		};
+
+		qcom,glinkpkt-loopback_data {
+			qcom,glinkpkt-transport = "lloop";
+			qcom,glinkpkt-edge = "local";
+			qcom,glinkpkt-ch-name = "glink_pkt_lloop_CLNT";
+			qcom,glinkpkt-dev-name = "glink_pkt_loopback";
+		};
+
+		qcom,glinkpkt-apr-apps2 {
+			qcom,glinkpkt-transport = "smem";
+			qcom,glinkpkt-edge = "adsp";
+			qcom,glinkpkt-ch-name = "apr_apps2";
+			qcom,glinkpkt-dev-name = "apr_apps2";
+		};
+
+		qcom,glinkpkt-data40-cntl {
+			qcom,glinkpkt-transport = "smem";
+			qcom,glinkpkt-edge = "mpss";
+			qcom,glinkpkt-ch-name = "DATA40_CNTL";
+			qcom,glinkpkt-dev-name = "smdcntl8";
+		};
+
+		qcom,glinkpkt-data1 {
+			qcom,glinkpkt-transport = "smem";
+			qcom,glinkpkt-edge = "mpss";
+			qcom,glinkpkt-ch-name = "DATA1";
+			qcom,glinkpkt-dev-name = "smd7";
+		};
+
+		qcom,glinkpkt-data4 {
+			qcom,glinkpkt-transport = "smem";
+			qcom,glinkpkt-edge = "mpss";
+			qcom,glinkpkt-ch-name = "DATA4";
+			qcom,glinkpkt-dev-name = "smd8";
+		};
+
+		qcom,glinkpkt-data11 {
+			qcom,glinkpkt-transport = "smem";
+			qcom,glinkpkt-edge = "mpss";
+			qcom,glinkpkt-ch-name = "DATA11";
+			qcom,glinkpkt-dev-name = "smd11";
+		};
+	};
+
 	qcom,chd_sliver {
 		compatible = "qcom,core-hang-detect";
 		label = "silver";
@@ -639,6 +933,39 @@
 		interrupts = <0 17 0>;
 	};
 
+	qcom,llcc@1100000 {
+		compatible = "qcom,llcc-core", "syscon", "simple-mfd";
+		reg = <0x1100000 0x250000>;
+		reg-names = "llcc_base";
+		qcom,llcc-banks-off = <0x0 0x80000 >;
+		qcom,llcc-broadcast-off = <0x200000>;
+
+		llcc: qcom,sdm670-llcc {
+			compatible = "qcom,sdm670-llcc";
+			#cache-cells = <1>;
+			max-slices = <32>;
+			qcom,dump-size = <0x80000>;
+		};
+
+		qcom,llcc-erp {
+			compatible = "qcom,llcc-erp";
+			interrupt-names = "ecc_irq";
+			interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		qcom,llcc-amon {
+			compatible = "qcom,llcc-amon";
+		};
+
+		LLCC_1: llcc_1_dcache {
+			qcom,dump-size = <0xd8000>;
+		};
+
+		LLCC_2: llcc_2_dcache {
+			qcom,dump-size = <0xd8000>;
+		};
+	};
+
 	dcc: dcc_v2@10a2000 {
 		compatible = "qcom,dcc_v2";
 		reg = <0x10a2000 0x1000>,
@@ -646,6 +973,164 @@
 		reg-names = "dcc-base", "dcc-ram-base";
 	};
 
+	spmi_bus: qcom,spmi@c440000 {
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0xc440000 0x1100>,
+		      <0xc600000 0x2000000>,
+		      <0xe600000 0x100000>,
+		      <0xe700000 0xa0000>,
+		      <0xc40a000 0x26000>;
+		reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+		interrupt-names = "periph_irq";
+		interrupts = <GIC_SPI 481 IRQ_TYPE_NONE>;
+		qcom,ee = <0>;
+		qcom,channel = <0>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+		interrupt-controller;
+		#interrupt-cells = <4>;
+		cell-index = <0>;
+	};
+
+	ufsphy_mem: ufsphy_mem@1d87000 {
+		reg = <0x1d87000 0xe00>; /* PHY regs */
+		reg-names = "phy_mem";
+		#phy-cells = <0>;
+
+		lanes-per-direction = <1>;
+
+		clock-names = "ref_clk_src",
+			"ref_clk",
+			"ref_aux_clk";
+		clocks = <&clock_rpmh RPMH_CXO_CLK>,
+			<&clock_gcc GCC_UFS_MEM_CLKREF_CLK>,
+			<&clock_gcc GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK>;
+
+		status = "disabled";
+	};
+
+	ufshc_mem: ufshc@1d84000 {
+		compatible = "qcom,ufshc";
+		reg = <0x1d84000 0x3000>;
+		interrupts = <0 265 0>;
+		phys = <&ufsphy_mem>;
+		phy-names = "ufsphy";
+
+		lanes-per-direction = <1>;
+		dev-ref-clk-freq = <0>; /* 19.2 MHz */
+
+		clock-names =
+			"core_clk",
+			"bus_aggr_clk",
+			"iface_clk",
+			"core_clk_unipro",
+			"core_clk_ice",
+			"ref_clk",
+			"tx_lane0_sync_clk",
+			"rx_lane0_sync_clk";
+		clocks =
+			<&clock_gcc GCC_UFS_PHY_AXI_HW_CTL_CLK>,
+			<&clock_gcc GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK>,
+			<&clock_gcc GCC_UFS_PHY_AHB_CLK>,
+			<&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK>,
+			<&clock_gcc GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK>,
+			<&clock_rpmh RPMH_CXO_CLK>,
+			<&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
+			<&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>;
+		freq-table-hz =
+			<50000000 200000000>,
+			<0 0>,
+			<0 0>,
+			<37500000 150000000>,
+			<75000000 300000000>,
+			<0 0>,
+			<0 0>,
+			<0 0>;
+
+		resets = <&clock_gcc GCC_UFS_PHY_BCR>;
+		reset-names = "core_reset";
+
+		status = "disabled";
+	};
 };
 
 #include "sdm670-pinctrl.dtsi"
+#include "msm-arm-smmu-sdm670.dtsi"
+#include "msm-gdsc-sdm845.dtsi"
+
+&usb30_prim_gdsc {
+	status = "ok";
+};
+
+&ufs_phy_gdsc {
+	status = "ok";
+};
+
+&hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc {
+	status = "ok";
+};
+
+&hlos1_vote_aggre_noc_mmu_tbu1_gdsc {
+	status = "ok";
+};
+
+&hlos1_vote_aggre_noc_mmu_tbu2_gdsc {
+	status = "ok";
+};
+
+&bps_gdsc {
+	status = "ok";
+};
+
+&ife_0_gdsc {
+	status = "ok";
+};
+
+&ife_1_gdsc {
+	status = "ok";
+};
+
+&ipe_0_gdsc {
+	status = "ok";
+};
+
+&ipe_1_gdsc {
+	status = "ok";
+};
+
+&titan_top_gdsc {
+	status = "ok";
+};
+
+&mdss_core_gdsc {
+	status = "ok";
+};
+
+&gpu_cx_gdsc {
+	status = "ok";
+};
+
+&gpu_gx_gdsc {
+	clock-names = "core_root_clk";
+	clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK_SRC>;
+	qcom,force-enable-root-clk;
+	status = "ok";
+};
+
+&vcodec0_gdsc {
+	qcom,support-hw-trigger;
+	status = "ok";
+};
+
+&vcodec1_gdsc {
+	qcom,support-hw-trigger;
+	status = "ok";
+};
+
+&venus_gdsc {
+	status = "ok";
+};
+
+#include "pm660.dtsi"
+#include "pm660l.dtsi"
+#include "sdm670-regulator.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
index 4b7a680..94d74e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
@@ -22,7 +22,7 @@
 	qcom,board-id = <1 1>;
 };
 
-&dsi_dual_nt35597_truly_cmd_display {
+&dsi_nt35597_truly_dsc_cmd_display {
 	/delete-property/ qcom,dsi-display-active;
 };
 
@@ -41,6 +41,17 @@
 	qcom,platform-reset-gpio = <&tlmm 6 0>;
 };
 
+&dsi_sharp_4k_dsc_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
 &dsi_sharp_4k_dsc_video_display {
 	qcom,dsi-display-active;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
index fcf6ad1..fca87e1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
@@ -22,12 +22,12 @@
 	qcom,board-id = <8 1>;
 };
 
-&dsi_dual_nt35597_truly_cmd_display {
+&dsi_nt35597_truly_dsc_cmd_display {
 	/delete-property/ qcom,dsi-display-active;
 };
 
 &mdss_mdp {
-	connectors = <&sde_rscc &sde_wb>;
+	connectors = <&sde_rscc &sde_wb &sde_dp>;
 };
 
 &dsi_sharp_4k_dsc_video {
@@ -41,6 +41,17 @@
 	qcom,platform-reset-gpio = <&tlmm 6 0>;
 };
 
+&dsi_sharp_4k_dsc_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
 &dsi_sharp_4k_dsc_video_display {
 	qcom,dsi-display-active;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
new file mode 100644
index 0000000..9208302
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm845-wcd.dtsi"
+#include "msm-wsa881x.dtsi"
+#include <dt-bindings/clock/qcom,audio-ext-clk.h>
+
+&snd_934x {
+	qcom,audio-routing =
+		"AIF4 VI", "MCLK",
+		"RX_BIAS", "MCLK",
+		"MADINPUT", "MCLK",
+		"hifi amp", "LINEOUT1",
+		"hifi amp", "LINEOUT2",
+		"AMIC2", "MIC BIAS2",
+		"MIC BIAS2", "Headset Mic",
+		"AMIC3", "MIC BIAS2",
+		"MIC BIAS2", "ANCRight Headset Mic",
+		"AMIC4", "MIC BIAS2",
+		"MIC BIAS2", "ANCLeft Headset Mic",
+		"AMIC5", "MIC BIAS3",
+		"MIC BIAS3", "Handset Mic",
+		"DMIC0", "MIC BIAS1",
+		"MIC BIAS1", "Digital Mic0",
+		"DMIC1", "MIC BIAS1",
+		"MIC BIAS1", "Digital Mic1",
+		"DMIC2", "MIC BIAS3",
+		"MIC BIAS3", "Digital Mic2",
+		"DMIC3", "MIC BIAS3",
+		"MIC BIAS3", "Digital Mic3",
+		"DMIC4", "MIC BIAS4",
+		"MIC BIAS4", "Digital Mic4",
+		"DMIC5", "MIC BIAS4",
+		"MIC BIAS4", "Digital Mic5",
+		"SpkrLeft IN", "SPK1 OUT",
+		"SpkrRight IN", "SPK2 OUT";
+
+	qcom,msm-mbhc-hphl-swh = <1>;
+	qcom,msm-mbhc-gnd-swh = <1>;
+	qcom,hph-en0-gpio = <&tavil_hph_en0>;
+	qcom,hph-en1-gpio = <&tavil_hph_en1>;
+	qcom,tavil-mclk-clk-freq = <9600000>;
+
+	asoc-codec = <&stub_codec>;
+	asoc-codec-names = "msm-stub-codec.1";
+
+	qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>;
+	qcom,usbc-analog-en2-gpio = <&tlmm 51 0>;
+	pinctrl-names = "aud_active", "aud_sleep";
+	pinctrl-0 = <&wcd_usbc_analog_en2_active>;
+	pinctrl-1 = <&wcd_usbc_analog_en2_idle>;
+
+	qcom,wsa-max-devs = <2>;
+	qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+			<&wsa881x_0213>, <&wsa881x_0214>;
+	qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+				  "SpkrLeft", "SpkrRight";
+};
+
+&soc {
+	wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl@49 {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wcd_usbc_analog_en1_active>;
+		pinctrl-1 = <&wcd_usbc_analog_en1_idle>;
+	};
+
+	wcd9xxx_intc: wcd9xxx-irq {
+		status = "ok";
+		compatible = "qcom,wcd9xxx-irq";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&tlmm>;
+		qcom,gpio-connect = <&tlmm 54 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&wcd_intr_default>;
+	};
+
+	clock_audio_lnbb: audio_ext_clk_lnbb {
+		status = "ok";
+		compatible = "qcom,audio-ref-clk";
+		clock-names = "osr_clk";
+		clocks = <&clock_rpmh RPMH_LN_BB_CLK2>;
+		qcom,node_has_rpm_clock;
+		#clock-cells = <1>;
+	};
+
+	wcd_rst_gpio: msm_cdc_pinctrl@64 {
+		compatible = "qcom,msm-cdc-pinctrl";
+		qcom,cdc-rst-n-gpio = <&tlmm 64 0>;
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cdc_reset_active>;
+		pinctrl-1 = <&cdc_reset_sleep>;
+	};
+
+	qocm,wcd-dsp-glink {
+		compatible = "qcom,wcd-dsp-glink";
+	};
+
+	qcom,wcd-dsp-mgr {
+		compatible = "qcom,wcd-dsp-mgr";
+		qcom,wdsp-components = <&wcd934x_cdc 0>,
+				       <&wcd_spi_0 1>,
+				       <&glink_spi_xprt_wdsp 2>;
+		qcom,img-filename = "cpe_9340";
+	};
+};
+
+&slim_aud {
+	wcd934x_cdc: tavil_codec {
+		compatible = "qcom,tavil-slim-pgd";
+		elemental-addr = [00 01 50 02 17 02];
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+			      17 18 19 20 21 22 23 24 25 26 27 28 29
+			      30 31>;
+
+		qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+		clock-names = "wcd_clk";
+		clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>;
+
+		cdc-vdd-buck-supply = <&pm8998_s4>;
+		qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-buck-current = <650000>;
+
+		cdc-buck-sido-supply = <&pm8998_s4>;
+		qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+		qcom,cdc-buck-sido-current = <250000>;
+
+		cdc-vdd-tx-h-supply = <&pm8998_s4>;
+		qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-tx-h-current = <25000>;
+
+		cdc-vdd-rx-h-supply = <&pm8998_s4>;
+		qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+		qcom,cdc-vdd-rx-h-current = <25000>;
+
+		cdc-vddpx-1-supply = <&pm8998_s4>;
+		qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+		qcom,cdc-vddpx-1-current = <10000>;
+
+		qcom,cdc-static-supplies = "cdc-vdd-buck",
+					   "cdc-buck-sido",
+					   "cdc-vdd-tx-h",
+					   "cdc-vdd-rx-h",
+					   "cdc-vddpx-1";
+
+		qcom,cdc-micbias1-mv = <1800>;
+		qcom,cdc-micbias2-mv = <1800>;
+		qcom,cdc-micbias3-mv = <1800>;
+		qcom,cdc-micbias4-mv = <1800>;
+
+		qcom,cdc-mclk-clk-rate = <9600000>;
+		qcom,cdc-slim-ifd = "tavil-slim-ifd";
+		qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02];
+		qcom,cdc-dmic-sample-rate = <4800000>;
+		qcom,cdc-mad-dmic-rate = <600000>;
+
+		qcom,wdsp-cmpnt-dev-name = "tavil_codec";
+
+		wcd_spi_0: wcd_spi {
+			compatible = "qcom,wcd-spi-v2";
+			qcom,master-bus-num = <0>;
+			qcom,chip-select = <0>;
+			qcom,max-frequency = <9600000>;
+			qcom,mem-base-addr = <0x100000>;
+		};
+
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
index 709c89d..dd82ad7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
@@ -12,9 +12,6 @@
  */
 
 #include "msm-audio-lpass.dtsi"
-#include "sdm845-wcd.dtsi"
-#include "msm-wsa881x.dtsi"
-#include <dt-bindings/clock/qcom,audio-ext-clk.h>
 
 &msm_audio_ion {
 	iommus = <&apps_smmu 0x1821 0x0>;
@@ -31,7 +28,7 @@
 		qcom,clk-mult = <10>;
 	};
 
-	sound-tavil {
+	snd_934x: sound-tavil {
 		compatible = "qcom,sdm845-asoc-snd-tavil";
 		qcom,model = "sdm845-tavil-snd-card";
 		qcom,wcn-btfm;
@@ -48,39 +45,6 @@
 			    "lpaif_tert_mode_muxsel",
 			    "lpaif_quat_mode_muxsel";
 
-		qcom,audio-routing =
-			"AIF4 VI", "MCLK",
-			"RX_BIAS", "MCLK",
-			"MADINPUT", "MCLK",
-			"hifi amp", "LINEOUT1",
-			"hifi amp", "LINEOUT2",
-			"AMIC2", "MIC BIAS2",
-			"MIC BIAS2", "Headset Mic",
-			"AMIC5", "MIC BIAS3",
-			"MIC BIAS3", "Handset Mic",
-			"DMIC0", "MIC BIAS1",
-			"MIC BIAS1", "Digital Mic0",
-			"DMIC1", "MIC BIAS1",
-			"MIC BIAS1", "Digital Mic1",
-			"DMIC2", "MIC BIAS3",
-			"MIC BIAS3", "Digital Mic2",
-			"DMIC3", "MIC BIAS3",
-			"MIC BIAS3", "Digital Mic3",
-			"DMIC4", "MIC BIAS4",
-			"MIC BIAS4", "Digital Mic4",
-			"DMIC5", "MIC BIAS4",
-			"MIC BIAS4", "Digital Mic5",
-			"SpkrLeft IN", "SPK1 OUT",
-			"SpkrRight IN", "SPK2 OUT";
-
-		qcom,msm-mbhc-hphl-swh = <1>;
-		qcom,msm-mbhc-gnd-swh = <1>;
-		qcom,hph-en0-gpio = <&tavil_hph_en0>;
-		qcom,hph-en1-gpio = <&tavil_hph_en1>;
-		qcom,tavil-mclk-clk-freq = <9600000>;
-
-		qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>;
-
 		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
 				<&loopback>, <&compress>, <&hostless>,
 				<&afe>, <&lsm>, <&routing>, <&compr>,
@@ -132,65 +96,6 @@
 				"msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
 				"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
 				"msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
-		asoc-codec = <&stub_codec>;
-		asoc-codec-names = "msm-stub-codec.1";
-		qcom,wsa-max-devs = <2>;
-		qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
-				<&wsa881x_0213>, <&wsa881x_0214>;
-		qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
-					  "SpkrLeft", "SpkrRight";
-
-		qcom,usbc-analog-en2-gpio = <&tlmm 51 0>;
-		pinctrl-names = "aud_active", "aud_sleep";
-		pinctrl-0 = <&wcd_usbc_analog_en2_active>;
-		pinctrl-1 = <&wcd_usbc_analog_en2_idle>;
-	};
-
-	wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl@49 {
-		compatible = "qcom,msm-cdc-pinctrl";
-		pinctrl-names = "aud_active", "aud_sleep";
-		pinctrl-0 = <&wcd_usbc_analog_en1_active>;
-		pinctrl-1 = <&wcd_usbc_analog_en1_idle>;
-	};
-
-	wcd9xxx_intc: wcd9xxx-irq {
-		status = "ok";
-		compatible = "qcom,wcd9xxx-irq";
-		interrupt-controller;
-		#interrupt-cells = <1>;
-		interrupt-parent = <&tlmm>;
-		qcom,gpio-connect = <&tlmm 54 0>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&wcd_intr_default>;
-	};
-
-	clock_audio_lnbb: audio_ext_clk_lnbb {
-		status = "ok";
-		compatible = "qcom,audio-ref-clk";
-		clock-names = "osr_clk";
-		clocks = <&clock_rpmh RPMH_LN_BB_CLK2>;
-		qcom,node_has_rpm_clock;
-		#clock-cells = <1>;
-	};
-
-	wcd_rst_gpio: msm_cdc_pinctrl@64 {
-		compatible = "qcom,msm-cdc-pinctrl";
-		qcom,cdc-rst-n-gpio = <&tlmm 64 0>;
-		pinctrl-names = "aud_active", "aud_sleep";
-		pinctrl-0 = <&cdc_reset_active>;
-		pinctrl-1 = <&cdc_reset_sleep>;
-	};
-
-	qocm,wcd-dsp-glink {
-		compatible = "qcom,wcd-dsp-glink";
-	};
-
-	qcom,wcd-dsp-mgr {
-		compatible = "qcom,wcd-dsp-mgr";
-		qcom,wdsp-components = <&wcd934x_cdc 0>,
-				       <&wcd_spi_0 1>,
-				       <&glink_spi_xprt_wdsp 2>;
-		qcom,img-filename = "cpe_9340";
 	};
 };
 
@@ -199,66 +104,4 @@
 		compatible = "qcom,msm-dai-slim";
 		elemental-addr = [ff ff ff fe 17 02];
 	};
-
-	wcd934x_cdc: tavil_codec {
-		compatible = "qcom,tavil-slim-pgd";
-		elemental-addr = [00 01 50 02 17 02];
-
-		interrupt-parent = <&wcd9xxx_intc>;
-		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-			      17 18 19 20 21 22 23 24 25 26 27 28 29
-			      30 31>;
-
-		qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
-
-		clock-names = "wcd_clk";
-		clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>;
-
-		cdc-vdd-buck-supply = <&pm8998_s4>;
-		qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
-		qcom,cdc-vdd-buck-current = <650000>;
-
-		cdc-buck-sido-supply = <&pm8998_s4>;
-		qcom,cdc-buck-sido-voltage = <1800000 1800000>;
-		qcom,cdc-buck-sido-current = <250000>;
-
-		cdc-vdd-tx-h-supply = <&pm8998_s4>;
-		qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
-		qcom,cdc-vdd-tx-h-current = <25000>;
-
-		cdc-vdd-rx-h-supply = <&pm8998_s4>;
-		qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
-		qcom,cdc-vdd-rx-h-current = <25000>;
-
-		cdc-vddpx-1-supply = <&pm8998_s4>;
-		qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
-		qcom,cdc-vddpx-1-current = <10000>;
-
-		qcom,cdc-static-supplies = "cdc-vdd-buck",
-					   "cdc-buck-sido",
-					   "cdc-vdd-tx-h",
-					   "cdc-vdd-rx-h",
-					   "cdc-vddpx-1";
-
-		qcom,cdc-micbias1-mv = <1800>;
-		qcom,cdc-micbias2-mv = <1800>;
-		qcom,cdc-micbias3-mv = <1800>;
-		qcom,cdc-micbias4-mv = <1800>;
-
-		qcom,cdc-mclk-clk-rate = <9600000>;
-		qcom,cdc-slim-ifd = "tavil-slim-ifd";
-		qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02];
-		qcom,cdc-dmic-sample-rate = <4800000>;
-		qcom,cdc-mad-dmic-rate = <600000>;
-
-		qcom,wdsp-cmpnt-dev-name = "tavil_codec";
-
-		wcd_spi_0: wcd_spi {
-			compatible = "qcom,wcd-spi-v2";
-			qcom,master-bus-num = <0>;
-			qcom,chip-select = <0>;
-			qcom,max-frequency = <9600000>;
-			qcom,mem-base-addr = <0x100000>;
-		};
-	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index e26f888..3ce5611 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -12,6 +12,7 @@
 
 #include <dt-bindings/msm/msm-bus-ids.h>
 #include <dt-bindings/soc/qcom,tcs-mbox.h>
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
 
 &soc {
 	ad_hoc_bus: ad-hoc-bus {
@@ -355,7 +356,8 @@
 			label = "fab-aggre1_noc";
 			qcom,fab-dev;
 			qcom,base-name = "aggre1_noc-base";
-			qcom,bypass-qos-prg;
+			qcom,qos-off = <4096>;
+			qcom,base-offset = <16384>;
 			qcom,bus-type = <1>;
 			clocks = <>;
 		};
@@ -365,7 +367,8 @@
 			label = "fab-aggre2_noc";
 			qcom,fab-dev;
 			qcom,base-name = "aggre2_noc-base";
-			qcom,bypass-qos-prg;
+			qcom,qos-off = <4096>;
+			qcom,base-offset = <16384>;
 			qcom,bus-type = <1>;
 			clocks = <>;
 		};
@@ -432,7 +435,8 @@
 			label = "fab-mem_noc";
 			qcom,fab-dev;
 			qcom,base-name = "mem_noc-base";
-			qcom,bypass-qos-prg;
+			qcom,qos-off = <4096>;
+			qcom,base-offset = <65536>;
 			qcom,bus-type = <1>;
 			clocks = <>;
 		};
@@ -442,7 +446,8 @@
 			label = "fab-mmss_noc";
 			qcom,fab-dev;
 			qcom,base-name = "mmss_noc-base";
-			qcom,bypass-qos-prg;
+			qcom,qos-off = <4096>;
+			qcom,base-offset = <36864>;
 			qcom,bus-type = <1>;
 			clocks = <>;
 		};
@@ -452,7 +457,8 @@
 			label = "fab-system_noc";
 			qcom,fab-dev;
 			qcom,base-name = "system_noc-base";
-			qcom,bypass-qos-prg;
+			qcom,qos-off = <4096>;
+			qcom,base-offset = <36864>;
 			qcom,bus-type = <1>;
 			clocks = <>;
 		};
@@ -471,6 +477,8 @@
 			label = "fab-mem_noc_display";
 			qcom,fab-dev;
 			qcom,base-name = "mem_noc-base";
+			qcom,qos-off = <4096>;
+			qcom,base-offset = <65536>;
 			qcom,bypass-qos-prg;
 			qcom,bus-type = <1>;
 			clocks = <>;
@@ -524,6 +532,8 @@
 			qcom,qport = <1>;
 			qcom,connections = <&slv_qns_a1noc_snoc>;
 			qcom,bus-dev = <&fab_aggre1_noc>;
+			qcom,ap-owned;
+			qcom,prio = <1>;
 		};
 
 		mas_xm_sdc4: mas-xm-sdc4 {
@@ -534,6 +544,8 @@
 			qcom,qport = <2>;
 			qcom,connections = <&slv_qns_a1noc_snoc>;
 			qcom,bus-dev = <&fab_aggre1_noc>;
+			qcom,ap-owned;
+			qcom,prio = <1>;
 		};
 
 		mas_xm_ufs_card: mas-xm-ufs-card {
@@ -544,6 +556,8 @@
 			qcom,qport = <3>;
 			qcom,connections = <&slv_qns_a1noc_snoc>;
 			qcom,bus-dev = <&fab_aggre1_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		mas_xm_ufs_mem: mas-xm-ufs-mem {
@@ -554,6 +568,8 @@
 			qcom,qport = <4>;
 			qcom,connections = <&slv_qns_a1noc_snoc>;
 			qcom,bus-dev = <&fab_aggre1_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		mas_qhm_a2noc_cfg: mas-qhm-a2noc-cfg {
@@ -592,6 +608,8 @@
 			qcom,qport = <0>;
 			qcom,connections = <&slv_qns_a2noc_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
+			qcom,ap-owned;
+			qcom,prio = <1>;
 		};
 
 		mas_qxm_crypto: mas-qxm-crypto {
@@ -603,6 +621,8 @@
 			qcom,connections = <&slv_qns_a2noc_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
 			qcom,bcms = <&bcm_ce0>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		mas_qxm_ipa: mas-qxm-ipa {
@@ -613,6 +633,7 @@
 			qcom,qport = <2>;
 			qcom,connections = <&slv_qns_a2noc_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
+			qcom,prio = <2>;
 		};
 
 		mas_xm_pcie3_1: mas-xm-pcie3-1 {
@@ -623,6 +644,8 @@
 			qcom,qport = <6>;
 			qcom,connections = <&slv_qns_pcie_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		mas_xm_pcie_0: mas-xm-pcie-0 {
@@ -632,7 +655,9 @@
 			qcom,agg-ports = <1>;
 			qcom,qport = <5>;
 			qcom,connections = <&slv_qns_pcie_snoc>;
-			qcom,bus-dev = <&fab_aggre2_noc>;
+			qcom,bus-dev = <&fab_aggre1_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		mas_xm_qdss_etr: mas-xm-qdss-etr {
@@ -643,6 +668,8 @@
 			qcom,qport = <7>;
 			qcom,connections = <&slv_qns_a2noc_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		mas_xm_usb3_0: mas-xm-usb3-0 {
@@ -653,6 +680,14 @@
 			qcom,qport = <10>;
 			qcom,connections = <&slv_qns_a2noc_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
+			qcom,node-qos-clks {
+				clocks =
+				<&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>;
+				clock-names =
+				"clk-usb3-prim-axi-no-rate";
+			};
 		};
 
 		mas_xm_usb3_1: mas-xm-usb3-1 {
@@ -663,6 +698,14 @@
 			qcom,qport = <11>;
 			qcom,connections = <&slv_qns_a2noc_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
+			qcom,node-qos-clks {
+				clocks =
+				<&clock_gcc GCC_AGGRE_USB3_SEC_AXI_CLK>;
+				clock-names =
+				"clk-usb3-sec-axi-no-rate";
+			};
 		};
 
 		mas_qxm_camnoc_hf0_uncomp: mas-qxm-camnoc-hf0-uncomp {
@@ -825,12 +868,12 @@
 			qcom,bus-dev = <&fab_gladiator_noc>;
 		};
 
-		mas_ipa_core: mas-ipa-core {
+		mas_ipa_core_master: mas-ipa-core-master {
 			cell-id = <MSM_BUS_MASTER_IPA_CORE>;
-			label = "mas-ipa-core";
-			qcom,buswidth = <1>;
+			label = "mas-ipa-core-master";
+			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
-			qcom,connections = <&slv_ipa_core>;
+			qcom,connections = <&slv_ipa_core_slave>;
 			qcom,bus-dev = <&fab_ipa_virt>;
 		};
 
@@ -853,6 +896,8 @@
 				&slv_qns_memnoc_snoc>;
 			qcom,bus-dev = <&fab_mem_noc>;
 			qcom,bcms = <&bcm_sh3>;
+			qcom,ap-owned;
+			qcom,prio = <6>;
 		};
 
 		mas_qhm_memnoc_cfg: mas-qhm-memnoc-cfg {
@@ -874,6 +919,8 @@
 			qcom,connections = <&slv_qns_llcc>;
 			qcom,bus-dev = <&fab_mem_noc>;
 			qcom,bcms = <&bcm_sh5>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
 		};
 
 		mas_qnm_mnoc_hf: mas-qnm-mnoc-hf {
@@ -884,6 +931,10 @@
 			qcom,qport = <4 5>;
 			qcom,connections = <&slv_qns_apps_io &slv_qns_llcc>;
 			qcom,bus-dev = <&fab_mem_noc>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qnm_mnoc_sf: mas-qnm-mnoc-sf {
@@ -895,6 +946,10 @@
 			qcom,connections = <&slv_qns_apps_io
 				 &slv_qns_llcc &slv_qns_memnoc_snoc>;
 			qcom,bus-dev = <&fab_mem_noc>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qnm_snoc_gc: mas-qnm-snoc-gc {
@@ -905,6 +960,9 @@
 			qcom,qport = <8>;
 			qcom,connections = <&slv_qns_llcc>;
 			qcom,bus-dev = <&fab_mem_noc>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
 		};
 
 		mas_qnm_snoc_sf: mas-qnm-snoc-sf {
@@ -915,6 +973,9 @@
 			qcom,qport = <9>;
 			qcom,connections = <&slv_qns_apps_io &slv_qns_llcc>;
 			qcom,bus-dev = <&fab_mem_noc>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
 		};
 
 		mas_qxm_gpu: mas-qxm-gpu {
@@ -926,7 +987,8 @@
 			qcom,connections = <&slv_qns_apps_io
 				 &slv_qns_llcc &slv_qns_memnoc_snoc>;
 			qcom,bus-dev = <&fab_mem_noc>;
-			qcom,bcms = <&bcm_sh4>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
 		};
 
 		mas_qhm_mnoc_cfg: mas-qhm-mnoc-cfg {
@@ -947,6 +1009,10 @@
 			qcom,connections = <&slv_qns_mem_noc_hf>;
 			qcom,bus-dev = <&fab_mmss_noc>;
 			qcom,bcms = <&bcm_mm1>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qxm_camnoc_hf1: mas-qxm-camnoc-hf1 {
@@ -958,6 +1024,10 @@
 			qcom,connections = <&slv_qns_mem_noc_hf>;
 			qcom,bus-dev = <&fab_mmss_noc>;
 			qcom,bcms = <&bcm_mm1>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qxm_camnoc_sf: mas-qxm-camnoc-sf {
@@ -969,6 +1039,10 @@
 			qcom,connections = <&slv_qns2_mem_noc>;
 			qcom,bus-dev = <&fab_mmss_noc>;
 			qcom,bcms = <&bcm_mm3>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qxm_mdp0: mas-qxm-mdp0 {
@@ -980,6 +1054,10 @@
 			qcom,connections = <&slv_qns_mem_noc_hf>;
 			qcom,bus-dev = <&fab_mmss_noc>;
 			qcom,bcms = <&bcm_mm1>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qxm_mdp1: mas-qxm-mdp1 {
@@ -991,6 +1069,10 @@
 			qcom,connections = <&slv_qns_mem_noc_hf>;
 			qcom,bus-dev = <&fab_mmss_noc>;
 			qcom,bcms = <&bcm_mm1>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qxm_rot: mas-qxm-rot {
@@ -1002,6 +1084,10 @@
 			qcom,connections = <&slv_qns2_mem_noc>;
 			qcom,bus-dev = <&fab_mmss_noc>;
 			qcom,bcms = <&bcm_mm3>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qxm_venus0: mas-qxm-venus0 {
@@ -1013,6 +1099,10 @@
 			qcom,connections = <&slv_qns2_mem_noc>;
 			qcom,bus-dev = <&fab_mmss_noc>;
 			qcom,bcms = <&bcm_mm3>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qxm_venus1: mas-qxm-venus1 {
@@ -1024,6 +1114,10 @@
 			qcom,connections = <&slv_qns2_mem_noc>;
 			qcom,bus-dev = <&fab_mmss_noc>;
 			qcom,bcms = <&bcm_mm3>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qxm_venus_arm9: mas-qxm-venus-arm9 {
@@ -1035,6 +1129,10 @@
 			qcom,connections = <&slv_qns2_mem_noc>;
 			qcom,bus-dev = <&fab_mmss_noc>;
 			qcom,bcms = <&bcm_mm3>;
+			qcom,ap-owned;
+			qcom,prio = <0>;
+			qcom,forwarding;
+			qcom,node-qos-bcms = <7012 0 1>;
 		};
 
 		mas_qhm_snoc_cfg: mas-qhm-snoc-cfg {
@@ -1120,6 +1218,8 @@
 			qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn4>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		mas_alc: mas-alc {
@@ -1687,10 +1787,10 @@
 			qcom,bus-dev = <&fab_gladiator_noc>;
 		};
 
-		slv_ipa_core:slv-ipa-core {
-			cell-id = <MSM_BUS_SLAVE_IPA>;
-			label = "slv-ipa-core";
-			qcom,buswidth = <1>;
+		slv_ipa_core_slave:slv-ipa-core-slave {
+			cell-id = <MSM_BUS_SLAVE_IPA_CORE>;
+			label = "slv-ipa-core-slave";
+			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
 			qcom,bus-dev = <&fab_ipa_virt>;
 			qcom,bcms = <&bcm_ip0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 885234f..91b8738 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -343,17 +343,17 @@
 		clock-names = "gcc_ahb_clk",
 			"gcc_axi_clk",
 			"soc_ahb_clk",
-			"cpas_ahb_clk",
 			"slow_ahb_clk_src",
+			"cpas_ahb_clk",
 			"camnoc_axi_clk";
 		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
 			<&clock_gcc GCC_CAMERA_AXI_CLK>,
 			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
-			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
 			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
 			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>;
 		src-clock-name = "slow_ahb_clk_src";
-		clock-rates = <0 0 0 0 80000000 0>;
+		clock-rates = <0 0 0 80000000 0 0>;
 		qcom,msm-bus,name = "cam_ahb";
 		qcom,msm-bus,num-cases = <4>;
 		qcom,msm-bus,num-paths = <1>;
@@ -772,6 +772,7 @@
 		camss-vdd-supply = <&titan_top_gdsc>;
 		clock-names = "gcc_cam_ahb_clk",
 			"gcc_cam_axi_clk",
+			"soc_fast_ahb",
 			"soc_ahb_clk",
 			"cpas_ahb_clk",
 			"camnoc_axi_clk",
@@ -780,6 +781,7 @@
 			"icp_clk_src";
 		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
 				<&clock_gcc GCC_CAMERA_AXI_CLK>,
+				<&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>,
 				<&clock_camcc CAM_CC_SOC_AHB_CLK>,
 				<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
 				<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
@@ -787,7 +789,7 @@
 				<&clock_camcc CAM_CC_ICP_CLK>,
 				<&clock_camcc CAM_CC_ICP_CLK_SRC>;
 
-		clock-rates = <0 0 0 80000000 0 0 0 600000000>;
+		clock-rates = <0 0 400000000 0 0 0 0 0 600000000>;
 		fw_name = "CAMERA_ICP.elf";
 		status = "ok";
 	};
@@ -808,7 +810,7 @@
 				<&clock_camcc CAM_CC_IPE_0_CLK>,
 				<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
 
-		clock-rates = <80000000 400000000 0 0 600000000>;
+		clock-rates = <0 0 0 0 600000000>;
 		status = "ok";
 	};
 
@@ -828,7 +830,7 @@
 				<&clock_camcc CAM_CC_IPE_1_CLK>,
 				<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
 
-		clock-rates = <80000000 400000000 0 0 600000000>;
+		clock-rates = <0 0 0 0 600000000>;
 		status = "ok";
 	};
 
@@ -848,7 +850,7 @@
 				<&clock_camcc CAM_CC_BPS_CLK>,
 				<&clock_camcc CAM_CC_BPS_CLK_SRC>;
 
-		clock-rates = <80000000 400000000 0 0 600000000>;
+		clock-rates = <0 0 0 0 600000000>;
 		status = "ok";
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi
new file mode 100644
index 0000000..68f2e51
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm845-audio-overlay.dtsi"
+
+&soc {
+	sound-tavil {
+		qcom,us-euro-gpios = <&tavil_us_euro_sw>;
+	};
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
index ef964ae..4747c99 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
@@ -19,7 +19,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 #include "sdm845-cdp.dtsi"
-#include "sdm845-qupv3.dtsi"
+#include "sdm845-cdp-audio-overlay.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM845 v1 CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 5e370d6..dee2ec2 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -37,10 +37,6 @@
 };
 
 &soc {
-	sound-tavil {
-		qcom,us-euro-gpios = <&tavil_us_euro_sw>;
-	};
-
 	gpio_keys {
 		compatible = "gpio-keys";
 		label = "gpio-keys";
@@ -155,6 +151,8 @@
 	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
 	qcom,vddp-ref-clk-max-microamp = <100>;
 
+	extcon = <&extcon_storage_cd>;
+
 	status = "ok";
 };
 
@@ -213,14 +211,6 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&usb2_vbus_boost_default>;
 	};
-
-aliases {
-		serial0 = &qupv3_se9_2uart;
-		spi0 = &qupv3_se8_spi;
-		i2c0 = &qupv3_se10_i2c;
-		i2c1 = &qupv3_se3_i2c;
-		hsuart0 = &qupv3_se6_4uart;
-	};
 };
 
 &qupv3_se9_2uart {
@@ -274,6 +264,14 @@
 	qcom,platform-reset-gpio = <&tlmm 6 0>;
 };
 
+&dsi_sharp_1080_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
 &dsi_sim_vid {
 	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
 	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
@@ -298,7 +296,7 @@
 	qcom,platform-reset-gpio = <&tlmm 6 0>;
 };
 
-&dsi_dual_nt35597_truly_cmd_display {
+&dsi_nt35597_truly_dsc_cmd_display {
 	qcom,dsi-display-active;
 };
 
@@ -307,6 +305,12 @@
 	qcom,led-strings-list = [01 02];
 };
 
+&pmi8998_haptics {
+	qcom,vmax-mv = <2400>;
+	qcom,lra-auto-mode;
+	status = "okay";
+};
+
 &qupv3_se8_spi {
 	status = "ok";
 };
@@ -326,7 +330,9 @@
 		interrupts = <63 0>;
 		interrupt-names = "nfc_irq";
 		pinctrl-names = "nfc_active", "nfc_suspend";
-		pinctrl-0 = <&nfc_int_active &nfc_enable_active>;
+		pinctrl-0 = <&nfc_int_active
+			     &nfc_enable_active
+			     &nfc_clk_default>;
 		pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
 		clocks = <&clock_rpmh RPMH_LN_BB_CLK3>;
 		clock-names = "ref_clk";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index e32ec6e..d2189a7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -245,6 +245,8 @@
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
 
+		qcom,msr-fix-req;
+
 		port {
 			tpdm_swao1_out_tpda_swao: endpoint {
 				remote-endpoint = <&tpda_swao_in_tpdm_swao1>;
@@ -767,13 +769,42 @@
 					    <&tpdm_lpass_out_funnel_lpass>;
 				};
 			};
+		};
+	};
 
-			port@2 {
+	funnel_lpass_1: funnel_1@6845000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6867010 0x10>,
+		      <0x6845000 0x1000>;
+		reg-names = "funnel-base-dummy", "funnel-base-real";
+
+		coresight-name = "coresight-funnel-lpass-1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		qcom,duplicate-funnel;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_lpass_1_out_funnel_qatb: endpoint {
+					remote-endpoint =
+					    <&funnel_qatb_in_funnel_lpass_1>;
+				};
+			};
+
+			port@1 {
 				reg = <1>;
-				funnel_lpass_in_audio_etm0: endpoint {
+				funnel_lpass_1_in_audio_etm0: endpoint {
 					slave-mode;
 					remote-endpoint =
-					    <&audio_etm0_out_funnel_lpass>;
+					    <&audio_etm0_out_funnel_lpass_1>;
 				};
 			};
 		};
@@ -790,6 +821,8 @@
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
 
+		qcom,msr-fix-req;
+
 		port {
 			tpdm_lpass_out_funnel_lpass: endpoint {
 				remote-endpoint = <&funnel_lpass_in_tpdm_lpass>;
@@ -808,6 +841,8 @@
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
 
+		qcom,msr-fix-req;
+
 		port {
 			tpdm_center_out_tpda: endpoint {
 				remote-endpoint = <&tpda_in_tpdm_center>;
@@ -826,6 +861,8 @@
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
 
+		qcom,msr-fix-req;
+
 		port {
 			tpdm_north_out_tpda: endpoint {
 				remote-endpoint = <&tpda_in_tpdm_north>;
@@ -1061,6 +1098,8 @@
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
 
+		qcom,msr-fix-req;
+
 		port {
 			tpdm_mm_out_funnel_dl_mm: endpoint {
 				remote-endpoint = <&funnel_dl_mm_in_tpdm_mm>;
@@ -1100,13 +1139,42 @@
 					    <&tpdm_turing_out_funnel_turing>;
 				};
 			};
+		};
+	};
 
-			port@2 {
+	funnel_turing_1: funnel_1@6861000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6867000 0x10>,
+		      <0x6861000 0x1000>;
+		reg-names = "funnel-base-dummy", "funnel-base-real";
+
+		coresight-name = "coresight-funnel-turing-1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		qcom,duplicate-funnel;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_turing_1_out_funnel_qatb: endpoint {
+					remote-endpoint =
+					    <&funnel_qatb_in_funnel_turing_1>;
+				};
+			};
+
+			port@1 {
 				reg = <1>;
-				funnel_turing_in_turing_etm0: endpoint {
+				funnel_turing_1_in_turing_etm0: endpoint {
 					slave-mode;
 					remote-endpoint =
-					    <&turing_etm0_out_funnel_turing>;
+					    <&turing_etm0_out_funnel_turing_1>;
 				};
 			};
 		};
@@ -1123,6 +1191,8 @@
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
 
+		qcom,msr-fix-req;
+
 		port {
 			tpdm_turing_out_funnel_turing: endpoint {
 				remote-endpoint =
@@ -1177,6 +1247,8 @@
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
 
+		qcom,msr-fix-req;
+
 		port {
 			tpdm_ddr_out_funnel_ddr_0: endpoint {
 				remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>;
@@ -1318,7 +1390,6 @@
 
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
-		qcom,msr-fix-req;
 
 		port{
 			tpdm_spss_out_tpda_spss: endpoint {
@@ -1394,6 +1465,24 @@
 						<&tpda_out_funnel_qatb>;
 				};
 			};
+
+			port@2 {
+				reg = <6>;
+				funnel_qatb_in_funnel_lpass_1: endpoint {
+					slave-mode;
+					remote-endpoint =
+					    <&funnel_lpass_1_out_funnel_qatb>;
+				};
+			};
+
+			port@3 {
+				reg = <7>;
+				funnel_qatb_in_funnel_turing_1: endpoint {
+					slave-mode;
+					remote-endpoint =
+					    <&funnel_turing_1_out_funnel_qatb>;
+				};
+			};
 		};
 	};
 
@@ -1780,9 +1869,9 @@
 		qcom,inst-id = <13>;
 
 		port{
-			turing_etm0_out_funnel_turing: endpoint {
+			turing_etm0_out_funnel_turing_1: endpoint {
 				remote-endpoint =
-					<&funnel_turing_in_turing_etm0>;
+					<&funnel_turing_1_in_turing_etm0>;
 			};
 		};
 	};
@@ -1823,8 +1912,9 @@
 		qcom,inst-id = <5>;
 
 		port {
-			audio_etm0_out_funnel_lpass: endpoint {
-				remote-endpoint = <&funnel_lpass_in_audio_etm0>;
+			audio_etm0_out_funnel_lpass_1: endpoint {
+				remote-endpoint =
+					<&funnel_lpass_1_in_audio_etm0>;
 			};
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index e5ea108..1ce68e1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -278,7 +278,7 @@
 
 			qcom,gmu-pwrlevel@1 {
 				reg = <1>;
-				qcom,gmu-freq = <19200000>;
+				qcom,gmu-freq = <200000000>;
 			};
 
 			qcom,gmu-pwrlevel@2 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
index 548bd49..52c0f05 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
@@ -19,7 +19,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 #include "sdm845-mtp.dtsi"
-#include "sdm845-qupv3.dtsi"
+#include "sdm845-audio-overlay.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM845 v1 MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index dc3f14f..fb31b05 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -150,7 +150,7 @@
 	qcom,platform-reset-gpio = <&tlmm 6 0>;
 };
 
-&dsi_dual_nt35597_truly_cmd_display {
+&dsi_nt35597_truly_dsc_cmd_display {
 	qcom,dsi-display-active;
 };
 
@@ -159,6 +159,12 @@
 	qcom,led-strings-list = [01 02];
 };
 
+&pmi8998_haptics {
+	qcom,vmax-mv = <2400>;
+	qcom,lra-auto-mode;
+	status = "okay";
+};
+
 &mdss_mdp {
 	#cooling-cells = <2>;
 };
@@ -221,6 +227,8 @@
 	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
 	qcom,vddp-ref-clk-max-microamp = <100>;
 
+	extcon = <&extcon_storage_cd>;
+
 	status = "ok";
 };
 
@@ -277,16 +285,6 @@
 	status = "ok";
 };
 
-/ {
-aliases {
-		serial0 = &qupv3_se9_2uart;
-		spi0 = &qupv3_se8_spi;
-		i2c0 = &qupv3_se10_i2c;
-		i2c1 = &qupv3_se3_i2c;
-		hsuart0 = &qupv3_se6_4uart;
-	};
-};
-
 &qupv3_se9_2uart {
 	status = "ok";
 };
@@ -310,7 +308,9 @@
 		interrupts = <63 0>;
 		interrupt-names = "nfc_irq";
 		pinctrl-names = "nfc_active", "nfc_suspend";
-		pinctrl-0 = <&nfc_int_active &nfc_enable_active>;
+		pinctrl-0 = <&nfc_int_active
+			     &nfc_enable_active
+			     &nfc_clk_default>;
 		pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
 		clocks = <&clock_rpmh RPMH_LN_BB_CLK3>;
 		clock-names = "ref_clk";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 9946a25..2a7b6d1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -2796,18 +2796,70 @@
 				bias-disable;
 			};
 		};
+
+		tsif0_signals_active: tsif0_signals_active {
+			tsif1_clk {
+				pins = "gpio89"; /* TSIF0 CLK */
+				function = "tsif1_clk";
+			};
+			tsif1_en {
+				pins = "gpio90"; /* TSIF0 Enable */
+				function = "tsif1_en";
+			};
+			tsif1_data {
+				pins = "gpio91"; /* TSIF0 DATA */
+				function = "tsif1_data";
+			};
+			signals_cfg {
+				pins = "gpio89", "gpio90", "gpio91";
+				drive_strength = <2>;	/* 2 mA */
+				bias-pull-down;		/* pull down */
+			};
+		};
+
+		/* sync signal is only used if configured to mode-2 */
+		tsif0_sync_active: tsif0_sync_active {
+			tsif1_sync {
+				pins = "gpio12";	/* TSIF0 SYNC */
+				function = "tsif1_sync";
+				drive_strength = <2>;	/* 2 mA */
+				bias-pull-down;		/* pull down */
+			};
+		};
+
+		tsif1_signals_active: tsif1_signals_active {
+			tsif2_clk {
+				pins = "gpio93"; /* TSIF1 CLK */
+				function = "tsif2_clk";
+			};
+			tsif2_en {
+				pins = "gpio94"; /* TSIF1 Enable */
+				function = "tsif2_en";
+			};
+			tsif2_data {
+				pins = "gpio95"; /* TSIF1 DATA */
+				function = "tsif2_data";
+			};
+			signals_cfg {
+				pins = "gpio93", "gpio94", "gpio95";
+				drive_strength = <2>;	/* 2 mA */
+				bias-pull-down;		/* pull down */
+			};
+		};
+
+		/* sync signal is only used if configured to mode-2 */
+		tsif1_sync_active: tsif1_sync_active {
+			tsif2_sync {
+				pins = "gpio96";	/* TSIF1 SYNC */
+				function = "tsif2_sync";
+				drive_strength = <2>;	/* 2 mA */
+				bias-pull-down;		/* pull down */
+			};
+		};
 	};
 };
 
 &pm8998_gpios {
-	gpio@d400 {
-		qcom,mode = <0>;
-		qcom,vin-sel = <1>;
-		qcom,src-sel = <0>;
-		qcom,master-en = <1>;
-		status = "okay";
-	};
-
 	key_home {
 		key_home_default: key_home_default {
 			pins = "gpio5";
@@ -2865,6 +2917,15 @@
 			output-low;
 		};
 	};
+
+	nfc_clk {
+		nfc_clk_default: nfc_clk_default {
+			pins = "gpio21";
+			function = "normal";
+			input-enable;
+			power-source = <1>;
+		};
+	};
 };
 
 &pmi8998_gpios {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
index 6806145..6215771 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
@@ -23,8 +23,6 @@
 			#size-cells = <0>;
 			label = "L3";
 			qcom,spm-device-names = "L3";
-			qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5 &CPU6
-				&CPU7>;
 			qcom,psci-mode-shift = <4>;
 			qcom,psci-mode-mask = <0xfff>;
 
@@ -86,12 +84,64 @@
 				qcom,is-reset;
 				qcom,notify-rpm;
 			};
-
-			qcom,pm-cpu {
+			qcom,pm-cpu@0 {
 				#address-cells = <1>;
 				#size-cells = <0>;
 				qcom,psci-mode-shift = <0>;
 				qcom,psci-mode-mask = <0xf>;
+				qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>;
+
+				qcom,pm-cpu-level@0 { /* C1 */
+					reg = <0>;
+					qcom,spm-cpu-mode = "wfi";
+					qcom,psci-cpu-mode = <0x1>;
+					qcom,latency-us = <43>;
+					qcom,ss-power = <454>;
+					qcom,energy-overhead = <38639>;
+					qcom,time-overhead = <83>;
+				};
+
+				qcom,pm-cpu-level@1 { /* C2D */
+					reg = <1>;
+					qcom,psci-cpu-mode = <0x2>;
+					qcom,spm-cpu-mode = "ret";
+					qcom,latency-us = <86>;
+					qcom,ss-power = <449>;
+					qcom,energy-overhead = <78456>;
+					qcom,time-overhead = <167>;
+				};
+
+				qcom,pm-cpu-level@2 {  /* C3 */
+					reg = <2>;
+					qcom,spm-cpu-mode = "pc";
+					qcom,psci-cpu-mode = <0x3>;
+					qcom,latency-us = <612>;
+					qcom,ss-power = <436>;
+					qcom,energy-overhead = <418225>;
+					qcom,time-overhead = <885>;
+					qcom,is-reset;
+					qcom,use-broadcast-timer;
+				};
+
+				qcom,pm-cpu-level@3 {  /* C4 */
+					reg = <3>;
+					qcom,spm-cpu-mode = "rail-pc";
+					qcom,psci-cpu-mode = <0x4>;
+					qcom,latency-us = <700>;
+					qcom,ss-power = <400>;
+					qcom,energy-overhead = <428225>;
+					qcom,time-overhead = <1000>;
+					qcom,is-reset;
+					qcom,use-broadcast-timer;
+				};
+			};
+
+			qcom,pm-cpu@1 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				qcom,psci-mode-shift = <0>;
+				qcom,psci-mode-mask = <0xf>;
+				qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>;
 
 				qcom,pm-cpu-level@0 { /* C1 */
 					reg = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
new file mode 100644
index 0000000..2ee9031
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm845-audio-overlay.dtsi"
+
+&soc {
+	sound-tavil {
+		qcom,wsa-max-devs = <1>;
+		qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>;
+		qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight";
+
+		qcom,msm-mbhc-usbc-audio-supported = <1>;
+
+		qcom,usbc-analog-en2-gpio = <&tlmm 51 0>;
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wcd_usbc_analog_en2_active>;
+		pinctrl-1 = <&wcd_usbc_analog_en2_idle>;
+	};
+};
+
+&wcd934x_cdc {
+	wcd_pinctrl@5 {
+		us_euro_sw_wcd_active {
+			mux {
+				pins = "gpio1";
+			};
+
+			config {
+				pins = "gpio1";
+				/delete-property/ output-high;
+				bias-high-impedance;
+			};
+		};
+
+		us_euro_sw_wcd_sleep {
+			mux {
+				pins = "gpio1";
+			};
+
+			config {
+				pins = "gpio1";
+				/delete-property/ output-low;
+				bias-high-impedance;
+			};
+		};
+	};
+
+	swr_master {
+		wsa881x@20170211 {
+			compatible = "qcom,wsa881x";
+			reg = <0x00 0x20170211>;
+			qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+		};
+
+		wsa881x@21170213 {
+			compatible = "qcom,wsa881x";
+			reg = <0x00 0x21170213>;
+			qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+		};
+	};
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
new file mode 100644
index 0000000..5729d76
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-overlay.dts
@@ -0,0 +1,29 @@
+/* Copyright (c) 2017, 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-qrd.dtsi"
+#include "sdm845-qrd-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM845 v1 QRD";
+	compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+	qcom,msm-id = <321 0x0>;
+	qcom,board-id = <11 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 8ed3edb..7982625 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -40,14 +40,6 @@
 		#include "fg-gen3-batterydata-itech-3000mah.dtsi"
 		#include "fg-gen3-batterydata-ascent-3450mah.dtsi"
 	};
-
-	aliases {
-		serial0 = &qupv3_se9_2uart;
-		spi0 = &qupv3_se8_spi;
-		i2c0 = &qupv3_se10_i2c;
-		i2c1 = &qupv3_se3_i2c;
-		hsuart0 = &qupv3_se6_4uart;
-	};
 };
 
 &qupv3_se9_2uart {
@@ -73,7 +65,9 @@
 		interrupts = <63 0>;
 		interrupt-names = "nfc_irq";
 		pinctrl-names = "nfc_active", "nfc_suspend";
-		pinctrl-0 = <&nfc_int_active &nfc_enable_active>;
+		pinctrl-0 = <&nfc_int_active
+			     &nfc_enable_active
+			     &nfc_clk_default>;
 		pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
 		clocks = <&clock_rpmh RPMH_LN_BB_CLK3>;
 		clock-names = "ref_clk";
@@ -100,49 +94,6 @@
 	#cooling-cells = <2>;
 };
 
-&soc {
-	sound-tavil {
-		qcom,wsa-max-devs = <1>;
-		qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>;
-		qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight";
-
-		qcom,msm-mbhc-usbc-audio-supported = <1>;
-
-		qcom,usbc-analog-en2-gpio = <&tlmm 51 0>;
-		pinctrl-names = "aud_active", "aud_sleep";
-		pinctrl-0 = <&wcd_usbc_analog_en2_active>;
-		pinctrl-1 = <&wcd_usbc_analog_en2_idle>;
-	};
-};
-
-&wcd934x_cdc {
-	wcd: wcd_pinctrl@5 {
-		us_euro_sw_wcd_active: us_euro_sw_wcd_active {
-			mux {
-				pins = "gpio1";
-			};
-
-			config {
-				pins = "gpio1";
-				/delete-property/ output-high;
-				bias-high-impedance;
-			};
-		};
-
-		us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep {
-			mux {
-				pins = "gpio1";
-			};
-
-			config {
-				pins = "gpio1";
-				/delete-property/ output-low;
-				bias-high-impedance;
-			};
-		};
-	};
-};
-
 &ufsphy_mem {
 	compatible = "qcom,ufs-phy-qmp-v3";
 
@@ -201,6 +152,8 @@
 	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
 	qcom,vddp-ref-clk-max-microamp = <100>;
 
+	extcon = <&extcon_storage_cd>;
+
 	status = "ok";
 };
 
@@ -252,6 +205,18 @@
 	qcom,mdss-dsi-panel-orientation = "180";
 };
 
+&dsi_sharp_4k_dsc_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+	qcom,mdss-dsi-panel-orientation = "180";
+};
+
 &dsi_sharp_4k_dsc_video_display {
 	qcom,dsi-display-active;
 };
@@ -263,3 +228,189 @@
 &ext_5v_boost {
 	status = "ok";
 };
+
+&pm8998_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@85 {
+		label = "vcoin";
+		reg = <0x85>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4d {
+		label = "msm_therm";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4f {
+		label = "pa_therm1";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@51 {
+		label = "quiet_therm";
+		reg = <0x51>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+};
+
+&pm8998_adc_tm {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,btm-channel-number = <0x60>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x68>;
+		qcom,thermal-node;
+	};
+
+	chan@4d {
+		label = "msm_therm";
+		reg = <0x4d>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x70>;
+		qcom,thermal-node;
+	};
+
+	chan@4f {
+		label = "pa_therm1";
+		reg = <0x4f>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x78>;
+		qcom,thermal-node;
+	};
+
+	chan@51 {
+		label = "quiet_therm";
+		reg = <0x51>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x80>;
+		qcom,thermal-node;
+	};
+};
+
+&thermal_zones {
+	xo-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4c>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	msm-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4d>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	pa-therm1-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4f>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	quiet-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x51>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 7befe3b..661de93 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -192,10 +192,62 @@
 					 1950 2632>;
 
 				qcom,cpr-open-loop-voltage-fuse-adjustment =
-					<100000 100000 100000 100000>;
+					/* Speed bin 0 */
+					<100000 100000 100000 100000>,
+					<     0      0      0 100000>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					/* Speed bin 1 */
+					<100000 100000 100000 100000>,
+					<     0      0      0 100000>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					/* Speed bin 2 */
+					<100000 100000 100000 100000>,
+					<     0      0      0 100000>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>;
 
 				qcom,cpr-closed-loop-voltage-fuse-adjustment =
-					<100000 100000 100000 100000>;
+					/* Speed bin 0 */
+					<100000 100000 100000 100000>,
+					<     0      0      0 100000>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					/* Speed bin 1 */
+					<100000 100000 100000 100000>,
+					<     0      0      0 100000>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					/* Speed bin 2 */
+					<100000 100000 100000 100000>,
+					<     0      0      0 100000>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>,
+					<     0      0      0      0>;
 
 				qcom,allow-voltage-interpolation;
 				qcom,allow-quotient-interpolation;
@@ -323,10 +375,62 @@
 					 2501 2095>;
 
 				qcom,cpr-open-loop-voltage-fuse-adjustment =
-					<100000 100000 100000 100000>;
+					/* Speed bin 0 */
+					<100000 100000 100000 100000>,
+					<     0  24000   4000 100000>,
+					<     0  24000   4000      0>,
+					<     0  24000   4000      0>,
+					<     0  24000   4000      0>,
+					<     0  24000   4000      0>,
+					<     0  24000   4000      0>,
+					<     0  24000   4000      0>,
+					/* Speed bin 1 */
+					<100000 100000 100000 100000>,
+					<     0  24000   4000 100000>,
+					<     0  24000   4000  20000>,
+					<     0  24000   4000  20000>,
+					<     0  24000   4000  20000>,
+					<     0  24000   4000  20000>,
+					<     0  24000   4000  20000>,
+					<     0  24000   4000  20000>,
+					/* Speed bin 2 */
+					<100000 100000 100000 100000>,
+					<     0  24000   4000 100000>,
+					<     0  24000   4000  40000>,
+					<     0  24000   4000  40000>,
+					<     0  24000   4000  40000>,
+					<     0  24000   4000  40000>,
+					<     0  24000   4000  40000>,
+					<     0  24000   4000  40000>;
 
 				qcom,cpr-closed-loop-voltage-fuse-adjustment =
-					<100000 100000 100000 100000>;
+					/* Speed bin 0 */
+					<100000 100000 100000 100000>,
+					<     0  29000   6000 100000>,
+					<     0  29000   6000      0>,
+					<     0  29000   6000      0>,
+					<     0  29000   6000      0>,
+					<     0  29000   6000      0>,
+					<     0  29000   6000      0>,
+					<     0  29000   6000      0>,
+					/* Speed bin 1 */
+					<100000 100000 100000 100000>,
+					<     0  29000   6000 100000>,
+					<     0  29000   6000  20000>,
+					<     0  29000   6000  20000>,
+					<     0  29000   6000  20000>,
+					<     0  29000   6000  20000>,
+					<     0  29000   6000  20000>,
+					<     0  29000   6000  20000>,
+					/* Speed bin 2 */
+					<100000 100000 100000 100000>,
+					<     0  29000   6000 100000>,
+					<     0  29000   6000  40000>,
+					<     0  29000   6000  40000>,
+					<     0  29000   6000  40000>,
+					<     0  29000   6000  40000>,
+					<     0  29000   6000  40000>,
+					<     0  29000   6000  40000>;
 
 				qcom,allow-voltage-interpolation;
 				qcom,allow-quotient-interpolation;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 1500bb5..83feac0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -153,8 +153,8 @@
 		label = "dsi_sharp_1080_cmd_display";
 		qcom,display-type = "primary";
 
-		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
-		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+		qcom,dsi-ctrl = <&mdss_dsi0>;
+		qcom,dsi-phy = <&mdss_dsi_phy0>;
 		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
 			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
 		clock-names = "src_byte_clk", "src_pixel_clk";
@@ -399,15 +399,15 @@
 			 <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
 			 <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>,
 			 <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
-			 <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
 			 <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+			 <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
 			 <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>,
 			 <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>;
 		clock-names = "core_aux_clk", "core_usb_ref_clk_src",
 			"core_usb_ref_clk", "core_usb_cfg_ahb_clk",
 			"core_usb_pipe_clk", "ctrl_link_clk",
-			"ctrl_link_iface_clk", "ctrl_crypto_clk",
-			"ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent";
+			"ctrl_link_iface_clk", "ctrl_pixel_clk",
+			"crypto_clk", "pixel_clk_rcg", "pixel_parent";
 
 		qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
 
@@ -493,7 +493,8 @@
 	qcom,mdss-dsi-t-clk-post = <0x0b>;
 	qcom,mdss-dsi-t-clk-pre = <0x23>;
 	qcom,display-topology = <1 1 1>,
-				<2 2 1>;
+				<2 2 1>, /* dsc merge */
+				<2 1 1>; /* 3d mux */
 	qcom,default-topology-index = <0>;
 };
 
@@ -502,7 +503,8 @@
 	qcom,mdss-dsi-t-clk-post = <0x0b>;
 	qcom,mdss-dsi-t-clk-pre = <0x23>;
 	qcom,display-topology = <1 1 1>,
-				<2 2 1>;
+				<2 2 1>, /* dsc merge */
+				<2 1 1>; /* 3d mux */
 	qcom,default-topology-index = <0>;
 };
 
@@ -532,8 +534,10 @@
 };
 
 &dsi_sharp_1080_cmd {
-	qcom,display-topology = <2 0 2>,
-				<1 0 2>;
+	qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 07 04 03 04 00];
+	qcom,mdss-dsi-t-clk-post = <0x0c>;
+	qcom,mdss-dsi-t-clk-pre = <0x29>;
+	qcom,display-topology = <1 0 1>;
 	qcom,default-topology-index = <0>;
 };
 
@@ -541,22 +545,34 @@
 	qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
 	qcom,mdss-dsi-t-clk-post = <0x0d>;
 	qcom,mdss-dsi-t-clk-pre = <0x2d>;
+	qcom,display-topology = <1 0 1>,
+				<2 0 1>;
+	qcom,default-topology-index = <0>;
 };
 
 &dsi_dual_sim_vid {
 	qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
 	qcom,mdss-dsi-t-clk-post = <0x0d>;
 	qcom,mdss-dsi-t-clk-pre = <0x2d>;
+	qcom,display-topology = <2 0 2>,
+				<1 0 2>;
+	qcom,default-topology-index = <0>;
 };
 
 &dsi_sim_cmd {
 	qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
 	qcom,mdss-dsi-t-clk-post = <0x0d>;
 	qcom,mdss-dsi-t-clk-pre = <0x2d>;
+	qcom,display-topology = <1 0 1>,
+				<2 0 1>;
+	qcom,default-topology-index = <0>;
 };
 
 &dsi_dual_sim_cmd {
 	qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
 	qcom,mdss-dsi-t-clk-post = <0x0d>;
 	qcom,mdss-dsi-t-clk-pre = <0x2d>;
+	qcom,display-topology = <2 0 2>,
+				<1 0 2>;
+	qcom,default-topology-index = <0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 2a29283..e31f8fd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -86,8 +86,6 @@
 		qcom,sde-dither-version = <0x00010000>;
 		qcom,sde-dither-size = <0x20>;
 
-		qcom,sde-intf-max-prefetch-lines = <0x15 0x15 0x15 0x15>;
-
 		qcom,sde-sspp-type = "vig", "vig", "vig", "vig",
 					"dma", "dma", "dma", "dma";
 
@@ -170,7 +168,14 @@
 		qcom,sde-qos-lut-cwb =
 			<0 0x75300000 0x00000000>;
 
+		qcom,sde-cdp-setting = <1 1>, <1 0>;
+
 		qcom,sde-inline-rotator = <&mdss_rotator 0>;
+		qcom,sde-inline-rot-xin = <10 11>;
+		qcom,sde-inline-rot-xin-type = "sspp", "wb";
+
+		/* offsets are relative to "mdp_phys + qcom,sde-off */
+		qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>;
 
 		qcom,sde-reg-dma-off = <0>;
 		qcom,sde-reg-dma-version = <0x1>;
@@ -204,13 +209,33 @@
 
 		/* data and reg bus scale settings */
 		qcom,sde-data-bus {
-			qcom,msm-bus,name = "mdss_sde";
+			qcom,msm-bus,name = "mdss_sde_mnoc";
 			qcom,msm-bus,num-cases = <3>;
 			qcom,msm-bus,num-paths = <2>;
 			qcom,msm-bus,vectors-KBps =
-				<22 512 0 0>, <23 512 0 0>,
-				<22 512 0 6400000>, <23 512 0 6400000>,
-				<22 512 0 6400000>, <23 512 0 6400000>;
+			    <22 773 0 0>, <23 773 0 0>,
+			    <22 773 0 6400000>, <23 773 0 6400000>,
+			    <22 773 0 6400000>, <23 773 0 6400000>;
+		};
+
+		qcom,sde-llcc-bus {
+			qcom,msm-bus,name = "mdss_sde_llcc";
+			qcom,msm-bus,num-cases = <3>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+			    <132 770 0 0>,
+			    <132 770 0 6400000>,
+			    <132 770 0 6400000>;
+		};
+
+		qcom,sde-ebi-bus {
+			qcom,msm-bus,name = "mdss_sde_ebi";
+			qcom,msm-bus,num-cases = <3>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+			    <129 512 0 0>,
+			    <129 512 0 6400000>,
+			    <129 512 0 6400000>;
 		};
 
 		qcom,sde-reg-bus {
@@ -247,14 +272,36 @@
 
 		/* data and reg bus scale settings */
 		qcom,sde-data-bus {
-			qcom,msm-bus,name = "disp_rsc";
+			qcom,msm-bus,name = "disp_rsc_mnoc";
 			qcom,msm-bus,active-only;
 			qcom,msm-bus,num-cases = <3>;
 			qcom,msm-bus,num-paths = <2>;
 			qcom,msm-bus,vectors-KBps =
-			    <20003 20512 0 0>, <20004 20512 0 0>,
-			    <20003 20512 0 6400000>, <20004 20512 0 6400000>,
-			    <20003 20512 0 6400000>, <20004 20512 0 6400000>;
+			    <20003 20515 0 0>, <20004 20515 0 0>,
+			    <20003 20515 0 6400000>, <20004 20515 0 6400000>,
+			    <20003 20515 0 6400000>, <20004 20515 0 6400000>;
+		};
+
+		qcom,sde-llcc-bus {
+			qcom,msm-bus,name = "disp_rsc_llcc";
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-cases = <3>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+			    <20001 20513 0 0>,
+			    <20001 20513 0 6400000>,
+			    <20001 20513 0 6400000>;
+		};
+
+		qcom,sde-ebi-bus {
+			qcom,msm-bus,name = "disp_rsc_ebi";
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,num-cases = <3>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+			    <20000 20512 0 0>,
+			    <20000 20512 0 6400000>,
+			    <20000 20512 0 6400000>;
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index 3870d8f..53cb27e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -25,13 +25,15 @@
 		#size-cells = <1>;
 		ranges;
 
-		interrupts = <0 489 0>, <0 130 0>, <0 486 0>;
-		interrupt-names = "hs_phy_irq", "pwr_event_irq", "ss_phy_irq";
+		interrupts = <0 489 0>, <0 130 0>, <0 486 0>, <0 488 0>;
+		interrupt-names = "dp_hs_phy_irq", "pwr_event_irq",
+				"ss_phy_irq", "dm_hs_phy_irq";
 
 		USB3_GDSC-supply = <&usb30_prim_gdsc>;
 		qcom,usb-dbm = <&dbm_1p5>;
 		qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
 		qcom,num-gsi-evt-buffs = <0x3>;
+		qcom,use-pdc-interrupts;
 		extcon = <&pmi8998_pdphy>, <&pmi8998_pdphy>, <&eud>;
 
 		clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>,
@@ -139,6 +141,8 @@
 			    0x00 0x23c /* CHG_CTRL2 */
 			    0x22 0x210>; /* PWR_CTRL1 */
 
+		qcom,phy-auto-resume-offset = <0x254>;
+
 		phy_type= "utmi";
 		clocks = <&clock_rpmh RPMH_CXO_CLK>,
 			 <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
@@ -322,11 +326,13 @@
 		#size-cells = <1>;
 		ranges;
 
-		interrupts = <0 491 0>, <0 135 0>, <0 487 0>;
-		interrupt-names = "hs_phy_irq", "pwr_event_irq", "ss_phy_irq";
+		interrupts = <0 491 0>, <0 135 0>, <0 487 0>, <0 490 0>;
+		interrupt-names = "dp_hs_phy_irq", "pwr_event_irq",
+				"ss_phy_irq", "dm_hs_phy_irq";
 
 		USB3_GDSC-supply = <&usb30_sec_gdsc>;
 		qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
+		qcom,use-pdc-interrupts;
 
 		clocks = <&clock_gcc GCC_USB30_SEC_MASTER_CLK>,
 			 <&clock_gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>,
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts
new file mode 100644
index 0000000..8a9a544
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-qrd.dts
@@ -0,0 +1,23 @@
+/* Copyright (c) 2017, 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm845-v2.dtsi"
+#include "sdm845-qrd.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM845 V2 QRD";
+	compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+	qcom,board-id = <11 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index efd8c32..bf72741 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -20,3 +20,19 @@
 &spmi_debug_bus {
 	status = "ok";
 };
+
+&clock_gcc {
+	compatible = "qcom,gcc-sdm845-v2";
+};
+
+&clock_camcc {
+	compatible = "qcom,cam_cc-sdm845-v2";
+};
+
+&clock_dispcc {
+	compatible = "qcom,dispcc-sdm845-v2";
+};
+
+&clock_videocc {
+	compatible = "qcom,video_cc-sdm845-v2";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index af12224..1c07c5e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -16,16 +16,10 @@
 
 &soc {
 	msm_vidc: qcom,vidc@aa00000 {
-		compatible = "qcom,msm-vidc";
+		compatible = "qcom,msm-vidc", "qcom,sdm845-vidc";
 		status = "ok";
 		reg = <0xaa00000 0x200000>;
 		interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
-		qcom,hfi = "venus";
-		qcom,firmware-name = "venus";
-		qcom,never-unload-fw;
-		qcom,sw-power-collapse;
-		qcom,max-secure-instances = <5>;
-		qcom,max-hw-load = <2563200>; /* Full 4k @ 60 + 1080p @ 60 */
 
 		/* LLCC Info */
 		cache-slice-names = "vidsc0", "vidsc1";
@@ -51,23 +45,8 @@
 			"bus_clk", "core0_clk", "core0_bus_clk",
 			"core1_clk", "core1_bus_clk";
 		qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x1 0x0>;
-		qcom,allowed-clock-rates = <200000000 320000000 380000000
-			444000000 533000000>;
-		qcom,max-hq-mbs-per-frame = <8160>;
-		qcom,max-hq-frames-per-sec = <60>;
-		qcom,clock-freq-tbl {
-			qcom,profile-enc {
-				qcom,codec-mask = <0x55555555>;
-				qcom,vpp-cycles-per-mb = <675>;
-				qcom,vsp-cycles-per-mb = <125>;
-				qcom,low-power-cycles-per-mb = <320>;
-			};
-			qcom,profile-dec {
-				qcom,codec-mask = <0xffffffff>;
-				qcom,vpp-cycles-per-mb = <200>;
-				qcom,vsp-cycles-per-mb = <50>;
-			};
-		};
+		qcom,allowed-clock-rates = <100000000 200000000 320000000
+			380000000 444000000 533000000>;
 
 		/* Buses */
 		bus_cnoc {
@@ -84,7 +63,7 @@
 			label = "venus-ddr";
 			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
 			qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
-			qcom,bus-governor = "performance";
+			qcom,bus-governor = "msm-vidc-ddr";
 			qcom,bus-range-kbps = <1000 3388000>;
 		};
 		arm9_bus_ddr {
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 6284361..555718d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -39,6 +39,14 @@
 		sdhc2 = &sdhc_2; /* SDC2 SD card slot */
 	};
 
+	aliases {
+		serial0 = &qupv3_se9_2uart;
+		spi0 = &qupv3_se8_spi;
+		i2c0 = &qupv3_se10_i2c;
+		i2c1 = &qupv3_se3_i2c;
+		hsuart0 = &qupv3_se6_4uart;
+	};
+
 	cpus {
 		#address-cells = <2>;
 		#size-cells = <0>;
@@ -337,25 +345,31 @@
 	};
 
 	energy-costs {
+		compatible = "sched-energy";
+
 		CPU_COST_0: core-cost0 {
 			busy-cost-data = <
-				 92   34 /*  300000 */
-				129   40 /*  422400 */
-				153   43 /*  499200 */
-				177   48 /*  576000 */
-				200   52 /*  652800 */
-				230   58 /*  748800 */
-				253   64 /*  825600 */
-				277   70 /*  902400 */
-				301   76 /*  979200 */
-				324   83 /* 1056000 */
-				348   90 /* 1132800 */
-				371   98 /* 1209600 */
-				395  105 /* 1286400 */
-				419  114 /* 1363200 */
-				442  123 /* 1440000 */
-				466  135 /* 1516800 */
-				490  152 /* 1593600 */
+				 300000   31
+				 422400   38
+				 499200   42
+				 576000   46
+				 652800   51
+				 748800   58
+				 825600   64
+				 902400   70
+				 979200   76
+				1056000   83
+				1132800   90
+				1209600   97
+				1286400  105
+				1363200  114
+				1440000  124
+				1516800  136
+				1593600  152
+				1651200  167 /* speedbin 0,1 */
+				1670400  173 /* speedbin 2 */
+				1708800  186 /* speedbin 0,1 */
+				1747200  201 /* speedbin 2 */
 			>;
 			idle-cost-data = <
 				22 18 14 12
@@ -363,28 +377,32 @@
 		};
 		CPU_COST_1: core-cost1 {
 			busy-cost-data = <
-				156  240 /*  300000 */
-				220  247 /*  422400 */
-				261  252 /*  499200 */
-				301  257 /*  576000 */
-				341  264 /*  652800 */
-				381  272 /*  729600 */
-				421  281 /*  806400 */
-				461  292 /*  883200 */
-				501  306 /*  960000 */
-				542  324 /* 1036800 */
-				582  346 /* 1113600 */
-				622  373 /* 1190400 */
-				662  407 /* 1267200 */
-				702  450 /* 1344000 */
-				742  504 /* 1420800 */
-				783  570 /* 1497600 */
-				823  649 /* 1574400 */
-				863  743 /* 1651200 */
-				903  849 /* 1728000 */
-				943  960 /* 1804800 */
-				983 1062 /* 1881600 */
-			       1024 1131 /* 1958400 */
+				300000   258
+				422400   260
+				499200   261
+				576000   263
+				652800   267
+				729600   272
+				806400   280
+				883200   291
+				960000   305
+			       1036800   324
+			       1113600   348
+			       1190400   378
+			       1267200   415
+			       1344000   460
+			       1420800   513
+			       1497600   576
+			       1574400   649
+			       1651200   732
+			       1728000   824
+			       1804800   923
+			       1881600  1027
+			       1958400  1131
+			       2035000  1228 /* speedbin 1,2 */
+			       2092000  1290 /* speedbin 1 */
+			       2112000  1308 /* speedbin 2 */
+			       2208000  1363 /* speedbin 2 */
 			>;
 			idle-cost-data = <
 				100 80 60 40
@@ -392,23 +410,27 @@
 		};
 		CLUSTER_COST_0: cluster-cost0 {
 			busy-cost-data = <
-				 92   3 /*  300000 */
-				129   4 /*  422400 */
-				153   4 /*  499200 */
-				177   4 /*  576000 */
-				200   5 /*  652800 */
-				230   5 /*  748800 */
-				253   6 /*  825600 */
-				277   7 /*  902400 */
-				301   7 /*  979200 */
-				324   8 /* 1056000 */
-				348   9 /* 1132800 */
-				371   9 /* 1209600 */
-				395  10 /* 1286400 */
-				419  11 /* 1363200 */
-				442  12 /* 1440000 */
-				466  13 /* 1516800 */
-				490  15 /* 1593600 */
+				 300000   3
+				 422400   4
+				 499200   4
+				 576000   4
+				 652800   5
+				 748800   5
+				 825600   6
+				 902400   7
+				 979200   7
+				1056000   8
+				1132800   9
+				1209600   9
+				1286400  10
+				1363200  11
+				1440000  12
+				1516800  13
+				1593600  15
+				1651200  17 /* speedbin 0,1 */
+				1670400  19 /* speedbin 2 */
+				1708800  21 /* speedbin 0,1 */
+				1747200  23 /* speedbin 2 */
 			>;
 			idle-cost-data = <
 				4 3 2 1
@@ -416,28 +438,32 @@
 		};
 		CLUSTER_COST_1: cluster-cost1 {
 			busy-cost-data = <
-				156  24 /*  300000 */
-				220  24 /*  422400 */
-				261  25 /*  499200 */
-				301  25 /*  576000 */
-				341  26 /*  652800 */
-				381  27 /*  729600 */
-				421  28 /*  806400 */
-				461  29 /*  883200 */
-				501  30 /*  960000 */
-				542  32 /* 1036800 */
-				582  34 /* 1113600 */
-				622  37 /* 1190400 */
-				662  40 /* 1267200 */
-				702  45 /* 1344000 */
-				742  50 /* 1420800 */
-				783  57 /* 1497600 */
-				823  64 /* 1574400 */
-				863  74 /* 1651200 */
-				903  84 /* 1728000 */
-				943  96 /* 1804800 */
-				983 106 /* 1881600 */
-			       1024 113 /* 1958400 */
+				300000  24
+				422400  24
+				499200  25
+				576000  25
+				652800  26
+				729600  27
+				806400  28
+				883200  29
+				960000  30
+			       1036800  32
+			       1113600  34
+			       1190400  37
+			       1267200  40
+			       1344000  45
+			       1420800  50
+			       1497600  57
+			       1574400  64
+			       1651200  74
+			       1728000  84
+			       1804800  96
+			       1881600 106
+			       1958400 113
+			       2035000 120 /* speedbin 1,2 */
+			       2092000 125 /* speedbin 1 */
+			       2112000 127 /* speedbin 2 */
+			       2208000 130 /* speedbin 2 */
 			>;
 			idle-cost-data = <
 				4 3 2 1
@@ -462,6 +488,11 @@
 	firmware: firmware {
 		android {
 			compatible = "android,firmware";
+			vbmeta {
+				compatible = "android,vbmeta";
+				parts = "vbmeta,boot,system,vendor,dtbo";
+			};
+
 			fstab {
 				compatible = "android,fstab";
 				vendor {
@@ -469,7 +500,7 @@
 					dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor";
 					type = "ext4";
 					mnt_flags = "ro,barrier=1,discard";
-					fsmgr_flags = "wait,slotselect";
+					fsmgr_flags = "wait,slotselect,avb";
 				};
 			};
 		};
@@ -608,6 +639,7 @@
 
 #include "msm-gdsc-sdm845.dtsi"
 #include "sdm845-sde-pll.dtsi"
+#include "msm-rdbg.dtsi"
 #include "sdm845-sde.dtsi"
 #include "sdm845-sde-display.dtsi"
 #include "sdm845-qupv3.dtsi"
@@ -779,19 +811,16 @@
 	cpubw: qcom,cpubw {
 		compatible = "qcom,devbw";
 		governor = "performance";
-		qcom,src-dst-ports = <1 512>;
+		qcom,src-dst-ports =
+			<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_LLCC>;
 		qcom,active-only;
 		qcom,bw-tbl =
-			<  762 /*  200 MHz */ >,
-			< 1144 /*  300 MHz */ >,
-			< 1720 /*  451 MHz */ >,
-			< 2086 /*  547 MHz */ >,
-			< 2597 /*  681 MHz */ >,
-			< 2929 /*  768 MHz */ >,
-			< 3879 /* 1017 MHz */ >,
-			< 4943 /* 1296 MHz */ >,
-			< 5931 /* 1555 MHz */ >,
-			< 6881 /* 1804 MHz */ >;
+			<  2288 /* 150 MHz */ >,
+			<  4577 /* 300 MHz */ >,
+			<  6500 /* 426 MHz */ >,
+			<  8132 /* 533 MHz */ >,
+			<  9155 /* 600 MHz */ >,
+			< 10681 /* 700 MHz */ >;
 	};
 
 	bwmon: qcom,cpu-bwmon {
@@ -808,7 +837,7 @@
 		compatible = "qcom,devbw";
 		governor = "powersave";
 		qcom,src-dst-ports =
-			<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_EBI_CH0>;
+			<MSM_BUS_MASTER_LLCC MSM_BUS_SLAVE_EBI_CH0>;
 		qcom,active-only;
 		qcom,bw-tbl =
 			<  762 /*  200 MHz */ >,
@@ -916,20 +945,6 @@
 		clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>;
 		governor = "performance";
 		qcom,prepare-clk;
-		freq-tbl-khz =
-			< 300000 >,
-			< 422400 >,
-			< 499200 >,
-			< 576000 >,
-			< 652800 >,
-			< 729600 >,
-			< 806400 >,
-			< 883200 >,
-			< 960000 >,
-			< 1036800 >,
-			< 1094400 >,
-			< 1209600 >,
-			< 1305600 >;
 	};
 
 	l3_cpu4: qcom,l3-cpu4 {
@@ -938,20 +953,6 @@
 		clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>;
 		governor = "performance";
 		qcom,prepare-clk;
-		freq-tbl-khz =
-			< 300000 >,
-			< 422400 >,
-			< 499200 >,
-			< 576000 >,
-			< 652800 >,
-			< 729600 >,
-			< 806400 >,
-			< 883200 >,
-			< 960000 >,
-			< 1036800 >,
-			< 1094400 >,
-			< 1209600 >,
-			< 1305600 >;
 	};
 
 	devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
@@ -960,12 +961,13 @@
 		qcom,target-dev = <&l3_cpu0>;
 		qcom,cachemiss-ev = <0x17>;
 		qcom,core-dev-table =
-			<  300000 300000 >,
-			<  748800 576000 >,
-			<  979200 652800 >,
-			< 1209600 806400 >,
-			< 1516800 883200 >,
-			< 1593600 960000 >;
+			<  300000  300000 >,
+			<  748800  576000 >,
+			<  979200  652800 >,
+			< 1209600  806400 >,
+			< 1516800  883200 >,
+			< 1593600  960000 >,
+			< 1708800 1094400 >;
 	};
 
 	devfreq_l3lat_4: qcom,cpu4-l3lat-mon {
@@ -974,11 +976,12 @@
 		qcom,target-dev = <&l3_cpu4>;
 		qcom,cachemiss-ev = <0x17>;
 		qcom,core-dev-table =
-			<  300000 300000 >,
-			< 1036800 652800 >,
-			< 1190400 806400 >,
-			< 1574400 883200 >,
-			< 1651200 960000 >;
+			<  300000  300000 >,
+			< 1036800  576000 >,
+			< 1190400  806400 >,
+			< 1574400  883200 >,
+			< 1804800  960000 >,
+			< 2092800 1094400 >;
 	};
 
 	cpu_pmu: cpu-pmu {
@@ -1771,9 +1774,8 @@
 		interrupts = <0 494 1>;
 
 		vdd_cx-supply = <&pm8998_l27_level>;
-		vdd_px-supply = <&pm8998_lvs2>;
 		qcom,vdd_cx-uV-uA = <RPMH_REGULATOR_LEVEL_TURBO 0>;
-		qcom,proxy-reg-names = "vdd_cx", "vdd_px";
+		qcom,proxy-reg-names = "vdd_cx";
 		qcom,keep-proxy-regs-on;
 
 		clocks = <&clock_rpmh RPMH_CXO_CLK>;
@@ -1809,6 +1811,15 @@
 		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
 		qcom,apps-ch-pipes = <0x780000>;
 		qcom,ea-pc = <0x270>;
+		qcom,iommu-s1-bypass;
+
+		iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb {
+			compatible = "qcom,iommu-slim-ctrl-cb";
+			iommus = <&apps_smmu 0x1806 0x0>,
+				 <&apps_smmu 0x180d 0x0>,
+				 <&apps_smmu 0x180e 0x1>,
+				 <&apps_smmu 0x1810 0x1>;
+		};
 	};
 
 	slim_qca: slim@17240000 {
@@ -1820,6 +1831,12 @@
 		reg-names = "slimbus_physical", "slimbus_bam_physical";
 		interrupts = <0 291 0>, <0 292 0>;
 		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+		qcom,iommu-s1-bypass;
+
+		iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb {
+			compatible = "qcom,iommu-slim-ctrl-cb";
+			iommus = <&apps_smmu 0x1813 0x0>;
+		};
 
 		/* Slimbus Slave DT for WCN3990 */
 		btfmslim_codec: wcn3990 {
@@ -2272,7 +2289,7 @@
 		qcom,rx-ring-size = <0x400>;
 	};
 
-	qmp_aop: mailbox@1799000c {
+	qmp_aop: qcom,qmp-aop@c300000 {
 		compatible = "qcom,qmp-mbox";
 		label = "aop";
 		reg = <0xc300000 0x100000>,
@@ -2280,6 +2297,7 @@
 		reg-names = "msgram", "irq-reg-base";
 		qcom,irq-mask = <0x1>;
 		interrupts = <0 389 1>;
+		priority = <0>;
 		mbox-desc-offset = <0x0>;
 		#mbox-cells = <1>;
 	};
@@ -2589,6 +2607,7 @@
 		qcom,disk-encrypt-pipe-pair = <2>;
 		qcom,support-fde;
 		qcom,no-clock-support;
+		qcom,fde-key-size;
 		qcom,msm-bus,name = "qseecom-noc";
 		qcom,msm-bus,num-cases = <4>;
 		qcom,msm-bus,num-paths = <1>;
@@ -3262,10 +3281,10 @@
 			};
 		};
 
-		silver-virt-max-usr {
-			polling-delay-passive = <100>;
-			polling-delay = <100>;
-			thermal-governor = "user_space";
+		silv-virt-max-step {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "step_wise";
 			trips {
 				silver-trip {
 					temperature = <120000>;
@@ -3275,10 +3294,10 @@
 			};
 		};
 
-		gold-virt-max-usr {
-			polling-delay-passive = <100>;
-			polling-delay = <100>;
-			thermal-governor = "user_space";
+		gold-virt-max-step {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "step_wise";
 			trips {
 				gold-trip {
 					temperature = <120000>;
@@ -3301,10 +3320,29 @@
 				};
 			};
 			cooling-maps {
-				pop_cdev {
+				pop_cdev4 {
 					trip = <&pop_trip>;
 					cooling-device =
-						<&CPU4 1 THERMAL_NO_LIMIT>;
+						<&CPU4 THERMAL_NO_LIMIT
+							(THERMAL_MAX_LIMIT-1)>;
+				};
+				pop_cdev5 {
+					trip = <&pop_trip>;
+					cooling-device =
+						<&CPU5 THERMAL_NO_LIMIT
+							(THERMAL_MAX_LIMIT-1)>;
+				};
+				pop_cdev6 {
+					trip = <&pop_trip>;
+					cooling-device =
+						<&CPU6 THERMAL_NO_LIMIT
+							(THERMAL_MAX_LIMIT-1)>;
+				};
+				pop_cdev7 {
+					trip = <&pop_trip>;
+					cooling-device =
+						<&CPU7 THERMAL_NO_LIMIT
+							(THERMAL_MAX_LIMIT-1)>;
 				};
 			};
 		};
@@ -3325,15 +3363,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&aoss0_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&aoss0_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&aoss0_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3354,15 +3392,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&cpu0_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&cpu0_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&cpu0_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3383,15 +3421,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&cpu1_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&cpu1_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&cpu1_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3412,15 +3450,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&cpu2_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&cpu2_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&cpu2_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3441,15 +3479,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&cpu3_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&cpu3_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&cpu3_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3470,15 +3508,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&l3_0_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&l3_0_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&l3_0_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3499,15 +3537,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&l3_1_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&l3_1_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&l3_1_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3528,15 +3566,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&cpug0_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&cpug0_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&cpug0_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3557,15 +3595,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&cpug1_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&cpug1_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&cpug1_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3586,15 +3624,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&cpug2_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&cpug2_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&cpug2_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3615,15 +3653,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&cpug3_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&cpug3_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&cpug3_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3644,15 +3682,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&gpu0_trip_l>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&gpu0_trip_l>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&gpu0_trip_l>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3673,15 +3711,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&gpu1_trip_l>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&gpu1_trip_l>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&gpu1_trip_l>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3702,15 +3740,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&aoss1_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&aoss1_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&aoss1_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3731,15 +3769,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&dsp_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&dsp_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&dsp_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3760,15 +3798,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&ddr_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&ddr_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&ddr_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3789,15 +3827,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&wlan_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&wlan_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&wlan_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3818,15 +3856,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&hvx_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&hvx_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&hvx_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3847,15 +3885,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&camera_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&camera_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&camera_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3876,15 +3914,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&mmss_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&mmss_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&mmss_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -3905,15 +3943,15 @@
 			cooling-maps {
 				cpu0_vdd_cdev {
 					trip = <&mdm_trip>;
-					cooling-device = <&CPU0 12 12>;
+					cooling-device = <&CPU0 4 4>;
 				};
 				cpu4_vdd_cdev {
 					trip = <&mdm_trip>;
-					cooling-device = <&CPU4 12 12>;
+					cooling-device = <&CPU4 9 9>;
 				};
 				gpu_vdd_cdev {
 					trip = <&mdm_trip>;
-					cooling-device = <&msm_gpu 4 4>;
+					cooling-device = <&msm_gpu 1 1>;
 				};
 			};
 		};
@@ -4053,6 +4091,57 @@
 		iommus = <&apps_smmu 0x06d6 0x0>;
 		status = "ok";
 	};
+
+	tspp: msm_tspp@0x8880000 {
+		compatible = "qcom,msm_tspp";
+		reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */
+		      <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */
+		      <0x088a9000 0x1000>, /* MSM_TSPP_PHYS  */
+		      <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */
+		reg-names = "MSM_TSIF0_PHYS",
+			"MSM_TSIF1_PHYS",
+			"MSM_TSPP_PHYS",
+			"MSM_TSPP_BAM_PHYS";
+		interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */
+			<0 119 0>, /* TSIF0_IRQ */
+			<0 120 0>, /* TSIF1_IRQ */
+			<0 122 0>; /* TSIF_BAM_IRQ */
+		interrupt-names = "TSIF_TSPP_IRQ",
+			"TSIF0_IRQ",
+			"TSIF1_IRQ",
+			"TSIF_BAM_IRQ";
+
+		clock-names = "iface_clk", "ref_clk";
+		clocks = <&clock_gcc GCC_TSIF_AHB_CLK>,
+			<&clock_gcc GCC_TSIF_REF_CLK>;
+
+		qcom,msm-bus,name = "tsif";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<82 512 0 0>, /* No vote */
+				<82 512 12288 24576>;
+				/* Max. bandwidth, 2xTSIF, each max of 96Mbps */
+
+		pinctrl-names = "disabled",
+			"tsif0-mode1", "tsif0-mode2",
+			"tsif1-mode1", "tsif1-mode2",
+			"dual-tsif-mode1", "dual-tsif-mode2";
+
+		pinctrl-0 = <>;				/* disabled */
+		pinctrl-1 = <&tsif0_signals_active>;	/* tsif0-mode1 */
+		pinctrl-2 = <&tsif0_signals_active
+			&tsif0_sync_active>;		/* tsif0-mode2 */
+		pinctrl-3 = <&tsif1_signals_active>;	/* tsif1-mode1 */
+		pinctrl-4 = <&tsif1_signals_active
+			&tsif1_sync_active>;		/* tsif1-mode2 */
+		pinctrl-5 = <&tsif0_signals_active
+			&tsif1_signals_active>;		/* dual-tsif-mode1 */
+		pinctrl-6 = <&tsif0_signals_active
+			&tsif0_sync_active
+			&tsif1_signals_active
+			&tsif1_sync_active>;		/* dual-tsif-mode2 */
+	};
 };
 
 &clock_cpucc {
@@ -4220,39 +4309,86 @@
 	cooling-maps {
 		trip0_cpu0 {
 			trip = <&pm8998_trip0>;
-			cooling-device = <&CPU0 21 21>;
+			cooling-device =
+				<&CPU0 (THERMAL_MAX_LIMIT-1)
+					(THERMAL_MAX_LIMIT-1)>;
+		};
+		trip0_cpu1 {
+			trip = <&pm8998_trip0>;
+			cooling-device =
+				<&CPU1 (THERMAL_MAX_LIMIT-1)
+					(THERMAL_MAX_LIMIT-1)>;
+		};
+		trip0_cpu2 {
+			trip = <&pm8998_trip0>;
+			cooling-device =
+				<&CPU2 (THERMAL_MAX_LIMIT-1)
+					(THERMAL_MAX_LIMIT-1)>;
+		};
+		trip0_cpu3 {
+			trip = <&pm8998_trip0>;
+			cooling-device =
+				<&CPU3 (THERMAL_MAX_LIMIT-1)
+					(THERMAL_MAX_LIMIT-1)>;
 		};
 		trip0_cpu4 {
 			trip = <&pm8998_trip0>;
-			cooling-device = <&CPU4 21 21>;
+			cooling-device =
+				<&CPU4 (THERMAL_MAX_LIMIT-1)
+					(THERMAL_MAX_LIMIT-1)>;
+		};
+		trip0_cpu5 {
+			trip = <&pm8998_trip0>;
+			cooling-device =
+				<&CPU5 (THERMAL_MAX_LIMIT-1)
+					(THERMAL_MAX_LIMIT-1)>;
+		};
+		trip0_cpu6 {
+			trip = <&pm8998_trip0>;
+			cooling-device =
+				<&CPU6 (THERMAL_MAX_LIMIT-1)
+					(THERMAL_MAX_LIMIT-1)>;
+		};
+		trip0_cpu7 {
+			trip = <&pm8998_trip0>;
+			cooling-device =
+				<&CPU7 (THERMAL_MAX_LIMIT-1)
+					(THERMAL_MAX_LIMIT-1)>;
 		};
 		trip1_cpu1 {
 			trip = <&pm8998_trip1>;
-			cooling-device = <&CPU1 22 22>;
+			cooling-device =
+				<&CPU1 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>;
 		};
 		trip1_cpu2 {
 			trip = <&pm8998_trip1>;
-			cooling-device = <&CPU2 22 22>;
+			cooling-device =
+				<&CPU2 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>;
 		};
 		trip1_cpu3 {
 			trip = <&pm8998_trip1>;
-			cooling-device = <&CPU3 22 22>;
+			cooling-device =
+				<&CPU3 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>;
 		};
 		trip1_cpu4 {
 			trip = <&pm8998_trip1>;
-			cooling-device = <&CPU4 22 22>;
+			cooling-device =
+				<&CPU4 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>;
 		};
 		trip1_cpu5 {
 			trip = <&pm8998_trip1>;
-			cooling-device = <&CPU5 22 22>;
+			cooling-device =
+				<&CPU5 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>;
 		};
 		trip1_cpu6 {
 			trip = <&pm8998_trip1>;
-			cooling-device = <&CPU6 22 22>;
+			cooling-device =
+				<&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>;
 		};
 		trip1_cpu7 {
 			trip = <&pm8998_trip1>;
-			cooling-device = <&CPU7 22 22>;
+			cooling-device =
+				<&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>;
 		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/smb1355.dtsi b/arch/arm64/boot/dts/qcom/smb1355.dtsi
index 33c5e97..999d87a 100644
--- a/arch/arm64/boot/dts/qcom/smb1355.dtsi
+++ b/arch/arm64/boot/dts/qcom/smb1355.dtsi
@@ -39,6 +39,11 @@
 			interrupt-parent = <&smb1355>;
 			status = "disabled";
 
+			io-channels = <&pmi8998_rradc 2>,
+				      <&pmi8998_rradc 12>;
+			io-channel-names = "charger_temp",
+					   "charger_temp_max";
+
 			qcom,chgr@1000 {
 				reg = <0x1000 0x100>;
 				interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index f10047f..9ec1beb 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -19,6 +19,7 @@
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_SCHEDTUNE=y
 CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
 CONFIG_SCHED_CORE_CTL=y
 CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
@@ -31,13 +32,14 @@
 # CONFIG_RD_LZO is not set
 # CONFIG_RD_LZ4 is not set
 CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
 # CONFIG_AIO is not set
 # CONFIG_MEMBARRIER is not set
 CONFIG_EMBEDDED=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
-CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_CC_STACKPROTECTOR_STRONG=y
 CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -83,7 +85,6 @@
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPU_BOOST=y
 CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
-CONFIG_CPU_FREQ_MSM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -157,6 +158,7 @@
 CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
 CONFIG_NETFILTER_XT_MATCH_POLICY=y
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
@@ -204,8 +206,6 @@
 CONFIG_NET_SCH_INGRESS=y
 CONFIG_NET_CLS_FW=y
 CONFIG_NET_CLS_U32=y
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_FLOW=y
 CONFIG_NET_EMATCH=y
 CONFIG_NET_EMATCH_CMP=y
 CONFIG_NET_EMATCH_NBYTE=y
@@ -246,9 +246,12 @@
 CONFIG_SCSI_UFSHCD_PLATFORM=y
 CONFIG_SCSI_UFS_QCOM=y
 CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
 CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
 CONFIG_DM_UEVENT=y
 CONFIG_DM_VERITY=y
 CONFIG_DM_VERITY_FEC=y
@@ -257,7 +260,6 @@
 CONFIG_DUMMY=y
 CONFIG_TUN=y
 CONFIG_SKY2=y
-CONFIG_RNDIS_IPA=y
 CONFIG_SMSC911X=y
 CONFIG_PPP=y
 CONFIG_PPP_BSDCOMP=y
@@ -288,6 +290,7 @@
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QCOM_GENI=y
 CONFIG_SOUNDWIRE=y
@@ -319,15 +322,17 @@
 CONFIG_THERMAL_GOV_LOW_LIMITS=y
 CONFIG_CPU_THERMAL=y
 CONFIG_DEVFREQ_THERMAL=y
+CONFIG_QCOM_SPMI_TEMP_ALARM=y
 CONFIG_THERMAL_QPNP=y
 CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_THERMAL_TSENS=y
 CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
 CONFIG_QTI_VIRTUAL_SENSOR=y
+CONFIG_QTI_REG_COOLING_DEVICE=y
 CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
-CONFIG_WCD934X_CODEC=y
+CONFIG_WCD9XXX_CODEC_CORE=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_CPRH_KBSS=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
@@ -336,6 +341,7 @@
 CONFIG_REGULATOR_STUB=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_VIDEO_ADV_DEBUG=y
@@ -346,6 +352,10 @@
 CONFIG_MSM_VIDC_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_DVB_MPQ=m
+CONFIG_DVB_MPQ_DEMUX=m
+CONFIG_DVB_MPQ_TSPP1=y
+CONFIG_TSPP=m
 CONFIG_QCOM_KGSL=y
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
@@ -361,10 +371,15 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_USB_AUDIO_QMI=y
 CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MACHINE_SDM845=y
 CONFIG_SND_SOC_SDM845=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_PLANTRONICS=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_XHCI_HCD=y
@@ -403,6 +418,8 @@
 CONFIG_USB_CONFIGFS_F_GSI=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
@@ -415,6 +432,7 @@
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_QPNP_FLASH_V2=y
 CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_QPNP=y
@@ -430,6 +448,7 @@
 CONFIG_GSI=y
 CONFIG_IPA3=y
 CONFIG_RMNET_IPA3=y
+CONFIG_RNDIS_IPA=y
 CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
@@ -455,6 +474,7 @@
 CONFIG_ARM_SMMU=y
 CONFIG_QCOM_LAZY_MAPPING=y
 CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_DEBUG_TRACKING=y
 CONFIG_IOMMU_TESTS=y
 CONFIG_QCOM_RUN_QUEUE_STATS=y
 CONFIG_QCOM_LLCC=y
@@ -524,6 +544,7 @@
 CONFIG_EXT4_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
 CONFIG_FUSE_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 4cd202c..30d0d4b 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -23,6 +23,7 @@
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_SCHEDTUNE=y
 CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
 CONFIG_SCHED_CORE_CTL=y
 CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
@@ -35,12 +36,13 @@
 # CONFIG_RD_LZO is not set
 # CONFIG_RD_LZ4 is not set
 CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
 # CONFIG_AIO is not set
 # CONFIG_MEMBARRIER is not set
 CONFIG_EMBEDDED=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
-CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_CC_STACKPROTECTOR_STRONG=y
 CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -89,7 +91,6 @@
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPU_BOOST=y
 CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
-CONFIG_CPU_FREQ_MSM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -163,9 +164,9 @@
 CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
 CONFIG_NETFILTER_XT_MATCH_POLICY=y
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -212,8 +213,6 @@
 CONFIG_NET_SCH_INGRESS=y
 CONFIG_NET_CLS_FW=y
 CONFIG_NET_CLS_U32=y
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_FLOW=y
 CONFIG_NET_EMATCH=y
 CONFIG_NET_EMATCH_CMP=y
 CONFIG_NET_EMATCH_NBYTE=y
@@ -260,7 +259,9 @@
 CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
 CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
 CONFIG_DM_UEVENT=y
 CONFIG_DM_VERITY=y
 CONFIG_DM_VERITY_FEC=y
@@ -268,7 +269,6 @@
 CONFIG_BONDING=y
 CONFIG_DUMMY=y
 CONFIG_TUN=y
-CONFIG_RNDIS_IPA=y
 CONFIG_PPP=y
 CONFIG_PPP_BSDCOMP=y
 CONFIG_PPP_DEFLATE=y
@@ -297,6 +297,7 @@
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QCOM_GENI=y
 CONFIG_SOUNDWIRE=y
@@ -328,15 +329,17 @@
 CONFIG_THERMAL_GOV_LOW_LIMITS=y
 CONFIG_CPU_THERMAL=y
 CONFIG_DEVFREQ_THERMAL=y
+CONFIG_QCOM_SPMI_TEMP_ALARM=y
 CONFIG_THERMAL_QPNP=y
 CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_THERMAL_TSENS=y
 CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
 CONFIG_QTI_VIRTUAL_SENSOR=y
+CONFIG_QTI_REG_COOLING_DEVICE=y
 CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
-CONFIG_WCD934X_CODEC=y
+CONFIG_WCD9XXX_CODEC_CORE=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_CPRH_KBSS=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
@@ -345,6 +348,7 @@
 CONFIG_REGULATOR_STUB=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_VIDEO_ADV_DEBUG=y
@@ -355,6 +359,10 @@
 CONFIG_MSM_VIDC_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_DVB_MPQ=m
+CONFIG_DVB_MPQ_DEMUX=m
+CONFIG_DVB_MPQ_TSPP1=y
+CONFIG_TSPP=m
 CONFIG_QCOM_KGSL=y
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
@@ -370,10 +378,15 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_USB_AUDIO_QMI=y
 CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MACHINE_SDM845=y
 CONFIG_SND_SOC_SDM845=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_PLANTRONICS=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
@@ -411,6 +424,9 @@
 CONFIG_USB_CONFIGFS_F_GSI=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_RING_BUFFER=y
+CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
@@ -423,6 +439,7 @@
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_QPNP_FLASH_V2=y
 CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
@@ -447,6 +464,7 @@
 CONFIG_GSI=y
 CONFIG_IPA3=y
 CONFIG_RMNET_IPA3=y
+CONFIG_RNDIS_IPA=y
 CONFIG_IPA_UT=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
@@ -478,6 +496,7 @@
 CONFIG_QCOM_RUN_QUEUE_STATS=y
 CONFIG_QCOM_LLCC=y
 CONFIG_QCOM_SDM845_LLCC=y
+CONFIG_QCOM_SDM670_LLCC=y
 CONFIG_MSM_SERVICE_LOCATOR=y
 CONFIG_MSM_SERVICE_NOTIFIER=y
 CONFIG_MSM_BOOT_STATS=y
@@ -548,6 +567,7 @@
 CONFIG_EXT4_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
 CONFIG_FUSE_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
@@ -595,6 +615,7 @@
 CONFIG_DEBUG_LIST=y
 CONFIG_FAULT_INJECTION=y
 CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_UFS_FAULT_INJECTION=y
 CONFIG_FAULT_INJECTION_DEBUG_FS=y
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_IPC_LOGGING=y
diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h
new file mode 100644
index 0000000..be2d234
--- /dev/null
+++ b/arch/arm64/include/asm/asm-uaccess.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_ASM_UACCESS_H
+#define __ASM_ASM_UACCESS_H
+
+/*
+ * Remove the address tag from a virtual address, if present.
+ */
+	.macro	clear_address_tag, dst, addr
+	tst	\addr, #(1 << 55)
+	bic	\dst, \addr, #(0xff << 56)
+	csel	\dst, \dst, \addr, eq
+	.endm
+
+#endif
diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h
index b89a7f3..0f2704c 100644
--- a/arch/arm64/include/asm/dma-mapping.h
+++ b/arch/arm64/include/asm/dma-mapping.h
@@ -65,8 +65,6 @@
 /* do not use this function in a driver */
 static inline bool is_device_dma_coherent(struct device *dev)
 {
-	if (!dev)
-		return false;
 	return dev->archdata.dma_coherent;
 }
 
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 6c80b36..7393cc7 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -94,6 +94,10 @@
 #define SCTLR_ELx_A	(1 << 1)
 #define SCTLR_ELx_M	1
 
+#define SCTLR_EL2_RES1	((1 << 4)  | (1 << 5)  | (1 << 11) | (1 << 16) | \
+			 (1 << 16) | (1 << 18) | (1 << 22) | (1 << 23) | \
+			 (1 << 28) | (1 << 29))
+
 #define SCTLR_ELx_FLAGS	(SCTLR_ELx_M | SCTLR_ELx_A | SCTLR_ELx_C | \
 			 SCTLR_ELx_SA | SCTLR_ELx_I)
 
diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
index 61e032f2..b58f429 100644
--- a/arch/arm64/include/asm/topology.h
+++ b/arch/arm64/include/asm/topology.h
@@ -41,6 +41,9 @@
 #define arch_scale_cpu_capacity scale_cpu_capacity
 extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu);
 
+#define arch_update_cpu_capacity update_cpu_power_capacity
+extern void update_cpu_power_capacity(int cpu);
+
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_ARM_TOPOLOGY_H */
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 21934d1..2df5d5f 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -110,9 +110,9 @@
 })
 
 /*
- * When dealing with data aborts or instruction traps we may end up with
- * a tagged userland pointer. Clear the tag to get a sane pointer to pass
- * on to access_ok(), for instance.
+ * When dealing with data aborts, watchpoints, or instruction traps we may end
+ * up with a tagged userland pointer. Clear the tag to get a sane pointer to
+ * pass on to access_ok(), for instance.
  */
 #define untagged_addr(addr)		sign_extend64(addr, 55)
 
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 1f0cea7..c44a933 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -32,6 +32,7 @@
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 #include <asm/uaccess.h>
+#include <asm/asm-uaccess.h>
 #include <asm/unistd.h>
 
 /*
@@ -428,12 +429,13 @@
 	/*
 	 * Data abort handling
 	 */
-	mrs	x0, far_el1
+	mrs	x3, far_el1
 	enable_dbg
 	// re-enable interrupts if they were enabled in the aborted context
 	tbnz	x23, #7, 1f			// PSR_I_BIT
 	enable_irq
 1:
+	clear_address_tag x0, x3
 	mov	x2, sp				// struct pt_regs
 	bl	do_mem_abort
 
@@ -594,7 +596,7 @@
 	// enable interrupts before calling the main handler
 	enable_dbg_and_irq
 	ct_user_exit
-	bic	x0, x26, #(0xff << 56)
+	clear_address_tag x0, x26
 	mov	x1, x25
 	mov	x2, sp
 	bl	do_mem_abort
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index 1b3c747..fb0082a 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -36,6 +36,7 @@
 #include <asm/traps.h>
 #include <asm/cputype.h>
 #include <asm/system_misc.h>
+#include <asm/uaccess.h>
 
 /* Breakpoint currently in use for each BRP. */
 static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 852548c..bb24b4e 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -29,6 +29,8 @@
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
 
+static DEFINE_PER_CPU(bool, is_hotplugging);
+
 /*
  * ARMv8 PMUv3 Performance Events handling code.
  * Common event types (some are defined in asm/perf_event.h).
@@ -982,6 +984,9 @@
 	if (!cpu_pmu)
 		return;
 
+	if (__this_cpu_read(is_hotplugging))
+		return;
+
 	hw_events = this_cpu_ptr(cpu_pmu->hw_events);
 
 	if (!hw_events)
@@ -1031,14 +1036,13 @@
 
 	pmu_idle_nb->cpu_pmu = cpu_pmu;
 	pmu_idle_nb->perf_cpu_idle_nb.notifier_call = perf_cpu_idle_notifier;
-	idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb);
 
 	ret = smp_call_function_any(&cpu_pmu->supported_cpus,
 				    __armv8pmu_probe_pmu,
 				    cpu_pmu, 1);
 
-	if (ret)
-		idle_notifier_unregister(&pmu_idle_nb->perf_cpu_idle_nb);
+	if (!ret)
+		idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb);
 
 	return ret;
 }
@@ -1140,6 +1144,37 @@
 	{},
 };
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int perf_event_hotplug_coming_up(unsigned int cpu)
+{
+	per_cpu(is_hotplugging, cpu) = false;
+	return 0;
+}
+
+static int perf_event_hotplug_going_down(unsigned int cpu)
+{
+	per_cpu(is_hotplugging, cpu) = true;
+	return 0;
+}
+
+static int perf_event_cpu_hp_init(void)
+{
+	int ret;
+
+	ret = cpuhp_setup_state_nocalls(CPUHP_AP_NOTIFY_ONLINE,
+				"PERF_EVENT/CPUHP_AP_NOTIFY_ONLINE",
+				perf_event_hotplug_coming_up,
+				perf_event_hotplug_going_down);
+	if (ret)
+		pr_err("CPU hotplug notifier for perf_event.c could not be registered: %d\n",
+		       ret);
+
+	return ret;
+}
+#else
+static int perf_event_cpu_hp_init(void) { return 0; }
+#endif
+
 /*
  * Non DT systems have their micro/arch events probed at run-time.
  * A fairly complete list of generic events are provided and ones that
@@ -1152,6 +1187,16 @@
 
 static int armv8_pmu_device_probe(struct platform_device *pdev)
 {
+	int ret, cpu;
+
+	for_each_possible_cpu(cpu)
+		per_cpu(is_hotplugging, cpu) = false;
+
+	ret = perf_event_cpu_hp_init();
+
+	if (ret)
+		return ret;
+
 	if (acpi_disabled)
 		return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids,
 					    NULL);
diff --git a/arch/arm64/kernel/perf_trace_counters.c b/arch/arm64/kernel/perf_trace_counters.c
index 1f0b74a..d87106d 100644
--- a/arch/arm64/kernel/perf_trace_counters.c
+++ b/arch/arm64/kernel/perf_trace_counters.c
@@ -59,7 +59,7 @@
 {
 	u32 cnten_val;
 	int current_pid;
-	u32 cpu = task_thread_info(next)->cpu;
+	u32 cpu = task_cpu(next);
 
 	if (tp_pid_state != 1)
 		return;
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index fe8f94a..fc1a286 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -225,18 +225,12 @@
 static void show_extra_register_data(struct pt_regs *regs, int nbytes)
 {
 	mm_segment_t fs;
-	unsigned int i;
 
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	show_data(regs->pc - nbytes, nbytes * 2, "PC");
 	show_data(regs->regs[30] - nbytes, nbytes * 2, "LR");
 	show_data(regs->sp - nbytes, nbytes * 2, "SP");
-	for (i = 0; i < 30; i++) {
-		char name[4];
-		snprintf(name, sizeof(name), "X%u", i);
-		show_data(regs->regs[i] - nbytes, nbytes * 2, name);
-	}
 	set_fs(fs);
 }
 
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index c2efddf..bedf97d 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -203,6 +203,7 @@
 	if (trace->nr_entries < trace->max_entries)
 		trace->entries[trace->nr_entries++] = ULONG_MAX;
 }
+EXPORT_SYMBOL(save_stack_trace_tsk);
 
 void save_stack_trace(struct stack_trace *trace)
 {
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index aaf4bd7..7b670f1 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -449,6 +449,12 @@
 		cpu, arch_scale_cpu_capacity(NULL, cpu));
 }
 
+void update_cpu_power_capacity(int cpu)
+{
+	update_cpu_power(cpu);
+	update_cpu_capacity(cpu);
+}
+
 static void update_siblings_masks(unsigned int cpuid)
 {
 	struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
@@ -510,8 +516,6 @@
 
 topology_populated:
 	update_siblings_masks(cpuid);
-	update_cpu_power(cpuid);
-	update_cpu_capacity(cpuid);
 }
 
 static void __init reset_cpu_topology(void)
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index d84c7d0..d8253fb 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -470,7 +470,7 @@
 }
 
 #define __user_cache_maint(insn, address, res)			\
-	if (untagged_addr(address) >= user_addr_max()) {	\
+	if (address >= user_addr_max()) {			\
 		res = -EFAULT;					\
 	} else {						\
 		uaccess_ttbr0_enable();				\
@@ -496,7 +496,7 @@
 	int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
 	int ret = 0;
 
-	address = (rt == 31) ? 0 : regs->regs[rt];
+	address = (rt == 31) ? 0 : untagged_addr(regs->regs[rt]);
 
 	switch (crm) {
 	case ESR_ELx_SYS64_ISS_CRM_DC_CVAU:	/* DC CVAU, gets promoted */
diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
index 6b29d3d..4bbff90 100644
--- a/arch/arm64/kvm/hyp-init.S
+++ b/arch/arm64/kvm/hyp-init.S
@@ -102,10 +102,13 @@
 	tlbi	alle2
 	dsb	sy
 
-	mrs	x4, sctlr_el2
-	and	x4, x4, #SCTLR_ELx_EE	// preserve endianness of EL2
-	ldr	x5, =SCTLR_ELx_FLAGS
-	orr	x4, x4, x5
+	/*
+	 * Preserve all the RES1 bits while setting the default flags,
+	 * as well as the EE bit on BE. Drop the A flag since the compiler
+	 * is allowed to generate unaligned accesses.
+	 */
+	ldr	x4, =(SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A))
+CPU_BE(	orr	x4, x4, #SCTLR_ELx_EE)
 	msr	sctlr_el2, x4
 	isb
 
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 75088c00..acbe515 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -157,11 +157,6 @@
 				  dma_addr_t *dma_handle, gfp_t flags,
 				  unsigned long attrs)
 {
-	if (dev == NULL) {
-		WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
-		return NULL;
-	}
-
 	if (IS_ENABLED(CONFIG_ZONE_DMA) &&
 	    dev->coherent_dma_mask <= DMA_BIT_MASK(32))
 		flags |= GFP_DMA;
@@ -201,10 +196,6 @@
 	phys_addr_t paddr = dma_to_phys(dev, dma_handle);
 
 	size = PAGE_ALIGN(size);
-	if (dev == NULL) {
-		WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
-		return;
-	}
 
 	if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) ||
 	    (attrs & DMA_ATTR_STRONGLY_ORDERED))
@@ -1153,16 +1144,6 @@
 		set_bit(PG_dcache_clean, &page->flags);
 }
 
-static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
-{
-	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
-		return -EIO;
-
-	*dev->dma_mask = dma_mask;
-
-	return 0;
-}
-
 /* IOMMU */
 
 static void __dma_clear_buffer(struct page *page, size_t size,
@@ -1810,10 +1791,8 @@
 						mapping->domain, iova));
 	int offset = handle & ~PAGE_MASK;
 	int len = PAGE_ALIGN(size + offset);
-	bool iova_coherent = iommu_is_iova_coherent(mapping->domain,
-							handle);
 
-	if (!(iova_coherent ||
+	if (!(is_dma_coherent(dev, attrs) ||
 	      (attrs & DMA_ATTR_SKIP_CPU_SYNC)))
 		__dma_page_dev_to_cpu(page, offset, size, dir);
 
@@ -1913,7 +1892,6 @@
 	.map_resource		= arm_iommu_dma_map_resource,
 	.unmap_resource		= arm_iommu_dma_unmap_resource,
 
-	.set_dma_mask		= arm_dma_set_mask,
 	.mapping_error		= arm_iommu_mapping_error,
 };
 
@@ -2006,6 +1984,7 @@
 	int err;
 	int s1_bypass = 0, is_fast = 0;
 	struct iommu_group *group;
+	dma_addr_t iova_end;
 
 	group = dev->iommu_group;
 	if (!group) {
@@ -2018,6 +1997,13 @@
 		return -EINVAL;
 	}
 
+	iova_end = mapping->base + (mapping->bits << PAGE_SHIFT) - 1;
+	if (iova_end > dma_get_mask(dev)) {
+		dev_err(dev, "dma mask %llx too small for requested iova range %pad to %pad\n",
+			dma_get_mask(dev), &mapping->base, &iova_end);
+		return -EINVAL;
+	}
+
 	iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
 	if (is_fast)
 		return fast_smmu_attach_device(dev, mapping);
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 8b3b46b..3297715 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -44,8 +44,22 @@
 extern int sysfs_add_device_to_node(struct device *dev, int nid);
 extern void sysfs_remove_device_from_node(struct device *dev, int nid);
 
+static inline int early_cpu_to_node(int cpu)
+{
+	int nid;
+
+	nid = numa_cpu_lookup_table[cpu];
+
+	/*
+	 * Fall back to node 0 if nid is unset (it should be, except bugs).
+	 * This allows callers to safely do NODE_DATA(early_cpu_to_node(cpu)).
+	 */
+	return (nid < 0) ? 0 : nid;
+}
 #else
 
+static inline int early_cpu_to_node(int cpu) { return 0; }
+
 static inline void dump_numa_cpu_topology(void) {}
 
 static inline int sysfs_add_device_to_node(struct device *dev, int nid)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index c716473..b249c2f 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1659,6 +1659,7 @@
 #ifdef CONFIG_VSX
 	current->thread.used_vsr = 0;
 #endif
+	current->thread.load_fp = 0;
 	memset(&current->thread.fp_state, 0, sizeof(current->thread.fp_state));
 	current->thread.fp_save_area = NULL;
 #ifdef CONFIG_ALTIVEC
@@ -1667,6 +1668,7 @@
 	current->thread.vr_save_area = NULL;
 	current->thread.vrsave = 0;
 	current->thread.used_vr = 0;
+	current->thread.load_vec = 0;
 #endif /* CONFIG_ALTIVEC */
 #ifdef CONFIG_SPE
 	memset(current->thread.evr, 0, sizeof(current->thread.evr));
@@ -1678,6 +1680,7 @@
 	current->thread.tm_tfhar = 0;
 	current->thread.tm_texasr = 0;
 	current->thread.tm_tfiar = 0;
+	current->thread.load_tm = 0;
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 }
 EXPORT_SYMBOL(start_thread);
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index a12be60..ada71be 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -595,7 +595,7 @@
 
 static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
 {
-	return __alloc_bootmem_node(NODE_DATA(cpu_to_node(cpu)), size, align,
+	return __alloc_bootmem_node(NODE_DATA(early_cpu_to_node(cpu)), size, align,
 				    __pa(MAX_DMA_ADDRESS));
 }
 
@@ -606,7 +606,7 @@
 
 static int pcpu_cpu_distance(unsigned int from, unsigned int to)
 {
-	if (cpu_to_node(from) == cpu_to_node(to))
+	if (early_cpu_to_node(from) == early_cpu_to_node(to))
 		return LOCAL_DISTANCE;
 	else
 		return REMOTE_DISTANCE;
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 76ec104..c0a0947 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -124,6 +124,7 @@
 	for (i = 0; i < num_lmbs; i++) {
 		lmbs[i].base_addr = be64_to_cpu(lmbs[i].base_addr);
 		lmbs[i].drc_index = be32_to_cpu(lmbs[i].drc_index);
+		lmbs[i].aa_index = be32_to_cpu(lmbs[i].aa_index);
 		lmbs[i].flags = be32_to_cpu(lmbs[i].flags);
 	}
 
@@ -147,6 +148,7 @@
 	for (i = 0; i < num_lmbs; i++) {
 		lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr);
 		lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index);
+		lmbs[i].aa_index = cpu_to_be32(lmbs[i].aa_index);
 		lmbs[i].flags = cpu_to_be32(lmbs[i].flags);
 	}
 
diff --git a/arch/powerpc/sysdev/simple_gpio.c b/arch/powerpc/sysdev/simple_gpio.c
index ef470b4..6afddae 100644
--- a/arch/powerpc/sysdev/simple_gpio.c
+++ b/arch/powerpc/sysdev/simple_gpio.c
@@ -75,7 +75,8 @@
 
 static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
 {
-	struct u8_gpio_chip *u8_gc = gpiochip_get_data(&mm_gc->gc);
+	struct u8_gpio_chip *u8_gc =
+		container_of(mm_gc, struct u8_gpio_chip, mm_gc);
 
 	u8_gc->data = in_8(mm_gc->regs);
 }
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 165ecdd..b27e48e 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -187,9 +187,9 @@
 	int "Maximum number of CPUs"
 	depends on SMP
 	range 2 32 if SPARC32
-	range 2 1024 if SPARC64
+	range 2 4096 if SPARC64
 	default 32 if SPARC32
-	default 64 if SPARC64
+	default 4096 if SPARC64
 
 source kernel/Kconfig.hz
 
diff --git a/arch/sparc/include/asm/mmu_64.h b/arch/sparc/include/asm/mmu_64.h
index f7de0db..83b36a5 100644
--- a/arch/sparc/include/asm/mmu_64.h
+++ b/arch/sparc/include/asm/mmu_64.h
@@ -52,7 +52,7 @@
 #define CTX_NR_MASK		TAG_CONTEXT_BITS
 #define CTX_HW_MASK		(CTX_NR_MASK | CTX_PGSZ_MASK)
 
-#define CTX_FIRST_VERSION	((_AC(1,UL) << CTX_VERSION_SHIFT) + _AC(1,UL))
+#define CTX_FIRST_VERSION	BIT(CTX_VERSION_SHIFT)
 #define CTX_VALID(__ctx)	\
 	 (!(((__ctx.sparc64_ctx_val) ^ tlb_context_cache) & CTX_VERSION_MASK))
 #define CTX_HWBITS(__ctx)	((__ctx.sparc64_ctx_val) & CTX_HW_MASK)
diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h
index b84be67..349dd23 100644
--- a/arch/sparc/include/asm/mmu_context_64.h
+++ b/arch/sparc/include/asm/mmu_context_64.h
@@ -17,13 +17,8 @@
 extern unsigned long tlb_context_cache;
 extern unsigned long mmu_context_bmap[];
 
+DECLARE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm);
 void get_new_mmu_context(struct mm_struct *mm);
-#ifdef CONFIG_SMP
-void smp_new_mmu_context_version(void);
-#else
-#define smp_new_mmu_context_version() do { } while (0)
-#endif
-
 int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
 void destroy_context(struct mm_struct *mm);
 
@@ -74,8 +69,9 @@
 static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk)
 {
 	unsigned long ctx_valid, flags;
-	int cpu;
+	int cpu = smp_processor_id();
 
+	per_cpu(per_cpu_secondary_mm, cpu) = mm;
 	if (unlikely(mm == &init_mm))
 		return;
 
@@ -121,7 +117,6 @@
 	 * for the first time, we must flush that context out of the
 	 * local TLB.
 	 */
-	cpu = smp_processor_id();
 	if (!ctx_valid || !cpumask_test_cpu(cpu, mm_cpumask(mm))) {
 		cpumask_set_cpu(cpu, mm_cpumask(mm));
 		__flush_tlb_mm(CTX_HWBITS(mm->context),
@@ -131,26 +126,7 @@
 }
 
 #define deactivate_mm(tsk,mm)	do { } while (0)
-
-/* Activate a new MM instance for the current task. */
-static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
-{
-	unsigned long flags;
-	int cpu;
-
-	spin_lock_irqsave(&mm->context.lock, flags);
-	if (!CTX_VALID(mm->context))
-		get_new_mmu_context(mm);
-	cpu = smp_processor_id();
-	if (!cpumask_test_cpu(cpu, mm_cpumask(mm)))
-		cpumask_set_cpu(cpu, mm_cpumask(mm));
-
-	load_secondary_context(mm);
-	__flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT);
-	tsb_context_switch(mm);
-	spin_unlock_irqrestore(&mm->context.lock, flags);
-}
-
+#define activate_mm(active_mm, mm) switch_mm(active_mm, mm, NULL)
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC64_MMU_CONTEXT_H) */
diff --git a/arch/sparc/include/asm/pil.h b/arch/sparc/include/asm/pil.h
index 26693703..522b43d 100644
--- a/arch/sparc/include/asm/pil.h
+++ b/arch/sparc/include/asm/pil.h
@@ -20,7 +20,6 @@
 #define PIL_SMP_CALL_FUNC	1
 #define PIL_SMP_RECEIVE_SIGNAL	2
 #define PIL_SMP_CAPTURE		3
-#define PIL_SMP_CTX_NEW_VERSION	4
 #define PIL_DEVICE_IRQ		5
 #define PIL_SMP_CALL_FUNC_SNGL	6
 #define PIL_DEFERRED_PCR_WORK	7
diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h
index 8174f6c..9dca7a8 100644
--- a/arch/sparc/include/asm/vio.h
+++ b/arch/sparc/include/asm/vio.h
@@ -327,6 +327,7 @@
 	int			compat_len;
 
 	u64			dev_no;
+	u64			id;
 
 	unsigned long		channel_id;
 
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c
index 34a7930..e1b1ce6 100644
--- a/arch/sparc/kernel/irq_64.c
+++ b/arch/sparc/kernel/irq_64.c
@@ -1034,17 +1034,26 @@
 {
 #ifdef CONFIG_SMP
 	unsigned long page;
+	void *mondo, *p;
 
-	BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
+	BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > PAGE_SIZE);
+
+	/* Make sure mondo block is 64byte aligned */
+	p = kzalloc(127, GFP_KERNEL);
+	if (!p) {
+		prom_printf("SUN4V: Error, cannot allocate mondo block.\n");
+		prom_halt();
+	}
+	mondo = (void *)(((unsigned long)p + 63) & ~0x3f);
+	tb->cpu_mondo_block_pa = __pa(mondo);
 
 	page = get_zeroed_page(GFP_KERNEL);
 	if (!page) {
-		prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
+		prom_printf("SUN4V: Error, cannot allocate cpu list page.\n");
 		prom_halt();
 	}
 
-	tb->cpu_mondo_block_pa = __pa(page);
-	tb->cpu_list_pa = __pa(page + 64);
+	tb->cpu_list_pa = __pa(page);
 #endif
 }
 
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index c9804551..6ae1e77 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -37,7 +37,6 @@
 /* smp_64.c */
 void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs);
 void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs);
-void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs);
 void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs);
 void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs);
 
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index 8182f7c..d5807d2 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -963,37 +963,6 @@
 	preempt_enable();
 }
 
-void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
-{
-	struct mm_struct *mm;
-	unsigned long flags;
-
-	clear_softint(1 << irq);
-
-	/* See if we need to allocate a new TLB context because
-	 * the version of the one we are using is now out of date.
-	 */
-	mm = current->active_mm;
-	if (unlikely(!mm || (mm == &init_mm)))
-		return;
-
-	spin_lock_irqsave(&mm->context.lock, flags);
-
-	if (unlikely(!CTX_VALID(mm->context)))
-		get_new_mmu_context(mm);
-
-	spin_unlock_irqrestore(&mm->context.lock, flags);
-
-	load_secondary_context(mm);
-	__flush_tlb_mm(CTX_HWBITS(mm->context),
-		       SECONDARY_CONTEXT);
-}
-
-void smp_new_mmu_context_version(void)
-{
-	smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0);
-}
-
 #ifdef CONFIG_KGDB
 void kgdb_roundup_cpus(unsigned long flags)
 {
diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S
index d568c82..395ec18 100644
--- a/arch/sparc/kernel/tsb.S
+++ b/arch/sparc/kernel/tsb.S
@@ -470,13 +470,16 @@
 	.type	copy_tsb,#function
 copy_tsb:		/* %o0=old_tsb_base, %o1=old_tsb_size
 			 * %o2=new_tsb_base, %o3=new_tsb_size
+			 * %o4=page_size_shift
 			 */
 	sethi		%uhi(TSB_PASS_BITS), %g7
 	srlx		%o3, 4, %o3
-	add		%o0, %o1, %g1	/* end of old tsb */
+	add		%o0, %o1, %o1	/* end of old tsb */
 	sllx		%g7, 32, %g7
 	sub		%o3, 1, %o3	/* %o3 == new tsb hash mask */
 
+	mov		%o4, %g1	/* page_size_shift */
+
 661:	prefetcha	[%o0] ASI_N, #one_read
 	.section	.tsb_phys_patch, "ax"
 	.word		661b
@@ -501,9 +504,9 @@
 	/* This can definitely be computed faster... */
 	srlx		%o0, 4, %o5	/* Build index */
 	and		%o5, 511, %o5	/* Mask index */
-	sllx		%o5, PAGE_SHIFT, %o5 /* Put into vaddr position */
+	sllx		%o5, %g1, %o5	/* Put into vaddr position */
 	or		%o4, %o5, %o4	/* Full VADDR. */
-	srlx		%o4, PAGE_SHIFT, %o4 /* Shift down to create index */
+	srlx		%o4, %g1, %o4	/* Shift down to create index */
 	and		%o4, %o3, %o4	/* Mask with new_tsb_nents-1 */
 	sllx		%o4, 4, %o4	/* Shift back up into tsb ent offset */
 	TSB_STORE(%o2 + %o4, %g2)	/* Store TAG */
@@ -511,7 +514,7 @@
 	TSB_STORE(%o2 + %o4, %g3)	/* Store TTE */
 
 80:	add		%o0, 16, %o0
-	cmp		%o0, %g1
+	cmp		%o0, %o1
 	bne,pt		%xcc, 90b
 	 nop
 
diff --git a/arch/sparc/kernel/ttable_64.S b/arch/sparc/kernel/ttable_64.S
index c6dfdaa..170ead6 100644
--- a/arch/sparc/kernel/ttable_64.S
+++ b/arch/sparc/kernel/ttable_64.S
@@ -50,7 +50,7 @@
 tl0_irq1:	TRAP_IRQ(smp_call_function_client, 1)
 tl0_irq2:	TRAP_IRQ(smp_receive_signal_client, 2)
 tl0_irq3:	TRAP_IRQ(smp_penguin_jailcell, 3)
-tl0_irq4:	TRAP_IRQ(smp_new_mmu_context_version_client, 4)
+tl0_irq4:       BTRAP(0x44)
 #else
 tl0_irq1:	BTRAP(0x41)
 tl0_irq2:	BTRAP(0x42)
diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c
index f6bb857..075d389 100644
--- a/arch/sparc/kernel/vio.c
+++ b/arch/sparc/kernel/vio.c
@@ -302,13 +302,16 @@
 	if (!id) {
 		dev_set_name(&vdev->dev, "%s", bus_id_name);
 		vdev->dev_no = ~(u64)0;
+		vdev->id = ~(u64)0;
 	} else if (!cfg_handle) {
 		dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id);
 		vdev->dev_no = *id;
+		vdev->id = ~(u64)0;
 	} else {
 		dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name,
 			     *cfg_handle, *id);
 		vdev->dev_no = *cfg_handle;
+		vdev->id = *id;
 	}
 
 	vdev->dev.parent = parent;
@@ -351,27 +354,84 @@
 	(void) vio_create_one(hp, node, &root_vdev->dev);
 }
 
+struct vio_md_node_query {
+	const char *type;
+	u64 dev_no;
+	u64 id;
+};
+
 static int vio_md_node_match(struct device *dev, void *arg)
 {
+	struct vio_md_node_query *query = (struct vio_md_node_query *) arg;
 	struct vio_dev *vdev = to_vio_dev(dev);
 
-	if (vdev->mp == (u64) arg)
-		return 1;
+	if (vdev->dev_no != query->dev_no)
+		return 0;
+	if (vdev->id != query->id)
+		return 0;
+	if (strcmp(vdev->type, query->type))
+		return 0;
 
-	return 0;
+	return 1;
 }
 
 static void vio_remove(struct mdesc_handle *hp, u64 node)
 {
+	const char *type;
+	const u64 *id, *cfg_handle;
+	u64 a;
+	struct vio_md_node_query query;
 	struct device *dev;
 
-	dev = device_find_child(&root_vdev->dev, (void *) node,
+	type = mdesc_get_property(hp, node, "device-type", NULL);
+	if (!type) {
+		type = mdesc_get_property(hp, node, "name", NULL);
+		if (!type)
+			type = mdesc_node_name(hp, node);
+	}
+
+	query.type = type;
+
+	id = mdesc_get_property(hp, node, "id", NULL);
+	cfg_handle = NULL;
+	mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+		u64 target;
+
+		target = mdesc_arc_target(hp, a);
+		cfg_handle = mdesc_get_property(hp, target,
+						"cfg-handle", NULL);
+		if (cfg_handle)
+			break;
+	}
+
+	if (!id) {
+		query.dev_no = ~(u64)0;
+		query.id = ~(u64)0;
+	} else if (!cfg_handle) {
+		query.dev_no = *id;
+		query.id = ~(u64)0;
+	} else {
+		query.dev_no = *cfg_handle;
+		query.id = *id;
+	}
+
+	dev = device_find_child(&root_vdev->dev, &query,
 				vio_md_node_match);
 	if (dev) {
 		printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev));
 
 		device_unregister(dev);
 		put_device(dev);
+	} else {
+		if (!id)
+			printk(KERN_ERR "VIO: Removed unknown %s node.\n",
+			       type);
+		else if (!cfg_handle)
+			printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n",
+			       type, *id);
+		else
+			printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n",
+			       type, *cfg_handle, *id);
 	}
 }
 
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 69912d2..07c03e7 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -15,6 +15,7 @@
 lib-$(CONFIG_SPARC64) += atomic_64.o
 lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o
 lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o
+lib-$(CONFIG_SPARC64) += multi3.o
 
 lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o
 lib-$(CONFIG_SPARC64) += csum_copy.o csum_copy_from_user.o csum_copy_to_user.o
diff --git a/arch/sparc/lib/multi3.S b/arch/sparc/lib/multi3.S
new file mode 100644
index 0000000..d6b6c97
--- /dev/null
+++ b/arch/sparc/lib/multi3.S
@@ -0,0 +1,35 @@
+#include <linux/linkage.h>
+#include <asm/export.h>
+
+	.text
+	.align	4
+ENTRY(__multi3) /* %o0 = u, %o1 = v */
+	mov	%o1, %g1
+	srl	%o3, 0, %g4
+	mulx	%g4, %g1, %o1
+	srlx	%g1, 0x20, %g3
+	mulx	%g3, %g4, %g5
+	sllx	%g5, 0x20, %o5
+	srl	%g1, 0, %g4
+	sub	%o1, %o5, %o5
+	srlx	%o5, 0x20, %o5
+	addcc	%g5, %o5, %g5
+	srlx	%o3, 0x20, %o5
+	mulx	%g4, %o5, %g4
+	mulx	%g3, %o5, %o5
+	sethi	%hi(0x80000000), %g3
+	addcc	%g5, %g4, %g5
+	srlx	%g5, 0x20, %g5
+	add	%g3, %g3, %g3
+	movcc	%xcc, %g0, %g3
+	addcc	%o5, %g5, %o5
+	sllx	%g4, 0x20, %g4
+	add	%o1, %g4, %o1
+	add	%o5, %g3, %g2
+	mulx	%g1, %o2, %g1
+	add	%g1, %g2, %g1
+	mulx	%o0, %o3, %o0
+	retl
+	 add	%g1, %o0, %o0
+ENDPROC(__multi3)
+EXPORT_SYMBOL(__multi3)
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index bd7e2aa..57154c6 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -658,10 +658,58 @@
 
 /* get_new_mmu_context() uses "cache + 1".  */
 DEFINE_SPINLOCK(ctx_alloc_lock);
-unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
+unsigned long tlb_context_cache = CTX_FIRST_VERSION;
 #define MAX_CTX_NR	(1UL << CTX_NR_BITS)
 #define CTX_BMAP_SLOTS	BITS_TO_LONGS(MAX_CTX_NR)
 DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR);
+DEFINE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm) = {0};
+
+static void mmu_context_wrap(void)
+{
+	unsigned long old_ver = tlb_context_cache & CTX_VERSION_MASK;
+	unsigned long new_ver, new_ctx, old_ctx;
+	struct mm_struct *mm;
+	int cpu;
+
+	bitmap_zero(mmu_context_bmap, 1 << CTX_NR_BITS);
+
+	/* Reserve kernel context */
+	set_bit(0, mmu_context_bmap);
+
+	new_ver = (tlb_context_cache & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
+	if (unlikely(new_ver == 0))
+		new_ver = CTX_FIRST_VERSION;
+	tlb_context_cache = new_ver;
+
+	/*
+	 * Make sure that any new mm that are added into per_cpu_secondary_mm,
+	 * are going to go through get_new_mmu_context() path.
+	 */
+	mb();
+
+	/*
+	 * Updated versions to current on those CPUs that had valid secondary
+	 * contexts
+	 */
+	for_each_online_cpu(cpu) {
+		/*
+		 * If a new mm is stored after we took this mm from the array,
+		 * it will go into get_new_mmu_context() path, because we
+		 * already bumped the version in tlb_context_cache.
+		 */
+		mm = per_cpu(per_cpu_secondary_mm, cpu);
+
+		if (unlikely(!mm || mm == &init_mm))
+			continue;
+
+		old_ctx = mm->context.sparc64_ctx_val;
+		if (likely((old_ctx & CTX_VERSION_MASK) == old_ver)) {
+			new_ctx = (old_ctx & ~CTX_VERSION_MASK) | new_ver;
+			set_bit(new_ctx & CTX_NR_MASK, mmu_context_bmap);
+			mm->context.sparc64_ctx_val = new_ctx;
+		}
+	}
+}
 
 /* Caller does TLB context flushing on local CPU if necessary.
  * The caller also ensures that CTX_VALID(mm->context) is false.
@@ -677,48 +725,30 @@
 {
 	unsigned long ctx, new_ctx;
 	unsigned long orig_pgsz_bits;
-	int new_version;
 
 	spin_lock(&ctx_alloc_lock);
+retry:
+	/* wrap might have happened, test again if our context became valid */
+	if (unlikely(CTX_VALID(mm->context)))
+		goto out;
 	orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK);
 	ctx = (tlb_context_cache + 1) & CTX_NR_MASK;
 	new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx);
-	new_version = 0;
 	if (new_ctx >= (1 << CTX_NR_BITS)) {
 		new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);
 		if (new_ctx >= ctx) {
-			int i;
-			new_ctx = (tlb_context_cache & CTX_VERSION_MASK) +
-				CTX_FIRST_VERSION;
-			if (new_ctx == 1)
-				new_ctx = CTX_FIRST_VERSION;
-
-			/* Don't call memset, for 16 entries that's just
-			 * plain silly...
-			 */
-			mmu_context_bmap[0] = 3;
-			mmu_context_bmap[1] = 0;
-			mmu_context_bmap[2] = 0;
-			mmu_context_bmap[3] = 0;
-			for (i = 4; i < CTX_BMAP_SLOTS; i += 4) {
-				mmu_context_bmap[i + 0] = 0;
-				mmu_context_bmap[i + 1] = 0;
-				mmu_context_bmap[i + 2] = 0;
-				mmu_context_bmap[i + 3] = 0;
-			}
-			new_version = 1;
-			goto out;
+			mmu_context_wrap();
+			goto retry;
 		}
 	}
+	if (mm->context.sparc64_ctx_val)
+		cpumask_clear(mm_cpumask(mm));
 	mmu_context_bmap[new_ctx>>6] |= (1UL << (new_ctx & 63));
 	new_ctx |= (tlb_context_cache & CTX_VERSION_MASK);
-out:
 	tlb_context_cache = new_ctx;
 	mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits;
+out:
 	spin_unlock(&ctx_alloc_lock);
-
-	if (unlikely(new_version))
-		smp_new_mmu_context_version();
 }
 
 static int numa_enabled = 1;
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
index e20fbba..84cd593 100644
--- a/arch/sparc/mm/tsb.c
+++ b/arch/sparc/mm/tsb.c
@@ -451,7 +451,8 @@
 		extern void copy_tsb(unsigned long old_tsb_base,
 				     unsigned long old_tsb_size,
 				     unsigned long new_tsb_base,
-				     unsigned long new_tsb_size);
+				     unsigned long new_tsb_size,
+				     unsigned long page_size_shift);
 		unsigned long old_tsb_base = (unsigned long) old_tsb;
 		unsigned long new_tsb_base = (unsigned long) new_tsb;
 
@@ -459,7 +460,9 @@
 			old_tsb_base = __pa(old_tsb_base);
 			new_tsb_base = __pa(new_tsb_base);
 		}
-		copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size);
+		copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size,
+			tsb_index == MM_TSB_BASE ?
+			PAGE_SHIFT : REAL_HPAGE_SHIFT);
 	}
 
 	mm->context.tsb_block[tsb_index].tsb = new_tsb;
diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S
index 5d2fd6c..fcf4d27 100644
--- a/arch/sparc/mm/ultra.S
+++ b/arch/sparc/mm/ultra.S
@@ -971,11 +971,6 @@
 	wr		%g0, (1 << PIL_SMP_CAPTURE), %set_softint
 	retry
 
-	.globl		xcall_new_mmu_context_version
-xcall_new_mmu_context_version:
-	wr		%g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint
-	retry
-
 #ifdef CONFIG_KGDB
 	.globl		xcall_kgdb_capture
 xcall_kgdb_capture:
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index edbbfc8..9cf697c 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -162,8 +162,8 @@
 			 */
 			rcu_irq_exit();
 			native_safe_halt();
-			rcu_irq_enter();
 			local_irq_disable();
+			rcu_irq_enter();
 		}
 	}
 	if (!n.halted)
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 967e459..649d8f2 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -765,18 +765,20 @@
 static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
 {
 	struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i];
-	int j, nent = vcpu->arch.cpuid_nent;
+	struct kvm_cpuid_entry2 *ej;
+	int j = i;
+	int nent = vcpu->arch.cpuid_nent;
 
 	e->flags &= ~KVM_CPUID_FLAG_STATE_READ_NEXT;
 	/* when no next entry is found, the current entry[i] is reselected */
-	for (j = i + 1; ; j = (j + 1) % nent) {
-		struct kvm_cpuid_entry2 *ej = &vcpu->arch.cpuid_entries[j];
-		if (ej->function == e->function) {
-			ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
-			return j;
-		}
-	}
-	return 0; /* silence gcc, even though control never reaches here */
+	do {
+		j = (j + 1) % nent;
+		ej = &vcpu->arch.cpuid_entries[j];
+	} while (ej->function != e->function);
+
+	ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
+
+	return j;
 }
 
 /* find an entry with matching function, matching index (if needed), and that
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index d9c7e98..5f24127 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3489,12 +3489,15 @@
 	return kvm_setup_async_pf(vcpu, gva, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch);
 }
 
-static bool can_do_async_pf(struct kvm_vcpu *vcpu)
+bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
 {
 	if (unlikely(!lapic_in_kernel(vcpu) ||
 		     kvm_event_needs_reinjection(vcpu)))
 		return false;
 
+	if (is_guest_mode(vcpu))
+		return false;
+
 	return kvm_x86_ops->interrupt_allowed(vcpu);
 }
 
@@ -3510,7 +3513,7 @@
 	if (!async)
 		return false; /* *pfn has correct page already */
 
-	if (!prefault && can_do_async_pf(vcpu)) {
+	if (!prefault && kvm_can_do_async_pf(vcpu)) {
 		trace_kvm_try_async_get_page(gva, gfn);
 		if (kvm_find_async_pf_gfn(vcpu, gfn)) {
 			trace_kvm_async_pf_doublefault(gva, gfn);
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index ddc56e9..c92834c5 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -75,6 +75,7 @@
 int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct);
 void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu);
 void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly);
+bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu);
 
 static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
 {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 81bba3c..62cde4f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8444,8 +8444,7 @@
 	if (!(vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED))
 		return true;
 	else
-		return !kvm_event_needs_reinjection(vcpu) &&
-			kvm_x86_ops->interrupt_allowed(vcpu);
+		return kvm_can_do_async_pf(vcpu);
 }
 
 void kvm_arch_start_assignment(struct kvm *kvm)
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index cdfe8c6..393a0c0 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -358,6 +358,9 @@
 		free_bootmem_late(start, size);
 	}
 
+	if (!num_entries)
+		return;
+
 	new_size = efi.memmap.desc_size * num_entries;
 	new_phys = efi_memmap_alloc(num_entries);
 	if (!new_phys) {
diff --git a/block/blk-core.c b/block/blk-core.c
index 710c93b..d8fba67 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1438,6 +1438,9 @@
 	/* this is a bio leak */
 	WARN_ON(req->bio != NULL);
 
+	/* this is a bio leak if the bio is not tagged with BIO_DONTFREE */
+	WARN_ON(req->bio && !bio_flagged(req->bio, BIO_DONTFREE));
+
 	/*
 	 * Request may not have originated from ll_rw_blk. if not,
 	 * it didn't come out of our reserved rq pools
@@ -2619,6 +2622,15 @@
 	blk_account_io_completion(req, nr_bytes);
 
 	total_bytes = 0;
+
+	/*
+	 * Check for this if flagged, Req based dm needs to perform
+	 * post processing, hence dont end bios or request.DM
+	 * layer takes care.
+	 */
+	if (bio_flagged(req->bio, BIO_DONTFREE))
+		return false;
+
 	while (req->bio) {
 		struct bio *bio = req->bio;
 		unsigned bio_bytes = min(bio->bi_iter.bi_size, nr_bytes);
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 2642e5f..abde370 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -492,6 +492,64 @@
 }
 EXPORT_SYMBOL(blk_rq_map_sg);
 
+/*
+ * map a request to scatterlist without combining PHY CONT
+ * blocks, return number of sg entries setup. Caller
+ * must make sure sg can hold rq->nr_phys_segments entries
+ */
+int blk_rq_map_sg_no_cluster(struct request_queue *q, struct request *rq,
+		  struct scatterlist *sglist)
+{
+	struct bio_vec bvec, bvprv = { NULL };
+	struct req_iterator iter;
+	struct scatterlist *sg;
+	int nsegs, cluster = 0;
+
+	nsegs = 0;
+
+	/*
+	 * for each bio in rq
+	 */
+	sg = NULL;
+	rq_for_each_segment(bvec, rq, iter) {
+		__blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg,
+				     &nsegs, &cluster);
+	} /* segments in rq */
+
+
+	if (!sg)
+		return nsegs;
+
+	if (unlikely(rq->cmd_flags & REQ_COPY_USER) &&
+	    (blk_rq_bytes(rq) & q->dma_pad_mask)) {
+		unsigned int pad_len =
+			(q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1;
+
+		sg->length += pad_len;
+		rq->extra_len += pad_len;
+	}
+
+	if (q->dma_drain_size && q->dma_drain_needed(rq)) {
+		if (rq->cmd_flags & REQ_OP_WRITE)
+			memset(q->dma_drain_buffer, 0, q->dma_drain_size);
+
+		sg->page_link &= ~0x02;
+		sg = sg_next(sg);
+		sg_set_page(sg, virt_to_page(q->dma_drain_buffer),
+			    q->dma_drain_size,
+			    ((unsigned long)q->dma_drain_buffer) &
+			    (PAGE_SIZE - 1));
+		nsegs++;
+		rq->extra_len += q->dma_drain_size;
+	}
+
+	if (sg)
+		sg_mark_end(sg);
+
+	return nsegs;
+}
+EXPORT_SYMBOL(blk_rq_map_sg_no_cluster);
+
 static inline int ll_new_hw_segment(struct request_queue *q,
 				    struct request *req,
 				    struct bio *bio)
diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c
index 19b1d9c..df02faf 100644
--- a/block/blk-mq-cpumap.c
+++ b/block/blk-mq-cpumap.c
@@ -35,37 +35,19 @@
 {
 	unsigned int *map = set->mq_map;
 	unsigned int nr_queues = set->nr_hw_queues;
-	const struct cpumask *online_mask = cpu_online_mask;
-	unsigned int i, nr_cpus, nr_uniq_cpus, queue, first_sibling;
+	unsigned int i, queue, first_sibling;
 	cpumask_var_t cpus;
 
-	if (!alloc_cpumask_var(&cpus, GFP_ATOMIC))
-		return -ENOMEM;
-
-	cpumask_clear(cpus);
-	nr_cpus = nr_uniq_cpus = 0;
-	for_each_cpu(i, online_mask) {
-		nr_cpus++;
-		first_sibling = get_first_sibling(i);
-		if (!cpumask_test_cpu(first_sibling, cpus))
-			nr_uniq_cpus++;
-		cpumask_set_cpu(i, cpus);
-	}
-
 	queue = 0;
 	for_each_possible_cpu(i) {
-		if (!cpumask_test_cpu(i, online_mask)) {
-			map[i] = 0;
-			continue;
-		}
-
 		/*
 		 * Easy case - we have equal or more hardware queues. Or
 		 * there are no thread siblings to take into account. Do
 		 * 1:1 if enough, or sequential mapping if less.
 		 */
-		if (nr_queues >= nr_cpus || nr_cpus == nr_uniq_cpus) {
-			map[i] = cpu_to_queue_index(nr_cpus, nr_queues, queue);
+		if (nr_queues >= nr_cpu_ids) {
+			map[i] = cpu_to_queue_index(nr_cpu_ids, nr_queues,
+						queue);
 			queue++;
 			continue;
 		}
@@ -77,7 +59,7 @@
 		 */
 		first_sibling = get_first_sibling(i);
 		if (first_sibling == i) {
-			map[i] = cpu_to_queue_index(nr_uniq_cpus, nr_queues,
+			map[i] = cpu_to_queue_index(nr_cpu_ids, nr_queues,
 							queue);
 			queue++;
 		} else
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 7b597ec..a7db634 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1713,10 +1713,6 @@
 		INIT_LIST_HEAD(&__ctx->rq_list);
 		__ctx->queue = q;
 
-		/* If the cpu isn't online, the cpu is mapped to first hctx */
-		if (!cpu_online(i))
-			continue;
-
 		hctx = blk_mq_map_queue(q, i);
 
 		/*
@@ -1750,14 +1746,11 @@
 	 * Map software to hardware queues
 	 */
 	for_each_possible_cpu(i) {
-		/* If the cpu isn't online, the cpu is mapped to first hctx */
-		if (!cpumask_test_cpu(i, online_mask))
-			continue;
-
 		ctx = per_cpu_ptr(q->queue_ctx, i);
 		hctx = blk_mq_map_queue(q, i);
 
-		cpumask_set_cpu(i, hctx->cpumask);
+		if (cpumask_test_cpu(i, online_mask))
+			cpumask_set_cpu(i, hctx->cpumask);
 		ctx->index_hw = hctx->nr_ctx;
 		hctx->ctxs[hctx->nr_ctx++] = ctx;
 	}
@@ -1793,9 +1786,16 @@
 
 		/*
 		 * Initialize batch roundrobin counts
+		 * Set next_cpu for only those hctxs that have an online CPU
+		 * in their cpumask field. For hctxs that belong to few online
+		 * and few offline CPUs, this will always provide one CPU from
+		 * online ones. For hctxs belonging to all offline CPUs, their
+		 * cpumask will be updated in reinit_notify.
 		 */
-		hctx->next_cpu = cpumask_first(hctx->cpumask);
-		hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH;
+		if (cpumask_first(hctx->cpumask) < nr_cpu_ids) {
+			hctx->next_cpu = cpumask_first(hctx->cpumask);
+			hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH;
+		}
 	}
 }
 
@@ -2067,50 +2067,20 @@
 	blk_mq_sysfs_register(q);
 }
 
-/*
- * New online cpumask which is going to be set in this hotplug event.
- * Declare this cpumasks as global as cpu-hotplug operation is invoked
- * one-by-one and dynamically allocating this could result in a failure.
- */
-static struct cpumask cpuhp_online_new;
-
-static void blk_mq_queue_reinit_work(void)
-{
-	struct request_queue *q;
-
-	mutex_lock(&all_q_mutex);
-	/*
-	 * We need to freeze and reinit all existing queues.  Freezing
-	 * involves synchronous wait for an RCU grace period and doing it
-	 * one by one may take a long time.  Start freezing all queues in
-	 * one swoop and then wait for the completions so that freezing can
-	 * take place in parallel.
-	 */
-	list_for_each_entry(q, &all_q_list, all_q_node)
-		blk_mq_freeze_queue_start(q);
-	list_for_each_entry(q, &all_q_list, all_q_node) {
-		blk_mq_freeze_queue_wait(q);
-
-		/*
-		 * timeout handler can't touch hw queue during the
-		 * reinitialization
-		 */
-		del_timer_sync(&q->timeout);
-	}
-
-	list_for_each_entry(q, &all_q_list, all_q_node)
-		blk_mq_queue_reinit(q, &cpuhp_online_new);
-
-	list_for_each_entry(q, &all_q_list, all_q_node)
-		blk_mq_unfreeze_queue(q);
-
-	mutex_unlock(&all_q_mutex);
-}
-
 static int blk_mq_queue_reinit_dead(unsigned int cpu)
 {
-	cpumask_copy(&cpuhp_online_new, cpu_online_mask);
-	blk_mq_queue_reinit_work();
+	struct request_queue *q;
+	struct blk_mq_hw_ctx *hctx;
+	int i;
+
+	mutex_lock(&all_q_mutex);
+	list_for_each_entry(q, &all_q_list, all_q_node) {
+		queue_for_each_hw_ctx(q, hctx, i) {
+			cpumask_clear_cpu(cpu, hctx->cpumask);
+		}
+	}
+	mutex_unlock(&all_q_mutex);
+
 	return 0;
 }
 
@@ -2132,9 +2102,17 @@
  */
 static int blk_mq_queue_reinit_prepare(unsigned int cpu)
 {
-	cpumask_copy(&cpuhp_online_new, cpu_online_mask);
-	cpumask_set_cpu(cpu, &cpuhp_online_new);
-	blk_mq_queue_reinit_work();
+	struct request_queue *q;
+	struct blk_mq_hw_ctx *hctx;
+	int i;
+
+	mutex_lock(&all_q_mutex);
+	list_for_each_entry(q, &all_q_list, all_q_node) {
+		queue_for_each_hw_ctx(q, hctx, i) {
+			cpumask_set_cpu(cpu, hctx->cpumask);
+		}
+	}
+	mutex_unlock(&all_q_mutex);
 	return 0;
 }
 
diff --git a/block/blk.h b/block/blk.h
index 74444c4..ae07666 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -207,7 +207,6 @@
 int attempt_front_merge(struct request_queue *q, struct request *rq);
 int blk_attempt_req_merge(struct request_queue *q, struct request *rq,
 				struct request *next);
-void blk_recalc_rq_segments(struct request *rq);
 void blk_rq_set_mixed_merge(struct request *rq);
 bool blk_rq_merge_ok(struct request *rq, struct bio *bio);
 int blk_try_merge(struct request *rq, struct bio *bio);
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 3ab6807..c7c3d4e 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -36,9 +36,13 @@
 static const int cfq_hist_divisor = 4;
 
 /*
- * offset from end of service tree
+ * offset from end of queue service tree for idle class
  */
 #define CFQ_IDLE_DELAY		(NSEC_PER_SEC / 5)
+/* offset from end of group service tree under time slice mode */
+#define CFQ_SLICE_MODE_GROUP_DELAY (NSEC_PER_SEC / 5)
+/* offset from end of group service under IOPS mode */
+#define CFQ_IOPS_MODE_GROUP_DELAY (HZ / 5)
 
 /*
  * below this threshold, we consider thinktime immediate
@@ -1370,6 +1374,14 @@
 	cfqg->vfraction = max_t(unsigned, vfr, 1);
 }
 
+static inline u64 cfq_get_cfqg_vdisktime_delay(struct cfq_data *cfqd)
+{
+	if (!iops_mode(cfqd))
+		return CFQ_SLICE_MODE_GROUP_DELAY;
+	else
+		return CFQ_IOPS_MODE_GROUP_DELAY;
+}
+
 static void
 cfq_group_notify_queue_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
 {
@@ -1389,7 +1401,8 @@
 	n = rb_last(&st->rb);
 	if (n) {
 		__cfqg = rb_entry_cfqg(n);
-		cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY;
+		cfqg->vdisktime = __cfqg->vdisktime +
+			cfq_get_cfqg_vdisktime_delay(cfqd);
 	} else
 		cfqg->vdisktime = st->min_vdisktime;
 	cfq_group_service_tree_add(st, cfqg);
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index fd76b5f..4955eb6 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -140,7 +140,7 @@
 	 * signature and returns that to us.
 	 */
 	ret = crypto_akcipher_verify(req);
-	if (ret == -EINPROGRESS) {
+	if ((ret == -EINPROGRESS) || (ret == -EBUSY)) {
 		wait_for_completion(&compl.completion);
 		ret = compl.err;
 	}
diff --git a/crypto/drbg.c b/crypto/drbg.c
index 053035b..123d211 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -1768,9 +1768,8 @@
 			break;
 		case -EINPROGRESS:
 		case -EBUSY:
-			ret = wait_for_completion_interruptible(
-				&drbg->ctr_completion);
-			if (!ret && !drbg->ctr_async_err) {
+			wait_for_completion(&drbg->ctr_completion);
+			if (!drbg->ctr_async_err) {
 				reinit_completion(&drbg->ctr_completion);
 				break;
 			}
diff --git a/crypto/gcm.c b/crypto/gcm.c
index f624ac9..dd33fbd 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -152,10 +152,8 @@
 
 	err = crypto_skcipher_encrypt(&data->req);
 	if (err == -EINPROGRESS || err == -EBUSY) {
-		err = wait_for_completion_interruptible(
-			&data->result.completion);
-		if (!err)
-			err = data->result.err;
+		wait_for_completion(&data->result.completion);
+		err = data->result.err;
 	}
 
 	if (err)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 74f4c66..c940382 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1362,6 +1362,40 @@
 {}
 #endif
 
+/*
+ * On the Acer Aspire Switch Alpha 12, sometimes all SATA ports are detected
+ * as DUMMY, or detected but eventually get a "link down" and never get up
+ * again. When this happens, CAP.NP may hold a value of 0x00 or 0x01, and the
+ * port_map may hold a value of 0x00.
+ *
+ * Overriding CAP.NP to 0x02 and the port_map to 0x7 will reveal all 3 ports
+ * and can significantly reduce the occurrence of the problem.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=189471
+ */
+static void acer_sa5_271_workaround(struct ahci_host_priv *hpriv,
+				    struct pci_dev *pdev)
+{
+	static const struct dmi_system_id sysids[] = {
+		{
+			.ident = "Acer Switch Alpha 12",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "Switch SA5-271")
+			},
+		},
+		{ }
+	};
+
+	if (dmi_check_system(sysids)) {
+		dev_info(&pdev->dev, "enabling Acer Switch Alpha 12 workaround\n");
+		if ((hpriv->saved_cap & 0xC734FF00) == 0xC734FF00) {
+			hpriv->port_map = 0x7;
+			hpriv->cap = 0xC734FF02;
+		}
+	}
+}
+
 #ifdef CONFIG_ARM64
 /*
  * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently.
@@ -1597,6 +1631,10 @@
 			 "online status unreliable, applying workaround\n");
 	}
 
+
+	/* Acer SA5-271 workaround modifies private_data */
+	acer_sa5_271_workaround(hpriv, pdev);
+
 	/* CAP.NP sometimes indicate the index of the last enabled
 	 * port, at other times, that of the last possible port, so
 	 * determining the maximum port number requires looking at
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 4609244..624f069 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -182,8 +182,8 @@
 
 #ifdef CONFIG_HOTPLUG_CPU
 
-static ssize_t show_cpu_isolated(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t isolate_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
 {
 	struct cpu *cpu = container_of(dev, struct cpu, dev);
 	ssize_t rc;
@@ -195,31 +195,7 @@
 	return rc;
 }
 
-static ssize_t __ref store_cpu_isolated(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf, size_t count)
-{
-	struct cpu *cpu = container_of(dev, struct cpu, dev);
-	int err;
-	int cpuid = cpu->dev.id;
-	unsigned int isolated;
-
-	err = kstrtouint(strstrip((char *)buf), 0, &isolated);
-	if (err)
-		return err;
-
-	if (isolated > 1)
-		return -EINVAL;
-
-	if (isolated)
-		sched_isolate_cpu(cpuid);
-	else
-		sched_unisolate_cpu(cpuid);
-
-	return count;
-}
-
-static DEVICE_ATTR(isolate, 0644, show_cpu_isolated, store_cpu_isolated);
+static DEVICE_ATTR_RO(isolate);
 
 static struct attribute *cpu_isolated_attrs[] = {
 	&dev_attr_isolate.attr,
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index df3c97c..d6ec1c5 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -118,51 +118,19 @@
 	return sysfs_create_group(&dev->kobj, &topology_attr_group);
 }
 
-static void topology_remove_dev(unsigned int cpu)
+static int topology_remove_dev(unsigned int cpu)
 {
 	struct device *dev = get_cpu_device(cpu);
 
 	sysfs_remove_group(&dev->kobj, &topology_attr_group);
-}
-
-static int topology_cpu_callback(struct notifier_block *nfb,
-				 unsigned long action, void *hcpu)
-{
-	unsigned int cpu = (unsigned long)hcpu;
-	int rc = 0;
-
-	switch (action) {
-	case CPU_UP_PREPARE:
-	case CPU_UP_PREPARE_FROZEN:
-		rc = topology_add_dev(cpu);
-		break;
-	case CPU_UP_CANCELED:
-	case CPU_UP_CANCELED_FROZEN:
-	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
-		topology_remove_dev(cpu);
-		break;
-	}
-	return notifier_from_errno(rc);
+	return 0;
 }
 
 static int topology_sysfs_init(void)
 {
-	int cpu;
-	int rc = 0;
-
-	cpu_notifier_register_begin();
-
-	for_each_online_cpu(cpu) {
-		rc = topology_add_dev(cpu);
-		if (rc)
-			goto out;
-	}
-	__hotcpu_notifier(topology_cpu_callback, 0);
-
-out:
-	cpu_notifier_register_done();
-	return rc;
+	return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE,
+				 "base/topology:prepare", topology_add_dev,
+				 topology_remove_dev);
 }
 
 device_initcall(topology_sysfs_init);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 3e1367a..49fb8e5 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -604,5 +604,12 @@
           applications DSP processor. Say M if you want to enable this
           module.
 
+config MSM_RDBG
+	tristate "QTI Remote debug driver"
+	help
+	  Implements a shared memory based transport mechanism that allows
+	  for a debugger running on a host PC to communicate with a remote
+	  stub running on peripheral subsystems such as the ADSP, MODEM etc.
+
 endmenu
 
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index b73165a..19c3c98 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -65,3 +65,4 @@
 ifdef CONFIG_COMPAT
 obj-$(CONFIG_MSM_ADSPRPC)       += adsprpc_compat.o
 endif
+obj-$(CONFIG_MSM_RDBG)		+= rdbg.o
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 9102df7..9ea639a 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1049,6 +1049,9 @@
 		if (err)
 			goto bail;
 	}
+	if (ctx->buf->virt && metalen <= copylen)
+		memset(ctx->buf->virt, 0, metalen);
+
 	/* copy metadata */
 	rpra = ctx->buf->virt;
 	ctx->rpra = rpra;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index e907d0d..8f0597f 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -2849,6 +2849,8 @@
 		new_entry->num_buffers = 1;
 		break;
 	}
+
+	new_entry->buffers = NULL;
 	new_entry->real_time = MODE_REALTIME;
 	new_entry->in_service = 0;
 	INIT_LIST_HEAD(&new_entry->list_write_buf);
@@ -2919,7 +2921,8 @@
 
 fail_alloc:
 	if (new_entry) {
-		for (i = 0; i < new_entry->num_buffers; i++) {
+		for (i = 0; ((i < new_entry->num_buffers) &&
+			new_entry->buffers); i++) {
 			proc_buf = &new_entry->buffers[i];
 			if (proc_buf) {
 				mutex_destroy(&proc_buf->health_mutex);
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index c4d378e..b5a594a 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -60,7 +60,8 @@
 	{ .ssid_first = MSG_SSID_21, .ssid_last = MSG_SSID_21_LAST },
 	{ .ssid_first = MSG_SSID_22, .ssid_last = MSG_SSID_22_LAST },
 	{ .ssid_first = MSG_SSID_23, .ssid_last = MSG_SSID_23_LAST },
-	{ .ssid_first = MSG_SSID_24, .ssid_last = MSG_SSID_24_LAST }
+	{ .ssid_first = MSG_SSID_24, .ssid_last = MSG_SSID_24_LAST },
+	{ .ssid_first = MSG_SSID_25, .ssid_last = MSG_SSID_25_LAST }
 };
 
 static int diag_apps_responds(void)
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 5a8ef04..119f5ac 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -848,7 +848,7 @@
 			 __func__, fwd_info->peripheral, fwd_info->type);
 		return 0;
 	}
-
+	mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
 	fwd_info->ch_open = 1;
 	diagfwd_buffers_init(fwd_info);
 	diagfwd_write_buffers_init(fwd_info);
@@ -866,7 +866,7 @@
 		if (fwd_info->p_ops && fwd_info->p_ops->open)
 			fwd_info->p_ops->open(fwd_info->ctxt);
 	}
-
+	mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
 	return 0;
 }
 
@@ -877,6 +877,7 @@
 	if (!fwd_info)
 		return -EIO;
 
+	mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
 	fwd_info->ch_open = 0;
 	if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close)
 		fwd_info->c_ops->close(fwd_info);
@@ -892,7 +893,7 @@
 	}
 	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d considered closed\n",
 		 fwd_info->peripheral, fwd_info->type);
-
+	mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
 	return 0;
 }
 
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 6e0cbe0..593a881 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -343,7 +343,7 @@
 	phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT;
 
 	/* It's illegal to wrap around the end of the physical address space. */
-	if (offset + (phys_addr_t)size < offset)
+	if (offset + (phys_addr_t)size - 1 < offset)
 		return -EINVAL;
 
 	if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 8069b36..a7511a1 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -59,7 +59,7 @@
 /*
  * Assigned numbers, used for dynamic minors
  */
-#define DYNAMIC_MINORS 64 /* like dynamic majors */
+#define DYNAMIC_MINORS 75 /* like dynamic majors */
 static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
 
 #ifdef CONFIG_PROC_FS
diff --git a/drivers/char/rdbg.c b/drivers/char/rdbg.c
new file mode 100644
index 0000000..92d9399
--- /dev/null
+++ b/drivers/char/rdbg.c
@@ -0,0 +1,1167 @@
+/*
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <soc/qcom/smem.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+
+#define SMP2P_NUM_PROCS				8
+#define MAX_RETRIES				20
+
+#define SM_VERSION				1
+#define SM_BLOCKSIZE				128
+
+#define SMQ_MAGIC_INIT				0xFF00FF00
+#define SMQ_MAGIC_PRODUCER			(SMQ_MAGIC_INIT | 0x1)
+#define SMQ_MAGIC_CONSUMER			(SMQ_MAGIC_INIT | 0x2)
+
+enum SMQ_STATUS {
+	SMQ_SUCCESS    =  0,
+	SMQ_ENOMEMORY  = -1,
+	SMQ_EBADPARM   = -2,
+	SMQ_UNDERFLOW  = -3,
+	SMQ_OVERFLOW   = -4
+};
+
+enum smq_type {
+	PRODUCER = 1,
+	CONSUMER = 2,
+	INVALID  = 3
+};
+
+struct smq_block_map {
+	uint32_t index_read;
+	uint32_t num_blocks;
+	uint8_t *map;
+};
+
+struct smq_node {
+	uint16_t index_block;
+	uint16_t num_blocks;
+} __attribute__ ((__packed__));
+
+struct smq_hdr {
+	uint8_t producer_version;
+	uint8_t consumer_version;
+} __attribute__ ((__packed__));
+
+struct smq_out_state {
+	uint32_t init;
+	uint32_t index_check_queue_for_reset;
+	uint32_t index_sent_write;
+	uint32_t index_free_read;
+} __attribute__ ((__packed__));
+
+struct smq_out {
+	struct smq_out_state s;
+	struct smq_node sent[1];
+};
+
+struct smq_in_state {
+	uint32_t init;
+	uint32_t index_check_queue_for_reset_ack;
+	uint32_t index_sent_read;
+	uint32_t index_free_write;
+} __attribute__ ((__packed__));
+
+struct smq_in {
+	struct smq_in_state s;
+	struct smq_node free[1];
+};
+
+struct smq {
+	struct smq_hdr *hdr;
+	struct smq_out *out;
+	struct smq_in *in;
+	uint8_t *blocks;
+	uint32_t num_blocks;
+	struct mutex *lock;
+	uint32_t initialized;
+	struct smq_block_map block_map;
+	enum smq_type type;
+};
+
+struct gpio_info {
+	int gpio_base_id;
+	int irq_base_id;
+};
+
+struct rdbg_data {
+	struct device *device;
+	struct completion work;
+	struct gpio_info in;
+	struct gpio_info out;
+	bool   device_initialized;
+	int    gpio_out_offset;
+	bool   device_opened;
+	void   *smem_addr;
+	size_t smem_size;
+	struct smq    producer_smrb;
+	struct smq    consumer_smrb;
+	struct mutex  write_mutex;
+};
+
+struct rdbg_device {
+	struct cdev cdev;
+	struct class *class;
+	dev_t dev_no;
+	int num_devices;
+	struct rdbg_data *rdbg_data;
+};
+
+static struct rdbg_device g_rdbg_instance = {
+	{ {0} },
+	NULL,
+	0,
+	SMP2P_NUM_PROCS,
+	NULL
+};
+
+struct processor_specific_info {
+	char *name;
+	unsigned int smem_buffer_addr;
+	size_t smem_buffer_size;
+};
+
+static struct processor_specific_info proc_info[SMP2P_NUM_PROCS] = {
+		{0},	/*APPS*/
+		{"rdbg_modem", 0, 0},	/*MODEM*/
+		{"rdbg_adsp", SMEM_LC_DEBUGGER, 16*1024},	/*ADSP*/
+		{0},	/*SMP2P_RESERVED_PROC_1*/
+		{"rdbg_wcnss", 0, 0},		/*WCNSS*/
+		{0},	/*SMP2P_RESERVED_PROC_2*/
+		{0},	/*SMP2P_POWER_PROC*/
+		{0}		/*SMP2P_REMOTE_MOCK_PROC*/
+};
+
+static int smq_blockmap_get(struct smq_block_map *block_map,
+	uint32_t *block_index, uint32_t n)
+{
+	uint32_t start;
+	uint32_t mark = 0;
+	uint32_t found = 0;
+	uint32_t i = 0;
+
+	start = block_map->index_read;
+
+	if (n == 1) {
+		do {
+			if (!block_map->map[block_map->index_read]) {
+				*block_index = block_map->index_read;
+				block_map->map[block_map->index_read] = 1;
+				block_map->index_read++;
+				block_map->index_read %= block_map->num_blocks;
+				return SMQ_SUCCESS;
+			}
+			block_map->index_read++;
+		} while (start != (block_map->index_read %=
+			block_map->num_blocks));
+	} else {
+		mark = block_map->num_blocks;
+
+		do {
+			if (!block_map->map[block_map->index_read]) {
+				if (mark > block_map->index_read) {
+					mark = block_map->index_read;
+					start = block_map->index_read;
+					found = 0;
+				}
+
+				found++;
+				if (found == n) {
+					*block_index = mark;
+					for (i = 0; i < n; i++)
+						block_map->map[mark + i] =
+							(uint8_t)(n - i);
+					block_map->index_read += block_map->map
+						[block_map->index_read] - 1;
+					return SMQ_SUCCESS;
+				}
+			} else {
+				found = 0;
+				block_map->index_read += block_map->map
+					[block_map->index_read] - 1;
+				mark = block_map->num_blocks;
+			}
+			block_map->index_read++;
+		} while (start != (block_map->index_read %=
+			block_map->num_blocks));
+	}
+
+	return SMQ_ENOMEMORY;
+}
+
+static void smq_blockmap_put(struct smq_block_map *block_map, uint32_t i)
+{
+	uint32_t num_blocks = block_map->map[i];
+
+	while (num_blocks--) {
+		block_map->map[i] = 0;
+		i++;
+	}
+}
+
+static int smq_blockmap_reset(struct smq_block_map *block_map)
+{
+	if (!block_map->map)
+		return SMQ_ENOMEMORY;
+	memset(block_map->map, 0, block_map->num_blocks + 1);
+	block_map->index_read = 0;
+
+	return SMQ_SUCCESS;
+}
+
+static int smq_blockmap_ctor(struct smq_block_map *block_map,
+	uint32_t num_blocks)
+{
+	if (num_blocks <= 1)
+		return SMQ_ENOMEMORY;
+
+	block_map->map = kcalloc(num_blocks, sizeof(uint8_t), GFP_KERNEL);
+	if (!block_map->map)
+		return SMQ_ENOMEMORY;
+
+	block_map->num_blocks = num_blocks - 1;
+	smq_blockmap_reset(block_map);
+
+	return SMQ_SUCCESS;
+}
+
+static void smq_blockmap_dtor(struct smq_block_map *block_map)
+{
+	kfree(block_map->map);
+	block_map->map = NULL;
+}
+
+static int smq_free(struct smq *smq, void *data)
+{
+	struct smq_node node;
+	uint32_t index_block;
+	int err = SMQ_SUCCESS;
+
+	if (smq->lock)
+		mutex_lock(smq->lock);
+
+	if ((smq->hdr->producer_version != SM_VERSION) &&
+		(smq->out->s.init != SMQ_MAGIC_PRODUCER)) {
+		err = SMQ_UNDERFLOW;
+		goto bail;
+	}
+
+	index_block = ((uint8_t *)data - smq->blocks) / SM_BLOCKSIZE;
+	if (index_block >= smq->num_blocks) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	node.index_block = (uint16_t)index_block;
+	node.num_blocks = 0;
+	*((struct smq_node *)(smq->in->free + smq->in->
+		s.index_free_write)) = node;
+
+	smq->in->s.index_free_write = (smq->in->s.index_free_write + 1)
+		% smq->num_blocks;
+
+bail:
+	if (smq->lock)
+		mutex_unlock(smq->lock);
+	return err;
+}
+
+static int smq_receive(struct smq *smq, void **pp, int *pnsize, int *pbmore)
+{
+	struct smq_node *node;
+	int err = SMQ_SUCCESS;
+	int more = 0;
+
+	if ((smq->hdr->producer_version != SM_VERSION) &&
+		(smq->out->s.init != SMQ_MAGIC_PRODUCER))
+		return SMQ_UNDERFLOW;
+
+	if (smq->in->s.index_sent_read == smq->out->s.index_sent_write) {
+		err = SMQ_UNDERFLOW;
+		goto bail;
+	}
+
+	node = (struct smq_node *)(smq->out->sent + smq->in->s.index_sent_read);
+	if (node->index_block >= smq->num_blocks) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	smq->in->s.index_sent_read = (smq->in->s.index_sent_read + 1)
+		% smq->num_blocks;
+
+	*pp = smq->blocks + (node->index_block * SM_BLOCKSIZE);
+	*pnsize = SM_BLOCKSIZE * node->num_blocks;
+
+	/*
+	 * Ensure that the reads and writes are updated in the memory
+	 * when they are done and not cached. Also, ensure that the reads
+	 * and writes are not reordered as they are shared between two cores.
+	 */
+	rmb();
+	if (smq->in->s.index_sent_read != smq->out->s.index_sent_write)
+		more = 1;
+
+bail:
+	*pbmore = more;
+	return err;
+}
+
+static int smq_alloc_send(struct smq *smq, const uint8_t *pcb, int nsize)
+{
+	void *pv = 0;
+	int num_blocks;
+	uint32_t index_block = 0;
+	int err = SMQ_SUCCESS;
+	struct smq_node *node = NULL;
+
+	mutex_lock(smq->lock);
+
+	if ((smq->in->s.init == SMQ_MAGIC_CONSUMER) &&
+	 (smq->hdr->consumer_version == SM_VERSION)) {
+		if (smq->out->s.index_check_queue_for_reset ==
+			smq->in->s.index_check_queue_for_reset_ack) {
+			while (smq->out->s.index_free_read !=
+				smq->in->s.index_free_write) {
+				node = (struct smq_node *)(
+					smq->in->free +
+					smq->out->s.index_free_read);
+				if (node->index_block >= smq->num_blocks) {
+					err = SMQ_EBADPARM;
+					goto bail;
+				}
+
+				smq->out->s.index_free_read =
+					(smq->out->s.index_free_read + 1)
+						% smq->num_blocks;
+
+				smq_blockmap_put(&smq->block_map,
+					node->index_block);
+				/*
+				 * Ensure that the reads and writes are
+				 * updated in the memory when they are done
+				 * and not cached. Also, ensure that the reads
+				 * and writes are not reordered as they are
+				 * shared between two cores.
+				 */
+				rmb();
+			}
+		}
+	}
+
+	num_blocks = ALIGN(nsize, SM_BLOCKSIZE)/SM_BLOCKSIZE;
+	err = smq_blockmap_get(&smq->block_map, &index_block, num_blocks);
+	if (err != SMQ_SUCCESS)
+		goto bail;
+
+	pv = smq->blocks + (SM_BLOCKSIZE * index_block);
+
+	err = copy_from_user((void *)pv, (void *)pcb, nsize);
+	if (err != 0)
+		goto bail;
+
+	((struct smq_node *)(smq->out->sent +
+		smq->out->s.index_sent_write))->index_block
+			= (uint16_t)index_block;
+	((struct smq_node *)(smq->out->sent +
+		smq->out->s.index_sent_write))->num_blocks
+			= (uint16_t)num_blocks;
+
+	smq->out->s.index_sent_write = (smq->out->s.index_sent_write + 1)
+		% smq->num_blocks;
+
+bail:
+	if (err != SMQ_SUCCESS) {
+		if (pv)
+			smq_blockmap_put(&smq->block_map, index_block);
+	}
+	mutex_unlock(smq->lock);
+	return err;
+}
+
+static int smq_reset_producer_queue_internal(struct smq *smq,
+	uint32_t reset_num)
+{
+	int retval = 0;
+	uint32_t i;
+
+	if (smq->type != PRODUCER)
+		goto bail;
+
+	mutex_lock(smq->lock);
+	if (smq->out->s.index_check_queue_for_reset != reset_num) {
+		smq->out->s.index_check_queue_for_reset = reset_num;
+		for (i = 0; i < smq->num_blocks; i++)
+			(smq->out->sent + i)->index_block = 0xFFFF;
+
+		smq_blockmap_reset(&smq->block_map);
+		smq->out->s.index_sent_write = 0;
+		smq->out->s.index_free_read = 0;
+		retval = 1;
+	}
+	mutex_unlock(smq->lock);
+
+bail:
+	return retval;
+}
+
+static int smq_check_queue_reset(struct smq *p_cons, struct smq *p_prod)
+{
+	int retval = 0;
+	uint32_t reset_num, i;
+
+	if ((p_cons->type != CONSUMER) ||
+		(p_cons->out->s.init != SMQ_MAGIC_PRODUCER) ||
+		(p_cons->hdr->producer_version != SM_VERSION))
+		goto bail;
+
+	reset_num = p_cons->out->s.index_check_queue_for_reset;
+	if (p_cons->in->s.index_check_queue_for_reset_ack != reset_num) {
+		p_cons->in->s.index_check_queue_for_reset_ack = reset_num;
+		for (i = 0; i < p_cons->num_blocks; i++)
+			(p_cons->in->free + i)->index_block = 0xFFFF;
+
+		p_cons->in->s.index_sent_read = 0;
+		p_cons->in->s.index_free_write = 0;
+
+		retval = smq_reset_producer_queue_internal(p_prod, reset_num);
+	}
+
+bail:
+	return retval;
+}
+
+static int check_subsystem_debug_enabled(void *base_addr, int size)
+{
+	int num_blocks;
+	uint8_t *pb_orig;
+	uint8_t *pb;
+	struct smq smq;
+	int err = 0;
+
+	pb = pb_orig = (uint8_t *)base_addr;
+	pb += sizeof(struct smq_hdr);
+	pb = PTR_ALIGN(pb, 8);
+	size -= pb - (uint8_t *)pb_orig;
+	num_blocks = (int)((size - sizeof(struct smq_out_state) -
+		sizeof(struct smq_in_state))/(SM_BLOCKSIZE +
+		sizeof(struct smq_node) * 2));
+	if (num_blocks <= 0) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	pb += num_blocks * SM_BLOCKSIZE;
+	smq.out = (struct smq_out *)pb;
+	pb += sizeof(struct smq_out_state) + (num_blocks *
+		sizeof(struct smq_node));
+	smq.in = (struct smq_in *)pb;
+
+	if (smq.in->s.init != SMQ_MAGIC_CONSUMER) {
+		pr_err("%s, smq in consumer not initialized", __func__);
+		err = -ECOMM;
+	}
+
+bail:
+	return err;
+}
+
+static void smq_dtor(struct smq *smq)
+{
+	if (smq->initialized == SMQ_MAGIC_INIT) {
+		switch (smq->type) {
+		case PRODUCER:
+			smq->out->s.init = 0;
+			smq_blockmap_dtor(&smq->block_map);
+			break;
+		case CONSUMER:
+			smq->in->s.init = 0;
+			break;
+		default:
+		case INVALID:
+			break;
+		}
+
+		smq->initialized = 0;
+	}
+}
+
+/*
+ * The shared memory is used as a circular ring buffer in each direction.
+ * Thus we have a bi-directional shared memory channel between the AP
+ * and a subsystem. We call this SMQ. Each memory channel contains a header,
+ * data and a control mechanism that is used to synchronize read and write
+ * of data between the AP and the remote subsystem.
+ *
+ * Overall SMQ memory view:
+ *
+ *    +------------------------------------------------+
+ *    | SMEM buffer                                    |
+ *    |-----------------------+------------------------|
+ *    |Producer: LA           | Producer: Remote       |
+ *    |Consumer: Remote       |           subsystem    |
+ *    |          subsystem    | Consumer: LA           |
+ *    |                       |                        |
+ *    |               Producer|                Consumer|
+ *    +-----------------------+------------------------+
+ *    |                       |
+ *    |                       |
+ *    |                       +--------------------------------------+
+ *    |                                                              |
+ *    |                                                              |
+ *    v                                                              v
+ *    +--------------------------------------------------------------+
+ *    |   Header  |       Data      |            Control             |
+ *    +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+ *    |           | b | b | b |     | S  |n |n |     | S |n |n |     |
+ *    |  Producer | l | l | l |     | M  |o |o |     | M |o |o |     |
+ *    |    Ver    | o | o | o |     | Q  |d |d |     | Q |d |d |     |
+ *    |-----------| c | c | c | ... |    |e |e | ... |   |e |e | ... |
+ *    |           | k | k | k |     | O  |  |  |     | I |  |  |     |
+ *    |  Consumer |   |   |   |     | u  |0 |1 |     | n |0 |1 |     |
+ *    |    Ver    | 0 | 1 | 2 |     | t  |  |  |     |   |  |  |     |
+ *    +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+ *                                       |           |
+ *                                       +           |
+ *                                                   |
+ *                          +------------------------+
+ *                          |
+ *                          v
+ *                        +----+----+----+----+
+ *                        | SMQ Nodes         |
+ *                        |----|----|----|----|
+ *                 Node # |  0 |  1 |  2 | ...|
+ *                        |----|----|----|----|
+ * Starting Block Index # |  0 |  3 |  8 | ...|
+ *                        |----|----|----|----|
+ *            # of blocks |  3 |  5 |  1 | ...|
+ *                        +----+----+----+----+
+ *
+ * Header: Contains version numbers for software compatibility to ensure
+ * that both producers and consumers on the AP and subsystems know how to
+ * read from and write to the queue.
+ * Both the producer and consumer versions are 1.
+ *     +---------+-------------------+
+ *     | Size    | Field             |
+ *     +---------+-------------------+
+ *     | 1 byte  | Producer Version  |
+ *     +---------+-------------------+
+ *     | 1 byte  | Consumer Version  |
+ *     +---------+-------------------+
+ *
+ * Data: The data portion contains multiple blocks [0..N] of a fixed size.
+ * The block size SM_BLOCKSIZE is fixed to 128 bytes for header version #1.
+ * Payload sent from the debug agent app is split (if necessary) and placed
+ * in these blocks. The first data block is placed at the next 8 byte aligned
+ * address after the header.
+ *
+ * The number of blocks for a given SMEM allocation is derived as follows:
+ *   Number of Blocks = ((Total Size - Alignment - Size of Header
+ *		- Size of SMQIn - Size of SMQOut)/(SM_BLOCKSIZE))
+ *
+ * The producer maintains a private block map of each of these blocks to
+ * determine which of these blocks in the queue is available and which are free.
+ *
+ * Control:
+ * The control portion contains a list of nodes [0..N] where N is number
+ * of available data blocks. Each node identifies the data
+ * block indexes that contain a particular debug message to be transferred,
+ * and the number of blocks it took to hold the contents of the message.
+ *
+ * Each node has the following structure:
+ *     +---------+-------------------+
+ *     | Size    | Field             |
+ *     +---------+-------------------+
+ *     | 2 bytes |Staring Block Index|
+ *     +---------+-------------------+
+ *     | 2 bytes |Number of Blocks   |
+ *     +---------+-------------------+
+ *
+ * The producer and the consumer update different parts of the control channel
+ * (SMQOut / SMQIn) respectively. Each of these control data structures contains
+ * information about the last node that was written / read, and the actual nodes
+ * that were written/read.
+ *
+ * SMQOut Structure (R/W by producer, R by consumer):
+ *     +---------+-------------------+
+ *     | Size    | Field             |
+ *     +---------+-------------------+
+ *     | 4 bytes | Magic Init Number |
+ *     +---------+-------------------+
+ *     | 4 bytes | Reset             |
+ *     +---------+-------------------+
+ *     | 4 bytes | Last Sent Index   |
+ *     +---------+-------------------+
+ *     | 4 bytes | Index Free Read   |
+ *     +---------+-------------------+
+ *
+ * SMQIn Structure (R/W by consumer, R by producer):
+ *     +---------+-------------------+
+ *     | Size    | Field             |
+ *     +---------+-------------------+
+ *     | 4 bytes | Magic Init Number |
+ *     +---------+-------------------+
+ *     | 4 bytes | Reset ACK         |
+ *     +---------+-------------------+
+ *     | 4 bytes | Last Read Index   |
+ *     +---------+-------------------+
+ *     | 4 bytes | Index Free Write  |
+ *     +---------+-------------------+
+ *
+ * Magic Init Number:
+ * Both SMQ Out and SMQ In initialize this field with a predefined magic
+ * number so as to make sure that both the consumer and producer blocks
+ * have fully initialized and have valid data in the shared memory control area.
+ *	Producer Magic #: 0xFF00FF01
+ *	Consumer Magic #: 0xFF00FF02
+ */
+static int smq_ctor(struct smq *smq, void *base_addr, int size,
+	enum smq_type type, struct mutex *lock_ptr)
+{
+	int num_blocks;
+	uint8_t *pb_orig;
+	uint8_t *pb;
+	uint32_t i;
+	int err;
+
+	if (smq->initialized == SMQ_MAGIC_INIT) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	if (!base_addr || !size) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	if (type == PRODUCER)
+		smq->lock = lock_ptr;
+
+	pb_orig = (uint8_t *)base_addr;
+	smq->hdr = (struct smq_hdr *)pb_orig;
+	pb = pb_orig;
+	pb += sizeof(struct smq_hdr);
+	pb = PTR_ALIGN(pb, 8);
+	size -= pb - (uint8_t *)pb_orig;
+	num_blocks = (int)((size - sizeof(struct smq_out_state) -
+		sizeof(struct smq_in_state))/(SM_BLOCKSIZE +
+		sizeof(struct smq_node) * 2));
+	if (num_blocks <= 0) {
+		err = SMQ_ENOMEMORY;
+		goto bail;
+	}
+
+	smq->blocks = pb;
+	smq->num_blocks = num_blocks;
+	pb += num_blocks * SM_BLOCKSIZE;
+	smq->out = (struct smq_out *)pb;
+	pb += sizeof(struct smq_out_state) + (num_blocks *
+		sizeof(struct smq_node));
+	smq->in = (struct smq_in *)pb;
+	smq->type = type;
+	if (type == PRODUCER) {
+		smq->hdr->producer_version = SM_VERSION;
+		for (i = 0; i < smq->num_blocks; i++)
+			(smq->out->sent + i)->index_block = 0xFFFF;
+
+		err = smq_blockmap_ctor(&smq->block_map, smq->num_blocks);
+		if (err != SMQ_SUCCESS)
+			goto bail;
+
+		smq->out->s.index_sent_write = 0;
+		smq->out->s.index_free_read = 0;
+		if (smq->out->s.init == SMQ_MAGIC_PRODUCER) {
+			smq->out->s.index_check_queue_for_reset += 1;
+		} else {
+			smq->out->s.index_check_queue_for_reset = 1;
+			smq->out->s.init = SMQ_MAGIC_PRODUCER;
+		}
+	} else {
+		smq->hdr->consumer_version = SM_VERSION;
+		for (i = 0; i < smq->num_blocks; i++)
+			(smq->in->free + i)->index_block = 0xFFFF;
+
+		smq->in->s.index_sent_read = 0;
+		smq->in->s.index_free_write = 0;
+		if (smq->out->s.init == SMQ_MAGIC_PRODUCER) {
+			smq->in->s.index_check_queue_for_reset_ack =
+				smq->out->s.index_check_queue_for_reset;
+		} else {
+			smq->in->s.index_check_queue_for_reset_ack = 0;
+		}
+
+		smq->in->s.init = SMQ_MAGIC_CONSUMER;
+	}
+	smq->initialized = SMQ_MAGIC_INIT;
+	err = SMQ_SUCCESS;
+
+bail:
+	return err;
+}
+
+static void send_interrupt_to_subsystem(struct rdbg_data *rdbgdata)
+{
+	int offset = rdbgdata->gpio_out_offset;
+	int val = 1 ^ gpio_get_value(rdbgdata->out.gpio_base_id + offset);
+
+	gpio_set_value(rdbgdata->out.gpio_base_id + offset, val);
+	rdbgdata->gpio_out_offset = (offset + 1) % 32;
+
+	dev_dbg(rdbgdata->device, "%s: sent interrupt %d to subsystem",
+		__func__, val);
+}
+
+static irqreturn_t on_interrupt_from(int irq, void *ptr)
+{
+	struct rdbg_data *rdbgdata = (struct rdbg_data *) ptr;
+
+	dev_dbg(rdbgdata->device, "%s: Received interrupt %d from subsystem",
+		__func__, irq);
+
+	complete(&(rdbgdata->work));
+	return IRQ_HANDLED;
+}
+
+static int initialize_smq(struct rdbg_data *rdbgdata)
+{
+	int err = 0;
+	unsigned char *smem_consumer_buffer = rdbgdata->smem_addr;
+
+	smem_consumer_buffer += (rdbgdata->smem_size/2);
+
+	if (smq_ctor(&(rdbgdata->producer_smrb), (void *)(rdbgdata->smem_addr),
+		((rdbgdata->smem_size)/2), PRODUCER, &rdbgdata->write_mutex)) {
+		dev_err(rdbgdata->device, "%s: smq producer allocation failed",
+			__func__);
+		err = -ENOMEM;
+		goto bail;
+	}
+
+	if (smq_ctor(&(rdbgdata->consumer_smrb), (void *)smem_consumer_buffer,
+		((rdbgdata->smem_size)/2), CONSUMER, NULL)) {
+		dev_err(rdbgdata->device, "%s: smq conmsumer allocation failed",
+			__func__);
+		err = -ENOMEM;
+	}
+
+bail:
+	return err;
+
+}
+
+static int rdbg_open(struct inode *inode, struct file *filp)
+{
+	int device_id = -1;
+	struct rdbg_device *device = &g_rdbg_instance;
+	struct rdbg_data *rdbgdata = NULL;
+	int err = 0;
+
+	if (!inode || !device->rdbg_data) {
+		pr_err("Memory not allocated yet");
+		err = -ENODEV;
+		goto bail;
+	}
+
+	device_id = MINOR(inode->i_rdev);
+	rdbgdata = &device->rdbg_data[device_id];
+
+	if (rdbgdata->device_opened) {
+		dev_err(rdbgdata->device, "%s: Device already opened",
+			__func__);
+		err = -EEXIST;
+		goto bail;
+	}
+
+	rdbgdata->smem_size = proc_info[device_id].smem_buffer_size;
+	if (!rdbgdata->smem_size) {
+		dev_err(rdbgdata->device, "%s: smem not initialized", __func__);
+		err = -ENOMEM;
+		goto bail;
+	}
+
+	rdbgdata->smem_addr = smem_find(proc_info[device_id].smem_buffer_addr,
+		rdbgdata->smem_size, 0, SMEM_ANY_HOST_FLAG);
+	if (!rdbgdata->smem_addr) {
+		dev_err(rdbgdata->device, "%s: Could not allocate smem memory",
+			__func__);
+		err = -ENOMEM;
+		goto bail;
+	}
+	dev_dbg(rdbgdata->device, "%s: SMEM address=0x%lx smem_size=%d",
+		__func__, (unsigned long)rdbgdata->smem_addr,
+		(unsigned int)rdbgdata->smem_size);
+
+	if (check_subsystem_debug_enabled(rdbgdata->smem_addr,
+		rdbgdata->smem_size/2)) {
+		dev_err(rdbgdata->device, "%s: Subsystem %s is not debug enabled",
+			__func__, proc_info[device_id].name);
+		err = -ECOMM;
+		goto bail;
+	}
+
+	init_completion(&rdbgdata->work);
+
+	err = request_irq(rdbgdata->in.irq_base_id, on_interrupt_from,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			proc_info[device_id].name,
+			(void *)&device->rdbg_data[device_id]);
+	if (err) {
+		dev_err(rdbgdata->device,
+			"%s: Failed to register interrupt.Err=%d,irqid=%d.",
+			__func__, err, rdbgdata->in.irq_base_id);
+		goto irq_bail;
+	}
+
+	err = enable_irq_wake(rdbgdata->in.irq_base_id);
+	if (err < 0) {
+		dev_dbg(rdbgdata->device, "enable_irq_wake() failed with err=%d",
+			err);
+		err = 0;
+	}
+
+	mutex_init(&rdbgdata->write_mutex);
+
+	err = initialize_smq(rdbgdata);
+	if (err) {
+		dev_err(rdbgdata->device, "Error initializing smq. Err=%d",
+			err);
+		goto smq_bail;
+	}
+
+	rdbgdata->device_opened = 1;
+
+	filp->private_data = (void *)rdbgdata;
+
+	return 0;
+
+smq_bail:
+	smq_dtor(&(rdbgdata->producer_smrb));
+	smq_dtor(&(rdbgdata->consumer_smrb));
+	mutex_destroy(&rdbgdata->write_mutex);
+irq_bail:
+	free_irq(rdbgdata->in.irq_base_id, (void *)
+		&device->rdbg_data[device_id]);
+bail:
+	return err;
+}
+
+static int rdbg_release(struct inode *inode, struct file *filp)
+{
+	int device_id = -1;
+	struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+	struct rdbg_data *rdbgdata = NULL;
+	int err = 0;
+
+	if (!inode || !rdbgdevice->rdbg_data) {
+		pr_err("Memory not allocated yet");
+		err = -ENODEV;
+		goto bail;
+	}
+
+	device_id = MINOR(inode->i_rdev);
+	rdbgdata = &rdbgdevice->rdbg_data[device_id];
+
+	if (rdbgdata->device_opened == 1) {
+		dev_dbg(rdbgdata->device, "%s: Destroying %s.", __func__,
+			proc_info[device_id].name);
+		rdbgdata->device_opened = 0;
+		complete(&(rdbgdata->work));
+		free_irq(rdbgdata->in.irq_base_id, (void *)
+			&rdbgdevice->rdbg_data[device_id]);
+		if (rdbgdevice->rdbg_data[device_id].producer_smrb.initialized)
+			smq_dtor(&(rdbgdevice->rdbg_data[device_id].
+				producer_smrb));
+		if (rdbgdevice->rdbg_data[device_id].consumer_smrb.initialized)
+			smq_dtor(&(rdbgdevice->rdbg_data[device_id].
+				consumer_smrb));
+		mutex_destroy(&rdbgdata->write_mutex);
+	}
+
+	filp->private_data = NULL;
+
+bail:
+	return err;
+}
+
+static ssize_t rdbg_read(struct file *filp, char __user *buf, size_t size,
+	loff_t *offset)
+{
+	int err = 0;
+	struct rdbg_data *rdbgdata = filp->private_data;
+	void *p_sent_buffer = NULL;
+	int nsize = 0;
+	int more = 0;
+
+	if (!rdbgdata) {
+		pr_err("Invalid argument");
+		err = -EINVAL;
+		goto bail;
+	}
+
+	dev_dbg(rdbgdata->device, "%s: In receive", __func__);
+	err = wait_for_completion_interruptible(&(rdbgdata->work));
+	if (err) {
+		dev_err(rdbgdata->device, "%s: Error in wait", __func__);
+		goto bail;
+	}
+
+	smq_check_queue_reset(&(rdbgdata->consumer_smrb),
+		&(rdbgdata->producer_smrb));
+	if (smq_receive(&(rdbgdata->consumer_smrb), &p_sent_buffer,
+			&nsize, &more) != SMQ_SUCCESS) {
+		dev_err(rdbgdata->device, "%s: Error in smq_recv(). Err code = %d",
+			__func__, err);
+		err = -ENODATA;
+		goto bail;
+	}
+
+	size = ((size < nsize) ? size : nsize);
+	err = copy_to_user(buf, p_sent_buffer, size);
+	if (err != 0) {
+		dev_err(rdbgdata->device, "%s: Error in copy_to_user(). Err code = %d",
+			__func__, err);
+		err = -ENODATA;
+		goto bail;
+	}
+
+	smq_free(&(rdbgdata->consumer_smrb), p_sent_buffer);
+	err = size;
+	dev_dbg(rdbgdata->device, "%s: Read data to buffer with address 0x%lx",
+		__func__, (unsigned long) buf);
+
+bail:
+	return err;
+}
+
+static ssize_t rdbg_write(struct file *filp, const char __user *buf,
+	size_t size, loff_t *offset)
+{
+	int err = 0;
+	int num_retries = 0;
+	struct rdbg_data *rdbgdata = filp->private_data;
+
+	if (!rdbgdata) {
+		pr_err("Invalid argument");
+		err = -EINVAL;
+		goto bail;
+	}
+
+	do {
+		err = smq_alloc_send(&(rdbgdata->producer_smrb), buf, size);
+		dev_dbg(rdbgdata->device, "%s, smq_alloc_send returned %d.",
+			__func__, err);
+	} while (err != 0 && num_retries++ < MAX_RETRIES);
+
+	if (err != 0) {
+		err = -ECOMM;
+		goto bail;
+	}
+
+	send_interrupt_to_subsystem(rdbgdata);
+
+	err = size;
+
+bail:
+	return err;
+}
+
+
+static const struct file_operations rdbg_fops = {
+	.open = rdbg_open,
+	.read =  rdbg_read,
+	.write =  rdbg_write,
+	.release = rdbg_release,
+};
+
+static int register_smp2p(char *node_name, struct gpio_info *gpio_info_ptr)
+{
+	struct device_node *node = NULL;
+	int cnt = 0;
+	int id = 0;
+
+	node = of_find_compatible_node(NULL, NULL, node_name);
+	if (node) {
+		cnt = of_gpio_count(node);
+		if (cnt && gpio_info_ptr) {
+			id = of_get_gpio(node, 0);
+			gpio_info_ptr->gpio_base_id = id;
+			gpio_info_ptr->irq_base_id = gpio_to_irq(id);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int __init rdbg_init(void)
+{
+	int err = 0;
+	struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+	int minor = 0;
+	int major = 0;
+	int minor_nodes_created = 0;
+
+	char *rdbg_compatible_string = "qcom,smp2pgpio_client_rdbg_";
+	int max_len = strlen(rdbg_compatible_string) + strlen("xx_out");
+
+	char *node_name = kcalloc(max_len, sizeof(char), GFP_KERNEL);
+
+	if (!node_name) {
+		err = -ENOMEM;
+		goto bail;
+	}
+
+	if (rdbgdevice->num_devices < 1 ||
+		rdbgdevice->num_devices > SMP2P_NUM_PROCS) {
+		pr_err("rgdb: invalid num_devices");
+		err = -EDOM;
+		goto name_bail;
+	}
+
+	rdbgdevice->rdbg_data = kcalloc(rdbgdevice->num_devices,
+		sizeof(struct rdbg_data), GFP_KERNEL);
+	if (!rdbgdevice->rdbg_data) {
+		err = -ENOMEM;
+		goto name_bail;
+	}
+
+	err = alloc_chrdev_region(&rdbgdevice->dev_no, 0,
+		rdbgdevice->num_devices, "rdbgctl");
+	if (err) {
+		pr_err("Error in alloc_chrdev_region.");
+		goto data_bail;
+	}
+	major = MAJOR(rdbgdevice->dev_no);
+
+	cdev_init(&rdbgdevice->cdev, &rdbg_fops);
+	rdbgdevice->cdev.owner = THIS_MODULE;
+	err = cdev_add(&rdbgdevice->cdev, MKDEV(major, 0),
+		rdbgdevice->num_devices);
+	if (err) {
+		pr_err("Error in cdev_add");
+		goto chrdev_bail;
+	}
+
+	rdbgdevice->class = class_create(THIS_MODULE, "rdbg");
+	if (IS_ERR(rdbgdevice->class)) {
+		err = PTR_ERR(rdbgdevice->class);
+		pr_err("Error in class_create");
+		goto cdev_bail;
+	}
+
+	for (minor = 0; minor < rdbgdevice->num_devices; minor++) {
+		if (!proc_info[minor].name)
+			continue;
+
+		if (snprintf(node_name, max_len, "%s%d_in",
+			rdbg_compatible_string, minor) <= 0) {
+			pr_err("Error in snprintf");
+			err = -ENOMEM;
+			goto device_bail;
+		}
+
+		if (register_smp2p(node_name,
+			&rdbgdevice->rdbg_data[minor].in)) {
+			pr_debug("No incoming device tree entry found for %s",
+				proc_info[minor].name);
+			continue;
+		}
+
+		if (snprintf(node_name, max_len, "%s%d_out",
+			rdbg_compatible_string, minor) <= 0) {
+			pr_err("Error in snprintf");
+			err = -ENOMEM;
+			goto device_bail;
+		}
+
+		if (register_smp2p(node_name,
+			&rdbgdevice->rdbg_data[minor].out)) {
+			pr_err("No outgoing device tree entry found for %s",
+				proc_info[minor].name);
+			err = -EINVAL;
+			goto device_bail;
+		}
+
+		rdbgdevice->rdbg_data[minor].device = device_create(
+			rdbgdevice->class, NULL, MKDEV(major, minor),
+			NULL, "%s", proc_info[minor].name);
+		if (IS_ERR(rdbgdevice->rdbg_data[minor].device)) {
+			err = PTR_ERR(rdbgdevice->rdbg_data[minor].device);
+			pr_err("Error in device_create");
+			goto device_bail;
+		}
+		rdbgdevice->rdbg_data[minor].device_initialized = 1;
+		minor_nodes_created++;
+		dev_dbg(rdbgdevice->rdbg_data[minor].device,
+			"%s: created /dev/%s c %d %d'", __func__,
+			proc_info[minor].name, major, minor);
+	}
+
+	if (!minor_nodes_created) {
+		pr_err("No device tree entries found");
+		err = -EINVAL;
+		goto class_bail;
+	}
+
+	goto name_bail;
+
+device_bail:
+	for (--minor; minor >= 0; minor--) {
+		if (rdbgdevice->rdbg_data[minor].device_initialized)
+			device_destroy(rdbgdevice->class,
+				MKDEV(MAJOR(rdbgdevice->dev_no), minor));
+	}
+class_bail:
+	class_destroy(rdbgdevice->class);
+cdev_bail:
+	cdev_del(&rdbgdevice->cdev);
+chrdev_bail:
+	unregister_chrdev_region(rdbgdevice->dev_no, rdbgdevice->num_devices);
+data_bail:
+	kfree(rdbgdevice->rdbg_data);
+name_bail:
+	kfree(node_name);
+bail:
+	return err;
+}
+
+static void __exit rdbg_exit(void)
+{
+	struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+	int minor;
+
+	for (minor = 0; minor < rdbgdevice->num_devices; minor++) {
+		if (rdbgdevice->rdbg_data[minor].device_initialized) {
+			device_destroy(rdbgdevice->class,
+				MKDEV(MAJOR(rdbgdevice->dev_no), minor));
+		}
+	}
+	class_destroy(rdbgdevice->class);
+	cdev_del(&rdbgdevice->cdev);
+	unregister_chrdev_region(rdbgdevice->dev_no, 1);
+	kfree(rdbgdevice->rdbg_data);
+}
+
+module_init(rdbg_init);
+module_exit(rdbg_exit);
+
+MODULE_DESCRIPTION("rdbg module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 3d6754e..bb7c862 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -258,6 +258,9 @@
 {
 	if (flags & CLK_DIVIDER_ROUND_CLOSEST)
 		return abs(rate - now) < abs(rate - best);
+	else if (flags & CLK_DIVIDER_ROUND_KHZ)
+		return (DIV_ROUND_CLOSEST(abs(rate - now), 1000)
+			< DIV_ROUND_CLOSEST(abs(rate - best), 1000));
 
 	return now <= rate && now > best;
 }
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 89201e2..7cdf45b 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -10,6 +10,8 @@
  * Standard functionality for the common clock API.  See Documentation/clk.txt
  */
 
+#define pr_fmt(fmt) "clk: " fmt
+
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clk/clk-conf.h>
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 930e281..6a8c43b 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -9,6 +9,7 @@
 clk-qcom-y += clk-branch.o
 clk-qcom-y += clk-regmap-divider.o
 clk-qcom-y += clk-regmap-mux.o
+clk-qcom-y += clk-regmap-mux-div.o
 clk-qcom-y += reset.o clk-voter.o
 clk-qcom-y += clk-dummy.o clk-debug.o
 clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o gdsc-regulator.o
diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c
index 03d3ab9..1984d4a 100644
--- a/drivers/clk/qcom/camcc-sdm845.c
+++ b/drivers/clk/qcom/camcc-sdm845.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
@@ -345,6 +347,12 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src_sdm845_v2[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 cam_cc_cphy_rx_clk_src = {
 	.cmd_rcgr = 0x9060,
 	.mnd_width = 0,
@@ -429,6 +437,25 @@
 	},
 };
 
+static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = {
+	.cmd_rcgr = 0x5070,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = cam_cc_parent_map_0,
+	.freq_tbl = NULL,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "cam_cc_csi3phytimer_clk_src",
+		.parent_names = cam_cc_parent_names_0,
+		.num_parents = 6,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_ops,
+		VDD_CX_FMAX_MAP3(
+			MIN, 19200000,
+			LOWER, 240000000,
+			LOW, 269333333),
+	},
+};
+
 static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = {
 	F(19200000, P_BI_TCXO, 1, 0, 0),
 	F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0),
@@ -469,6 +496,15 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_cam_cc_fd_core_clk_src_sdm845_v2[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+	F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0),
+	F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0),
+	F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 cam_cc_fd_core_clk_src = {
 	.cmd_rcgr = 0xb0b0,
 	.mnd_width = 0,
@@ -500,6 +536,15 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_cam_cc_icp_clk_src_sdm845_v2[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+	F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0),
+	F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0),
+	F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 cam_cc_icp_clk_src = {
 	.cmd_rcgr = 0xb088,
 	.mnd_width = 0,
@@ -755,6 +800,16 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_cam_cc_lrme_clk_src_sdm845_v2[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0),
+	F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0),
+	F(269333333, P_CAM_CC_PLL1_OUT_EVEN, 3, 0, 0),
+	F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0),
+	F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 cam_cc_lrme_clk_src = {
 	.cmd_rcgr = 0xb0f8,
 	.mnd_width = 0,
@@ -1073,6 +1128,24 @@
 	},
 };
 
+static struct clk_branch cam_cc_csi3phytimer_clk = {
+	.halt_reg = 0x5088,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x5088,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "cam_cc_csi3phytimer_clk",
+			.parent_names = (const char *[]){
+				"cam_cc_csi3phytimer_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
 static struct clk_branch cam_cc_csiphy0_clk = {
 	.halt_reg = 0x5020,
 	.halt_check = BRANCH_HALT,
@@ -1130,6 +1203,25 @@
 	},
 };
 
+static struct clk_branch cam_cc_csiphy3_clk = {
+	.halt_reg = 0x508c,
+	.halt_check = BRANCH_HALT,
+	.aggr_sibling_rates = true,
+	.clkr = {
+		.enable_reg = 0x508c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "cam_cc_csiphy3_clk",
+			.parent_names = (const char *[]){
+				"cam_cc_cphy_rx_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
 static struct clk_branch cam_cc_fd_core_clk = {
 	.halt_reg = 0xb0c8,
 	.halt_check = BRANCH_HALT,
@@ -1763,9 +1855,12 @@
 	[CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr,
 	[CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr,
 	[CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr,
+	[CAM_CC_CSI3PHYTIMER_CLK] = NULL,
+	[CAM_CC_CSI3PHYTIMER_CLK_SRC] = NULL,
 	[CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr,
 	[CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr,
 	[CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr,
+	[CAM_CC_CSIPHY3_CLK] = NULL,
 	[CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
 	[CAM_CC_FD_CORE_CLK] = &cam_cc_fd_core_clk.clkr,
 	[CAM_CC_FD_CORE_CLK_SRC] = &cam_cc_fd_core_clk_src.clkr,
@@ -1833,22 +1928,11 @@
 };
 
 static const struct qcom_reset_map cam_cc_sdm845_resets[] = {
-	[TITAN_CAM_CC_BPS_BCR] = { 0x6000 },
-	[TITAN_CAM_CC_CAMNOC_BCR] = { 0xb120 },
 	[TITAN_CAM_CC_CCI_BCR] = { 0xb0d4 },
 	[TITAN_CAM_CC_CPAS_BCR] = { 0xb118 },
 	[TITAN_CAM_CC_CSI0PHY_BCR] = { 0x5000 },
 	[TITAN_CAM_CC_CSI1PHY_BCR] = { 0x5024 },
 	[TITAN_CAM_CC_CSI2PHY_BCR] = { 0x5048 },
-	[TITAN_CAM_CC_FD_BCR] = { 0xb0ac },
-	[TITAN_CAM_CC_ICP_BCR] = { 0xb074 },
-	[TITAN_CAM_CC_IFE_0_BCR] = { 0x9000 },
-	[TITAN_CAM_CC_IFE_1_BCR] = { 0xa000 },
-	[TITAN_CAM_CC_IFE_LITE_BCR] = { 0xb000 },
-	[TITAN_CAM_CC_IPE_0_BCR] = { 0x7000 },
-	[TITAN_CAM_CC_IPE_1_BCR] = { 0x8000 },
-	[TITAN_CAM_CC_JPEG_BCR] = { 0xb048 },
-	[TITAN_CAM_CC_LRME_BCR] = { 0xb0f4 },
 	[TITAN_CAM_CC_MCLK0_BCR] = { 0x4000 },
 	[TITAN_CAM_CC_MCLK1_BCR] = { 0x4020 },
 	[TITAN_CAM_CC_MCLK2_BCR] = { 0x4040 },
@@ -1874,10 +1958,49 @@
 
 static const struct of_device_id cam_cc_sdm845_match_table[] = {
 	{ .compatible = "qcom,cam_cc-sdm845" },
+	{ .compatible = "qcom,cam_cc-sdm845-v2" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, cam_cc_sdm845_match_table);
 
+static void cam_cc_sdm845_fixup_sdm845v2(void)
+{
+	cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK] =
+		&cam_cc_csi3phytimer_clk.clkr;
+	cam_cc_sdm845_clocks[CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr;
+	cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK_SRC] =
+		&cam_cc_csi3phytimer_clk_src.clkr;
+	cam_cc_cphy_rx_clk_src.freq_tbl = ftbl_cam_cc_cphy_rx_clk_src_sdm845_v2;
+	cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 384000000;
+	cam_cc_fd_core_clk_src.freq_tbl = ftbl_cam_cc_fd_core_clk_src_sdm845_v2;
+	cam_cc_fd_core_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 384000000;
+	cam_cc_icp_clk_src.freq_tbl = ftbl_cam_cc_icp_clk_src_sdm845_v2;
+	cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 384000000;
+	cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 600000000;
+	cam_cc_ipe_0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000;
+	cam_cc_ipe_1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000;
+	cam_cc_lrme_clk_src.freq_tbl = ftbl_cam_cc_lrme_clk_src_sdm845_v2;
+	cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 269333333;
+	cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 320000000;
+	cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 400000000;
+	cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 80000000;
+}
+
+static int cam_cc_sdm845_fixup(struct platform_device *pdev)
+{
+	const char *compat = NULL;
+	int compatlen = 0;
+
+	compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+	if (!compat || (compatlen <= 0))
+		return -EINVAL;
+
+	if (!strcmp(compat, "qcom,cam_cc-sdm845-v2"))
+		cam_cc_sdm845_fixup_sdm845v2();
+
+	return 0;
+}
+
 static int cam_cc_sdm845_probe(struct platform_device *pdev)
 {
 	struct regmap *regmap;
@@ -1905,6 +2028,10 @@
 		return PTR_ERR(vdd_mx.regulator[0]);
 	}
 
+	ret = cam_cc_sdm845_fixup(pdev);
+	if (ret)
+		return ret;
+
 	clk_fabia_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config);
 	clk_fabia_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config);
 	clk_fabia_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config);
@@ -1932,7 +2059,7 @@
 {
 	return platform_driver_register(&cam_cc_sdm845_driver);
 }
-core_initcall(cam_cc_sdm845_init);
+subsys_initcall(cam_cc_sdm845_init);
 
 static void __exit cam_cc_sdm845_exit(void)
 {
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index fd3617b..e7d3ee4 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/clk-provider.h>
@@ -100,7 +102,7 @@
 		udelay(1);
 	}
 
-	WARN(1, "%s failed to %s!\n", name, action);
+	WARN(1, "clk: %s failed to %s!\n", name, action);
 	return -ETIMEDOUT;
 }
 
@@ -635,7 +637,7 @@
 	udelay(1);
 	regmap_read(pll->clkr.regmap, off + PLL_MODE, &regval);
 	if (!(regval & FABIA_PLL_ACK_LATCH)) {
-		WARN(1, "PLL latch failed. Output may be unstable!\n");
+		WARN(1, "clk: PLL latch failed. Output may be unstable!\n");
 		return -EINVAL;
 	}
 
@@ -813,7 +815,7 @@
 		return -EINVAL;
 
 	return divider_round_rate(hw, rate, prate, pll->post_div_table,
-					pll->width, CLK_DIVIDER_ROUND_CLOSEST);
+					pll->width, CLK_DIVIDER_ROUND_KHZ);
 }
 
 static int clk_generic_pll_postdiv_set_rate(struct clk_hw *hw,
diff --git a/drivers/clk/qcom/clk-aop-qmp.c b/drivers/clk/qcom/clk-aop-qmp.c
index f698a55..f6aeb19 100644
--- a/drivers/clk/qcom/clk-aop-qmp.c
+++ b/drivers/clk/qcom/clk-aop-qmp.c
@@ -11,7 +11,7 @@
  * GNU General Public License for more details.
  */
 
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
 
 #include <linux/clk-provider.h>
 #include <linux/clk.h>
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index 5c4ddcc..3ca8e1c 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
@@ -97,7 +99,7 @@
 				return 0;
 			udelay(1);
 		}
-		WARN(1, "%s status stuck at 'o%s'", name,
+		WARN(1, "clk: %s status stuck at 'o%s'", name,
 				enabling ? "ff" : "n");
 		return -EBUSY;
 	}
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index 2902f87..78e0ae5 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -11,7 +11,7 @@
  * GNU General Public License for more details.
  */
 
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
 
 #include <linux/debugfs.h>
 #include <linux/kernel.h>
@@ -3401,7 +3401,7 @@
 		goto provider_err;
 	}
 	WARN(clk_prepare_enable(l3_clk.hw.clk),
-		     "Failed to enable clock for L3\n");
+		     "clk: Failed to enable clock for L3\n");
 	udelay(300);
 
 	/* Configure default rate to lowest frequency */
@@ -3455,7 +3455,7 @@
 {
 	return platform_driver_register(&clk_cpu_osm_driver);
 }
-arch_initcall(clk_cpu_osm_init);
+subsys_initcall(clk_cpu_osm_init);
 
 static void __exit clk_cpu_osm_exit(void)
 {
diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c
index fcc2493..d366ad4 100644
--- a/drivers/clk/qcom/clk-debug.c
+++ b/drivers/clk/qcom/clk-debug.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/clk.h>
 #include <linux/export.h>
 #include <linux/module.h>
@@ -141,7 +143,7 @@
 	for (i = 0; i < num_parents; i++) {
 		if (!strcmp(meas->parent[i].parents,
 					clk_hw_get_name(hw_clk))) {
-			pr_debug("%s: clock parent - %s, index %d\n", __func__,
+			pr_debug("clock parent - %s, index %d\n",
 					meas->parent[i].parents, i);
 			return i;
 		}
diff --git a/drivers/clk/qcom/clk-dummy.c b/drivers/clk/qcom/clk-dummy.c
index 3435999..07991b1 100644
--- a/drivers/clk/qcom/clk-dummy.c
+++ b/drivers/clk/qcom/clk-dummy.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -68,14 +70,14 @@
 static int dummy_reset_assert(struct reset_controller_dev *rcdev,
 				unsigned long id)
 {
-	pr_debug("%s\n", __func__);
+	pr_debug("\n");
 	return 0;
 }
 
 static int dummy_reset_deassert(struct reset_controller_dev *rcdev,
 				unsigned long id)
 {
-	pr_debug("%s\n", __func__);
+	pr_debug("\n");
 	return 0;
 }
 
diff --git a/drivers/clk/qcom/clk-qpnp-div.c b/drivers/clk/qcom/clk-qpnp-div.c
index 1c3eacb..2ee1c18 100644
--- a/drivers/clk/qcom/clk-qpnp-div.c
+++ b/drivers/clk/qcom/clk-qpnp-div.c
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 6bdea53..b63c3c3 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
@@ -99,8 +101,8 @@
 			return i;
 
 err:
-	pr_debug("%s: Clock %s has invalid parent, using default.\n",
-		 __func__, clk_hw_get_name(hw));
+	pr_debug("Clock %s has invalid parent, using default.\n",
+		 clk_hw_get_name(hw));
 	return 0;
 }
 
@@ -126,7 +128,7 @@
 		udelay(1);
 	}
 
-	WARN(1, "%s: rcg didn't update its configuration.", name);
+	WARN(1, "clk: %s: rcg didn't update its configuration.", name);
 	return 0;
 }
 
@@ -164,7 +166,7 @@
 		udelay(1);
 	}
 
-	WARN(1, "%s: rcg didn't turn on.", clk_hw_get_name(hw));
+	WARN(1, "clk: %s: rcg didn't turn on.", clk_hw_get_name(hw));
 	return ret;
 }
 
@@ -1220,8 +1222,8 @@
 		if (cfg == rcg->parent_map[i].cfg)
 			return i;
 err:
-	pr_debug("%s: Clock %s has invalid parent, using default.\n",
-		 __func__, clk_hw_get_name(hw));
+	pr_debug("Clock %s has invalid parent, using default.\n",
+		 clk_hw_get_name(hw));
 	return 0;
 }
 
diff --git a/drivers/clk/qcom/clk-regmap-mux-div.c b/drivers/clk/qcom/clk-regmap-mux-div.c
new file mode 100644
index 0000000..942a68e
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-mux-div.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+
+#include "clk-regmap-mux-div.h"
+
+#define CMD_RCGR			0x0
+#define CMD_RCGR_UPDATE			BIT(0)
+#define CMD_RCGR_DIRTY_CFG		BIT(4)
+#define CMD_RCGR_ROOT_OFF		BIT(31)
+#define CFG_RCGR			0x4
+
+#define to_clk_regmap_mux_div(_hw) \
+	container_of(to_clk_regmap(_hw), struct clk_regmap_mux_div, clkr)
+
+int __mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div)
+{
+	int ret, count;
+	u32 val, mask;
+	const char *name = clk_hw_get_name(&md->clkr.hw);
+
+	val = (div << md->hid_shift) | (src << md->src_shift);
+	mask = ((BIT(md->hid_width) - 1) << md->hid_shift) |
+	       ((BIT(md->src_width) - 1) << md->src_shift);
+
+	ret = regmap_update_bits(md->clkr.regmap, CFG_RCGR + md->reg_offset,
+				 mask, val);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(md->clkr.regmap, CMD_RCGR + md->reg_offset,
+				 CMD_RCGR_UPDATE, CMD_RCGR_UPDATE);
+	if (ret)
+		return ret;
+
+	/* Wait for update to take effect */
+	for (count = 500; count > 0; count--) {
+		ret = regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset,
+				  &val);
+		if (ret)
+			return ret;
+		if (!(val & CMD_RCGR_UPDATE))
+			return 0;
+		udelay(1);
+	}
+
+	pr_err("%s: RCG did not update its configuration", name);
+	return -EBUSY;
+}
+
+int mux_div_get_src_div(struct clk_regmap_mux_div *md, u32 *src,
+				  u32 *div)
+{
+	int ret = 0;
+	u32 val, __div, __src;
+	const char *name = clk_hw_get_name(&md->clkr.hw);
+
+	ret = regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset, &val);
+	if (ret)
+		return ret;
+
+	if (val & CMD_RCGR_DIRTY_CFG) {
+		pr_err("%s: RCG configuration is pending\n", name);
+		return -EBUSY;
+	}
+
+	ret = regmap_read(md->clkr.regmap, CFG_RCGR + md->reg_offset, &val);
+	if (ret)
+		return ret;
+
+	__src = (val >> md->src_shift);
+	__src &= BIT(md->src_width) - 1;
+	*src = __src;
+
+	__div = (val >> md->hid_shift);
+	__div &= BIT(md->hid_width) - 1;
+	*div = __div;
+
+	return ret;
+}
+
+static int mux_div_enable(struct clk_hw *hw)
+{
+	struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
+
+	return __mux_div_set_src_div(md, md->src, md->div);
+}
+
+static inline bool is_better_rate(unsigned long req, unsigned long best,
+				  unsigned long new)
+{
+	return (req <= new && new < best) || (best < req && best < new);
+}
+
+static int mux_div_determine_rate(struct clk_hw *hw,
+				  struct clk_rate_request *req)
+{
+	struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
+	unsigned int i, div, max_div;
+	unsigned long actual_rate, best_rate = 0;
+	unsigned long req_rate = req->rate;
+
+	for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+		struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
+		unsigned long parent_rate = clk_hw_get_rate(parent);
+
+		max_div = BIT(md->hid_width) - 1;
+		for (div = 1; div < max_div; div++) {
+			parent_rate = mult_frac(req_rate, div, 2);
+			parent_rate = clk_hw_round_rate(parent, parent_rate);
+			actual_rate = mult_frac(parent_rate, 2, div);
+
+			if (is_better_rate(req_rate, best_rate, actual_rate)) {
+				best_rate = actual_rate;
+				req->rate = best_rate;
+				req->best_parent_rate = parent_rate;
+				req->best_parent_hw = parent;
+			}
+
+			if (actual_rate < req_rate || best_rate <= req_rate)
+				break;
+		}
+	}
+
+	if (!best_rate)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int __mux_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+					 unsigned long prate, u32 src)
+{
+	struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
+	int ret;
+	u32 div, max_div, best_src = 0, best_div = 0;
+	unsigned int i;
+	unsigned long actual_rate, best_rate = 0;
+
+	for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+		struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
+		unsigned long parent_rate = clk_hw_get_rate(parent);
+
+		max_div = BIT(md->hid_width) - 1;
+		for (div = 1; div < max_div; div++) {
+			parent_rate = mult_frac(rate, div, 2);
+			parent_rate = clk_hw_round_rate(parent, parent_rate);
+			actual_rate = mult_frac(parent_rate, 2, div);
+
+			if (is_better_rate(rate, best_rate, actual_rate)) {
+				best_rate = actual_rate;
+				best_src = md->parent_map[i].cfg;
+				best_div = div - 1;
+			}
+
+			if (actual_rate < rate || best_rate <= rate)
+				break;
+		}
+	}
+
+	ret = __mux_div_set_src_div(md, best_src, best_div);
+	if (!ret) {
+		md->div = best_div;
+		md->src = best_src;
+	}
+
+	return ret;
+}
+
+static u8 mux_div_get_parent(struct clk_hw *hw)
+{
+	struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
+	const char *name = clk_hw_get_name(hw);
+	u32 i, div, src = 0;
+
+	mux_div_get_src_div(md, &src, &div);
+
+	for (i = 0; i < clk_hw_get_num_parents(hw); i++)
+		if (src == md->parent_map[i].cfg)
+			return i;
+
+	pr_err("%s: Can't find parent with src %d\n", name, src);
+	return 0;
+}
+
+static int mux_div_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
+
+	return __mux_div_set_src_div(md, md->parent_map[index].cfg, md->div);
+}
+
+static int mux_div_set_rate(struct clk_hw *hw,
+			    unsigned long rate, unsigned long prate)
+{
+	struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
+
+	return __mux_div_set_rate_and_parent(hw, rate, prate, md->src);
+}
+
+static int mux_div_set_rate_and_parent(struct clk_hw *hw,  unsigned long rate,
+				       unsigned long prate, u8 index)
+{
+	struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
+
+	return __mux_div_set_rate_and_parent(hw, rate, prate,
+					     md->parent_map[index].cfg);
+}
+
+static unsigned long mux_div_recalc_rate(struct clk_hw *hw, unsigned long prate)
+{
+	struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
+	u32 div, src;
+	int i, num_parents = clk_hw_get_num_parents(hw);
+	const char *name = clk_hw_get_name(hw);
+
+	mux_div_get_src_div(md, &src, &div);
+	for (i = 0; i < num_parents; i++)
+		if (src == md->parent_map[i].cfg) {
+			struct clk_hw *p = clk_hw_get_parent_by_index(hw, i);
+			unsigned long parent_rate = clk_hw_get_rate(p);
+
+			return mult_frac(parent_rate, 2, div + 1);
+		}
+
+	pr_err("%s: Can't find parent %d\n", name, src);
+	return 0;
+}
+
+static void mux_div_disable(struct clk_hw *hw)
+{
+	struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
+
+	__mux_div_set_src_div(md, md->safe_src, md->safe_div);
+}
+
+const struct clk_ops clk_regmap_mux_div_ops = {
+	.enable = mux_div_enable,
+	.disable = mux_div_disable,
+	.get_parent = mux_div_get_parent,
+	.set_parent = mux_div_set_parent,
+	.set_rate = mux_div_set_rate,
+	.set_rate_and_parent = mux_div_set_rate_and_parent,
+	.determine_rate = mux_div_determine_rate,
+	.recalc_rate = mux_div_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_mux_div_ops);
diff --git a/drivers/clk/qcom/clk-regmap-mux-div.h b/drivers/clk/qcom/clk-regmap-mux-div.h
new file mode 100644
index 0000000..63a696a
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-mux-div.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_CLK_REGMAP_MUX_DIV_H__
+#define __QCOM_CLK_REGMAP_MUX_DIV_H__
+
+#include <linux/clk-provider.h>
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+
+/**
+ * struct mux_div_clk - combined mux/divider clock
+ * @reg_offset: offset of the mux/divider register
+ * @hid_width:	number of bits in half integer divider
+ * @hid_shift:	lowest bit of hid value field
+ * @src_width:	number of bits in source select
+ * @src_shift:	lowest bit of source select field
+ * @div:	the divider raw configuration value
+ * @src:	the mux index which will be used if the clock is enabled
+ * @safe_src:	the safe source mux value we switch to, while the main PLL is
+ *		reconfigured
+ * @safe_div:	the safe divider value that we set, while the main PLL is
+ *		reconfigured
+ * @safe_freq:	When switching rates from A to B, the mux div clock will
+ *		instead switch from A -> safe_freq -> B. This allows the
+ *		mux_div clock to change rates while enabled, even if this
+ *		behavior is not supported by the parent clocks.
+ *		If changing the rate of parent A also causes the rate of
+ *		parent B to change, then safe_freq must be defined.
+ *		safe_freq is expected to have a source clock which is always
+ *		on and runs at only one rate.
+ * @parent_map:	pointer to parent_map struct
+ * @clkr:	handle between common and hardware-specific interfaces
+ */
+
+struct clk_regmap_mux_div {
+	u32				reg_offset;
+	u32				hid_width;
+	u32				hid_shift;
+	u32				src_width;
+	u32				src_shift;
+	u32				div;
+	u32				src;
+	u32				safe_src;
+	u32				safe_div;
+	unsigned long			safe_freq;
+	const struct parent_map		*parent_map;
+	struct clk_regmap		clkr;
+};
+
+extern const struct clk_ops clk_regmap_mux_div_ops;
+int __mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div);
+int mux_div_get_src_div(struct clk_regmap_mux_div *md, u32 *src, u32 *div);
+
+#endif
diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c
index 5e11485..e1cda90 100644
--- a/drivers/clk/qcom/clk-rpmh.c
+++ b/drivers/clk/qcom/clk-rpmh.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
@@ -243,7 +245,7 @@
 
 	if (ret) {
 		c->state = c->valid_state_mask;
-		WARN(1, "%s failed to disable\n", c->res_name);
+		WARN(1, "clk: %s failed to disable\n", c->res_name);
 	}
 
 out:
@@ -449,7 +451,7 @@
 {
 	return platform_driver_register(&clk_rpmh_driver);
 }
-core_initcall(clk_rpmh_init);
+subsys_initcall(clk_rpmh_init);
 
 static void __exit clk_rpmh_exit(void)
 {
diff --git a/drivers/clk/qcom/clk-voter.c b/drivers/clk/qcom/clk-voter.c
index b0c7e4a..1a8f0ca 100644
--- a/drivers/clk/qcom/clk-voter.c
+++ b/drivers/clk/qcom/clk-voter.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 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,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/clk.h>
 
 #include "clk-voter.h"
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index b2ff04a..d426691 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/export.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
@@ -181,7 +183,7 @@
 	unsigned int idx = clkspec->args[0];
 
 	if (idx >= cc->num_rclks) {
-		pr_err("%s: invalid index %u\n", __func__, idx);
+		pr_err("invalid index %u\n", idx);
 		return ERR_PTR(-EINVAL);
 	}
 
diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c
index 9ffa555..10b71ff 100644
--- a/drivers/clk/qcom/debugcc-sdm845.c
+++ b/drivers/clk/qcom/debugcc-sdm845.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
@@ -45,6 +47,7 @@
 	"cam_cc_csiphy0_clk",
 	"cam_cc_csiphy1_clk",
 	"cam_cc_csiphy2_clk",
+	"cam_cc_csiphy3_clk",
 	"cam_cc_fd_core_clk",
 	"cam_cc_fd_core_uar_clk",
 	"cam_cc_icp_apb_clk",
@@ -307,6 +310,8 @@
 			0x8, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
 		{ "cam_cc_csiphy2_clk", 0x46, 4, CAM_CC,
 			0xA, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+		{ "cam_cc_csiphy3_clk", 0x46, 4, CAM_CC,
+			0x36, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
 		{ "cam_cc_fd_core_clk", 0x46, 4, CAM_CC,
 			0x28, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
 		{ "cam_cc_fd_core_uar_clk", 0x46, 4, CAM_CC,
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index d3a28e6..53bfe77 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
@@ -126,13 +128,18 @@
 };
 
 static struct pll_vco fabia_vco[] = {
-	{ 250000000, 2000000000, 0 },
+	{ 249600000, 2000000000, 0 },
 	{ 125000000, 1000000000, 1 },
 };
 
 static const struct pll_config disp_cc_pll0_config = {
+	.l = 0x15,
+	.frac = 0x7c00,
+};
+
+static const struct pll_config disp_cc_pll0_config_v2 = {
 	.l = 0x2c,
-	.frac = 0xcaab,
+	.frac = 0xcaaa,
 };
 
 static struct clk_alpha_pll disp_cc_pll0 = {
@@ -365,6 +372,19 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src_sdm845_v2[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0),
+	F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+	F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
+	F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+	F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+	F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
+	F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
 	.cmd_rcgr = 0x2088,
 	.mnd_width = 0,
@@ -434,6 +454,15 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src_sdm845_v2[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
+	F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+	F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
+	F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 disp_cc_mdss_rot_clk_src = {
 	.cmd_rcgr = 0x20a0,
 	.mnd_width = 0,
@@ -963,8 +992,6 @@
 };
 
 static const struct qcom_reset_map disp_cc_sdm845_resets[] = {
-	[DISP_CC_MDSS_CORE_BCR] = { 0x2000 },
-	[DISP_CC_MDSS_GCC_CLOCKS_BCR] = { 0x4000 },
 	[DISP_CC_MDSS_RSCC_BCR] = { 0x5000 },
 };
 
@@ -986,10 +1013,73 @@
 
 static const struct of_device_id disp_cc_sdm845_match_table[] = {
 	{ .compatible = "qcom,dispcc-sdm845" },
+	{ .compatible = "qcom,dispcc-sdm845-v2" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, disp_cc_sdm845_match_table);
 
+static void disp_cc_sdm845_fixup_sdm845v2(struct regmap *regmap)
+{
+	clk_fabia_pll_configure(&disp_cc_pll0, regmap,
+					&disp_cc_pll0_config_v2);
+	disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+		180000000;
+	disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
+		275000000;
+	disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
+		358000000;
+	disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+		180000000;
+	disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
+		275000000;
+	disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
+		358000000;
+	disp_cc_mdss_dp_pixel1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
+		337500000;
+	disp_cc_mdss_dp_pixel_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
+		337500000;
+	disp_cc_mdss_mdp_clk_src.freq_tbl =
+		ftbl_disp_cc_mdss_mdp_clk_src_sdm845_v2;
+	disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+		171428571;
+	disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
+		344000000;
+	disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		430000000;
+	disp_cc_mdss_pclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+		280000000;
+	disp_cc_mdss_pclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
+		430000000;
+	disp_cc_mdss_pclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+		280000000;
+	disp_cc_mdss_pclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
+		430000000;
+	disp_cc_mdss_rot_clk_src.freq_tbl =
+		ftbl_disp_cc_mdss_rot_clk_src_sdm845_v2;
+	disp_cc_mdss_rot_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+		171428571;
+	disp_cc_mdss_rot_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
+		344000000;
+	disp_cc_mdss_rot_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		430000000;
+}
+
+static int disp_cc_sdm845_fixup(struct platform_device *pdev,
+						struct regmap *regmap)
+{
+	const char *compat = NULL;
+	int compatlen = 0;
+
+	compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+	if (!compat || (compatlen <= 0))
+		return -EINVAL;
+
+	if (!strcmp(compat, "qcom,dispcc-sdm845-v2"))
+		disp_cc_sdm845_fixup_sdm845v2(regmap);
+
+	return 0;
+}
+
 static int disp_cc_sdm845_probe(struct platform_device *pdev)
 {
 	struct regmap *regmap;
@@ -1014,6 +1104,10 @@
 	/* Enable clock gating for DSI and MDP clocks */
 	regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x7f0, 0x7f0);
 
+	ret = disp_cc_sdm845_fixup(pdev, regmap);
+	if (ret)
+		return ret;
+
 	ret = qcom_cc_really_probe(pdev, &disp_cc_sdm845_desc, regmap);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register Display CC clocks\n");
@@ -1036,7 +1130,7 @@
 {
 	return platform_driver_register(&disp_cc_sdm845_driver);
 }
-core_initcall(disp_cc_sdm845_init);
+subsys_initcall(disp_cc_sdm845_init);
 
 static void __exit disp_cc_sdm845_exit(void)
 {
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 4e0711d..25f9d62 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
@@ -466,6 +468,25 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2[] = {
+	F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625),
+	F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625),
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(29491200, P_GPLL0_OUT_EVEN, 1, 1536, 15625),
+	F(32000000, P_GPLL0_OUT_EVEN, 1, 8, 75),
+	F(48000000, P_GPLL0_OUT_EVEN, 1, 4, 25),
+	F(64000000, P_GPLL0_OUT_EVEN, 1, 16, 75),
+	F(80000000, P_GPLL0_OUT_EVEN, 1, 4, 15),
+	F(96000000, P_GPLL0_OUT_EVEN, 1, 8, 25),
+	F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0),
+	F(102400000, P_GPLL0_OUT_EVEN, 1, 128, 375),
+	F(112000000, P_GPLL0_OUT_EVEN, 1, 28, 75),
+	F(117964800, P_GPLL0_OUT_EVEN, 1, 6144, 15625),
+	F(120000000, P_GPLL0_OUT_EVEN, 2.5, 0, 0),
+	F(128000000, P_GPLL0_OUT_MAIN, 1, 16, 75),
+	{ }
+};
+
 static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
 	.cmd_rcgr = 0x17034,
 	.mnd_width = 16,
@@ -879,6 +900,15 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2[] = {
+	F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
+	F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
+	F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+	F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 gcc_ufs_card_axi_clk_src = {
 	.cmd_rcgr = 0x7501c,
 	.mnd_width = 8,
@@ -1210,6 +1240,8 @@
 static struct clk_branch gcc_aggre_ufs_card_axi_clk = {
 	.halt_reg = 0x82028,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x82028,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x82028,
 		.enable_mask = BIT(0),
@@ -1245,6 +1277,8 @@
 static struct clk_branch gcc_aggre_ufs_phy_axi_clk = {
 	.halt_reg = 0x82024,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x82024,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x82024,
 		.enable_mask = BIT(0),
@@ -1316,6 +1350,8 @@
 static struct clk_branch gcc_boot_rom_ahb_clk = {
 	.halt_reg = 0x38004,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x38004,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x52004,
 		.enable_mask = BIT(10),
@@ -1329,6 +1365,8 @@
 static struct clk_branch gcc_camera_ahb_clk = {
 	.halt_reg = 0xb008,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0xb008,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0xb008,
 		.enable_mask = BIT(0),
@@ -1368,6 +1406,8 @@
 static struct clk_branch gcc_ce1_ahb_clk = {
 	.halt_reg = 0x4100c,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x4100c,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x52004,
 		.enable_mask = BIT(3),
@@ -1474,6 +1514,8 @@
 static struct clk_branch gcc_cpuss_gnoc_clk = {
 	.halt_reg = 0x48004,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x48004,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x52004,
 		.enable_mask = BIT(22),
@@ -1518,6 +1560,8 @@
 static struct clk_branch gcc_disp_ahb_clk = {
 	.halt_reg = 0xb00c,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0xb00c,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0xb00c,
 		.enable_mask = BIT(0),
@@ -1645,6 +1689,8 @@
 static struct clk_branch gcc_gpu_cfg_ahb_clk = {
 	.halt_reg = 0x71004,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x71004,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x71004,
 		.enable_mask = BIT(0),
@@ -1744,6 +1790,8 @@
 static struct clk_branch gcc_mss_cfg_ahb_clk = {
 	.halt_reg = 0x8a000,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x8a000,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x8a000,
 		.enable_mask = BIT(0),
@@ -1769,6 +1817,8 @@
 static struct clk_branch gcc_mss_mfab_axis_clk = {
 	.halt_reg = 0x8a004,
 	.halt_check = BRANCH_VOTED,
+	.hwcg_reg = 0x8a004,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x8a004,
 		.enable_mask = BIT(0),
@@ -1826,6 +1876,8 @@
 static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
 	.halt_reg = 0x6b018,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x6b018,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x5200c,
 		.enable_mask = BIT(2),
@@ -1877,6 +1929,8 @@
 static struct clk_branch gcc_pcie_0_slv_axi_clk = {
 	.halt_reg = 0x6b010,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x6b010,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x5200c,
 		.enable_mask = BIT(0),
@@ -1921,6 +1975,8 @@
 static struct clk_branch gcc_pcie_1_cfg_ahb_clk = {
 	.halt_reg = 0x8d018,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x8d018,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x52004,
 		.enable_mask = BIT(28),
@@ -1972,6 +2028,8 @@
 static struct clk_branch gcc_pcie_1_slv_axi_clk = {
 	.halt_reg = 0x8d010,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x8d010,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x52004,
 		.enable_mask = BIT(26),
@@ -2052,6 +2110,8 @@
 static struct clk_branch gcc_pdm_ahb_clk = {
 	.halt_reg = 0x33004,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x33004,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x33004,
 		.enable_mask = BIT(0),
@@ -2078,6 +2138,8 @@
 static struct clk_branch gcc_prng_ahb_clk = {
 	.halt_reg = 0x34004,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x34004,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x52004,
 		.enable_mask = BIT(13),
@@ -2091,6 +2153,8 @@
 static struct clk_branch gcc_qmip_camera_ahb_clk = {
 	.halt_reg = 0xb014,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0xb014,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0xb014,
 		.enable_mask = BIT(0),
@@ -2104,6 +2168,8 @@
 static struct clk_branch gcc_qmip_disp_ahb_clk = {
 	.halt_reg = 0xb018,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0xb018,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0xb018,
 		.enable_mask = BIT(0),
@@ -2117,6 +2183,8 @@
 static struct clk_branch gcc_qmip_video_ahb_clk = {
 	.halt_reg = 0xb010,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0xb010,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0xb010,
 		.enable_mask = BIT(0),
@@ -2431,6 +2499,8 @@
 static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = {
 	.halt_reg = 0x17008,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x17008,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x5200c,
 		.enable_mask = BIT(7),
@@ -2457,6 +2527,8 @@
 static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = {
 	.halt_reg = 0x18010,
 	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x18010,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x5200c,
 		.enable_mask = BIT(21),
@@ -2594,6 +2666,8 @@
 static struct clk_branch gcc_ufs_card_ahb_clk = {
 	.halt_reg = 0x75010,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x75010,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x75010,
 		.enable_mask = BIT(0),
@@ -2607,6 +2681,8 @@
 static struct clk_branch gcc_ufs_card_axi_clk = {
 	.halt_reg = 0x7500c,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x7500c,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x7500c,
 		.enable_mask = BIT(0),
@@ -2655,6 +2731,8 @@
 static struct clk_branch gcc_ufs_card_ice_core_clk = {
 	.halt_reg = 0x75058,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x75058,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x75058,
 		.enable_mask = BIT(0),
@@ -2690,6 +2768,8 @@
 static struct clk_branch gcc_ufs_card_phy_aux_clk = {
 	.halt_reg = 0x7508c,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x7508c,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x7508c,
 		.enable_mask = BIT(0),
@@ -2761,6 +2841,8 @@
 static struct clk_branch gcc_ufs_card_unipro_core_clk = {
 	.halt_reg = 0x75054,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x75054,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x75054,
 		.enable_mask = BIT(0),
@@ -2809,6 +2891,8 @@
 static struct clk_branch gcc_ufs_phy_ahb_clk = {
 	.halt_reg = 0x77010,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x77010,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x77010,
 		.enable_mask = BIT(0),
@@ -2822,6 +2906,8 @@
 static struct clk_branch gcc_ufs_phy_axi_clk = {
 	.halt_reg = 0x7700c,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x7700c,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x7700c,
 		.enable_mask = BIT(0),
@@ -2857,6 +2943,8 @@
 static struct clk_branch gcc_ufs_phy_ice_core_clk = {
 	.halt_reg = 0x77058,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x77058,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x77058,
 		.enable_mask = BIT(0),
@@ -2892,6 +2980,8 @@
 static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
 	.halt_reg = 0x7708c,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x7708c,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x7708c,
 		.enable_mask = BIT(0),
@@ -2963,6 +3053,8 @@
 static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
 	.halt_reg = 0x77054,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x77054,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x77054,
 		.enable_mask = BIT(0),
@@ -3218,6 +3310,8 @@
 static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
 	.halt_reg = 0x6a004,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0x6a004,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0x6a004,
 		.enable_mask = BIT(0),
@@ -3231,6 +3325,8 @@
 static struct clk_branch gcc_video_ahb_clk = {
 	.halt_reg = 0xb004,
 	.halt_check = BRANCH_HALT,
+	.hwcg_reg = 0xb004,
+	.hwcg_bit = 1,
 	.clkr = {
 		.enable_reg = 0xb004,
 		.enable_mask = BIT(0),
@@ -3470,7 +3566,6 @@
 };
 
 static const struct qcom_reset_map gcc_sdm845_resets[] = {
-	[GCC_GPU_BCR] = { 0x71000 },
 	[GCC_MMSS_BCR] = { 0xb000 },
 	[GCC_PCIE_0_BCR] = { 0x6b000 },
 	[GCC_PCIE_1_BCR] = { 0x8d000 },
@@ -3542,10 +3637,132 @@
 
 static const struct of_device_id gcc_sdm845_match_table[] = {
 	{ .compatible = "qcom,gcc-sdm845" },
+	{ .compatible = "qcom,gcc-sdm845-v2" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table);
 
+static void gcc_sdm845_fixup_sdm845v2(void)
+{
+	gcc_qupv3_wrap0_s0_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap0_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap0_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap0_s1_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap0_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap0_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap0_s2_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap0_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap0_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap0_s3_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap0_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap0_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap0_s4_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap0_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap0_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap0_s5_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap0_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap0_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap0_s6_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap0_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap0_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap0_s7_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap0_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap0_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap1_s0_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap1_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap1_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap1_s1_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap1_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap1_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap1_s2_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap1_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap1_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap1_s3_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap1_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap1_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap1_s4_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap1_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap1_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap1_s5_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap1_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap1_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap1_s6_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap1_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap1_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_qupv3_wrap1_s7_clk_src.freq_tbl =
+		ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2;
+	gcc_qupv3_wrap1_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] =
+		50000000;
+	gcc_qupv3_wrap1_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+		128000000;
+	gcc_ufs_card_axi_clk_src.freq_tbl =
+		ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2;
+	gcc_ufs_card_axi_clk_src.clkr.hw.init->rate_max[VDD_CX_HIGH] =
+		240000000;
+	gcc_ufs_phy_axi_clk_src.freq_tbl =
+		ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2;
+}
+
+static int gcc_sdm845_fixup(struct platform_device *pdev)
+{
+	const char *compat = NULL;
+	int compatlen = 0;
+
+	compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+	if (!compat || (compatlen <= 0))
+		return -EINVAL;
+
+	if (!strcmp(compat, "qcom,gcc-sdm845-v2"))
+		gcc_sdm845_fixup_sdm845v2();
+
+	return 0;
+}
+
 static int gcc_sdm845_probe(struct platform_device *pdev)
 {
 	struct clk *clk;
@@ -3580,6 +3797,10 @@
 		return PTR_ERR(vdd_cx_ao.regulator[0]);
 	}
 
+	ret = gcc_sdm845_fixup(pdev);
+	if (ret)
+		return ret;
+
 	/* Register the dummy measurement clocks */
 	for (i = 0; i < ARRAY_SIZE(gcc_sdm845_hws); i++) {
 		clk = devm_clk_register(&pdev->dev, gcc_sdm845_hws[i]);
@@ -3635,7 +3856,7 @@
 {
 	return platform_driver_register(&gcc_sdm845_driver);
 }
-core_initcall(gcc_sdm845_init);
+subsys_initcall(gcc_sdm845_init);
 
 static void __exit gcc_sdm845_exit(void)
 {
diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c
index 90c76e6..0899138 100644
--- a/drivers/clk/qcom/gdsc-regulator.c
+++ b/drivers/clk/qcom/gdsc-regulator.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "gdsc: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/io.h>
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index f2fa577..b2f6a3c 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
@@ -35,7 +37,6 @@
 #include "vdd-level-sdm845.h"
 
 #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
-#define F_SLEW(f, s, h, m, n, sf) { (f), (s), (2 * (h) - 1), (m), (n), (sf) }
 
 static int vdd_gx_corner[] = {
 	RPMH_REGULATOR_LEVEL_OFF,		/* VDD_GX_NONE */
@@ -65,6 +66,7 @@
 	P_GPU_CC_PLL1_OUT_EVEN,
 	P_GPU_CC_PLL1_OUT_MAIN,
 	P_GPU_CC_PLL1_OUT_ODD,
+	P_CRC_DIV,
 };
 
 static const struct parent_map gpu_cc_parent_map_0[] = {
@@ -105,8 +107,28 @@
 	"core_bi_pll_test_se",
 };
 
+static const struct parent_map gpu_cc_parent_map_2[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_CRC_DIV,  1 },
+	{ P_GPU_CC_PLL0_OUT_ODD, 2 },
+	{ P_GPU_CC_PLL1_OUT_EVEN, 3 },
+	{ P_GPU_CC_PLL1_OUT_ODD, 4 },
+	{ P_GPLL0_OUT_MAIN, 5 },
+	{ P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpu_cc_parent_names_2[] = {
+	"bi_tcxo",
+	"crc_div",
+	"gpu_cc_pll0_out_odd",
+	"gpu_cc_pll1_out_even",
+	"gpu_cc_pll1_out_odd",
+	"gcc_gpu_gpll0_clk_src",
+	"core_bi_pll_test_se",
+};
+
 static struct pll_vco fabia_vco[] = {
-	{ 250000000, 2000000000, 0 },
+	{ 249600000, 2000000000, 0 },
 	{ 125000000, 1000000000, 1 },
 };
 
@@ -184,12 +206,27 @@
 	},
 };
 
+static struct clk_fixed_factor crc_div = {
+	.mult = 1,
+	.div = 1,
+	.hw.init = &(struct clk_init_data){
+		.name = "crc_div",
+		.parent_names = (const char *[]){ "gpu_cc_pll0_out_even" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
 static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = {
-	F_SLEW(147000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0,  294000000),
-	F_SLEW(210000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0,  420000000),
-	F_SLEW(338000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0,  676000000),
-	F_SLEW(425000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0,  850000000),
-	F_SLEW(600000000, P_GPU_CC_PLL0_OUT_EVEN,  1, 0, 0, 1200000000),
+	F(147000000, P_CRC_DIV,  1, 0, 0),
+	F(210000000, P_CRC_DIV,  1, 0, 0),
+	F(280000000, P_CRC_DIV,  1, 0, 0),
+	F(338000000, P_CRC_DIV,  1, 0, 0),
+	F(425000000, P_CRC_DIV,  1, 0, 0),
+	F(487000000, P_CRC_DIV,  1, 0, 0),
+	F(548000000, P_CRC_DIV,  1, 0, 0),
+	F(600000000, P_CRC_DIV,  1, 0, 0),
 	{ }
 };
 
@@ -197,12 +234,12 @@
 	.cmd_rcgr = 0x101c,
 	.mnd_width = 0,
 	.hid_width = 5,
-	.parent_map = gpu_cc_parent_map_1,
+	.parent_map = gpu_cc_parent_map_2,
 	.freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src,
 	.flags = FORCE_ENABLE_RCG,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gpu_cc_gx_gfx3d_clk_src",
-		.parent_names = gpu_cc_parent_names_1,
+		.parent_names = gpu_cc_parent_names_2,
 		.num_parents = 7,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops =  &clk_rcg2_ops,
@@ -530,16 +567,23 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL) {
-		dev_err(&pdev->dev, "Failed to get resources for clock_gfxcc.\n");
+		dev_err(&pdev->dev, "Failed to get resources for clock_gfxcc\n");
 		return -EINVAL;
 	}
 
 	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
 	if (IS_ERR(base)) {
-		dev_err(&pdev->dev, "Failed to ioremap the GFX CC base.\n");
+		dev_err(&pdev->dev, "Failed to ioremap the GFX CC base\n");
 		return PTR_ERR(base);
 	}
 
+	/* Register clock fixed factor for CRC divide. */
+	ret = devm_clk_hw_register(&pdev->dev, &crc_div.hw);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register hardware clock\n");
+		return ret;
+	}
+
 	regmap = devm_regmap_init_mmio(&pdev->dev, base,
 				gpu_cc_gfx_sdm845_desc.config);
 	if (IS_ERR(regmap)) {
@@ -575,7 +619,7 @@
 		return ret;
 	}
 
-	dev_info(&pdev->dev, "Registered GFX CC clocks.\n");
+	dev_info(&pdev->dev, "Registered GFX CC clocks\n");
 
 	return ret;
 }
@@ -592,7 +636,7 @@
 {
 	return platform_driver_register(&gpu_cc_gfx_sdm845_driver);
 }
-arch_initcall(gpu_cc_gfx_sdm845_init);
+subsys_initcall(gpu_cc_gfx_sdm845_init);
 
 static void __exit gpu_cc_gfx_sdm845_exit(void)
 {
@@ -624,7 +668,7 @@
 		return ret;
 	}
 
-	dev_info(&pdev->dev, "Registered GPU CC clocks.\n");
+	dev_info(&pdev->dev, "Registered GPU CC clocks\n");
 
 	return ret;
 }
@@ -641,7 +685,7 @@
 {
 	return platform_driver_register(&gpu_cc_sdm845_driver);
 }
-core_initcall(gpu_cc_sdm845_init);
+subsys_initcall(gpu_cc_sdm845_init);
 
 static void __exit gpu_cc_sdm845_exit(void)
 {
diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c
index 4eb8a04..ba4e591 100644
--- a/drivers/clk/qcom/videocc-sdm845.c
+++ b/drivers/clk/qcom/videocc-sdm845.c
@@ -11,6 +11,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
@@ -63,7 +65,7 @@
 };
 
 static struct pll_vco fabia_vco[] = {
-	{ 250000000, 2000000000, 0 },
+	{ 249600000, 2000000000, 0 },
 	{ 125000000, 1000000000, 1 },
 };
 
@@ -102,6 +104,16 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_video_cc_venus_clk_src_sdm845_v2[] = {
+	F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0),
+	F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0),
+	F(330000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
+	F(404000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
+	F(444000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
+	F(533000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 video_cc_venus_clk_src = {
 	.cmd_rcgr = 0x7f0,
 	.mnd_width = 0,
@@ -299,13 +311,6 @@
 	[VIDEO_PLL0] = &video_pll0.clkr,
 };
 
-static const struct qcom_reset_map video_cc_sdm845_resets[] = {
-	[VIDEO_CC_INTERFACE_BCR] = { 0x8f0 },
-	[VIDEO_CC_VCODEC0_BCR] = { 0x870 },
-	[VIDEO_CC_VCODEC1_BCR] = { 0x8b0 },
-	[VIDEO_CC_VENUS_BCR] = { 0x810 },
-};
-
 static const struct regmap_config video_cc_sdm845_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
@@ -318,16 +323,38 @@
 	.config = &video_cc_sdm845_regmap_config,
 	.clks = video_cc_sdm845_clocks,
 	.num_clks = ARRAY_SIZE(video_cc_sdm845_clocks),
-	.resets = video_cc_sdm845_resets,
-	.num_resets = ARRAY_SIZE(video_cc_sdm845_resets),
 };
 
 static const struct of_device_id video_cc_sdm845_match_table[] = {
 	{ .compatible = "qcom,video_cc-sdm845" },
+	{ .compatible = "qcom,video_cc-sdm845-v2" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, video_cc_sdm845_match_table);
 
+static void video_cc_sdm845_fixup_sdm845v2(void)
+{
+	video_cc_venus_clk_src.freq_tbl = ftbl_video_cc_venus_clk_src_sdm845_v2;
+	video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 330000000;
+	video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
+		404000000;
+}
+
+static int video_cc_sdm845_fixup(struct platform_device *pdev)
+{
+	const char *compat = NULL;
+	int compatlen = 0;
+
+	compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+	if (!compat || (compatlen <= 0))
+		return -EINVAL;
+
+	if (!strcmp(compat, "qcom,video_cc-sdm845-v2"))
+		video_cc_sdm845_fixup_sdm845v2();
+
+	return 0;
+}
+
 static int video_cc_sdm845_probe(struct platform_device *pdev)
 {
 	struct regmap *regmap;
@@ -347,6 +374,10 @@
 		return PTR_ERR(vdd_cx.regulator[0]);
 	}
 
+	ret = video_cc_sdm845_fixup(pdev);
+	if (ret)
+		return ret;
+
 	clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config);
 
 	ret = qcom_cc_really_probe(pdev, &video_cc_sdm845_desc, regmap);
@@ -371,7 +402,7 @@
 {
 	return platform_driver_register(&video_cc_sdm845_driver);
 }
-core_initcall(video_cc_sdm845_init);
+subsys_initcall(video_cc_sdm845_init);
 
 static void __exit video_cc_sdm845_exit(void)
 {
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index b315236..062d297 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2550,6 +2550,7 @@
 	if (!(cpufreq_driver->flags & CPUFREQ_STICKY) &&
 	    list_empty(&cpufreq_policy_list)) {
 		/* if all ->init() calls failed, unregister */
+		ret = -ENODEV;
 		pr_debug("%s: No CPU initialized for driver %s\n", __func__,
 			 driver_data->name);
 		goto err_if_unreg;
diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c
index 2404e17..39e0484 100644
--- a/drivers/cpuidle/lpm-levels-of.c
+++ b/drivers/cpuidle/lpm-levels-of.c
@@ -21,10 +21,10 @@
 #include <linux/moduleparam.h>
 #include "lpm-levels.h"
 
-bool use_psci;
 enum lpm_type {
 	IDLE = 0,
 	SUSPEND,
+	LATENCY,
 	LPM_TYPE_NR
 };
 
@@ -36,6 +36,7 @@
 static const struct lpm_type_str lpm_types[] = {
 	{IDLE, "idle_enabled"},
 	{SUSPEND, "suspend_enabled"},
+	{LATENCY, "latency_us"},
 };
 
 static DEFINE_PER_CPU(uint32_t *, max_residency);
@@ -67,6 +68,9 @@
 	else if (!strcmp(attr->attr.name, lpm_types[SUSPEND].str))
 		avail = container_of(attr, struct lpm_level_avail,
 					suspend_enabled_attr);
+	else if (!strcmp(attr->attr.name, lpm_types[LATENCY].str))
+		avail = container_of(attr, struct lpm_level_avail,
+					latency_attr);
 
 	return avail;
 }
@@ -163,6 +167,28 @@
 {
 	return per_cpu(min_residency, cpu);
 }
+
+static ssize_t lpm_latency_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	int ret = 0;
+	struct kernel_param kp;
+	struct lpm_level_avail *avail = get_avail_ptr(kobj, attr);
+
+	if (!avail)
+		pr_info("Error\n");
+
+	kp.arg = &avail->latency_us;
+
+	ret = param_get_uint(buf, &kp);
+	if (ret > 0) {
+		strlcat(buf, "\n", PAGE_SIZE);
+		ret++;
+	}
+
+	return ret;
+}
+
 ssize_t lpm_enable_show(struct kobject *kobj, struct kobj_attribute *attr,
 				char *buf)
 {
@@ -239,9 +265,16 @@
 	avail->suspend_enabled_attr.show = lpm_enable_show;
 	avail->suspend_enabled_attr.store = lpm_enable_store;
 
+	sysfs_attr_init(&avail->latency_attr.attr);
+	avail->latency_attr.attr.name = lpm_types[LATENCY].str;
+	avail->latency_attr.attr.mode = 0444;
+	avail->latency_attr.show = lpm_latency_show;
+	avail->latency_attr.store = NULL;
+
 	attr[0] = &avail->idle_enabled_attr.attr;
 	attr[1] = &avail->suspend_enabled_attr.attr;
-	attr[2] = NULL;
+	attr[2] = &avail->latency_attr.attr;
+	attr[3] = NULL;
 	attr_group->attrs = attr;
 
 	ret = sysfs_create_group(kobj, attr_group);
@@ -272,6 +305,7 @@
 	struct lpm_level_avail *level_list = NULL;
 	char cpu_name[20] = {0};
 	int ret = 0;
+	struct list_head *pos;
 
 	cpu_kobj = devm_kzalloc(&lpm_pdev->dev, sizeof(*cpu_kobj) *
 			cpumask_weight(&p->child_cpus), GFP_KERNEL);
@@ -279,37 +313,45 @@
 		return -ENOMEM;
 
 	cpu_idx = 0;
-	for_each_cpu(cpu, &p->child_cpus) {
-		snprintf(cpu_name, sizeof(cpu_name), "cpu%d", cpu);
-		cpu_kobj[cpu_idx] = kobject_create_and_add(cpu_name, parent);
-		if (!cpu_kobj[cpu_idx]) {
-			ret = -ENOMEM;
-			goto release_kobj;
-		}
+	list_for_each(pos, &p->cpu) {
+		struct lpm_cpu *lpm_cpu = list_entry(pos, struct lpm_cpu, list);
 
-		level_list = devm_kzalloc(&lpm_pdev->dev,
-				p->cpu->nlevels * sizeof(*level_list),
-				GFP_KERNEL);
-		if (!level_list) {
-			ret = -ENOMEM;
-			goto release_kobj;
-		}
-
-		/*
-		 * Skip enable/disable for WFI. cpuidle expects WFI to be
-		 * available at all times.
-		 */
-		for (i = 1; i < p->cpu->nlevels; i++) {
-
-			ret = create_lvl_avail_nodes(p->cpu->levels[i].name,
-					cpu_kobj[cpu_idx], &level_list[i],
-					(void *)p->cpu, cpu, true);
-			if (ret)
+		for_each_cpu(cpu, &lpm_cpu->related_cpus) {
+			snprintf(cpu_name, sizeof(cpu_name), "cpu%d", cpu);
+			cpu_kobj[cpu_idx] = kobject_create_and_add(cpu_name,
+					parent);
+			if (!cpu_kobj[cpu_idx]) {
+				ret = -ENOMEM;
 				goto release_kobj;
-		}
+			}
 
-		cpu_level_available[cpu] = level_list;
-		cpu_idx++;
+			level_list = devm_kzalloc(&lpm_pdev->dev,
+					lpm_cpu->nlevels * sizeof(*level_list),
+					GFP_KERNEL);
+			if (!level_list) {
+				ret = -ENOMEM;
+				goto release_kobj;
+			}
+
+			/*
+			 * Skip enable/disable for WFI. cpuidle expects WFI to
+			 * be available at all times.
+			 */
+			for (i = 1; i < lpm_cpu->nlevels; i++) {
+				level_list[i].latency_us =
+					p->levels[i].pwr.latency_us;
+				ret = create_lvl_avail_nodes(
+						lpm_cpu->levels[i].name,
+						cpu_kobj[cpu_idx],
+						&level_list[i],
+						(void *)lpm_cpu, cpu, true);
+				if (ret)
+					goto release_kobj;
+			}
+
+			cpu_level_available[cpu] = level_list;
+			cpu_idx++;
+		}
 	}
 
 	return ret;
@@ -336,6 +378,7 @@
 		return -ENOMEM;
 
 	for (i = 0; i < p->nlevels; i++) {
+		p->levels[i].available.latency_us = p->levels[i].pwr.latency_us;
 		ret = create_lvl_avail_nodes(p->levels[i].level_name,
 				cluster_kobj, &p->levels[i].available,
 				(void *)p, 0, false);
@@ -349,7 +392,7 @@
 			return ret;
 	}
 
-	if (p->cpu) {
+	if (!list_empty(&p->cpu)) {
 		ret = create_cpu_lvl_nodes(p, cluster_kobj);
 		if (ret)
 			return ret;
@@ -395,30 +438,27 @@
 		return ret;
 	}
 
-	if (use_psci) {
-		key = "qcom,psci-mode-shift";
-		ret = of_property_read_u32(node, key,
-				&c->psci_mode_shift);
-		if (ret) {
-			pr_err("%s(): Failed to read param: %s\n",
-							__func__, key);
-			return ret;
-		}
+	key = "qcom,psci-mode-shift";
+	ret = of_property_read_u32(node, key,
+			&c->psci_mode_shift);
+	if (ret) {
+		pr_err("%s(): Failed to read param: %s\n",
+				__func__, key);
+		return ret;
+	}
 
-		key = "qcom,psci-mode-mask";
-		ret = of_property_read_u32(node, key,
-				&c->psci_mode_mask);
-		if (ret) {
-			pr_err("%s(): Failed to read param: %s\n",
-							__func__, key);
-			return ret;
-		}
+	key = "qcom,psci-mode-mask";
+	ret = of_property_read_u32(node, key,
+			&c->psci_mode_mask);
+	if (ret) {
+		pr_err("%s(): Failed to read param: %s\n",
+				__func__, key);
+		return ret;
+	}
 
-		/* Set ndevice to 1 as default */
-		c->ndevices = 1;
+	/* Set ndevice to 1 as default */
+	c->ndevices = 1;
 
-	} else
-		pr_warn("Target supports PSCI only\n");
 	return 0;
 }
 
@@ -467,22 +507,14 @@
 	if (ret)
 		goto failed;
 
-	if (use_psci) {
-		char *k = "qcom,psci-mode";
+	key = "qcom,psci-mode";
 
-		ret = of_property_read_u32(node, k, &level->psci_id);
-		if (ret)
-			goto failed;
-
-		level->is_reset = of_property_read_bool(node, "qcom,is-reset");
-	} else
-		pr_warn("Build supports PSCI targets only");
-
-	key = "label";
-	ret = of_property_read_string(node, key, &level->level_name);
+	ret = of_property_read_u32(node, key, &level->psci_id);
 	if (ret)
 		goto failed;
 
+	level->is_reset = of_property_read_bool(node, "qcom,is-reset");
+
 	if (cluster->nlevels != cluster->default_level) {
 		key = "min child idx";
 		ret = of_property_read_u32(node, "qcom,min-child-idx",
@@ -495,10 +527,6 @@
 	}
 
 	level->notify_rpm = of_property_read_bool(node, "qcom,notify-rpm");
-	level->disable_dynamic_routing = of_property_read_bool(node,
-					"qcom,disable-dynamic-int-routing");
-	level->last_core_only = of_property_read_bool(node,
-					"qcom,last-core-only");
 
 	key = "parse_power_params";
 	ret = parse_power_params(node, &level->pwr);
@@ -533,20 +561,16 @@
 		return ret;
 	}
 
-	if (use_psci) {
-		key = "qcom,psci-cpu-mode";
+	key = "qcom,psci-cpu-mode";
+	ret = of_property_read_u32(n, key, &l->psci_id);
+	if (ret) {
+		pr_err("Failed reading %s on device %s\n", key,
+				n->name);
+		return ret;
+	}
+	key = "qcom,hyp-psci";
 
-		ret = of_property_read_u32(n, key, &l->psci_id);
-		if (ret) {
-			pr_err("Failed reading %s on device %s\n", key,
-					n->name);
-			return ret;
-		}
-		key = "qcom,hyp-psci";
-
-		l->hyp_psci = of_property_read_bool(n, key);
-	} else
-		pr_warn("Build supports PSCI targets only");
+	l->hyp_psci = of_property_read_bool(n, key);
 	return 0;
 
 }
@@ -603,51 +627,26 @@
 				next_pwr->time_overhead_us : residency;
 }
 
-static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c)
+static int parse_cpu(struct device_node *node, struct lpm_cpu *cpu)
 {
+
 	struct device_node *n;
-	int ret = -ENOMEM;
-	int i, j;
-	char *key;
-
-	c->cpu = devm_kzalloc(&lpm_pdev->dev, sizeof(*c->cpu), GFP_KERNEL);
-	if (!c->cpu)
-		return ret;
-
-	c->cpu->parent = c;
-	if (use_psci) {
-
-		key = "qcom,psci-mode-shift";
-
-		ret = of_property_read_u32(node, key, &c->cpu->psci_mode_shift);
-		if (ret) {
-			pr_err("Failed reading %s on device %s\n", key,
-					node->name);
-			return ret;
-		}
-		key = "qcom,psci-mode-mask";
-
-		ret = of_property_read_u32(node, key, &c->cpu->psci_mode_mask);
-		if (ret) {
-			pr_err("Failed reading %s on device %s\n", key,
-					node->name);
-			return ret;
-		}
-	}
+	int ret, i, j;
+	const char *key;
 	for_each_child_of_node(node, n) {
-		struct lpm_cpu_level *l = &c->cpu->levels[c->cpu->nlevels];
+		struct lpm_cpu_level *l = &cpu->levels[cpu->nlevels];
 
-		c->cpu->nlevels++;
+		cpu->nlevels++;
 
 		ret = parse_cpu_mode(n, l);
 		if (ret < 0) {
 			pr_info("Failed %s\n", l->name);
-			goto failed;
+			return ret;
 		}
 
 		ret = parse_power_params(n, &l->pwr);
 		if (ret)
-			goto failed;
+			return ret;
 
 		key = "qcom,use-broadcast-timer";
 		l->use_bc_timer = of_property_read_bool(n, key);
@@ -662,32 +661,83 @@
 		if (ret == -EINVAL)
 			l->reset_level = LPM_RESET_LVL_NONE;
 		else if (ret)
-			goto failed;
+			return ret;
 	}
-	for (i = 0; i < c->cpu->nlevels; i++) {
-		for (j = 0; j < c->cpu->nlevels; j++) {
+	for (i = 0; i < cpu->nlevels; i++) {
+		for (j = 0; j < cpu->nlevels; j++) {
 			if (i >= j) {
-				c->cpu->levels[i].pwr.residencies[j] = 0;
+				cpu->levels[i].pwr.residencies[j] = 0;
 				continue;
 			}
 
-			c->cpu->levels[i].pwr.residencies[j] =
-				calculate_residency(&c->cpu->levels[i].pwr,
-					&c->cpu->levels[j].pwr);
+			cpu->levels[i].pwr.residencies[j] =
+				calculate_residency(&cpu->levels[i].pwr,
+						&cpu->levels[j].pwr);
 
 			pr_err("%s: idx %d %u\n", __func__, j,
-					c->cpu->levels[i].pwr.residencies[j]);
+					cpu->levels[i].pwr.residencies[j]);
 		}
 	}
+	for_each_cpu(i, &cpu->related_cpus) {
+		per_cpu(max_residency, i) = devm_kzalloc(&lpm_pdev->dev,
+				sizeof(uint32_t) * cpu->nlevels,
+				GFP_KERNEL);
+		if (!per_cpu(max_residency, i))
+			return -ENOMEM;
+		per_cpu(min_residency, i) = devm_kzalloc(
+				&lpm_pdev->dev,
+				sizeof(uint32_t) * cpu->nlevels,
+				GFP_KERNEL);
+		if (!per_cpu(min_residency, i))
+			return -ENOMEM;
+		set_optimum_cpu_residency(cpu, i, true);
+	}
 
 	return 0;
-failed:
-	for (i = 0; i < c->cpu->nlevels; i++) {
-		kfree(c->cpu->levels[i].name);
-		c->cpu->levels[i].name = NULL;
+}
+
+static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c)
+{
+	int ret = -ENOMEM, i;
+	char *key;
+	struct lpm_cpu *cpu;
+
+	cpu = devm_kzalloc(&lpm_pdev->dev, sizeof(*cpu), GFP_KERNEL);
+	if (!cpu)
+		return ret;
+
+	if (get_cpumask_for_node(node, &cpu->related_cpus))
+		return -EINVAL;
+
+	cpu->parent = c;
+
+	key = "qcom,psci-mode-shift";
+	ret = of_property_read_u32(node, key, &cpu->psci_mode_shift);
+	if (ret) {
+		pr_err("Failed reading %s on device %s\n", key,
+				node->name);
+		return ret;
 	}
-	kfree(c->cpu);
-	c->cpu = NULL;
+	key = "qcom,psci-mode-mask";
+
+	ret = of_property_read_u32(node, key, &cpu->psci_mode_mask);
+	if (ret) {
+		pr_err("Failed reading %s on device %s\n", key,
+				node->name);
+		return ret;
+	}
+
+	if (parse_cpu(node, cpu))
+		goto failed;
+	cpumask_or(&c->child_cpus, &c->child_cpus, &cpu->related_cpus);
+	list_add(&cpu->list, &c->cpu);
+	return 0;
+failed:
+	for (i = 0; i < cpu->nlevels; i++) {
+		kfree(cpu->levels[i].name);
+		cpu->levels[i].name = NULL;
+	}
+	kfree(cpu);
 	pr_err("%s(): Failed with error code:%d\n", __func__, ret);
 	return ret;
 }
@@ -695,6 +745,7 @@
 void free_cluster_node(struct lpm_cluster *cluster)
 {
 	struct list_head *list;
+	struct lpm_cpu *cpu, *n;
 	int i;
 
 	list_for_each(list, &cluster->child) {
@@ -705,22 +756,21 @@
 		free_cluster_node(n);
 	};
 
-	if (cluster->cpu) {
-		for (i = 0; i < cluster->cpu->nlevels; i++) {
-			kfree(cluster->cpu->levels[i].name);
-			cluster->cpu->levels[i].name = NULL;
+	list_for_each_entry_safe(cpu, n, &cluster->cpu, list) {
+		struct lpm_cpu *cpu = list_entry(list, typeof(*cpu), list);
+
+		for (i = 0; i < cpu->nlevels; i++) {
+			kfree(cpu->levels[i].name);
+			cpu->levels[i].name = NULL;
 		}
+		list_del(list);
 	}
 	for (i = 0; i < cluster->nlevels; i++) {
 		kfree(cluster->levels[i].mode);
 		cluster->levels[i].mode = NULL;
 	}
-	kfree(cluster->cpu);
 	kfree(cluster->name);
-	kfree(cluster->lpm_dev);
-	cluster->cpu = NULL;
 	cluster->name = NULL;
-	cluster->lpm_dev = NULL;
 	cluster->ndevices = 0;
 }
 
@@ -749,6 +799,7 @@
 		goto failed_parse_params;
 
 	INIT_LIST_HEAD(&c->child);
+	INIT_LIST_HEAD(&c->cpu);
 	c->parent = parent;
 	spin_lock_init(&c->sync_lock);
 	c->min_child_level = NR_LPM_LEVELS;
@@ -759,7 +810,6 @@
 			continue;
 		key = "qcom,pm-cluster-level";
 		if (!of_node_cmp(n->name, key)) {
-			WARN_ON(!use_psci && c->no_saw_devices);
 			if (parse_cluster_level(n, c))
 				goto failed_parse_cluster;
 			continue;
@@ -769,7 +819,6 @@
 		if (!of_node_cmp(n->name, key)) {
 			struct lpm_cluster *child;
 
-			WARN_ON(!use_psci && c->no_saw_devices);
 			child = parse_cluster(n, c);
 			if (!child)
 				goto failed_parse_cluster;
@@ -783,34 +832,11 @@
 
 		key = "qcom,pm-cpu";
 		if (!of_node_cmp(n->name, key)) {
-			/*
-			 * Parse the the cpu node only if a pm-cpu node
-			 * is available, though the mask is defined @ the
-			 * cluster level
-			 */
-			if (get_cpumask_for_node(node, &c->child_cpus))
-				goto failed_parse_cluster;
-
 			if (parse_cpu_levels(n, c))
 				goto failed_parse_cluster;
 
 			c->aff_level = 1;
 
-			for_each_cpu(i, &c->child_cpus) {
-				per_cpu(max_residency, i) = devm_kzalloc(
-					&lpm_pdev->dev,
-					sizeof(uint32_t) * c->cpu->nlevels,
-					GFP_KERNEL);
-				if (!per_cpu(max_residency, i))
-					return ERR_PTR(-ENOMEM);
-				per_cpu(min_residency, i) = devm_kzalloc(
-					&lpm_pdev->dev,
-					sizeof(uint32_t) * c->cpu->nlevels,
-					GFP_KERNEL);
-				if (!per_cpu(min_residency, i))
-					return ERR_PTR(-ENOMEM);
-				set_optimum_cpu_residency(c->cpu, i, true);
-			}
 		}
 	}
 
@@ -847,8 +873,6 @@
 {
 	struct device_node *top = NULL;
 
-	use_psci = of_property_read_bool(pdev->dev.of_node, "qcom,use-psci");
-
 	top = of_find_node_by_name(pdev->dev.of_node, "qcom,pm-cluster");
 	if (!top) {
 		pr_err("Failed to find root node\n");
@@ -862,6 +886,7 @@
 void cluster_dt_walkthrough(struct lpm_cluster *cluster)
 {
 	struct list_head *list;
+	struct lpm_cpu *cpu;
 	int i, j;
 	static int id;
 	char str[10] = {0};
@@ -882,12 +907,12 @@
 					&cluster->name[j], &l->mode[i]);
 	}
 
-	if (cluster->cpu) {
+	list_for_each_entry(cpu, &cluster->cpu, list) {
 		pr_info("%d\n", __LINE__);
-		for (j = 0; j < cluster->cpu->nlevels; j++)
+		for (j = 0; j < cpu->nlevels; j++)
 			pr_info("%s\tCPU mode: %s id:%d\n", str,
-					cluster->cpu->levels[j].name,
-					cluster->cpu->levels[j].mode);
+					cpu->levels[j].name,
+					cpu->levels[j].mode);
 	}
 
 	id++;
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 8b59bee..7536aa9b 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -53,10 +53,8 @@
 #include <trace/events/trace_msm_low_power.h>
 
 #define SCLK_HZ (32768)
-#define SCM_HANDOFF_LOCK_ID "S:7"
 #define PSCI_POWER_STATE(reset) (reset << 30)
 #define PSCI_AFFINITY_LEVEL(lvl) ((lvl & 0x3) << 24)
-static remote_spinlock_t scm_handoff_lock;
 
 enum {
 	MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0),
@@ -106,7 +104,7 @@
 
 static DEFINE_PER_CPU(struct lpm_history, hist);
 
-static DEFINE_PER_CPU(struct lpm_cluster*, cpu_cluster);
+static DEFINE_PER_CPU(struct lpm_cpu*, cpu_lpm);
 static bool suspend_in_progress;
 static struct hrtimer lpm_hrtimer;
 static struct hrtimer histtimer;
@@ -135,10 +133,16 @@
 static bool sleep_disabled;
 module_param_named(sleep_disabled, sleep_disabled, bool, 0664);
 
+/**
+ * msm_cpuidle_get_deep_idle_latency - Get deep idle latency value
+ *
+ * Returns an s32 latency value
+ */
 s32 msm_cpuidle_get_deep_idle_latency(void)
 {
 	return 10;
 }
+EXPORT_SYMBOL(msm_cpuidle_get_deep_idle_latency);
 
 void lpm_suspend_wake_time(uint64_t wakeup_time)
 {
@@ -209,7 +213,7 @@
 	struct power_params *pwr_params;
 	struct lpm_cpu *cpu;
 	struct lpm_cluster *n;
-	uint32_t latency = 0;
+	uint32_t lat = 0;
 	int i;
 
 	list_for_each(list, child) {
@@ -218,19 +222,21 @@
 			if (strcmp(lat_level->level_name, n->cluster_name))
 				continue;
 		}
-		cpu = n->cpu;
-		for (i = 0; i < cpu->nlevels; i++) {
-			level = &cpu->levels[i];
-			pwr_params = &level->pwr;
-			if (lat_level->reset_level == level->reset_level) {
-				if ((latency > pwr_params->latency_us)
-							|| (!latency))
-					latency = pwr_params->latency_us;
-				break;
+		list_for_each_entry(cpu, &n->cpu, list) {
+			for (i = 0; i < cpu->nlevels; i++) {
+				level = &cpu->levels[i];
+				pwr_params = &level->pwr;
+				if (lat_level->reset_level
+						== level->reset_level) {
+					if ((lat > pwr_params->latency_us)
+							|| (!lat))
+						lat = pwr_params->latency_us;
+					break;
+				}
 			}
 		}
 	}
-	return latency;
+	return lat;
 }
 
 static struct lpm_cluster *cluster_aff_match(struct lpm_cluster *cluster,
@@ -239,9 +245,9 @@
 	struct lpm_cluster *n;
 
 	if ((cluster->aff_level == affinity_level)
-		|| ((cluster->cpu) && (affinity_level == 0)))
+		|| ((!list_empty(&cluster->cpu)) && (affinity_level == 0)))
 		return cluster;
-	else if (!cluster->cpu) {
+	else if (list_empty(&cluster->cpu)) {
 		n =  list_entry(cluster->child.next, typeof(*n), list);
 		return cluster_aff_match(n, affinity_level);
 	} else
@@ -316,7 +322,7 @@
 
 static int lpm_dying_cpu(unsigned int cpu)
 {
-	struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu);
+	struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent;
 
 	cluster_prepare(cluster, get_cpu_mask(cpu), NR_LPM_LEVELS, false, 0);
 	return 0;
@@ -324,7 +330,7 @@
 
 static int lpm_starting_cpu(unsigned int cpu)
 {
-	struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu);
+	struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent;
 
 	cluster_unprepare(cluster, get_cpu_mask(cpu), NR_LPM_LEVELS, false, 0);
 	return 0;
@@ -378,7 +384,7 @@
 static void clusttimer_cancel(void)
 {
 	int cpu = raw_smp_processor_id();
-	struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu);
+	struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent;
 
 	hrtimer_try_to_cancel(&cluster->histtimer);
 
@@ -414,22 +420,6 @@
 	hrtimer_start(&lpm_hrtimer, modified_ktime, HRTIMER_MODE_REL_PINNED);
 }
 
-static int set_device_mode(struct lpm_cluster *cluster, int ndevice,
-		struct lpm_cluster_level *level)
-{
-	struct low_power_ops *ops;
-
-	if (use_psci)
-		return 0;
-
-	ops = &cluster->lpm_dev[ndevice];
-	if (ops && ops->set_mode)
-		return ops->set_mode(ops, level->mode[ndevice],
-				level->notify_rpm);
-	else
-		return -EINVAL;
-}
-
 static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev,
 		struct lpm_cpu *cpu, int *idx_restrict,
 		uint32_t *idx_restrict_time)
@@ -953,10 +943,6 @@
 		if (!lpm_cluster_mode_allow(cluster, i, from_idle))
 			continue;
 
-		if (level->last_core_only &&
-			cpumask_weight(cpu_online_mask) > 1)
-			continue;
-
 		if (!cpumask_equal(&cluster->num_children_in_sync,
 					&level->num_cpu_votes))
 			continue;
@@ -1001,7 +987,6 @@
 		bool from_idle, int predicted)
 {
 	struct lpm_cluster_level *level = &cluster->levels[idx];
-	int ret, i;
 
 	if (!cpumask_equal(&cluster->num_children_in_sync, &cluster->child_cpus)
 			|| is_IPI_pending(&cluster->num_children_in_sync)) {
@@ -1022,30 +1007,16 @@
 						ktime_to_us(ktime_get()));
 	}
 
-	for (i = 0; i < cluster->ndevices; i++) {
-		ret = set_device_mode(cluster, i, level);
-		if (ret)
-			goto failed_set_mode;
-	}
 	if (level->notify_rpm) {
-		struct cpumask nextcpu, *cpumask;
 		uint64_t us;
 		uint32_t pred_us;
 
-		us = get_cluster_sleep_time(cluster, &nextcpu,
-						from_idle, &pred_us);
-		cpumask = level->disable_dynamic_routing ? NULL : &nextcpu;
-
-		if (ret) {
-			pr_info("Failed msm_rpm_enter_sleep() rc = %d\n", ret);
-			goto failed_set_mode;
-		}
-
+		us = get_cluster_sleep_time(cluster, NULL, from_idle,
+				&pred_us);
 		us = us + 1;
 		clear_predict_history();
 		clear_cl_predict_history();
 
-		do_div(us, USEC_PER_SEC/SCLK_HZ);
 		system_sleep_enter(us);
 	}
 	/* Notify cluster enter event after successfully config completion */
@@ -1062,17 +1033,6 @@
 	}
 
 	return 0;
-failed_set_mode:
-
-	for (i = 0; i < cluster->ndevices; i++) {
-		int rc = 0;
-
-		level = &cluster->levels[cluster->default_level];
-		// rc = set_device_mode(cluster, i, level);
-		WARN_ON(rc);
-	}
-
-	return ret;
 }
 
 static void cluster_prepare(struct lpm_cluster *cluster,
@@ -1152,7 +1112,7 @@
 {
 	struct lpm_cluster_level *level;
 	bool first_cpu;
-	int last_level, i, ret;
+	int last_level, i;
 
 	if (!cluster)
 		return;
@@ -1202,13 +1162,8 @@
 	last_level = cluster->last_level;
 	cluster->last_level = cluster->default_level;
 
-	for (i = 0; i < cluster->ndevices; i++) {
+	for (i = 0; i < cluster->ndevices; i++)
 		level = &cluster->levels[cluster->default_level];
-		ret = set_device_mode(cluster, i, level);
-
-		WARN_ON(ret);
-
-	}
 
 	cluster_notify(cluster, &cluster->levels[last_level], false);
 
@@ -1221,12 +1176,11 @@
 	spin_unlock(&cluster->sync_lock);
 }
 
-static inline void cpu_prepare(struct lpm_cluster *cluster, int cpu_index,
+static inline void cpu_prepare(struct lpm_cpu *cpu, int cpu_index,
 				bool from_idle)
 {
-	struct lpm_cpu_level *cpu_level = &cluster->cpu->levels[cpu_index];
-	bool jtag_save_restore =
-			cluster->cpu->levels[cpu_index].jtag_save_restore;
+	struct lpm_cpu_level *cpu_level = &cpu->levels[cpu_index];
+	bool jtag_save_restore = cpu->levels[cpu_index].jtag_save_restore;
 
 	/* Use broadcast timer for aggregating sleep mode within a cluster.
 	 * A broadcast timer could be used in the following scenarios
@@ -1254,12 +1208,11 @@
 		msm_jtag_save_state();
 }
 
-static inline void cpu_unprepare(struct lpm_cluster *cluster, int cpu_index,
+static inline void cpu_unprepare(struct lpm_cpu *cpu, int cpu_index,
 				bool from_idle)
 {
-	struct lpm_cpu_level *cpu_level = &cluster->cpu->levels[cpu_index];
-	bool jtag_save_restore =
-			cluster->cpu->levels[cpu_index].jtag_save_restore;
+	struct lpm_cpu_level *cpu_level = &cpu->levels[cpu_index];
+	bool jtag_save_restore = cpu->levels[cpu_index].jtag_save_restore;
 
 	if (from_idle && cpu_level->use_bc_timer)
 		tick_broadcast_exit();
@@ -1305,13 +1258,12 @@
 	return state_id;
 }
 
-#if !defined(CONFIG_CPU_V7)
-bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle)
+static bool psci_enter_sleep(struct lpm_cpu *cpu, int idx, bool from_idle)
 {
 	int affinity_level = 0;
-	int state_id = get_cluster_id(cluster, &affinity_level);
+	int state_id = get_cluster_id(cpu->parent, &affinity_level);
 	int power_state =
-		PSCI_POWER_STATE(cluster->cpu->levels[idx].is_reset);
+		PSCI_POWER_STATE(cpu->levels[idx].is_reset);
 	bool success = false;
 	/*
 	 * idx = 0 is the default LPM state
@@ -1325,7 +1277,7 @@
 
 	affinity_level = PSCI_AFFINITY_LEVEL(affinity_level);
 	state_id |= (power_state | affinity_level
-			| cluster->cpu->levels[idx].psci_id);
+			| cpu->levels[idx].psci_id);
 
 	update_debug_pc_event(CPU_ENTER, state_id,
 			0xdeaffeed, 0xdeaffeed, true);
@@ -1336,52 +1288,17 @@
 			success, 0xdeaffeed, true);
 	return success;
 }
-#elif defined(CONFIG_ARM_PSCI)
-bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle)
-{
-	int affinity_level = 0;
-	int state_id = get_cluster_id(cluster, &affinity_level);
-	int power_state =
-		PSCI_POWER_STATE(cluster->cpu->levels[idx].is_reset);
-	bool success = false;
-
-	if (!idx) {
-		stop_critical_timings();
-		wfi();
-		start_critical_timings();
-		return 1;
-	}
-
-	affinity_level = PSCI_AFFINITY_LEVEL(affinity_level);
-	state_id |= (power_state | affinity_level
-			| cluster->cpu->levels[idx].psci_id);
-
-	update_debug_pc_event(CPU_ENTER, state_id,
-			0xdeaffeed, 0xdeaffeed, true);
-	stop_critical_timings();
-	success = !arm_cpuidle_suspend(state_id);
-	start_critical_timings();
-	update_debug_pc_event(CPU_EXIT, state_id,
-			success, 0xdeaffeed, true);
-}
-#else
-bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle)
-{
-	WARN_ONCE(true, "PSCI cpu_suspend ops not supported\n");
-	return false;
-}
-#endif
 
 static int lpm_cpuidle_select(struct cpuidle_driver *drv,
 		struct cpuidle_device *dev)
 {
-	struct lpm_cluster *cluster = per_cpu(cpu_cluster, dev->cpu);
+	struct lpm_cpu *cpu = per_cpu(cpu_lpm, dev->cpu);
 	int idx;
 
-	if (!cluster)
+	if (!cpu)
 		return 0;
 
-	idx = cpu_power_select(dev, cluster->cpu);
+	idx = cpu_power_select(dev, cpu);
 
 	if (idx < 0)
 		return 0;
@@ -1425,18 +1342,18 @@
 static int lpm_cpuidle_enter(struct cpuidle_device *dev,
 		struct cpuidle_driver *drv, int idx)
 {
-	struct lpm_cluster *cluster = per_cpu(cpu_cluster, dev->cpu);
+	struct lpm_cpu *cpu = per_cpu(cpu_lpm, dev->cpu);
 	bool success = true;
 	const struct cpumask *cpumask = get_cpu_mask(dev->cpu);
 	int64_t start_time = ktime_to_ns(ktime_get()), end_time;
 	struct power_params *pwr_params;
 
-	pwr_params = &cluster->cpu->levels[idx].pwr;
+	pwr_params = &cpu->levels[idx].pwr;
 
-	pwr_params = &cluster->cpu->levels[idx].pwr;
+	pwr_params = &cpu->levels[idx].pwr;
 
-	cpu_prepare(cluster, idx, true);
-	cluster_prepare(cluster, cpumask, idx, true, ktime_to_ns(ktime_get()));
+	cpu_prepare(cpu, idx, true);
+	cluster_prepare(cpu->parent, cpumask, idx, true, start_time);
 
 	trace_cpu_idle_enter(idx);
 	lpm_stats_cpu_enter(idx, start_time);
@@ -1444,15 +1361,14 @@
 	if (need_resched() || (idx < 0))
 		goto exit;
 
-	WARN_ON(!use_psci);
-	success = psci_enter_sleep(cluster, idx, true);
+	success = psci_enter_sleep(cpu, idx, true);
 
 exit:
 	end_time = ktime_to_ns(ktime_get());
 	lpm_stats_cpu_exit(idx, end_time, success);
 
-	cluster_unprepare(cluster, cpumask, idx, true, end_time);
-	cpu_unprepare(cluster, idx, true);
+	cluster_unprepare(cpu->parent, cpumask, idx, true, end_time);
+	cpu_unprepare(cpu, idx, true);
 	sched_set_cpu_cstate(smp_processor_id(), 0, 0, 0);
 	end_time = ktime_to_ns(ktime_get()) - start_time;
 	do_div(end_time, 1000);
@@ -1522,8 +1438,9 @@
 	int i = 0, ret = 0;
 	unsigned int cpu;
 	struct lpm_cluster *p = NULL;
+	struct lpm_cpu *lpm_cpu;
 
-	if (!cl->cpu) {
+	if (list_empty(&cl->cpu)) {
 		struct lpm_cluster *n;
 
 		list_for_each_entry(n, &cl->child, list) {
@@ -1534,51 +1451,56 @@
 		return ret;
 	}
 
-	cl->drv = kcalloc(1, sizeof(*cl->drv), GFP_KERNEL);
-	if (!cl->drv)
-		return -ENOMEM;
+	list_for_each_entry(lpm_cpu, &cl->cpu, list) {
+		lpm_cpu->drv = kcalloc(1, sizeof(*lpm_cpu->drv), GFP_KERNEL);
+		if (!lpm_cpu->drv)
+			return -ENOMEM;
 
-	cl->drv->name = "msm_idle";
+		lpm_cpu->drv->name = "msm_idle";
 
-	for (i = 0; i < cl->cpu->nlevels; i++) {
-		struct cpuidle_state *st = &cl->drv->states[i];
-		struct lpm_cpu_level *cpu_level = &cl->cpu->levels[i];
+		for (i = 0; i < lpm_cpu->nlevels; i++) {
+			struct cpuidle_state *st = &lpm_cpu->drv->states[i];
+			struct lpm_cpu_level *cpu_level = &lpm_cpu->levels[i];
 
-		snprintf(st->name, CPUIDLE_NAME_LEN, "C%u\n", i);
-		snprintf(st->desc, CPUIDLE_DESC_LEN, cpu_level->name);
-		st->flags = 0;
-		st->exit_latency = cpu_level->pwr.latency_us;
-		st->power_usage = cpu_level->pwr.ss_power;
-		st->target_residency = 0;
-		st->enter = lpm_cpuidle_enter;
-	}
-
-	cl->drv->state_count = cl->cpu->nlevels;
-	cl->drv->safe_state_index = 0;
-	for_each_cpu(cpu, &cl->child_cpus)
-		per_cpu(cpu_cluster, cpu) = cl;
-
-	for_each_possible_cpu(cpu) {
-		if (cpu_online(cpu))
-			continue;
-		p = per_cpu(cpu_cluster, cpu);
-		while (p) {
-			int j;
-
-			spin_lock(&p->sync_lock);
-			cpumask_set_cpu(cpu, &p->num_children_in_sync);
-			for (j = 0; j < p->nlevels; j++)
-				cpumask_copy(&p->levels[j].num_cpu_votes,
-						&p->num_children_in_sync);
-			spin_unlock(&p->sync_lock);
-			p = p->parent;
+			snprintf(st->name, CPUIDLE_NAME_LEN, "C%u\n", i);
+			snprintf(st->desc, CPUIDLE_DESC_LEN, cpu_level->name);
+			st->flags = 0;
+			st->exit_latency = cpu_level->pwr.latency_us;
+			st->power_usage = cpu_level->pwr.ss_power;
+			st->target_residency = 0;
+			st->enter = lpm_cpuidle_enter;
 		}
-	}
-	ret = cpuidle_register_cpu(cl->drv, &cl->child_cpus);
 
-	if (ret) {
-		kfree(cl->drv);
-		return -ENOMEM;
+		lpm_cpu->drv->state_count = lpm_cpu->nlevels;
+		lpm_cpu->drv->safe_state_index = 0;
+		for_each_cpu(cpu, &lpm_cpu->related_cpus)
+			per_cpu(cpu_lpm, cpu) = lpm_cpu;
+
+		for_each_possible_cpu(cpu) {
+			if (cpu_online(cpu))
+				continue;
+			if (per_cpu(cpu_lpm, cpu))
+				p = per_cpu(cpu_lpm, cpu)->parent;
+			while (p) {
+				int j;
+
+				spin_lock(&p->sync_lock);
+				cpumask_set_cpu(cpu, &p->num_children_in_sync);
+				for (j = 0; j < p->nlevels; j++)
+					cpumask_copy(
+						&p->levels[j].num_cpu_votes,
+						&p->num_children_in_sync);
+				spin_unlock(&p->sync_lock);
+				p = p->parent;
+			}
+		}
+		ret = cpuidle_register_cpu(lpm_cpu->drv,
+					&lpm_cpu->related_cpus);
+
+		if (ret) {
+			kfree(lpm_cpu->drv);
+			return -ENOMEM;
+		}
 	}
 	return 0;
 }
@@ -1608,7 +1530,7 @@
 		level_name[i] = cpu->levels[i].name;
 
 	lpm_stats_config_level("cpu", level_name, cpu->nlevels,
-			parent->stats, &parent->child_cpus);
+			parent->stats, &cpu->related_cpus);
 
 	kfree(level_name);
 }
@@ -1617,8 +1539,9 @@
 		struct lpm_cluster *parent)
 {
 	const char **level_name;
-	int i;
 	struct lpm_cluster *child;
+	struct lpm_cpu *cpu;
+	int i;
 
 	if (!cl)
 		return;
@@ -1636,10 +1559,12 @@
 
 	kfree(level_name);
 
-	if (cl->cpu) {
-		register_cpu_lpm_stats(cl->cpu, cl);
-		return;
+	list_for_each_entry(cpu, &cl->cpu, list) {
+		pr_err("%s()\n", __func__);
+		register_cpu_lpm_stats(cpu, cl);
 	}
+	if (!list_empty(&cl->cpu))
+		return;
 
 	list_for_each_entry(child, &cl->child, list)
 		register_cluster_lpm_stats(child, cl);
@@ -1662,8 +1587,8 @@
 static int lpm_suspend_enter(suspend_state_t state)
 {
 	int cpu = raw_smp_processor_id();
-	struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu);
-	struct lpm_cpu *lpm_cpu = cluster->cpu;
+	struct lpm_cpu *lpm_cpu = per_cpu(cpu_lpm, cpu);
+	struct lpm_cluster *cluster = lpm_cpu->parent;
 	const struct cpumask *cpumask = get_cpu_mask(cpu);
 	int idx;
 
@@ -1676,7 +1601,7 @@
 		pr_err("Failed suspend\n");
 		return 0;
 	}
-	cpu_prepare(cluster, idx, false);
+	cpu_prepare(lpm_cpu, idx, false);
 	cluster_prepare(cluster, cpumask, idx, false, 0);
 	if (idx > 0)
 		update_debug_pc_event(CPU_ENTER, idx, 0xdeaffeed,
@@ -1689,15 +1614,14 @@
 	 * LPMs(XO and Vmin).
 	 */
 
-	WARN_ON(!use_psci);
-	psci_enter_sleep(cluster, idx, true);
+	psci_enter_sleep(lpm_cpu, idx, true);
 
 	if (idx > 0)
 		update_debug_pc_event(CPU_EXIT, idx, true, 0xdeaffeed,
 					false);
 
 	cluster_unprepare(cluster, cpumask, idx, false, 0);
-	cpu_unprepare(cluster, idx, false);
+	cpu_unprepare(lpm_cpu, idx, false);
 	return 0;
 }
 
@@ -1737,14 +1661,6 @@
 	hrtimer_init(&histtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	cluster_timer_init(lpm_root_node);
 
-	ret = remote_spin_lock_init(&scm_handoff_lock, SCM_HANDOFF_LOCK_ID);
-	if (ret) {
-		pr_err("%s: Failed initializing scm_handoff_lock (%d)\n",
-			__func__, ret);
-		put_online_cpus();
-		return ret;
-	}
-
 	size = num_dbg_elements * sizeof(struct lpm_debug);
 	lpm_debug = dma_alloc_coherent(&pdev->dev, size,
 			&lpm_debug_phys, GFP_KERNEL);
@@ -1813,54 +1729,3 @@
 	return rc;
 }
 late_initcall(lpm_levels_module_init);
-
-enum msm_pm_l2_scm_flag lpm_cpu_pre_pc_cb(unsigned int cpu)
-{
-	struct lpm_cluster *cluster = per_cpu(cpu_cluster, cpu);
-	enum msm_pm_l2_scm_flag retflag = MSM_SCM_L2_ON;
-
-	/*
-	 * No need to acquire the lock if probe isn't completed yet
-	 * In the event of the hotplug happening before lpm probe, we want to
-	 * flush the cache to make sure that L2 is flushed. In particular, this
-	 * could cause incoherencies for a cluster architecture. This wouldn't
-	 * affect the idle case as the idle driver wouldn't be registered
-	 * before the probe function
-	 */
-	if (!cluster)
-		return MSM_SCM_L2_OFF;
-
-	/*
-	 * Assumes L2 only. What/How parameters gets passed into TZ will
-	 * determine how this function reports this info back in msm-pm.c
-	 */
-	spin_lock(&cluster->sync_lock);
-
-	if (!cluster->lpm_dev) {
-		retflag = MSM_SCM_L2_OFF;
-		goto unlock_and_return;
-	}
-
-	if (!cpumask_equal(&cluster->num_children_in_sync,
-						&cluster->child_cpus))
-		goto unlock_and_return;
-
-	if (cluster->lpm_dev)
-		retflag = cluster->lpm_dev->tz_flag;
-	/*
-	 * The scm_handoff_lock will be release by the secure monitor.
-	 * It is used to serialize power-collapses from this point on,
-	 * so that both Linux and the secure context have a consistent
-	 * view regarding the number of running cpus (cpu_count).
-	 *
-	 * It must be acquired before releasing the cluster lock.
-	 */
-unlock_and_return:
-	update_debug_pc_event(PRE_PC_CB, retflag, 0xdeadbeef, 0xdeadbeef,
-			0xdeadbeef);
-	trace_pre_pc_cb(retflag);
-	remote_spin_lock_rlock_id(&scm_handoff_lock,
-				  REMOTE_SPINLOCK_TID_START + cpu);
-	spin_unlock(&cluster->sync_lock);
-	return retflag;
-}
diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h
index 6c9a50b..c9f272e 100644
--- a/drivers/cpuidle/lpm-levels.h
+++ b/drivers/cpuidle/lpm-levels.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,8 +17,6 @@
 #define MAXSAMPLES 5
 #define CLUST_SMPL_INVLD_TIME 40000
 
-extern bool use_psci;
-
 struct lpm_lookup_table {
 	uint32_t modes;
 	const char *mode_name;
@@ -47,19 +45,24 @@
 };
 
 struct lpm_cpu {
+	struct list_head list;
+	struct cpumask related_cpus;
 	struct lpm_cpu_level levels[NR_LPM_LEVELS];
 	int nlevels;
 	unsigned int psci_mode_shift;
 	unsigned int psci_mode_mask;
+	struct cpuidle_driver *drv;
 	struct lpm_cluster *parent;
 };
 
 struct lpm_level_avail {
 	bool idle_enabled;
 	bool suspend_enabled;
+	uint32_t latency_us;
 	struct kobject *kobj;
 	struct kobj_attribute idle_enabled_attr;
 	struct kobj_attribute suspend_enabled_attr;
+	struct kobj_attribute latency_attr;
 	void *data;
 	int idx;
 	bool cpu_node;
@@ -72,21 +75,13 @@
 	struct cpumask num_cpu_votes;
 	struct power_params pwr;
 	bool notify_rpm;
-	bool disable_dynamic_routing;
 	bool sync_level;
-	bool last_core_only;
 	struct lpm_level_avail available;
 	unsigned int psci_id;
 	bool is_reset;
 	int reset_level;
 };
 
-struct low_power_ops {
-	struct msm_spm_device *spm;
-	int (*set_mode)(struct low_power_ops *ops, int mode, bool notify_rpm);
-	enum msm_pm_l2_scm_flag tz_flag;
-};
-
 struct cluster_history {
 	uint32_t resi[MAXSAMPLES];
 	int mode[MAXSAMPLES];
@@ -106,16 +101,13 @@
 	const char *cluster_name;
 	const char **name;
 	unsigned long aff_level; /* Affinity level of the node */
-	struct low_power_ops *lpm_dev;
 	int ndevices;
 	struct lpm_cluster_level levels[NR_LPM_LEVELS];
 	int nlevels;
-	enum msm_pm_l2_scm_flag l2_flag;
 	int min_child_level;
 	int default_level;
 	int last_level;
-	struct lpm_cpu *cpu;
-	struct cpuidle_driver *drv;
+	struct list_head cpu;
 	spinlock_t sync_lock;
 	struct cpumask child_cpus;
 	struct cpumask num_children_in_sync;
@@ -123,14 +115,10 @@
 	struct lpm_stats *stats;
 	unsigned int psci_mode_shift;
 	unsigned int psci_mode_mask;
-	bool no_saw_devices;
 	struct cluster_history history;
 	struct hrtimer histtimer;
 };
 
-int set_l2_mode(struct low_power_ops *ops, int mode, bool notify_rpm);
-int set_system_mode(struct low_power_ops *ops, int mode, bool notify_rpm);
-int set_l3_mode(struct low_power_ops *ops, int mode, bool notify_rpm);
 void lpm_suspend_wake_time(uint64_t wakeup_time);
 
 struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 56fbb94..b979fb9 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -439,6 +439,7 @@
 	u8 rfc4309_iv[QCRYPTO_MAX_IV_LENGTH];
 	unsigned int ivsize;
 	int  aead;
+	int  ccmtype;			/* default: 0, rfc4309: 1 */
 	struct scatterlist asg;		/* Formatted associated data sg  */
 	unsigned char *adata;		/* Pointer to formatted assoc data */
 	enum qce_cipher_alg_enum alg;
@@ -1936,9 +1937,8 @@
 	return 0;
 }
 
-static int qccrypto_set_aead_ccm_nonce(struct qce_req *qreq)
+static int qccrypto_set_aead_ccm_nonce(struct qce_req *qreq, uint32_t assoclen)
 {
-	struct aead_request *areq = (struct aead_request *) qreq->areq;
 	unsigned int i = ((unsigned int)qreq->iv[0]) + 1;
 
 	memcpy(&qreq->nonce[0], qreq->iv, qreq->ivsize);
@@ -1947,7 +1947,7 @@
 	 * NIST Special Publication 800-38C
 	 */
 	qreq->nonce[0] |= (8 * ((qreq->authsize - 2) / 2));
-	if (areq->assoclen)
+	if (assoclen)
 		qreq->nonce[0] |= 64;
 
 	if (i > MAX_NONCE)
@@ -2153,24 +2153,31 @@
 	qreq.flags = cipher_ctx->flags;
 
 	if (qreq.mode == QCE_MODE_CCM) {
+		uint32_t assoclen;
+
 		if (qreq.dir == QCE_ENCRYPT)
 			qreq.cryptlen = req->cryptlen;
 		else
 			qreq.cryptlen = req->cryptlen -
 						qreq.authsize;
+
+		/* if rfc4309 ccm, adjust assoclen */
+		assoclen = req->assoclen;
+		if (rctx->ccmtype)
+			assoclen -= 8;
 		/* Get NONCE */
-		ret = qccrypto_set_aead_ccm_nonce(&qreq);
+		ret = qccrypto_set_aead_ccm_nonce(&qreq, assoclen);
 		if (ret)
 			return ret;
 
-		if (req->assoclen) {
-			rctx->adata = kzalloc((req->assoclen + 0x64),
+		if (assoclen) {
+			rctx->adata = kzalloc((assoclen + 0x64),
 								GFP_ATOMIC);
 			if (!rctx->adata)
 				return -ENOMEM;
 			/* Format Associated data    */
 			ret = qcrypto_aead_ccm_format_adata(&qreq,
-						req->assoclen,
+						assoclen,
 						req->src,
 						rctx->adata);
 		} else {
@@ -2633,6 +2640,7 @@
 	rctx->dir = QCE_ENCRYPT;
 	rctx->mode = QCE_MODE_CCM;
 	rctx->iv = req->iv;
+	rctx->ccmtype = 0;
 
 	pstat->aead_ccm_aes_enc++;
 	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
@@ -2647,6 +2655,8 @@
 
 	pstat = &_qcrypto_stat;
 
+	if (req->assoclen != 16 && req->assoclen != 20)
+		return -EINVAL;
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
 	rctx->alg = CIPHER_ALG_AES;
@@ -2656,6 +2666,7 @@
 	rctx->rfc4309_iv[0] = 3; /* L -1 */
 	memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
 	memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+	rctx->ccmtype = 1;
 	rctx->iv = rctx->rfc4309_iv;
 	pstat->aead_rfc4309_ccm_aes_enc++;
 	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
@@ -2963,6 +2974,7 @@
 	rctx->dir = QCE_DECRYPT;
 	rctx->mode = QCE_MODE_CCM;
 	rctx->iv = req->iv;
+	rctx->ccmtype = 0;
 
 	pstat->aead_ccm_aes_dec++;
 	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
@@ -2976,6 +2988,8 @@
 	struct crypto_stat *pstat;
 
 	pstat = &_qcrypto_stat;
+	if (req->assoclen != 16 && req->assoclen != 20)
+		return -EINVAL;
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
 	rctx->alg = CIPHER_ALG_AES;
@@ -2985,6 +2999,7 @@
 	rctx->rfc4309_iv[0] = 3; /* L -1 */
 	memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
 	memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+	rctx->ccmtype = 1;
 	rctx->iv = rctx->rfc4309_iv;
 	pstat->aead_rfc4309_ccm_aes_dec++;
 	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
@@ -4274,7 +4289,7 @@
 };
 EXPORT_SYMBOL(qcrypto_cipher_set_device);
 
-int qcrypto_cipher_set_device_hw(struct ablkcipher_request *req, u32 dev,
+int qcrypto_cipher_set_device_hw(struct skcipher_request *req, u32 dev,
 			u32 hw_inst)
 {
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
@@ -4320,7 +4335,7 @@
 };
 EXPORT_SYMBOL(qcrypto_ahash_set_device);
 
-int qcrypto_cipher_set_flag(struct ablkcipher_request *req, unsigned int flags)
+int qcrypto_cipher_set_flag(struct skcipher_request *req, unsigned int flags)
 {
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
 	struct crypto_priv *cp = ctx->cp;
diff --git a/drivers/devfreq/devfreq_simple_dev.c b/drivers/devfreq/devfreq_simple_dev.c
index 9c99fcf..b0757b6 100644
--- a/drivers/devfreq/devfreq_simple_dev.c
+++ b/drivers/devfreq/devfreq_simple_dev.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 2017, 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
@@ -34,6 +34,7 @@
 	struct clk *clk;
 	struct devfreq *df;
 	struct devfreq_dev_profile profile;
+	bool freq_in_khz;
 };
 
 static void find_freq(struct devfreq_dev_profile *p, unsigned long *freq,
@@ -65,7 +66,7 @@
 
 	find_freq(&d->profile, freq, flags);
 
-	rfreq = clk_round_rate(d->clk, *freq * 1000);
+	rfreq = clk_round_rate(d->clk, d->freq_in_khz ? *freq * 1000 : *freq);
 	if (IS_ERR_VALUE(rfreq)) {
 		dev_err(dev, "devfreq: Cannot find matching frequency for %lu\n",
 			*freq);
@@ -83,39 +84,30 @@
 	f = clk_get_rate(d->clk);
 	if (IS_ERR_VALUE(f))
 		return f;
-	*freq = f / 1000;
+	*freq = d->freq_in_khz ? f / 1000 : f;
 	return 0;
 }
 
 #define PROP_TBL "freq-tbl-khz"
-static int devfreq_clock_probe(struct platform_device *pdev)
+static int parse_freq_table(struct device *dev, struct dev_data *d)
 {
-	struct device *dev = &pdev->dev;
-	struct dev_data *d;
-	struct devfreq_dev_profile *p;
-	u32 *data, poll;
-	const char *gov_name;
+	struct devfreq_dev_profile *p = &d->profile;
 	int ret, len, i, j;
+	u32 *data;
 	unsigned long f;
 
-	d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
-	if (!d)
-		return -ENOMEM;
-	platform_set_drvdata(pdev, d);
+	if (!of_find_property(dev->of_node, PROP_TBL, &len)) {
+		if (dev_pm_opp_get_opp_count(dev) <= 0)
+			return -EPROBE_DEFER;
+		return 0;
+	}
 
-	d->clk = devm_clk_get(dev, "devfreq_clk");
-	if (IS_ERR(d->clk))
-		return PTR_ERR(d->clk);
-
-	if (!of_find_property(dev->of_node, PROP_TBL, &len))
-		return -EINVAL;
-
+	d->freq_in_khz = true;
 	len /= sizeof(*data);
 	data = devm_kzalloc(dev, len * sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
-	p = &d->profile;
 	p->freq_table = devm_kzalloc(dev, len * sizeof(*p->freq_table),
 				     GFP_KERNEL);
 	if (!p->freq_table)
@@ -142,6 +134,32 @@
 		return -EINVAL;
 	}
 
+	return 0;
+}
+
+static int devfreq_clock_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct dev_data *d;
+	struct devfreq_dev_profile *p;
+	u32 poll;
+	const char *gov_name;
+	int ret;
+
+	d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
+	if (!d)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, d);
+
+	d->clk = devm_clk_get(dev, "devfreq_clk");
+	if (IS_ERR(d->clk))
+		return PTR_ERR(d->clk);
+
+	ret = parse_freq_table(dev, d);
+	if (ret)
+		return ret;
+
+	p = &d->profile;
 	p->target = dev_target;
 	p->get_cur_freq = dev_get_cur_freq;
 	ret = dev_get_cur_freq(dev, &p->initial_freq);
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index d37e8dd..ec24059 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -201,6 +201,7 @@
 	struct dma_device	dma_dev;
 	bool			m2m;
 	int			(*hw_setup)(struct ep93xx_dma_chan *);
+	void			(*hw_synchronize)(struct ep93xx_dma_chan *);
 	void			(*hw_shutdown)(struct ep93xx_dma_chan *);
 	void			(*hw_submit)(struct ep93xx_dma_chan *);
 	int			(*hw_interrupt)(struct ep93xx_dma_chan *);
@@ -323,6 +324,8 @@
 		| M2P_CONTROL_ENABLE;
 	m2p_set_control(edmac, control);
 
+	edmac->buffer = 0;
+
 	return 0;
 }
 
@@ -331,21 +334,27 @@
 	return (readl(edmac->regs + M2P_STATUS) >> 4) & 0x3;
 }
 
-static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
+static void m2p_hw_synchronize(struct ep93xx_dma_chan *edmac)
 {
+	unsigned long flags;
 	u32 control;
 
+	spin_lock_irqsave(&edmac->lock, flags);
 	control = readl(edmac->regs + M2P_CONTROL);
 	control &= ~(M2P_CONTROL_STALLINT | M2P_CONTROL_NFBINT);
 	m2p_set_control(edmac, control);
+	spin_unlock_irqrestore(&edmac->lock, flags);
 
 	while (m2p_channel_state(edmac) >= M2P_STATE_ON)
-		cpu_relax();
+		schedule();
+}
 
+static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
+{
 	m2p_set_control(edmac, 0);
 
-	while (m2p_channel_state(edmac) == M2P_STATE_STALL)
-		cpu_relax();
+	while (m2p_channel_state(edmac) != M2P_STATE_IDLE)
+		dev_warn(chan2dev(edmac), "M2P: Not yet IDLE\n");
 }
 
 static void m2p_fill_desc(struct ep93xx_dma_chan *edmac)
@@ -1161,6 +1170,26 @@
 }
 
 /**
+ * ep93xx_dma_synchronize - Synchronizes the termination of transfers to the
+ * current context.
+ * @chan: channel
+ *
+ * Synchronizes the DMA channel termination to the current context. When this
+ * function returns it is guaranteed that all transfers for previously issued
+ * descriptors have stopped and and it is safe to free the memory associated
+ * with them. Furthermore it is guaranteed that all complete callback functions
+ * for a previously submitted descriptor have finished running and it is safe to
+ * free resources accessed from within the complete callbacks.
+ */
+static void ep93xx_dma_synchronize(struct dma_chan *chan)
+{
+	struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
+
+	if (edmac->edma->hw_synchronize)
+		edmac->edma->hw_synchronize(edmac);
+}
+
+/**
  * ep93xx_dma_terminate_all - terminate all transactions
  * @chan: channel
  *
@@ -1323,6 +1352,7 @@
 	dma_dev->device_prep_slave_sg = ep93xx_dma_prep_slave_sg;
 	dma_dev->device_prep_dma_cyclic = ep93xx_dma_prep_dma_cyclic;
 	dma_dev->device_config = ep93xx_dma_slave_config;
+	dma_dev->device_synchronize = ep93xx_dma_synchronize;
 	dma_dev->device_terminate_all = ep93xx_dma_terminate_all;
 	dma_dev->device_issue_pending = ep93xx_dma_issue_pending;
 	dma_dev->device_tx_status = ep93xx_dma_tx_status;
@@ -1340,6 +1370,7 @@
 	} else {
 		dma_cap_set(DMA_PRIVATE, dma_dev->cap_mask);
 
+		edma->hw_synchronize = m2p_hw_synchronize;
 		edma->hw_setup = m2p_hw_setup;
 		edma->hw_shutdown = m2p_hw_shutdown;
 		edma->hw_submit = m2p_hw_submit;
diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c
index a28a01f..f3e211f 100644
--- a/drivers/dma/mv_xor_v2.c
+++ b/drivers/dma/mv_xor_v2.c
@@ -161,6 +161,7 @@
 	struct mv_xor_v2_sw_desc *sw_desq;
 	int desc_size;
 	unsigned int npendings;
+	unsigned int hw_queue_idx;
 };
 
 /**
@@ -214,18 +215,6 @@
 }
 
 /*
- * Return the next available index in the DESQ.
- */
-static int mv_xor_v2_get_desq_write_ptr(struct mv_xor_v2_device *xor_dev)
-{
-	/* read the index for the next available descriptor in the DESQ */
-	u32 reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ALLOC_OFF);
-
-	return ((reg >> MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_SHIFT)
-		& MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_MASK);
-}
-
-/*
  * notify the engine of new descriptors, and update the available index.
  */
 static void mv_xor_v2_add_desc_to_desq(struct mv_xor_v2_device *xor_dev,
@@ -257,22 +246,6 @@
 	return MV_XOR_V2_EXT_DESC_SIZE;
 }
 
-/*
- * Set the IMSG threshold
- */
-static inline
-void mv_xor_v2_set_imsg_thrd(struct mv_xor_v2_device *xor_dev, int thrd_val)
-{
-	u32 reg;
-
-	reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
-
-	reg &= (~MV_XOR_V2_DMA_IMSG_THRD_MASK << MV_XOR_V2_DMA_IMSG_THRD_SHIFT);
-	reg |= (thrd_val << MV_XOR_V2_DMA_IMSG_THRD_SHIFT);
-
-	writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
-}
-
 static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data)
 {
 	struct mv_xor_v2_device *xor_dev = data;
@@ -288,12 +261,6 @@
 	if (!ndescs)
 		return IRQ_NONE;
 
-	/*
-	 * Update IMSG threshold, to disable new IMSG interrupts until
-	 * end of the tasklet
-	 */
-	mv_xor_v2_set_imsg_thrd(xor_dev, MV_XOR_V2_DESC_NUM);
-
 	/* schedule a tasklet to handle descriptors callbacks */
 	tasklet_schedule(&xor_dev->irq_tasklet);
 
@@ -306,7 +273,6 @@
 static dma_cookie_t
 mv_xor_v2_tx_submit(struct dma_async_tx_descriptor *tx)
 {
-	int desq_ptr;
 	void *dest_hw_desc;
 	dma_cookie_t cookie;
 	struct mv_xor_v2_sw_desc *sw_desc =
@@ -322,15 +288,15 @@
 	spin_lock_bh(&xor_dev->lock);
 	cookie = dma_cookie_assign(tx);
 
-	/* get the next available slot in the DESQ */
-	desq_ptr = mv_xor_v2_get_desq_write_ptr(xor_dev);
-
 	/* copy the HW descriptor from the SW descriptor to the DESQ */
-	dest_hw_desc = xor_dev->hw_desq_virt + desq_ptr;
+	dest_hw_desc = xor_dev->hw_desq_virt + xor_dev->hw_queue_idx;
 
 	memcpy(dest_hw_desc, &sw_desc->hw_desc, xor_dev->desc_size);
 
 	xor_dev->npendings++;
+	xor_dev->hw_queue_idx++;
+	if (xor_dev->hw_queue_idx >= MV_XOR_V2_DESC_NUM)
+		xor_dev->hw_queue_idx = 0;
 
 	spin_unlock_bh(&xor_dev->lock);
 
@@ -344,6 +310,7 @@
 mv_xor_v2_prep_sw_desc(struct mv_xor_v2_device *xor_dev)
 {
 	struct mv_xor_v2_sw_desc *sw_desc;
+	bool found = false;
 
 	/* Lock the channel */
 	spin_lock_bh(&xor_dev->lock);
@@ -355,19 +322,23 @@
 		return NULL;
 	}
 
-	/* get a free SW descriptor from the SW DESQ */
-	sw_desc = list_first_entry(&xor_dev->free_sw_desc,
-				   struct mv_xor_v2_sw_desc, free_list);
+	list_for_each_entry(sw_desc, &xor_dev->free_sw_desc, free_list) {
+		if (async_tx_test_ack(&sw_desc->async_tx)) {
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		spin_unlock_bh(&xor_dev->lock);
+		return NULL;
+	}
+
 	list_del(&sw_desc->free_list);
 
 	/* Release the channel */
 	spin_unlock_bh(&xor_dev->lock);
 
-	/* set the async tx descriptor */
-	dma_async_tx_descriptor_init(&sw_desc->async_tx, &xor_dev->dmachan);
-	sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit;
-	async_tx_ack(&sw_desc->async_tx);
-
 	return sw_desc;
 }
 
@@ -389,6 +360,8 @@
 		__func__, len, &src, &dest, flags);
 
 	sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
+	if (!sw_desc)
+		return NULL;
 
 	sw_desc->async_tx.flags = flags;
 
@@ -443,6 +416,8 @@
 		__func__, src_cnt, len, &dest, flags);
 
 	sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
+	if (!sw_desc)
+		return NULL;
 
 	sw_desc->async_tx.flags = flags;
 
@@ -491,6 +466,8 @@
 		container_of(chan, struct mv_xor_v2_device, dmachan);
 
 	sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
+	if (!sw_desc)
+		return NULL;
 
 	/* set the HW descriptor */
 	hw_descriptor = &sw_desc->hw_desc;
@@ -554,7 +531,6 @@
 {
 	struct mv_xor_v2_device *xor_dev = (struct mv_xor_v2_device *) data;
 	int pending_ptr, num_of_pending, i;
-	struct mv_xor_v2_descriptor *next_pending_hw_desc = NULL;
 	struct mv_xor_v2_sw_desc *next_pending_sw_desc = NULL;
 
 	dev_dbg(xor_dev->dmadev.dev, "%s %d\n", __func__, __LINE__);
@@ -562,17 +538,10 @@
 	/* get the pending descriptors parameters */
 	num_of_pending = mv_xor_v2_get_pending_params(xor_dev, &pending_ptr);
 
-	/* next HW descriptor */
-	next_pending_hw_desc = xor_dev->hw_desq_virt + pending_ptr;
-
 	/* loop over free descriptors */
 	for (i = 0; i < num_of_pending; i++) {
-
-		if (pending_ptr > MV_XOR_V2_DESC_NUM)
-			pending_ptr = 0;
-
-		if (next_pending_sw_desc != NULL)
-			next_pending_hw_desc++;
+		struct mv_xor_v2_descriptor *next_pending_hw_desc =
+			xor_dev->hw_desq_virt + pending_ptr;
 
 		/* get the SW descriptor related to the HW descriptor */
 		next_pending_sw_desc =
@@ -608,15 +577,14 @@
 
 		/* increment the next descriptor */
 		pending_ptr++;
+		if (pending_ptr >= MV_XOR_V2_DESC_NUM)
+			pending_ptr = 0;
 	}
 
 	if (num_of_pending != 0) {
 		/* free the descriptores */
 		mv_xor_v2_free_desc_from_desq(xor_dev, num_of_pending);
 	}
-
-	/* Update IMSG threshold, to enable new IMSG interrupts */
-	mv_xor_v2_set_imsg_thrd(xor_dev, 0);
 }
 
 /*
@@ -648,9 +616,6 @@
 	writel((xor_dev->hw_desq & 0xFFFF00000000) >> 32,
 	       xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BAHR_OFF);
 
-	/* enable the DMA engine */
-	writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF);
-
 	/*
 	 * This is a temporary solution, until we activate the
 	 * SMMU. Set the attributes for reading & writing data buffers
@@ -694,6 +659,9 @@
 	reg |= MV_XOR_V2_GLOB_PAUSE_AXI_TIME_DIS_VAL;
 	writel(reg, xor_dev->glob_base + MV_XOR_V2_GLOB_PAUSE);
 
+	/* enable the DMA engine */
+	writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF);
+
 	return 0;
 }
 
@@ -725,6 +693,10 @@
 
 	platform_set_drvdata(pdev, xor_dev);
 
+	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
+	if (ret)
+		return ret;
+
 	xor_dev->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER)
 		return -EPROBE_DEFER;
@@ -785,8 +757,15 @@
 
 	/* add all SW descriptors to the free list */
 	for (i = 0; i < MV_XOR_V2_DESC_NUM; i++) {
-		xor_dev->sw_desq[i].idx = i;
-		list_add(&xor_dev->sw_desq[i].free_list,
+		struct mv_xor_v2_sw_desc *sw_desc =
+			xor_dev->sw_desq + i;
+		sw_desc->idx = i;
+		dma_async_tx_descriptor_init(&sw_desc->async_tx,
+					     &xor_dev->dmachan);
+		sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit;
+		async_tx_ack(&sw_desc->async_tx);
+
+		list_add(&sw_desc->free_list,
 			 &xor_dev->free_sw_desc);
 	}
 
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 06ecdc3..6682b3e 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -117,7 +117,7 @@
 #define USB_DMASWR			0x0008
 #define USB_DMASWR_SWR			(1 << 0)
 #define USB_DMAOR			0x0060
-#define USB_DMAOR_AE			(1 << 2)
+#define USB_DMAOR_AE			(1 << 1)
 #define USB_DMAOR_DME			(1 << 0)
 
 #define USB_DMASAR			0x0000
diff --git a/drivers/edac/kryo3xx_arm64_edac.c b/drivers/edac/kryo3xx_arm64_edac.c
index 4ac880b..f5bb3ed 100644
--- a/drivers/edac/kryo3xx_arm64_edac.c
+++ b/drivers/edac/kryo3xx_arm64_edac.c
@@ -62,7 +62,7 @@
 
 static inline void set_errxmisc_overflow(void)
 {
-	u64 val = 0x7F7F00000000;
+	u64 val = 0x7F7F00000000ULL;
 
 	asm volatile("msr s3_0_c5_c5_0, %0" : : "r" (val));
 }
@@ -118,8 +118,9 @@
 #define DATA_BUF_ERR		0x2
 #define CACHE_DATA_ERR		0x6
 #define CACHE_TAG_DIRTY_ERR	0x7
-#define TLB_PARITY_ERR		0x8
-#define BUS_ERROR		0x18
+#define TLB_PARITY_ERR_DATA	0x8
+#define TLB_PARITY_ERR_TAG	0x9
+#define BUS_ERROR		0x12
 
 struct erp_drvdata {
 	struct edac_device_ctl_info *edev_ctl;
@@ -217,10 +218,13 @@
 		edac_printk(KERN_CRIT, EDAC_CPU, "ECC Error from cache tag or dirty RAM\n");
 		break;
 
-	case TLB_PARITY_ERR:
+	case TLB_PARITY_ERR_DATA:
 		edac_printk(KERN_CRIT, EDAC_CPU, "Parity error on TLB RAM\n");
 		break;
 
+	case TLB_PARITY_ERR_TAG:
+		edac_printk(KERN_CRIT, EDAC_CPU, "Parity error on TLB DATA\n");
+
 	case BUS_ERROR:
 		edac_printk(KERN_CRIT, EDAC_CPU, "Bus Error\n");
 		break;
@@ -283,6 +287,16 @@
 	spin_unlock_irqrestore(&local_handler_lock, flags);
 }
 
+static bool l3_is_bus_error(u64 errxstatus)
+{
+	if (KRYO3XX_ERRXSTATUS_SERR(errxstatus) == BUS_ERROR) {
+		edac_printk(KERN_CRIT, EDAC_CPU, "Bus Error\n");
+		return true;
+	}
+
+	return false;
+}
+
 static void kryo3xx_check_l3_scu_error(struct edac_device_ctl_info *edev_ctl)
 {
 	u64 errxstatus = 0;
@@ -296,6 +310,11 @@
 
 	if (KRYO3XX_ERRXSTATUS_VALID(errxstatus) &&
 		KRYO3XX_ERRXMISC_LVL(errxmisc) == L3) {
+		if (l3_is_bus_error(errxstatus)) {
+			if (edev_ctl->panic_on_ue)
+				panic("Causing panic due to Bus Error\n");
+			return;
+		}
 		if (KRYO3XX_ERRXSTATUS_UE(errxstatus)) {
 			edac_printk(KERN_CRIT, EDAC_CPU, "Detected L3 uncorrectable error\n");
 			dump_err_reg(KRYO3XX_L3_UE, L3, errxstatus, errxmisc,
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
index 5be788b..1679727 100644
--- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
@@ -900,6 +900,12 @@
 	u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
 	u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300;
 
+	/* disable mclk switching if the refresh is >120Hz, even if the
+	 * blanking period would allow it
+	 */
+	if (amdgpu_dpm_get_vrefresh(adev) > 120)
+		return true;
+
 	if (vblank_time < switch_limit)
 		return true;
 	else
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 6efdba4..0f2fa90 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -379,7 +379,12 @@
 void drm_unplug_dev(struct drm_device *dev)
 {
 	/* for a USB device */
-	drm_dev_unregister(dev);
+	if (drm_core_check_feature(dev, DRIVER_MODESET))
+		drm_modeset_unregister_all(dev);
+
+	drm_minor_unregister(dev, DRM_MINOR_PRIMARY);
+	drm_minor_unregister(dev, DRM_MINOR_RENDER);
+	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
 
 	mutex_lock(&drm_global_mutex);
 
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 923150d..ca6efb6 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -573,9 +573,7 @@
 	if (i915_inject_load_failure())
 		return -ENODEV;
 
-	ret = intel_bios_init(dev_priv);
-	if (ret)
-		DRM_INFO("failed to find VBIOS tables\n");
+	intel_bios_init(dev_priv);
 
 	/* If we have > 1 VGA cards, then we need to arbitrate access
 	 * to the common VGA resources.
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index e0d7245..36a665f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3584,7 +3584,7 @@
 extern void intel_i2c_reset(struct drm_device *dev);
 
 /* intel_bios.c */
-int intel_bios_init(struct drm_i915_private *dev_priv);
+void intel_bios_init(struct drm_i915_private *dev_priv);
 bool intel_bios_is_valid_vbt(const void *buf, size_t size);
 bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv);
 bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin);
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index cf25607..4ac36e3 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -1332,6 +1332,7 @@
 	return;
 }
 
+/* Common defaults which may be overridden by VBT. */
 static void
 init_vbt_defaults(struct drm_i915_private *dev_priv)
 {
@@ -1368,6 +1369,18 @@
 			&dev_priv->vbt.ddi_port_info[port];
 
 		info->hdmi_level_shift = HDMI_LEVEL_SHIFT_UNKNOWN;
+	}
+}
+
+/* Defaults to initialize only if there is no VBT. */
+static void
+init_vbt_missing_defaults(struct drm_i915_private *dev_priv)
+{
+	enum port port;
+
+	for (port = PORT_A; port < I915_MAX_PORTS; port++) {
+		struct ddi_vbt_port_info *info =
+			&dev_priv->vbt.ddi_port_info[port];
 
 		info->supports_dvi = (port != PORT_A && port != PORT_E);
 		info->supports_hdmi = info->supports_dvi;
@@ -1450,36 +1463,35 @@
  * intel_bios_init - find VBT and initialize settings from the BIOS
  * @dev_priv: i915 device instance
  *
- * Loads the Video BIOS and checks that the VBT exists.  Sets scratch registers
- * to appropriate values.
- *
- * Returns 0 on success, nonzero on failure.
+ * Parse and initialize settings from the Video BIOS Tables (VBT). If the VBT
+ * was not found in ACPI OpRegion, try to find it in PCI ROM first. Also
+ * initialize some defaults if the VBT is not present at all.
  */
-int
-intel_bios_init(struct drm_i915_private *dev_priv)
+void intel_bios_init(struct drm_i915_private *dev_priv)
 {
 	struct pci_dev *pdev = dev_priv->drm.pdev;
 	const struct vbt_header *vbt = dev_priv->opregion.vbt;
 	const struct bdb_header *bdb;
 	u8 __iomem *bios = NULL;
 
-	if (HAS_PCH_NOP(dev_priv))
-		return -ENODEV;
+	if (HAS_PCH_NOP(dev_priv)) {
+		DRM_DEBUG_KMS("Skipping VBT init due to disabled display.\n");
+		return;
+	}
 
 	init_vbt_defaults(dev_priv);
 
+	/* If the OpRegion does not have VBT, look in PCI ROM. */
 	if (!vbt) {
 		size_t size;
 
 		bios = pci_map_rom(pdev, &size);
 		if (!bios)
-			return -1;
+			goto out;
 
 		vbt = find_vbt(bios, size);
-		if (!vbt) {
-			pci_unmap_rom(pdev, bios);
-			return -1;
-		}
+		if (!vbt)
+			goto out;
 
 		DRM_DEBUG_KMS("Found valid VBT in PCI ROM\n");
 	}
@@ -1504,10 +1516,14 @@
 	parse_mipi_sequence(dev_priv, bdb);
 	parse_ddi_ports(dev_priv, bdb);
 
+out:
+	if (!vbt) {
+		DRM_INFO("Failed to find VBIOS tables (VBT)\n");
+		init_vbt_missing_defaults(dev_priv);
+	}
+
 	if (bios)
 		pci_unmap_rom(pdev, bios);
-
-	return 0;
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 9ded825..1ac5c6c 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -166,6 +166,7 @@
 	msm_gem_prime.o \
 	msm_gem_submit.o \
 	msm_gem_shrinker.o \
+	msm_gem_vma.o \
 	msm_gpu.o \
 	msm_iommu.o \
 	msm_smmu.o \
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
index fd266ed..156abf0 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -583,7 +583,7 @@
 #endif
 	}
 
-	if (!gpu->mmu) {
+	if (!gpu->aspace) {
 		/* TODO we think it is possible to configure the GPU to
 		 * restrict access to VRAM carveout.  But the required
 		 * registers are unknown.  For now just bail out and
diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
index d0d3c7b..2dc9412 100644
--- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
@@ -672,7 +672,7 @@
 #endif
 	}
 
-	if (!gpu->mmu) {
+	if (!gpu->aspace) {
 		/* TODO we think it is possible to configure the GPU to
 		 * restrict access to VRAM carveout.  But the required
 		 * registers are unknown.  For now just bail out and
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index f386f46..b468d2a 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -381,7 +381,7 @@
 		return ret;
 	}
 
-	mmu = gpu->mmu;
+	mmu = gpu->aspace->mmu;
 	if (mmu) {
 		ret = mmu->funcs->attach(mmu, iommu_ports,
 				ARRAY_SIZE(iommu_ports));
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 888c511..706398db2 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -21,7 +21,6 @@
 #include "dp_ctrl.h"
 
 #define DP_KHZ_TO_HZ 1000
-#define DP_CRYPTO_CLK_RATE_KHZ 180000
 
 #define DP_CTRL_INTR_READY_FOR_VIDEO     BIT(0)
 #define DP_CTRL_INTR_IDLE_PATTERN_SENT  BIT(3)
@@ -66,12 +65,7 @@
 	struct completion video_comp;
 	struct completion irq_comp;
 
-	bool hpd_irq_on;
-	bool power_on;
-	bool sink_info_read;
-	bool cont_splash;
 	bool psm_enabled;
-	bool initialized;
 	bool orientation;
 
 	u32 pixel_rate;
@@ -712,9 +706,6 @@
 {
 	int ret = 0;
 
-	if (ctrl->cont_splash)
-		return ret;
-
 	ret = wait_for_completion_timeout(&ctrl->video_comp, HZ / 2);
 	if (ret <= 0) {
 		pr_err("Link Train timedout\n");
@@ -1042,8 +1033,6 @@
 	dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
 		drm_dp_bw_code_to_link_rate(ctrl->link->link_rate));
 
-	dp_ctrl_set_clock_rate(ctrl, "ctrl_crypto_clk", DP_CRYPTO_CLK_RATE_KHZ);
-
 	dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->pixel_rate);
 
 	ret = ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, true);
@@ -1072,11 +1061,6 @@
 
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
-	if (ctrl->initialized) {
-		pr_debug("host init done already\n");
-		return 0;
-	}
-
 	ctrl->orientation = flip;
 	catalog = ctrl->catalog;
 
@@ -1084,8 +1068,6 @@
 	catalog->phy_reset(ctrl->catalog);
 	catalog->enable_irq(ctrl->catalog, true);
 
-	ctrl->initialized = true;
-
 	return 0;
 }
 
@@ -1107,11 +1089,6 @@
 
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
-	if (!ctrl->initialized) {
-		pr_debug("host deinit done already\n");
-		return;
-	}
-
 	ctrl->catalog->enable_irq(ctrl->catalog, false);
 	ctrl->catalog->reset(ctrl->catalog);
 
@@ -1120,7 +1097,6 @@
 
 	dp_ctrl_disable_mainlink_clocks(ctrl);
 
-	ctrl->initialized = false;
 	pr_debug("Host deinitialized successfully\n");
 }
 
@@ -1154,8 +1130,6 @@
 
 		reinit_completion(&ctrl->idle_comp);
 
-		ctrl->power_on = true;
-
 		if (ctrl->psm_enabled) {
 			ret = ctrl->link->send_psm_request(ctrl->link, false);
 			if (ret) {
@@ -1175,9 +1149,6 @@
 {
 	int ret = 0;
 
-	if (ctrl->cont_splash)
-		goto link_training;
-
 	ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true);
 	ctrl->catalog->hpd_config(ctrl->catalog, true);
 
@@ -1202,28 +1173,18 @@
 
 	if (ctrl->psm_enabled)
 		ret = ctrl->link->send_psm_request(ctrl->link, false);
-link_training:
-	ctrl->power_on = true;
 
 	while (-EAGAIN == dp_ctrl_setup_main_link(ctrl, true))
 		pr_debug("MAIN LINK TRAINING RETRY\n");
 
-	ctrl->cont_splash = 0;
-
-	ctrl->power_on = true;
 	pr_debug("End-\n");
 
 exit:
 	return ret;
 }
 
-static int dp_ctrl_off_irq(struct dp_ctrl_private *ctrl)
+static void dp_ctrl_off_irq(struct dp_ctrl_private *ctrl)
 {
-	if (!ctrl->power_on) {
-		pr_debug("ctrl already powered off\n");
-		return 0;
-	}
-
 	ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
 
 	/* Make sure DP mainlink and audio engines are disabled */
@@ -1231,28 +1192,15 @@
 
 	complete_all(&ctrl->irq_comp);
 	pr_debug("end\n");
-
-	return 0;
 }
 
-static int dp_ctrl_off_hpd(struct dp_ctrl_private *ctrl)
+static void dp_ctrl_off_hpd(struct dp_ctrl_private *ctrl)
 {
-	if (!ctrl->power_on) {
-		pr_debug("panel already powered off\n");
-		return 0;
-	}
-
 	ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
-
-	ctrl->power_on = false;
-	ctrl->sink_info_read = false;
-
 	pr_debug("DP off done\n");
-
-	return 0;
 }
 
-static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
+static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool hpd_irq)
 {
 	int rc = 0;
 	struct dp_ctrl_private *ctrl;
@@ -1264,7 +1212,7 @@
 
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
-	if (ctrl->hpd_irq_on)
+	if (hpd_irq)
 		rc = dp_ctrl_on_irq(ctrl, false);
 	else
 		rc = dp_ctrl_on_hpd(ctrl);
@@ -1272,24 +1220,19 @@
 	return rc;
 }
 
-static int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
+static void dp_ctrl_off(struct dp_ctrl *dp_ctrl, bool hpd_irq)
 {
-	int rc = 0;
 	struct dp_ctrl_private *ctrl;
 
-	if (!dp_ctrl) {
-		rc = -EINVAL;
-		goto end;
-	}
+	if (!dp_ctrl)
+		return;
 
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
-	if (ctrl->hpd_irq_on)
-		rc = dp_ctrl_off_irq(ctrl);
+	if (hpd_irq)
+		dp_ctrl_off_irq(ctrl);
 	else
-		rc = dp_ctrl_off_hpd(ctrl);
-end:
-	return rc;
+		dp_ctrl_off_hpd(ctrl);
 }
 
 static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 5efe505..474e0ad 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -25,8 +25,8 @@
 struct dp_ctrl {
 	int (*init)(struct dp_ctrl *dp_ctrl, bool flip);
 	void (*deinit)(struct dp_ctrl *dp_ctrl);
-	int (*on)(struct dp_ctrl *dp_ctrl);
-	int (*off)(struct dp_ctrl *dp_ctrl);
+	int (*on)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
+	void (*off)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
 	void (*push_idle)(struct dp_ctrl *dp_ctrl);
 	void (*isr)(struct dp_ctrl *dp_ctrl);
 };
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index d3f6bca..a3c6f58 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -38,6 +38,11 @@
 	char *name;
 	int irq;
 
+	/* state variables */
+	bool core_initialized;
+	bool power_on;
+	bool hpd_irq_on;
+
 	struct platform_device *pdev;
 	struct dentry *root;
 	struct mutex lock;
@@ -255,30 +260,63 @@
 
 static int dp_display_process_hpd_high(struct dp_display_private *dp)
 {
-	int rc;
+	int rc = 0;
 
 	rc = dp->panel->read_dpcd(dp->panel);
 	if (rc)
-		goto end;
+		return rc;
 
 	sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc,
 		(void **)&dp->panel->edid_ctrl);
 
-	return 0;
-end:
+	dp->dp_display.is_connected = true;
+	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+
 	return rc;
 }
 
-static int dp_display_process_hpd_low(struct dp_display_private *dp)
+static void dp_display_host_init(struct dp_display_private *dp)
+{
+	bool flip = false;
+
+	if (dp->core_initialized) {
+		pr_debug("DP core already initialized\n");
+		return;
+	}
+
+	if (dp->usbpd->orientation == ORIENTATION_CC2)
+		flip = true;
+
+	dp->power->init(dp->power, flip);
+	dp->ctrl->init(dp->ctrl, flip);
+	dp->aux->init(dp->aux, dp->parser->aux_cfg);
+	enable_irq(dp->irq);
+	dp->core_initialized = true;
+}
+
+static void dp_display_host_deinit(struct dp_display_private *dp)
+{
+	if (!dp->core_initialized) {
+		pr_debug("DP core already off\n");
+		return;
+	}
+
+	dp->aux->deinit(dp->aux);
+	dp->ctrl->deinit(dp->ctrl);
+	dp->power->deinit(dp->power);
+	disable_irq(dp->irq);
+	dp->core_initialized = false;
+}
+
+static void dp_display_process_hpd_low(struct dp_display_private *dp)
 {
 	dp->dp_display.is_connected = false;
-	return 0;
+	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
 }
 
 static int dp_display_usbpd_configure_cb(struct device *dev)
 {
 	int rc = 0;
-	bool flip = false;
 	struct dp_display_private *dp;
 
 	if (!dev) {
@@ -295,19 +333,9 @@
 	}
 
 	mutex_lock(&dp->lock);
-
-	if (dp->usbpd->orientation == ORIENTATION_CC2)
-		flip = true;
-
-	dp->power->init(dp->power, flip);
-	dp->ctrl->init(dp->ctrl, flip);
-	dp->aux->init(dp->aux, dp->parser->aux_cfg);
-	enable_irq(dp->irq);
-
+	dp_display_host_init(dp);
 	if (dp->usbpd->hpd_high)
 		dp_display_process_hpd_high(dp);
-	dp->dp_display.is_connected = true;
-
 	mutex_unlock(&dp->lock);
 end:
 	return rc;
@@ -332,10 +360,23 @@
 	}
 
 	mutex_lock(&dp->lock);
-	dp->dp_display.is_connected = false;
-	disable_irq(dp->irq);
-	mutex_unlock(&dp->lock);
 
+	dp->dp_display.is_connected = false;
+	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+
+	/*
+	 * If a cable/dongle is connected to the TX device but
+	 * no sink device is connected, we call host
+	 * initialization where orientation settings are
+	 * configured. When the cable/dongle is disconnect,
+	 * call host de-initialization to make sure
+	 * we re-configure the orientation settings during
+	 * the next connect event.
+	 */
+	if (!dp->power_on && dp->core_initialized)
+		dp_display_host_deinit(dp);
+
+	mutex_unlock(&dp->lock);
 end:
 	return rc;
 }
@@ -347,31 +388,36 @@
 
 	if (!dev) {
 		pr_err("invalid dev\n");
-		rc = -EINVAL;
-		goto end;
+		return -EINVAL;
 	}
 
 	dp = dev_get_drvdata(dev);
 	if (!dp) {
 		pr_err("no driver data found\n");
-		rc = -ENODEV;
-		goto end;
+		return -ENODEV;
 	}
 
 	mutex_lock(&dp->lock);
 
 	if (dp->usbpd->hpd_irq) {
-		if (!dp->link->process_request(dp->link))
+		dp->hpd_irq_on = true;
+		rc = dp->link->process_request(dp->link);
+		dp->hpd_irq_on = false;
+		if (!rc)
 			goto end;
 	}
 
-	if (dp->usbpd->hpd_high)
-		dp_display_process_hpd_high(dp);
-	else
+	if (!dp->usbpd->hpd_high) {
 		dp_display_process_hpd_low(dp);
+		goto end;
+	}
 
-	mutex_unlock(&dp->lock);
+	if (dp->usbpd->alt_mode_cfg_done) {
+		dp_display_host_init(dp);
+		dp_display_process_hpd_high(dp);
+	}
 end:
+	mutex_unlock(&dp->lock);
 	return rc;
 }
 
@@ -492,7 +538,9 @@
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
 	mutex_lock(&dp->lock);
-	dp->ctrl->on(dp->ctrl);
+	rc = dp->ctrl->on(dp->ctrl, dp->hpd_irq_on);
+	if (!rc)
+		dp->power_on = true;
 	mutex_unlock(&dp->lock);
 error:
 	return rc;
@@ -517,9 +565,7 @@
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
 	mutex_lock(&dp->lock);
-
-	dp->ctrl->off(dp->ctrl);
-
+	dp->ctrl->push_idle(dp->ctrl);
 	mutex_unlock(&dp->lock);
 error:
 	return rc;
@@ -539,11 +585,9 @@
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
 	mutex_lock(&dp->lock);
-
-	dp->aux->deinit(dp->aux);
-	dp->ctrl->deinit(dp->ctrl);
-	dp->power->deinit(dp->power);
-
+	dp->ctrl->off(dp->ctrl, dp->hpd_irq_on);
+	dp_display_host_deinit(dp);
+	dp->power_on = false;
 	mutex_unlock(&dp->lock);
 error:
 	return rc;
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index 722c436..e81bbb3 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -494,8 +494,7 @@
 			ctrl_clk_index++;
 
 			if (!strcmp(clk_name, "ctrl_link_clk") ||
-			    !strcmp(clk_name, "ctrl_pixel_clk") ||
-			    !strcmp(clk_name, "ctrl_crypto_clk"))
+			    !strcmp(clk_name, "ctrl_pixel_clk"))
 				clk->type = DSS_CLK_PCLK;
 			else
 				clk->type = DSS_CLK_AHB;
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index 089177f..6ef8266 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -345,8 +345,12 @@
 		pd->vdo = *vdos;
 		dp_usbpd_get_status(pd);
 
-		if (pd->dp_cb && pd->dp_cb->attention)
+		if (pd->dp_cb && pd->dp_cb->attention) {
 			pd->dp_cb->attention(pd->dev);
+
+			if (!pd->dp_usbpd.alt_mode_cfg_done)
+				dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE);
+		}
 		break;
 	case DP_USBPD_VDM_STATUS:
 		pd->vdo = *vdos;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index da7a7c0..e2a348d 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -9,7 +9,6 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
 #define pr_fmt(fmt)	"dsi-ctrl:[%s] " fmt, __func__
@@ -31,6 +30,8 @@
 #include "dsi_pwr.h"
 #include "dsi_catalog.h"
 
+#include "sde_dbg.h"
+
 #define DSI_CTRL_DEFAULT_LABEL "MDSS DSI CTRL"
 
 #define DSI_CTRL_TX_TO_MS     200
@@ -199,6 +200,7 @@
 {
 	int rc = 0;
 	struct dentry *dir, *state_file, *reg_dump;
+	char dbg_name[DSI_DEBUG_NAME_LEN];
 
 	dir = debugfs_create_dir(dsi_ctrl->name, parent);
 	if (IS_ERR_OR_NULL(dir)) {
@@ -233,6 +235,11 @@
 	}
 
 	dsi_ctrl->debugfs_root = dir;
+
+	snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_ctrl",
+						dsi_ctrl->cell_index);
+	sde_dbg_reg_register_base(dbg_name, dsi_ctrl->hw.base,
+				msm_iomap_size(dsi_ctrl->pdev, "dsi_ctrl"));
 error_remove_dir:
 	debugfs_remove(dir);
 error:
@@ -876,7 +883,7 @@
 			  const struct mipi_dsi_msg *msg,
 			  u32 flags)
 {
-	int rc = 0;
+	int rc = 0, ret = 0;
 	struct mipi_dsi_packet packet;
 	struct dsi_ctrl_cmd_dma_fifo_info cmd;
 	struct dsi_ctrl_cmd_dma_info cmd_mem;
@@ -940,42 +947,59 @@
 	hw_flags |= (flags & DSI_CTRL_CMD_DEFER_TRIGGER) ?
 			DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER : 0;
 
-	if (!(flags & DSI_CTRL_CMD_DEFER_TRIGGER))
-		reinit_completion(&dsi_ctrl->int_info.cmd_dma_done);
-
-	if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
-		dsi_ctrl->hw.ops.kickoff_command(&dsi_ctrl->hw,
-						&cmd_mem,
-						hw_flags);
-	} else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
-		dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw,
-						      &cmd,
-						      hw_flags);
+	if (flags & DSI_CTRL_CMD_DEFER_TRIGGER) {
+		if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
+			dsi_ctrl->hw.ops.kickoff_command(&dsi_ctrl->hw,
+							&cmd_mem,
+							hw_flags);
+		} else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
+			dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw,
+							      &cmd,
+							      hw_flags);
+		}
 	}
 
 	if (!(flags & DSI_CTRL_CMD_DEFER_TRIGGER)) {
-		u32 retry = 10;
-		u32 status = 0;
-		u64 error = 0;
-		u32 mask = (DSI_CMD_MODE_DMA_DONE);
+		dsi_ctrl_enable_status_interrupt(dsi_ctrl,
+					DSI_SINT_CMD_MODE_DMA_DONE, NULL);
+		reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done);
 
-		while ((status == 0) && (retry > 0)) {
-			udelay(1000);
-			status = dsi_ctrl->hw.ops.get_interrupt_status(
-								&dsi_ctrl->hw);
-			error = dsi_ctrl->hw.ops.get_error_status(
-								&dsi_ctrl->hw);
-			status &= mask;
-			retry--;
-			dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw,
-								status);
-			dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
-							    error);
+		if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
+			dsi_ctrl->hw.ops.kickoff_command(&dsi_ctrl->hw,
+						      &cmd_mem,
+						      hw_flags);
+		} else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
+			dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw,
+							      &cmd,
+							      hw_flags);
 		}
-		pr_debug("INT STATUS = %x, retry = %d\n", status, retry);
-		if (retry == 0)
-			pr_err("[DSI_%d]Command transfer failed\n",
-			       dsi_ctrl->cell_index);
+
+		ret = wait_for_completion_timeout(
+				&dsi_ctrl->irq_info.cmd_dma_done,
+				msecs_to_jiffies(DSI_CTRL_TX_TO_MS));
+
+		if (ret == 0) {
+			u32 status = 0;
+			u32 mask = DSI_CMD_MODE_DMA_DONE;
+
+			if (status & mask) {
+				status |= (DSI_CMD_MODE_DMA_DONE |
+						DSI_BTA_DONE);
+				dsi_ctrl->hw.ops.clear_interrupt_status(
+								&dsi_ctrl->hw,
+								status);
+				dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+						DSI_SINT_CMD_MODE_DMA_DONE);
+				complete_all(&dsi_ctrl->irq_info.cmd_dma_done);
+				pr_warn("dma_tx done but irq not triggered\n");
+			} else {
+				rc = -ETIMEDOUT;
+				dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+						DSI_SINT_CMD_MODE_DMA_DONE);
+				pr_err("[DSI_%d]Command transfer failed\n",
+						dsi_ctrl->cell_index);
+			}
+		}
 
 		dsi_ctrl->hw.ops.reset_cmd_fifo(&dsi_ctrl->hw);
 	}
@@ -1144,15 +1168,6 @@
 	return rc;
 }
 
-int dsi_ctrl_intr_deinit(struct dsi_ctrl *dsi_ctrl)
-{
-	struct dsi_ctrl_interrupts *ints = &dsi_ctrl->int_info;
-
-	devm_free_irq(&dsi_ctrl->pdev->dev, ints->irq, dsi_ctrl);
-
-	return 0;
-}
-
 static int dsi_ctrl_buffer_deinit(struct dsi_ctrl *dsi_ctrl)
 {
 	if (dsi_ctrl->tx_cmd_buf) {
@@ -1251,6 +1266,10 @@
 
 	dsi_ctrl->cell_index = index;
 	dsi_ctrl->version = version;
+	dsi_ctrl->irq_info.irq_num = -1;
+	dsi_ctrl->irq_info.irq_stat_mask = 0x0;
+
+	spin_lock_init(&dsi_ctrl->irq_info.irq_lock);
 
 	dsi_ctrl->name = of_get_property(pdev->dev.of_node, "label", NULL);
 	if (!dsi_ctrl->name)
@@ -1296,8 +1315,7 @@
 
 	dsi_ctrl->pdev = pdev;
 	platform_set_drvdata(pdev, dsi_ctrl);
-
-	pr_debug("Probe successful for %s\n", dsi_ctrl->name);
+	pr_info("Probe successful for %s\n", dsi_ctrl->name);
 
 	return 0;
 
@@ -1670,6 +1688,236 @@
 	return 0;
 }
 
+static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl,
+				unsigned long int error)
+{
+	pr_err("%s: %lu\n", __func__, error);
+
+	/* DTLN PHY error */
+	if (error & 0x3000e00)
+		if (dsi_ctrl->hw.ops.clear_error_status)
+			dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
+					0x3000e00);
+
+	/* DSI FIFO OVERFLOW error */
+	if (error & 0xf0000) {
+		if (dsi_ctrl->hw.ops.clear_error_status)
+			dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
+					0xf0000);
+	}
+
+	/* DSI FIFO UNDERFLOW error */
+	if (error & 0xf00000) {
+		if (dsi_ctrl->hw.ops.clear_error_status)
+			dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
+					0xf00000);
+	}
+
+	/* DSI PLL UNLOCK error */
+	if (error & BIT(8))
+		if (dsi_ctrl->hw.ops.clear_error_status)
+			dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
+					BIT(8));
+}
+
+/**
+ * dsi_ctrl_isr - interrupt service routine for DSI CTRL component
+ * @irq: Incoming IRQ number
+ * @ptr: Pointer to user data structure (struct dsi_ctrl)
+ * Returns: IRQ_HANDLED if no further action required
+ */
+static irqreturn_t dsi_ctrl_isr(int irq, void *ptr)
+{
+	struct dsi_ctrl *dsi_ctrl;
+	struct dsi_event_cb_info cb_info;
+	unsigned long flags;
+	uint32_t cell_index, status, i;
+	uint64_t errors;
+
+	if (!ptr)
+		return IRQ_NONE;
+	dsi_ctrl = ptr;
+
+	/* clear status interrupts */
+	if (dsi_ctrl->hw.ops.get_interrupt_status)
+		status = dsi_ctrl->hw.ops.get_interrupt_status(&dsi_ctrl->hw);
+	else
+		status = 0x0;
+
+	if (dsi_ctrl->hw.ops.clear_interrupt_status)
+		dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, status);
+
+	spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags);
+	cell_index = dsi_ctrl->cell_index;
+	spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags);
+
+	/* clear error interrupts */
+	if (dsi_ctrl->hw.ops.get_error_status)
+		errors = dsi_ctrl->hw.ops.get_error_status(&dsi_ctrl->hw);
+	else
+		errors = 0x0;
+
+	if (errors) {
+		/* handle DSI error recovery */
+		dsi_ctrl_handle_error_status(dsi_ctrl, errors);
+		if (dsi_ctrl->hw.ops.clear_error_status)
+			dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
+							errors);
+	}
+
+	if (status & DSI_CMD_MODE_DMA_DONE) {
+		dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+					DSI_SINT_CMD_MODE_DMA_DONE);
+		complete_all(&dsi_ctrl->irq_info.cmd_dma_done);
+	}
+
+	if (status & DSI_CMD_FRAME_DONE) {
+		dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+					DSI_SINT_CMD_FRAME_DONE);
+		complete_all(&dsi_ctrl->irq_info.cmd_frame_done);
+	}
+
+	if (status & DSI_VIDEO_MODE_FRAME_DONE) {
+		dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+					DSI_SINT_VIDEO_MODE_FRAME_DONE);
+		complete_all(&dsi_ctrl->irq_info.vid_frame_done);
+	}
+
+	if (status & DSI_BTA_DONE) {
+		dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+					DSI_SINT_BTA_DONE);
+		complete_all(&dsi_ctrl->irq_info.bta_done);
+	}
+
+	for (i = 0; status && i < DSI_STATUS_INTERRUPT_COUNT; ++i) {
+		if (status & 0x1) {
+			spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags);
+			cb_info = dsi_ctrl->irq_info.irq_stat_cb[i];
+			spin_unlock_irqrestore(
+					&dsi_ctrl->irq_info.irq_lock, flags);
+
+			if (cb_info.event_cb)
+				(void)cb_info.event_cb(cb_info.event_usr_ptr,
+						cb_info.event_idx,
+						cell_index, irq, 0, 0, 0);
+		}
+		status >>= 1;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * _dsi_ctrl_setup_isr - register ISR handler
+ * @dsi_ctrl: Pointer to associated dsi_ctrl structure
+ * Returns: Zero on success
+ */
+static int dsi_ctrl_setup_isr(struct dsi_ctrl *dsi_ctrl)
+{
+	int irq_num, rc;
+
+	if (!dsi_ctrl)
+		return -EINVAL;
+	if (dsi_ctrl->irq_info.irq_num != -1)
+		return 0;
+
+	init_completion(&dsi_ctrl->irq_info.cmd_dma_done);
+	init_completion(&dsi_ctrl->irq_info.vid_frame_done);
+	init_completion(&dsi_ctrl->irq_info.cmd_frame_done);
+	init_completion(&dsi_ctrl->irq_info.bta_done);
+
+	irq_num = platform_get_irq(dsi_ctrl->pdev, 0);
+	if (irq_num < 0) {
+		pr_err("[DSI_%d] Failed to get IRQ number, %d\n",
+				dsi_ctrl->cell_index, irq_num);
+		rc = irq_num;
+	} else {
+		rc = devm_request_threaded_irq(&dsi_ctrl->pdev->dev, irq_num,
+				dsi_ctrl_isr, NULL, 0, "dsi_ctrl", dsi_ctrl);
+		if (rc) {
+			pr_err("[DSI_%d] Failed to request IRQ, %d\n",
+					dsi_ctrl->cell_index, rc);
+		} else {
+			dsi_ctrl->irq_info.irq_num = irq_num;
+			disable_irq_nosync(irq_num);
+
+			pr_info("[DSI_%d] IRQ %d registered\n",
+					dsi_ctrl->cell_index, irq_num);
+		}
+	}
+	return rc;
+}
+
+/**
+ * _dsi_ctrl_destroy_isr - unregister ISR handler
+ * @dsi_ctrl: Pointer to associated dsi_ctrl structure
+ */
+static void _dsi_ctrl_destroy_isr(struct dsi_ctrl *dsi_ctrl)
+{
+	if (!dsi_ctrl || !dsi_ctrl->pdev || dsi_ctrl->irq_info.irq_num < 0)
+		return;
+
+	if (dsi_ctrl->irq_info.irq_num != -1) {
+		devm_free_irq(&dsi_ctrl->pdev->dev,
+				dsi_ctrl->irq_info.irq_num, dsi_ctrl);
+		dsi_ctrl->irq_info.irq_num = -1;
+	}
+}
+
+void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
+		uint32_t intr_idx, struct dsi_event_cb_info *event_info)
+{
+	unsigned long flags;
+
+	if (!dsi_ctrl || dsi_ctrl->irq_info.irq_num == -1 ||
+			intr_idx >= DSI_STATUS_INTERRUPT_COUNT)
+		return;
+
+	spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags);
+
+	if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx] == 0) {
+		/* enable irq on first request */
+		if (dsi_ctrl->irq_info.irq_stat_mask == 0)
+			enable_irq(dsi_ctrl->irq_info.irq_num);
+
+		/* update hardware mask */
+		dsi_ctrl->irq_info.irq_stat_mask |= BIT(intr_idx);
+		dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw,
+				dsi_ctrl->irq_info.irq_stat_mask);
+	}
+	++(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]);
+
+	if (event_info)
+		dsi_ctrl->irq_info.irq_stat_cb[intr_idx] = *event_info;
+
+	spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags);
+}
+
+void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
+		uint32_t intr_idx)
+{
+	unsigned long flags;
+
+	if (!dsi_ctrl || dsi_ctrl->irq_info.irq_num == -1 ||
+			intr_idx >= DSI_STATUS_INTERRUPT_COUNT)
+		return;
+
+	spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags);
+
+	if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx])
+		if (--(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]) == 0) {
+			dsi_ctrl->irq_info.irq_stat_mask &= ~BIT(intr_idx);
+			dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw,
+					dsi_ctrl->irq_info.irq_stat_mask);
+
+			/* don't need irq if no lines are enabled */
+			if (dsi_ctrl->irq_info.irq_stat_mask == 0)
+				disable_irq_nosync(dsi_ctrl->irq_info.irq_num);
+		}
+
+	spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags);
+}
+
 /**
  * dsi_ctrl_host_init() - Initialize DSI host hardware.
  * @dsi_ctrl:        DSI controller handle.
@@ -1722,7 +1970,7 @@
 					  &dsi_ctrl->host_config.video_timing);
 	}
 
-
+	dsi_ctrl_setup_isr(dsi_ctrl);
 
 	dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0);
 	dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0);
@@ -1770,6 +2018,8 @@
 
 	mutex_lock(&dsi_ctrl->ctrl_lock);
 
+	_dsi_ctrl_destroy_isr(dsi_ctrl);
+
 	rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x0);
 	if (rc) {
 		pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
@@ -1926,7 +2176,7 @@
  */
 int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
 {
-	int rc = 0;
+	int rc = 0, ret = 0;
 	u32 status = 0;
 	u32 mask = (DSI_CMD_MODE_DMA_DONE);
 
@@ -1937,27 +2187,43 @@
 
 	mutex_lock(&dsi_ctrl->ctrl_lock);
 
-	reinit_completion(&dsi_ctrl->int_info.cmd_dma_done);
-
-	dsi_ctrl->hw.ops.trigger_command_dma(&dsi_ctrl->hw);
+	if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER))
+		dsi_ctrl->hw.ops.trigger_command_dma(&dsi_ctrl->hw);
 
 	if ((flags & DSI_CTRL_CMD_BROADCAST) &&
-	    (flags & DSI_CTRL_CMD_BROADCAST_MASTER)) {
-		u32 retry = 10;
+		(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) {
+		dsi_ctrl_enable_status_interrupt(dsi_ctrl,
+					DSI_SINT_CMD_MODE_DMA_DONE, NULL);
+		reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done);
 
-		while ((status == 0) && (retry > 0)) {
-			udelay(1000);
+		/* trigger command */
+		dsi_ctrl->hw.ops.trigger_command_dma(&dsi_ctrl->hw);
+
+		ret = wait_for_completion_timeout(
+				&dsi_ctrl->irq_info.cmd_dma_done,
+				msecs_to_jiffies(DSI_CTRL_TX_TO_MS));
+
+		if (ret == 0) {
 			status = dsi_ctrl->hw.ops.get_interrupt_status(
 								&dsi_ctrl->hw);
-			status &= mask;
-			retry--;
-			dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw,
+			if (status & mask) {
+				status |= (DSI_CMD_MODE_DMA_DONE |
+						DSI_BTA_DONE);
+				dsi_ctrl->hw.ops.clear_interrupt_status(
+								&dsi_ctrl->hw,
 								status);
+				dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+						DSI_SINT_CMD_MODE_DMA_DONE);
+				complete_all(&dsi_ctrl->irq_info.cmd_dma_done);
+				pr_warn("dma_tx done but irq not triggered\n");
+			} else {
+				rc = -ETIMEDOUT;
+				dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+						DSI_SINT_CMD_MODE_DMA_DONE);
+				pr_err("[DSI_%d]Command transfer failed\n",
+						dsi_ctrl->cell_index);
+			}
 		}
-		pr_debug("INT STATUS = %x, retry = %d\n", status, retry);
-		if (retry == 0)
-			pr_err("[DSI_%d]Command transfer failed\n",
-			       dsi_ctrl->cell_index);
 	}
 
 	mutex_unlock(&dsi_ctrl->ctrl_lock);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index 7f36fde..ec535ce11 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -138,33 +138,26 @@
 
 /**
  * struct dsi_ctrl_interrupts - define interrupt information
- * @irq:                   IRQ id for the DSI controller.
- * @intr_lock:             Spinlock to protect access to interrupt registers.
- * @interrupt_status:      Status interrupts which need to be serviced.
- * @error_status:          Error interurpts which need to be serviced.
- * @interrupts_enabled:    Status interrupts which are enabled.
- * @errors_enabled:        Error interrupts which are enabled.
+ * @irq_lock:            Spinlock for ISR handler.
+ * @irq_num:             Linux interrupt number associated with device.
+ * @irq_stat_mask:       Hardware mask of currently enabled interrupts.
+ * @irq_stat_refcount:   Number of times each interrupt has been requested.
+ * @irq_stat_cb:         Status IRQ callback definitions.
  * @cmd_dma_done:          Completion signal for DSI_CMD_MODE_DMA_DONE interrupt
  * @vid_frame_done:        Completion signal for DSI_VIDEO_MODE_FRAME_DONE int.
  * @cmd_frame_done:        Completion signal for DSI_CMD_FRAME_DONE interrupt.
- * @interrupt_done_work:   Work item for servicing status interrupts.
- * @error_status_work:     Work item for servicing error interrupts.
  */
 struct dsi_ctrl_interrupts {
-	u32 irq;
-	spinlock_t intr_lock; /* protects access to interrupt registers */
-	u32 interrupt_status;
-	u64 error_status;
-
-	u32 interrupts_enabled;
-	u64 errors_enabled;
+	spinlock_t irq_lock;
+	int irq_num;
+	uint32_t irq_stat_mask;
+	int irq_stat_refcount[DSI_STATUS_INTERRUPT_COUNT];
+	struct dsi_event_cb_info irq_stat_cb[DSI_STATUS_INTERRUPT_COUNT];
 
 	struct completion cmd_dma_done;
 	struct completion vid_frame_done;
 	struct completion cmd_frame_done;
-
-	struct work_struct interrupt_done_work;
-	struct work_struct error_status_work;
+	struct completion bta_done;
 };
 
 /**
@@ -180,7 +173,7 @@
  * @hw:                  DSI controller hardware object.
  * @current_state:       Current driver and hardware state.
  * @clk_cb:		 Callback for DSI clock control.
- * @int_info:            Interrupt information.
+ * @irq_info:            Interrupt information.
  * @clk_info:            Clock information.
  * @clk_freq:            DSi Link clock frequency information.
  * @pwr_info:            Power information.
@@ -212,7 +205,8 @@
 	struct dsi_ctrl_state_info current_state;
 	struct clk_ctrl_cb clk_cb;
 
-	struct dsi_ctrl_interrupts int_info;
+	struct dsi_ctrl_interrupts irq_info;
+
 	/* Clock and power states */
 	struct dsi_ctrl_clk_info clk_info;
 	struct link_clk_freq clk_freq;
@@ -560,6 +554,23 @@
 			      struct dsi_clk_link_set *source_clks);
 
 /**
+ * dsi_ctrl_enable_status_interrupt() - enable status interrupts
+ * @dsi_ctrl:        DSI controller handle.
+ * @intr_idx:        Index interrupt to disable.
+ * @event_info:      Pointer to event callback definition
+ */
+void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
+		uint32_t intr_idx, struct dsi_event_cb_info *event_info);
+
+/**
+ * dsi_ctrl_disable_status_interrupt() - disable status interrupts
+ * @dsi_ctrl:        DSI controller handle.
+ * @intr_idx:        Index interrupt to disable.
+ */
+void dsi_ctrl_disable_status_interrupt(
+		struct dsi_ctrl *dsi_ctrl, uint32_t intr_idx);
+
+/**
  * dsi_ctrl_drv_register() - register platform driver for dsi controller
  */
 void dsi_ctrl_drv_register(void);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index bb72807..74be279 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -9,7 +9,6 @@
  * 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 _DSI_CTRL_HW_H_
@@ -84,6 +83,36 @@
 };
 
 /**
+ * enum dsi_status_int_index - index of interrupts generated by DSI controller
+ * @DSI_SINT_CMD_MODE_DMA_DONE:        Command mode DMA packets are sent out.
+ * @DSI_SINT_CMD_STREAM0_FRAME_DONE:   A frame of cmd mode stream0 is sent out.
+ * @DSI_SINT_CMD_STREAM1_FRAME_DONE:   A frame of cmd mode stream1 is sent out.
+ * @DSI_SINT_CMD_STREAM2_FRAME_DONE:   A frame of cmd mode stream2 is sent out.
+ * @DSI_SINT_VIDEO_MODE_FRAME_DONE:    A frame of video mode stream is sent out.
+ * @DSI_SINT_BTA_DONE:                 A BTA is completed.
+ * @DSI_SINT_CMD_FRAME_DONE:           A frame of selected cmd mode stream is
+ *                                     sent out by MDP.
+ * @DSI_SINT_DYN_REFRESH_DONE:         The dynamic refresh operation completed.
+ * @DSI_SINT_DESKEW_DONE:              The deskew calibration operation done.
+ * @DSI_SINT_DYN_BLANK_DMA_DONE:       The dynamic blankin DMA operation has
+ *                                     completed.
+ */
+enum dsi_status_int_index {
+	DSI_SINT_CMD_MODE_DMA_DONE = 0,
+	DSI_SINT_CMD_STREAM0_FRAME_DONE = 1,
+	DSI_SINT_CMD_STREAM1_FRAME_DONE = 2,
+	DSI_SINT_CMD_STREAM2_FRAME_DONE = 3,
+	DSI_SINT_VIDEO_MODE_FRAME_DONE = 4,
+	DSI_SINT_BTA_DONE = 5,
+	DSI_SINT_CMD_FRAME_DONE = 6,
+	DSI_SINT_DYN_REFRESH_DONE = 7,
+	DSI_SINT_DESKEW_DONE = 8,
+	DSI_SINT_DYN_BLANK_DMA_DONE = 9,
+
+	DSI_STATUS_INTERRUPT_COUNT
+};
+
+/**
  * enum dsi_status_int_type - status interrupts generated by DSI controller
  * @DSI_CMD_MODE_DMA_DONE:        Command mode DMA packets are sent out.
  * @DSI_CMD_STREAM0_FRAME_DONE:   A frame of command mode stream0 is sent out.
@@ -99,16 +128,89 @@
  *                                completed.
  */
 enum dsi_status_int_type {
-	DSI_CMD_MODE_DMA_DONE = BIT(0),
-	DSI_CMD_STREAM0_FRAME_DONE = BIT(1),
-	DSI_CMD_STREAM1_FRAME_DONE = BIT(2),
-	DSI_CMD_STREAM2_FRAME_DONE = BIT(3),
-	DSI_VIDEO_MODE_FRAME_DONE = BIT(4),
-	DSI_BTA_DONE = BIT(5),
-	DSI_CMD_FRAME_DONE = BIT(6),
-	DSI_DYN_REFRESH_DONE = BIT(7),
-	DSI_DESKEW_DONE = BIT(8),
-	DSI_DYN_BLANK_DMA_DONE = BIT(9)
+	DSI_CMD_MODE_DMA_DONE = BIT(DSI_SINT_CMD_MODE_DMA_DONE),
+	DSI_CMD_STREAM0_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM0_FRAME_DONE),
+	DSI_CMD_STREAM1_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM1_FRAME_DONE),
+	DSI_CMD_STREAM2_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM2_FRAME_DONE),
+	DSI_VIDEO_MODE_FRAME_DONE = BIT(DSI_SINT_VIDEO_MODE_FRAME_DONE),
+	DSI_BTA_DONE = BIT(DSI_SINT_BTA_DONE),
+	DSI_CMD_FRAME_DONE = BIT(DSI_SINT_CMD_FRAME_DONE),
+	DSI_DYN_REFRESH_DONE = BIT(DSI_SINT_DYN_REFRESH_DONE),
+	DSI_DESKEW_DONE = BIT(DSI_SINT_DESKEW_DONE),
+	DSI_DYN_BLANK_DMA_DONE = BIT(DSI_SINT_DYN_BLANK_DMA_DONE)
+};
+
+/**
+ * enum dsi_error_int_index - index of error interrupts from DSI controller
+ * @DSI_EINT_RDBK_SINGLE_ECC_ERR:        Single bit ECC error in read packet.
+ * @DSI_EINT_RDBK_MULTI_ECC_ERR:         Multi bit ECC error in read packet.
+ * @DSI_EINT_RDBK_CRC_ERR:               CRC error in read packet.
+ * @DSI_EINT_RDBK_INCOMPLETE_PKT:        Incomplete read packet.
+ * @DSI_EINT_PERIPH_ERROR_PKT:           Error packet returned from peripheral,
+ * @DSI_EINT_LP_RX_TIMEOUT:              Low power reverse transmission timeout.
+ * @DSI_EINT_HS_TX_TIMEOUT:              High speed fwd transmission timeout.
+ * @DSI_EINT_BTA_TIMEOUT:                BTA timeout.
+ * @DSI_EINT_PLL_UNLOCK:                 PLL has unlocked.
+ * @DSI_EINT_DLN0_ESC_ENTRY_ERR:         Incorrect LP Rx escape entry.
+ * @DSI_EINT_DLN0_ESC_SYNC_ERR:          LP Rx data is not byte aligned.
+ * @DSI_EINT_DLN0_LP_CONTROL_ERR:        Incorrect LP Rx state sequence.
+ * @DSI_EINT_PENDING_HS_TX_TIMEOUT:      Pending High-speed transfer timeout.
+ * @DSI_EINT_INTERLEAVE_OP_CONTENTION:   Interleave operation contention.
+ * @DSI_EINT_CMD_DMA_FIFO_UNDERFLOW:     Command mode DMA FIFO underflow.
+ * @DSI_EINT_CMD_MDP_FIFO_UNDERFLOW:     Command MDP FIFO underflow (failed to
+ *                                       receive one complete line from MDP).
+ * @DSI_EINT_DLN0_HS_FIFO_OVERFLOW:      High speed FIFO data lane 0 overflows.
+ * @DSI_EINT_DLN1_HS_FIFO_OVERFLOW:      High speed FIFO data lane 1 overflows.
+ * @DSI_EINT_DLN2_HS_FIFO_OVERFLOW:      High speed FIFO data lane 2 overflows.
+ * @DSI_EINT_DLN3_HS_FIFO_OVERFLOW:      High speed FIFO data lane 3 overflows.
+ * @DSI_EINT_DLN0_HS_FIFO_UNDERFLOW:     High speed FIFO data lane 0 underflows.
+ * @DSI_EINT_DLN1_HS_FIFO_UNDERFLOW:     High speed FIFO data lane 1 underflows.
+ * @DSI_EINT_DLN2_HS_FIFO_UNDERFLOW:     High speed FIFO data lane 2 underflows.
+ * @DSI_EINT_DLN3_HS_FIFO_UNDERFLOW:     High speed FIFO data lane 3 undeflows.
+ * @DSI_EINT_DLN0_LP0_CONTENTION:        PHY level contention while lane 0 low.
+ * @DSI_EINT_DLN1_LP0_CONTENTION:        PHY level contention while lane 1 low.
+ * @DSI_EINT_DLN2_LP0_CONTENTION:        PHY level contention while lane 2 low.
+ * @DSI_EINT_DLN3_LP0_CONTENTION:        PHY level contention while lane 3 low.
+ * @DSI_EINT_DLN0_LP1_CONTENTION:        PHY level contention while lane 0 high.
+ * @DSI_EINT_DLN1_LP1_CONTENTION:        PHY level contention while lane 1 high.
+ * @DSI_EINT_DLN2_LP1_CONTENTION:        PHY level contention while lane 2 high.
+ * @DSI_EINT_DLN3_LP1_CONTENTION:        PHY level contention while lane 3 high.
+ */
+enum dsi_error_int_index {
+	DSI_EINT_RDBK_SINGLE_ECC_ERR = 0,
+	DSI_EINT_RDBK_MULTI_ECC_ERR = 1,
+	DSI_EINT_RDBK_CRC_ERR = 2,
+	DSI_EINT_RDBK_INCOMPLETE_PKT = 3,
+	DSI_EINT_PERIPH_ERROR_PKT = 4,
+	DSI_EINT_LP_RX_TIMEOUT = 5,
+	DSI_EINT_HS_TX_TIMEOUT = 6,
+	DSI_EINT_BTA_TIMEOUT = 7,
+	DSI_EINT_PLL_UNLOCK = 8,
+	DSI_EINT_DLN0_ESC_ENTRY_ERR = 9,
+	DSI_EINT_DLN0_ESC_SYNC_ERR = 10,
+	DSI_EINT_DLN0_LP_CONTROL_ERR = 11,
+	DSI_EINT_PENDING_HS_TX_TIMEOUT = 12,
+	DSI_EINT_INTERLEAVE_OP_CONTENTION = 13,
+	DSI_EINT_CMD_DMA_FIFO_UNDERFLOW = 14,
+	DSI_EINT_CMD_MDP_FIFO_UNDERFLOW = 15,
+	DSI_EINT_DLN0_HS_FIFO_OVERFLOW = 16,
+	DSI_EINT_DLN1_HS_FIFO_OVERFLOW = 17,
+	DSI_EINT_DLN2_HS_FIFO_OVERFLOW = 18,
+	DSI_EINT_DLN3_HS_FIFO_OVERFLOW = 19,
+	DSI_EINT_DLN0_HS_FIFO_UNDERFLOW = 20,
+	DSI_EINT_DLN1_HS_FIFO_UNDERFLOW = 21,
+	DSI_EINT_DLN2_HS_FIFO_UNDERFLOW = 22,
+	DSI_EINT_DLN3_HS_FIFO_UNDERFLOW = 23,
+	DSI_EINT_DLN0_LP0_CONTENTION = 24,
+	DSI_EINT_DLN1_LP0_CONTENTION = 25,
+	DSI_EINT_DLN2_LP0_CONTENTION = 26,
+	DSI_EINT_DLN3_LP0_CONTENTION = 27,
+	DSI_EINT_DLN0_LP1_CONTENTION = 28,
+	DSI_EINT_DLN1_LP1_CONTENTION = 29,
+	DSI_EINT_DLN2_LP1_CONTENTION = 30,
+	DSI_EINT_DLN3_LP1_CONTENTION = 31,
+
+	DSI_ERROR_INTERRUPT_COUNT
 };
 
 /**
@@ -148,38 +250,38 @@
  * @DSI_DLN3_LP1_CONTENTION:        PHY level contention while lane 3 is high.
  */
 enum dsi_error_int_type {
-	DSI_RDBK_SINGLE_ECC_ERR = BIT(0),
-	DSI_RDBK_MULTI_ECC_ERR = BIT(1),
-	DSI_RDBK_CRC_ERR = BIT(2),
-	DSI_RDBK_INCOMPLETE_PKT = BIT(3),
-	DSI_PERIPH_ERROR_PKT = BIT(4),
-	DSI_LP_RX_TIMEOUT = BIT(5),
-	DSI_HS_TX_TIMEOUT = BIT(6),
-	DSI_BTA_TIMEOUT = BIT(7),
-	DSI_PLL_UNLOCK = BIT(8),
-	DSI_DLN0_ESC_ENTRY_ERR = BIT(9),
-	DSI_DLN0_ESC_SYNC_ERR = BIT(10),
-	DSI_DLN0_LP_CONTROL_ERR = BIT(11),
-	DSI_PENDING_HS_TX_TIMEOUT = BIT(12),
-	DSI_INTERLEAVE_OP_CONTENTION = BIT(13),
-	DSI_CMD_DMA_FIFO_UNDERFLOW = BIT(14),
-	DSI_CMD_MDP_FIFO_UNDERFLOW = BIT(15),
-	DSI_DLN0_HS_FIFO_OVERFLOW = BIT(16),
-	DSI_DLN1_HS_FIFO_OVERFLOW = BIT(17),
-	DSI_DLN2_HS_FIFO_OVERFLOW = BIT(18),
-	DSI_DLN3_HS_FIFO_OVERFLOW = BIT(19),
-	DSI_DLN0_HS_FIFO_UNDERFLOW = BIT(20),
-	DSI_DLN1_HS_FIFO_UNDERFLOW = BIT(21),
-	DSI_DLN2_HS_FIFO_UNDERFLOW = BIT(22),
-	DSI_DLN3_HS_FIFO_UNDERFLOW = BIT(23),
-	DSI_DLN0_LP0_CONTENTION = BIT(24),
-	DSI_DLN1_LP0_CONTENTION = BIT(25),
-	DSI_DLN2_LP0_CONTENTION = BIT(26),
-	DSI_DLN3_LP0_CONTENTION = BIT(27),
-	DSI_DLN0_LP1_CONTENTION = BIT(28),
-	DSI_DLN1_LP1_CONTENTION = BIT(29),
-	DSI_DLN2_LP1_CONTENTION = BIT(30),
-	DSI_DLN3_LP1_CONTENTION = BIT(31),
+	DSI_RDBK_SINGLE_ECC_ERR = BIT(DSI_EINT_RDBK_SINGLE_ECC_ERR),
+	DSI_RDBK_MULTI_ECC_ERR = BIT(DSI_EINT_RDBK_MULTI_ECC_ERR),
+	DSI_RDBK_CRC_ERR = BIT(DSI_EINT_RDBK_CRC_ERR),
+	DSI_RDBK_INCOMPLETE_PKT = BIT(DSI_EINT_RDBK_INCOMPLETE_PKT),
+	DSI_PERIPH_ERROR_PKT = BIT(DSI_EINT_PERIPH_ERROR_PKT),
+	DSI_LP_RX_TIMEOUT = BIT(DSI_EINT_LP_RX_TIMEOUT),
+	DSI_HS_TX_TIMEOUT = BIT(DSI_EINT_HS_TX_TIMEOUT),
+	DSI_BTA_TIMEOUT = BIT(DSI_EINT_BTA_TIMEOUT),
+	DSI_PLL_UNLOCK = BIT(DSI_EINT_PLL_UNLOCK),
+	DSI_DLN0_ESC_ENTRY_ERR = BIT(DSI_EINT_DLN0_ESC_ENTRY_ERR),
+	DSI_DLN0_ESC_SYNC_ERR = BIT(DSI_EINT_DLN0_ESC_SYNC_ERR),
+	DSI_DLN0_LP_CONTROL_ERR = BIT(DSI_EINT_DLN0_LP_CONTROL_ERR),
+	DSI_PENDING_HS_TX_TIMEOUT = BIT(DSI_EINT_PENDING_HS_TX_TIMEOUT),
+	DSI_INTERLEAVE_OP_CONTENTION = BIT(DSI_EINT_INTERLEAVE_OP_CONTENTION),
+	DSI_CMD_DMA_FIFO_UNDERFLOW = BIT(DSI_EINT_CMD_DMA_FIFO_UNDERFLOW),
+	DSI_CMD_MDP_FIFO_UNDERFLOW = BIT(DSI_EINT_CMD_MDP_FIFO_UNDERFLOW),
+	DSI_DLN0_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN0_HS_FIFO_OVERFLOW),
+	DSI_DLN1_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN1_HS_FIFO_OVERFLOW),
+	DSI_DLN2_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN2_HS_FIFO_OVERFLOW),
+	DSI_DLN3_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN3_HS_FIFO_OVERFLOW),
+	DSI_DLN0_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN0_HS_FIFO_UNDERFLOW),
+	DSI_DLN1_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN1_HS_FIFO_UNDERFLOW),
+	DSI_DLN2_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN2_HS_FIFO_UNDERFLOW),
+	DSI_DLN3_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN3_HS_FIFO_UNDERFLOW),
+	DSI_DLN0_LP0_CONTENTION = BIT(DSI_EINT_DLN0_LP0_CONTENTION),
+	DSI_DLN1_LP0_CONTENTION = BIT(DSI_EINT_DLN1_LP0_CONTENTION),
+	DSI_DLN2_LP0_CONTENTION = BIT(DSI_EINT_DLN2_LP0_CONTENTION),
+	DSI_DLN3_LP0_CONTENTION = BIT(DSI_EINT_DLN3_LP0_CONTENTION),
+	DSI_DLN0_LP1_CONTENTION = BIT(DSI_EINT_DLN0_LP1_CONTENTION),
+	DSI_DLN1_LP1_CONTENTION = BIT(DSI_EINT_DLN1_LP1_CONTENTION),
+	DSI_DLN2_LP1_CONTENTION = BIT(DSI_EINT_DLN2_LP1_CONTENTION),
+	DSI_DLN3_LP1_CONTENTION = BIT(DSI_EINT_DLN3_LP1_CONTENTION),
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index a024c43..0af6f25 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -706,6 +706,8 @@
 {
 	u32 reg = 0;
 
+	reg = DSI_R32(ctrl, DSI_INT_CTRL);
+
 	if (ints & DSI_CMD_MODE_DMA_DONE)
 		reg |= BIT(0);
 	if (ints & DSI_CMD_FRAME_DONE)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
index cf36315..1e6727b 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
@@ -9,7 +9,6 @@
  * 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 _DSI_DEFS_H_
@@ -36,6 +35,7 @@
 		value;\
 	})
 
+#define DSI_DEBUG_NAME_LEN		32
 /**
  * enum dsi_pixel_format - DSI pixel formats
  * @DSI_PIXEL_FORMAT_RGB565:
@@ -446,5 +446,14 @@
 			r1->h == r2->h;
 }
 
+struct dsi_event_cb_info {
+	uint32_t event_idx;
+	void *event_usr_ptr;
+
+	int (*event_cb)(void *event_usr_ptr,
+		uint32_t event_idx, uint32_t instance_idx,
+		uint32_t data0, uint32_t data1,
+		uint32_t data2, uint32_t data3);
+};
 
 #endif /* _DSI_DEFS_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 3dd4950..52b1dcb 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -19,6 +19,7 @@
 #include <linux/err.h>
 
 #include "msm_drv.h"
+#include "sde_connector.h"
 #include "dsi_display.h"
 #include "dsi_panel.h"
 #include "dsi_ctrl.h"
@@ -499,7 +500,45 @@
 	return 0;
 }
 
+void dsi_display_enable_event(struct dsi_display *display,
+		uint32_t event_idx, struct dsi_event_cb_info *event_info,
+		bool enable)
+{
+	uint32_t irq_status_idx = DSI_STATUS_INTERRUPT_COUNT;
+	int i;
 
+	if (!display) {
+		pr_err("invalid display\n");
+		return;
+	}
+
+	if (event_info)
+		event_info->event_idx = event_idx;
+
+	switch (event_idx) {
+	case SDE_CONN_EVENT_VID_DONE:
+		irq_status_idx = DSI_SINT_VIDEO_MODE_FRAME_DONE;
+		break;
+	case SDE_CONN_EVENT_CMD_DONE:
+		irq_status_idx = DSI_SINT_CMD_FRAME_DONE;
+		break;
+	default:
+		/* nothing to do */
+		pr_debug("[%s] unhandled event %d\n", display->name, event_idx);
+		return;
+	}
+
+	if (enable) {
+		for (i = 0; i < display->ctrl_count; i++)
+			dsi_ctrl_enable_status_interrupt(
+					display->ctrl[i].ctrl, irq_status_idx,
+					event_info);
+	} else {
+		for (i = 0; i < display->ctrl_count; i++)
+			dsi_ctrl_disable_status_interrupt(
+					display->ctrl[i].ctrl, irq_status_idx);
+	}
+}
 
 static int dsi_display_ctrl_power_on(struct dsi_display *display)
 {
@@ -1215,8 +1254,7 @@
 			goto error;
 		}
 
-		rc = dsi_ctrl_cmd_tx_trigger(ctrl->ctrl,
-			DSI_CTRL_CMD_BROADCAST);
+		rc = dsi_ctrl_cmd_tx_trigger(ctrl->ctrl, flags);
 		if (rc) {
 			pr_err("[%s] cmd trigger failed, rc=%d\n",
 			       display->name, rc);
@@ -1224,9 +1262,7 @@
 		}
 	}
 
-	rc = dsi_ctrl_cmd_tx_trigger(m_ctrl->ctrl,
-				(DSI_CTRL_CMD_BROADCAST_MASTER |
-				 DSI_CTRL_CMD_BROADCAST));
+	rc = dsi_ctrl_cmd_tx_trigger(m_ctrl->ctrl, m_flags);
 	if (rc) {
 		pr_err("[%s] cmd trigger failed for master, rc=%d\n",
 		       display->name, rc);
@@ -2780,6 +2816,9 @@
 				(void)_dsi_display_dev_deinit(main_display);
 				component_del(&main_display->pdev->dev,
 					      &dsi_display_comp_ops);
+				mutex_lock(&dsi_display_list_lock);
+				list_del(&main_display->list);
+				mutex_unlock(&dsi_display_list_lock);
 				comp_add_success = false;
 				default_active_node = NULL;
 				pr_debug("removed the existing comp ops\n");
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 9aa3113..38af37b 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -444,6 +444,17 @@
 int dsi_display_clock_gate(struct dsi_display *display, bool enable);
 int dsi_dispaly_static_frame(struct dsi_display *display, bool enable);
 
+/**
+ * dsi_display_enable_event() - enable interrupt based connector event
+ * @display:            Handle to display.
+ * @event_idx:          Event index.
+ * @event_info:         Event callback definition.
+ * @enable:             Whether to enable/disable the event interrupt.
+ */
+void dsi_display_enable_event(struct dsi_display *display,
+		uint32_t event_idx, struct dsi_event_cb_info *event_info,
+		bool enable);
+
 int dsi_display_set_backlight(void *display, u32 bl_lvl);
 
 /**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index 4e09cfb..b499bd6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -546,6 +546,19 @@
 	return dsi_display_pre_kickoff(display, params);
 }
 
+void dsi_conn_enable_event(struct drm_connector *connector,
+		uint32_t event_idx, bool enable, void *display)
+{
+	struct dsi_event_cb_info event_info;
+
+	memset(&event_info, 0, sizeof(event_info));
+
+	event_info.event_cb = sde_connector_trigger_event;
+	event_info.event_usr_ptr = connector;
+
+	dsi_display_enable_event(display, event_idx, &event_info, enable);
+}
+
 struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display,
 				       struct drm_device *dev,
 				       struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index 68520a8..45feec9 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -85,6 +85,16 @@
 		struct drm_display_mode *mode,
 		void *display);
 
+/**
+ * dsi_conn_enable_event - callback to notify DSI driver of event registeration
+ * @connector: Pointer to drm connector structure
+ * @event_idx: Connector event index
+ * @enable: Whether or not the event is enabled
+ * @display: Pointer to private display handle
+ */
+void dsi_conn_enable_event(struct drm_connector *connector,
+		uint32_t event_idx, bool enable, void *display);
+
 struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display,
 		struct drm_device *dev,
 		struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index a1a0e57..a91dba8 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -29,6 +29,8 @@
 #include "dsi_pwr.h"
 #include "dsi_catalog.h"
 
+#include "sde_dbg.h"
+
 #define DSI_PHY_DEFAULT_LABEL "MDSS PHY CTRL"
 
 struct dsi_phy_list_item {
@@ -547,6 +549,11 @@
  */
 int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy)
 {
+	char dbg_name[DSI_DEBUG_NAME_LEN];
+
+	snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_phy", dsi_phy->index);
+	sde_dbg_reg_register_base(dbg_name, dsi_phy->hw.base,
+				msm_iomap_size(dsi_phy->pdev, "dsi_phy"));
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index 571a91e..80b49a1 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
@@ -17,6 +17,7 @@
 
 
 #include "msm_drv.h"
+#include "msm_gem.h"
 #include "msm_mmu.h"
 #include "mdp4_kms.h"
 
@@ -151,12 +152,28 @@
 	}
 }
 
-static const char * const iommu_ports[] = {
-	"mdp_port0_cb0", "mdp_port1_cb0",
-};
+static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
+{
+	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+	struct msm_drm_private *priv = mdp4_kms->dev->dev_private;
+	unsigned int i;
+	struct msm_gem_address_space *aspace = mdp4_kms->aspace;
+
+	for (i = 0; i < priv->num_crtcs; i++)
+		mdp4_crtc_cancel_pending_flip(priv->crtcs[i], file);
+
+	if (aspace) {
+		aspace->mmu->funcs->detach(aspace->mmu,
+				iommu_ports, ARRAY_SIZE(iommu_ports));
+		msm_gem_address_space_destroy(aspace);
+	}
+}
 
 static void mdp4_destroy(struct msm_kms *kms)
 {
+	struct device *dev = mdp4_kms->dev->dev;
+	struct msm_gem_address_space *aspace = mdp4_kms->aspace;
+
 	struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
 	struct device *dev = mdp4_kms->dev->dev;
 	struct msm_mmu *mmu = mdp4_kms->mmu;
@@ -173,6 +190,12 @@
 	if (mdp4_kms->rpm_enabled)
 		pm_runtime_disable(dev);
 
+	if (aspace) {
+		aspace->mmu->funcs->detach(aspace->mmu,
+				iommu_ports, ARRAY_SIZE(iommu_ports));
+		msm_gem_address_space_destroy(aspace);
+	}
+
 	kfree(mdp4_kms);
 }
 
@@ -440,8 +463,8 @@
 	struct mdp4_platform_config *config = mdp4_get_config(pdev);
 	struct mdp4_kms *mdp4_kms;
 	struct msm_kms *kms = NULL;
-	struct msm_mmu *mmu;
 	int irq, ret;
+	struct msm_gem_address_space *aspace;
 
 	mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL);
 	if (!mdp4_kms) {
@@ -531,12 +554,23 @@
 	mdelay(16);
 
 	if (config->iommu) {
-		mmu = msm_iommu_new(&pdev->dev, config->iommu);
+		struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, config->iommu);
+
 		if (IS_ERR(mmu)) {
 			ret = PTR_ERR(mmu);
 			goto fail;
 		}
-		ret = mmu->funcs->attach(mmu, iommu_ports,
+
+		aspace = msm_gem_address_space_create(&pdev->dev,
+				mmu, "mdp4", 0x1000, 0xffffffff);
+		if (IS_ERR(aspace)) {
+			ret = PTR_ERR(aspace);
+			goto fail;
+		}
+
+		mdp4_kms->aspace = aspace;
+
+		ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
 				ARRAY_SIZE(iommu_ports));
 		if (ret)
 			goto fail;
@@ -545,10 +579,10 @@
 	} else {
 		dev_info(dev->dev, "no iommu, fallback to phys "
 				"contig buffers for scanout\n");
-		mmu = NULL;
+		aspace = NULL;
 	}
 
-	mdp4_kms->id = msm_register_mmu(dev, mmu);
+	mdp4_kms->id = msm_register_address_space(dev, aspace);
 	if (mdp4_kms->id < 0) {
 		ret = mdp4_kms->id;
 		dev_err(dev->dev, "failed to register mdp4 iommu: %d\n", ret);
@@ -599,5 +633,13 @@
 	config.max_clk = 266667000;
 	config.iommu = iommu_domain_alloc(&platform_bus_type);
 
+#else
+	if (cpu_is_apq8064())
+		config.max_clk = 266667000;
+	else
+		config.max_clk = 200000000;
+
+	config.iommu = msm_get_iommu_domain(DISPLAY_READ_DOMAIN);
+#endif
 	return &config;
 }
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
index ddfabde..1fe35b2 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
@@ -43,7 +43,7 @@
 	struct clk *pclk;
 	struct clk *lut_clk;
 	struct clk *axi_clk;
-	struct msm_mmu *mmu;
+	struct msm_gem_address_space *aspace;
 
 	struct mdp_irq error_handler;
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index 4f204ff..f022967 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -19,6 +19,7 @@
 #include <linux/of_irq.h>
 
 #include "msm_drv.h"
+#include "msm_gem.h"
 #include "msm_mmu.h"
 #include "mdp5_kms.h"
 
@@ -117,11 +118,12 @@
 static void mdp5_kms_destroy(struct msm_kms *kms)
 {
 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-	struct msm_mmu *mmu = mdp5_kms->mmu;
+	struct msm_gem_address_space *aspace = mdp5_kms->aspace;
 
-	if (mmu) {
-		mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports));
-		mmu->funcs->destroy(mmu);
+	if (aspace) {
+		aspace->mmu->funcs->detach(aspace->mmu,
+				iommu_ports, ARRAY_SIZE(iommu_ports));
+		msm_gem_address_space_destroy(aspace);
 	}
 }
 
@@ -564,8 +566,8 @@
 	struct mdp5_kms *mdp5_kms;
 	struct mdp5_cfg *config;
 	struct msm_kms *kms;
-	struct msm_mmu *mmu;
 	int irq, i, ret;
+	struct msm_gem_address_space *aspace;
 
 	/* priv->kms would have been populated by the MDP5 driver */
 	kms = priv->kms;
@@ -606,7 +608,8 @@
 	mdelay(16);
 
 	if (config->platform.iommu) {
-		mmu = msm_iommu_new(&pdev->dev, config->platform.iommu);
+		struct msm_mmu *mmu = msm_iommu_new(&pdev->dev,
+				config->platform.iommu);
 		if (IS_ERR(mmu)) {
 			ret = PTR_ERR(mmu);
 			dev_err(&pdev->dev, "failed to init iommu: %d\n", ret);
@@ -614,7 +617,16 @@
 			goto fail;
 		}
 
-		ret = mmu->funcs->attach(mmu, iommu_ports,
+		aspace = msm_gem_smmu_address_space_create(&pdev->dev,
+				mmu, "mdp5");
+		if (IS_ERR(aspace)) {
+			ret = PTR_ERR(aspace);
+			goto fail;
+		}
+
+		mdp5_kms->aspace = aspace;
+
+		ret = mmu->funcs->attach(aspace->mmu, iommu_ports,
 				ARRAY_SIZE(iommu_ports));
 		if (ret) {
 			dev_err(&pdev->dev, "failed to attach iommu: %d\n",
@@ -625,11 +637,10 @@
 	} else {
 		dev_info(&pdev->dev,
 			 "no iommu, fallback to phys contig buffers for scanout\n");
-		mmu = NULL;
+		aspace = NULL;
 	}
-	mdp5_kms->mmu = mmu;
 
-	mdp5_kms->id = msm_register_mmu(dev, mmu);
+	mdp5_kms->id = msm_register_address_space(dev, aspace);
 	if (mdp5_kms->id < 0) {
 		ret = mdp5_kms->id;
 		dev_err(&pdev->dev, "failed to register mdp5 iommu: %d\n", ret);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index 0373892..623ac07 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -39,7 +39,7 @@
 
 	/* mapper-id used to request GEM buffer mapped for scanout: */
 	int id;
-	struct msm_mmu *mmu;
+	struct msm_gem_address_space *aspace;
 
 	struct mdp5_smp *smp;
 	struct mdp5_ctl_manager *ctlm;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 83bf997..5e67e8b 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -218,9 +218,10 @@
 
 	mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
 			sizeof(*mdp5_state), GFP_KERNEL);
+	if (!mdp5_state)
+		return NULL;
 
-	if (mdp5_state && mdp5_state->base.fb)
-		drm_framebuffer_reference(mdp5_state->base.fb);
+	__drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base);
 
 	mdp5_state->mode_changed = false;
 	mdp5_state->pending = false;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 962087c..6a2d239 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -126,10 +126,21 @@
 int msm_atomic_check(struct drm_device *dev,
 			    struct drm_atomic_state *state)
 {
+	struct msm_drm_private *priv;
+
+	if (!dev)
+		return -EINVAL;
+
 	if (msm_is_suspend_blocked(dev)) {
 		DRM_DEBUG("rejecting commit during suspend\n");
 		return -EBUSY;
 	}
+
+	priv = dev->dev_private;
+	if (priv && priv->kms && priv->kms->funcs &&
+			priv->kms->funcs->atomic_check)
+		return priv->kms->funcs->atomic_check(priv->kms, state);
+
 	return drm_atomic_helper_check(dev, state);
 }
 
@@ -140,42 +151,20 @@
 	.atomic_commit = msm_atomic_commit,
 };
 
-int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu)
+int msm_register_address_space(struct drm_device *dev,
+		struct msm_gem_address_space *aspace)
 {
 	struct msm_drm_private *priv = dev->dev_private;
-	int idx = priv->num_mmus++;
+	int idx = priv->num_aspaces++;
 
-	if (WARN_ON(idx >= ARRAY_SIZE(priv->mmus)))
+	if (WARN_ON(idx >= ARRAY_SIZE(priv->aspace)))
 		return -EINVAL;
 
-	priv->mmus[idx] = mmu;
+	priv->aspace[idx] = aspace;
 
 	return idx;
 }
 
-void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu)
-{
-	struct msm_drm_private *priv = dev->dev_private;
-	int idx;
-
-	if (priv->num_mmus <= 0) {
-		dev_err(dev->dev, "invalid num mmus %d\n", priv->num_mmus);
-		return;
-	}
-
-	idx = priv->num_mmus - 1;
-
-	/* only support reverse-order deallocation */
-	if (priv->mmus[idx] != mmu) {
-		dev_err(dev->dev, "unexpected mmu at idx %d\n", idx);
-		return;
-	}
-
-	--priv->num_mmus;
-	priv->mmus[idx] = 0;
-}
-
-
 #ifdef CONFIG_DRM_MSM_REGISTER_LOGGING
 static bool reglog = false;
 MODULE_PARM_DESC(reglog, "Enable register read/write logging");
@@ -229,6 +218,24 @@
 	return ptr;
 }
 
+unsigned long msm_iomap_size(struct platform_device *pdev, const char *name)
+{
+	struct resource *res;
+
+	if (name)
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+	else
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get memory resource: %s\n",
+									name);
+		return 0;
+	}
+
+	return resource_size(res);
+}
+
 void msm_iounmap(struct platform_device *pdev, void __iomem *addr)
 {
 	devm_iounmap(&pdev->dev, addr);
@@ -304,7 +311,8 @@
 	list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list);
 	spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
 
-	kthread_queue_work(&priv->disp_thread[crtc_id].worker, &vbl_ctrl->work);
+	kthread_queue_work(&priv->event_thread[crtc_id].worker,
+			&vbl_ctrl->work);
 
 	return 0;
 }
@@ -330,13 +338,19 @@
 		kfree(vbl_ev);
 	}
 
-	/* clean up display commit worker threads */
+	/* clean up display commit/event worker threads */
 	for (i = 0; i < priv->num_crtcs; i++) {
 		if (priv->disp_thread[i].thread) {
 			kthread_flush_worker(&priv->disp_thread[i].worker);
 			kthread_stop(priv->disp_thread[i].thread);
 			priv->disp_thread[i].thread = NULL;
 		}
+
+		if (priv->event_thread[i].thread) {
+			kthread_flush_worker(&priv->event_thread[i].worker);
+			kthread_stop(priv->event_thread[i].thread);
+			priv->event_thread[i].thread = NULL;
+		}
 	}
 
 	msm_gem_shrinker_cleanup(ddev);
@@ -382,10 +396,11 @@
 			       priv->vram.paddr, attrs);
 	}
 
+	component_unbind_all(dev, ddev);
+
 	sde_dbg_destroy();
 	debugfs_remove_recursive(priv->debug_root);
 
-	component_unbind_all(dev, ddev);
 	sde_power_client_destroy(&priv->phandle, priv->pclient);
 	sde_power_resource_deinit(pdev, &priv->phandle);
 
@@ -579,6 +594,15 @@
 		goto power_client_fail;
 	}
 
+	dbg_power_ctrl.handle = &priv->phandle;
+	dbg_power_ctrl.client = priv->pclient;
+	dbg_power_ctrl.enable_fn = msm_power_enable_wrapper;
+	ret = sde_dbg_init(&pdev->dev, &dbg_power_ctrl);
+	if (ret) {
+		dev_err(dev, "failed to init sde dbg: %d\n", ret);
+		goto dbg_init_fail;
+	}
+
 	/* Bind all our sub-components: */
 	ret = msm_component_bind_all(dev, ddev);
 	if (ret)
@@ -588,15 +612,6 @@
 	if (ret)
 		goto fail;
 
-	dbg_power_ctrl.handle = &priv->phandle;
-	dbg_power_ctrl.client = priv->pclient;
-	dbg_power_ctrl.enable_fn = msm_power_enable_wrapper;
-	ret = sde_dbg_init(&pdev->dev, &dbg_power_ctrl);
-	if (ret) {
-		dev_err(dev, "failed to init sde dbg: %d\n", ret);
-		goto fail;
-	}
-
 	switch (get_mdp_ver(pdev)) {
 	case KMS_MDP4:
 		kms = mdp4_kms_init(ddev);
@@ -637,22 +652,50 @@
 	ddev->mode_config.funcs = &mode_config_funcs;
 
 	for (i = 0; i < priv->num_crtcs; i++) {
+
+		/* initialize display thread */
 		priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id;
 		kthread_init_worker(&priv->disp_thread[i].worker);
 		priv->disp_thread[i].dev = ddev;
 		priv->disp_thread[i].thread =
 			kthread_run(kthread_worker_fn,
 				&priv->disp_thread[i].worker,
-				"crtc_commit:%d",
-				priv->disp_thread[i].crtc_id);
+				"crtc_commit:%d", priv->disp_thread[i].crtc_id);
 
 		if (IS_ERR(priv->disp_thread[i].thread)) {
-			dev_err(dev, "failed to create kthread\n");
+			dev_err(dev, "failed to create crtc_commit kthread\n");
 			priv->disp_thread[i].thread = NULL;
+		}
+
+		/* initialize event thread */
+		priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id;
+		kthread_init_worker(&priv->event_thread[i].worker);
+		priv->event_thread[i].dev = ddev;
+		priv->event_thread[i].thread =
+			kthread_run(kthread_worker_fn,
+				&priv->event_thread[i].worker,
+				"crtc_event:%d", priv->event_thread[i].crtc_id);
+
+		if (IS_ERR(priv->event_thread[i].thread)) {
+			dev_err(dev, "failed to create crtc_event kthread\n");
+			priv->event_thread[i].thread = NULL;
+		}
+
+		if ((!priv->disp_thread[i].thread) ||
+				!priv->event_thread[i].thread) {
 			/* clean up previously created threads if any */
-			for (i -= 1; i >= 0; i--) {
-				kthread_stop(priv->disp_thread[i].thread);
-				priv->disp_thread[i].thread = NULL;
+			for ( ; i >= 0; i--) {
+				if (priv->disp_thread[i].thread) {
+					kthread_stop(
+						priv->disp_thread[i].thread);
+					priv->disp_thread[i].thread = NULL;
+				}
+
+				if (priv->event_thread[i].thread) {
+					kthread_stop(
+						priv->event_thread[i].thread);
+					priv->event_thread[i].thread = NULL;
+				}
 			}
 			goto fail;
 		}
@@ -722,6 +765,8 @@
 	msm_drm_uninit(dev);
 	return ret;
 bind_fail:
+	sde_dbg_destroy();
+dbg_init_fail:
 	sde_power_client_destroy(&priv->phandle, priv->pclient);
 power_client_fail:
 	sde_power_resource_deinit(pdev, &priv->phandle);
@@ -1328,7 +1373,7 @@
 	return ret;
 }
 
-void msm_mode_object_event_nofity(struct drm_mode_object *obj,
+void msm_mode_object_event_notify(struct drm_mode_object *obj,
 		struct drm_device *dev, struct drm_event *event, u8 *payload)
 {
 	struct msm_drm_private *priv = NULL;
@@ -1575,6 +1620,7 @@
 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 	.gem_prime_export   = drm_gem_prime_export,
 	.gem_prime_import   = drm_gem_prime_import,
+	.gem_prime_res_obj  = msm_gem_prime_res_obj,
 	.gem_prime_pin      = msm_gem_prime_pin,
 	.gem_prime_unpin    = msm_gem_prime_unpin,
 	.gem_prime_get_sg_table = msm_gem_prime_get_sg_table,
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 2cd9aa1..665ed365 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -61,6 +61,8 @@
 struct msm_gem_submit;
 struct msm_fence_context;
 struct msm_fence_cb;
+struct msm_gem_address_space;
+struct msm_gem_vma;
 
 #define NUM_DOMAINS    4    /* one for KMS, then one per gpu core (?) */
 #define MAX_CRTCS      8
@@ -136,8 +138,10 @@
 	CRTC_PROP_CORE_CLK,
 	CRTC_PROP_CORE_AB,
 	CRTC_PROP_CORE_IB,
-	CRTC_PROP_MEM_AB,
-	CRTC_PROP_MEM_IB,
+	CRTC_PROP_LLCC_AB,
+	CRTC_PROP_LLCC_IB,
+	CRTC_PROP_DRAM_AB,
+	CRTC_PROP_DRAM_IB,
 	CRTC_PROP_ROT_PREFILL_BW,
 	CRTC_PROP_ROT_CLK,
 	CRTC_PROP_ROI_V1,
@@ -206,6 +210,16 @@
 };
 
 /**
+ * enum msm_event_wait - type of HW events to wait for
+ * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
+ * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel
+ */
+enum msm_event_wait {
+	MSM_ENC_COMMIT_DONE = 0,
+	MSM_ENC_TX_COMPLETE,
+};
+
+/**
  * struct msm_roi_alignment - region of interest alignment restrictions
  * @xstart_pix_align: left x offset alignment restriction
  * @width_pix_align: width alignment restriction
@@ -461,8 +475,8 @@
 	u8 data[];
 };
 
-/* Commit thread specific structure */
-struct msm_drm_commit {
+/* Commit/Event thread specific structure */
+struct msm_drm_thread {
 	struct drm_device *dev;
 	struct task_struct *thread;
 	unsigned int crtc_id;
@@ -516,9 +530,13 @@
 	uint32_t pending_crtcs;
 	wait_queue_head_t pending_crtcs_event;
 
-	/* registered MMUs: */
-	unsigned int num_mmus;
-	struct msm_mmu *mmus[NUM_DOMAINS];
+	/* Registered address spaces.. currently this is fixed per # of
+	 * iommu's.  Ie. one for display block and one for gpu block.
+	 * Eventually, to do per-process gpu pagetables, we'll want one
+	 * of these per-process.
+	 */
+	unsigned int num_aspaces;
+	struct msm_gem_address_space *aspace[NUM_DOMAINS];
 
 	unsigned int num_planes;
 	struct drm_plane *planes[MAX_PLANES];
@@ -526,7 +544,8 @@
 	unsigned int num_crtcs;
 	struct drm_crtc *crtcs[MAX_CRTCS];
 
-	struct msm_drm_commit disp_thread[MAX_CRTCS];
+	struct msm_drm_thread disp_thread[MAX_CRTCS];
+	struct msm_drm_thread event_thread[MAX_CRTCS];
 
 	unsigned int num_encoders;
 	struct drm_encoder *encoders[MAX_ENCODERS];
@@ -622,10 +641,27 @@
 int msm_atomic_commit(struct drm_device *dev,
 		struct drm_atomic_state *state, bool nonblock);
 
-int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
-void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu);
-
 void msm_gem_submit_free(struct msm_gem_submit *submit);
+int msm_register_address_space(struct drm_device *dev,
+		struct msm_gem_address_space *aspace);
+void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
+		struct msm_gem_vma *vma, struct sg_table *sgt,
+		void *priv);
+int msm_gem_map_vma(struct msm_gem_address_space *aspace,
+		struct msm_gem_vma *vma, struct sg_table *sgt,
+		void *priv, unsigned int flags);
+void msm_gem_address_space_destroy(struct msm_gem_address_space *aspace);
+
+/* For GPU and legacy display */
+struct msm_gem_address_space *
+msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
+		const char *name);
+
+/* For SDE  display */
+struct msm_gem_address_space *
+msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
+		const char *name);
+
 int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
 		struct drm_file *file);
 
@@ -652,6 +688,7 @@
 void *msm_gem_prime_vmap(struct drm_gem_object *obj);
 void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
 int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
+struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj);
 struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
 		struct dma_buf_attachment *attach, struct sg_table *sg);
 int msm_gem_prime_pin(struct drm_gem_object *obj);
@@ -718,7 +755,7 @@
  * @event: event that needs to be notified.
  * @payload: payload for the event.
  */
-void msm_mode_object_event_nofity(struct drm_mode_object *obj,
+void msm_mode_object_event_notify(struct drm_mode_object *obj,
 		struct drm_device *dev, struct drm_event *event, u8 *payload);
 #ifdef CONFIG_DRM_MSM_DSI
 void __init msm_dsi_register(void);
@@ -760,6 +797,7 @@
 
 void __iomem *msm_ioremap(struct platform_device *pdev, const char *name,
 		const char *dbgname);
+unsigned long msm_iomap_size(struct platform_device *pdev, const char *name);
 void msm_iounmap(struct platform_device *dev, void __iomem *addr);
 void msm_writel(u32 data, void __iomem *addr);
 u32 msm_readl(const void __iomem *addr);
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index acd7af5..43e2a26 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -26,6 +26,11 @@
 #include "msm_gpu.h"
 #include "msm_mmu.h"
 
+static void *get_dmabuf_ptr(struct drm_gem_object *obj)
+{
+	return (obj && obj->import_attach) ? obj->import_attach->dmabuf : NULL;
+}
+
 static dma_addr_t physaddr(struct drm_gem_object *obj)
 {
 	struct msm_gem_object *msm_obj = to_msm_bo(obj);
@@ -296,19 +301,8 @@
 	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
 	for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) {
-		struct msm_mmu *mmu = priv->mmus[id];
-		if (mmu && msm_obj->domain[id].iova) {
-			uint32_t offset = msm_obj->domain[id].iova;
-
-			if (obj->import_attach && mmu->funcs->unmap_dma_buf)
-				mmu->funcs->unmap_dma_buf(mmu, msm_obj->sgt,
-						obj->import_attach->dmabuf,
-						DMA_BIDIRECTIONAL);
-			else
-				mmu->funcs->unmap(mmu, offset, msm_obj->sgt,
-						obj->size);
-			msm_obj->domain[id].iova = 0;
-		}
+		msm_gem_unmap_vma(priv->aspace[id], &msm_obj->domain[id],
+			msm_obj->sgt, get_dmabuf_ptr(obj));
 	}
 }
 
@@ -333,25 +327,11 @@
 			return PTR_ERR(pages);
 
 		if (iommu_present(&platform_bus_type)) {
-			struct msm_mmu *mmu = priv->mmus[id];
-
-			if (WARN_ON(!mmu))
-				return -EINVAL;
-
-			if (obj->import_attach && mmu->funcs->map_dma_buf) {
-				ret = mmu->funcs->map_dma_buf(mmu, msm_obj->sgt,
-						obj->import_attach->dmabuf,
-						DMA_BIDIRECTIONAL,
-						msm_obj->flags);
-				if (ret) {
-					DRM_ERROR("Unable to map dma buf\n");
-					return ret;
-				}
-			}
-			msm_obj->domain[id].iova =
-				sg_dma_address(msm_obj->sgt->sgl);
+			ret = msm_gem_map_vma(priv->aspace[id],
+				&msm_obj->domain[id], msm_obj->sgt,
+				get_dmabuf_ptr(obj),
+				msm_obj->flags);
 		} else {
-			WARN_ONCE(1, "physical address being used\n");
 			msm_obj->domain[id].iova = physaddr(obj);
 		}
 	}
@@ -666,6 +646,7 @@
 	}
 
 	seq_printf(m, "%08x: %c %2d (%2d) %08llx %p %zu%s\n",
+
 			msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
 			obj->name, obj->refcount.refcount.counter,
 			off, msm_obj->vaddr, obj->size, madv);
@@ -721,7 +702,8 @@
 
 	if (obj->import_attach) {
 		if (msm_obj->vaddr)
-			dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr);
+			dma_buf_vunmap(obj->import_attach->dmabuf,
+				msm_obj->vaddr);
 
 		/* Don't drop the pages for imported dmabuf, as they are not
 		 * ours, just free the array we allocated:
@@ -776,7 +758,6 @@
 {
 	struct msm_drm_private *priv = dev->dev_private;
 	struct msm_gem_object *msm_obj;
-	unsigned sz;
 	bool use_vram = false;
 
 	switch (flags & MSM_BO_CACHE_MASK) {
@@ -798,16 +779,12 @@
 	if (WARN_ON(use_vram && !priv->vram.size))
 		return -EINVAL;
 
-	sz = sizeof(*msm_obj);
-	if (use_vram)
-		sz += sizeof(struct drm_mm_node);
-
-	msm_obj = kzalloc(sz, GFP_KERNEL);
+	msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL);
 	if (!msm_obj)
 		return -ENOMEM;
 
 	if (use_vram)
-		msm_obj->vram_node = (void *)&msm_obj[1];
+		msm_obj->vram_node = &msm_obj->domain[0].node;
 
 	msm_obj->flags = flags;
 	msm_obj->madv = MSM_MADV_WILLNEED;
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index 19c7726..b176c11 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -25,6 +25,28 @@
 #define MSM_BO_STOLEN        0x10000000    /* try to use stolen/splash memory */
 #define MSM_BO_KEEPATTRS     0x20000000     /* keep h/w bus attributes */
 
+struct msm_gem_aspace_ops {
+	int (*map)(struct msm_gem_address_space *, struct msm_gem_vma *,
+		struct sg_table *sgt, void *priv, unsigned int flags);
+
+	void (*unmap)(struct msm_gem_address_space *, struct msm_gem_vma *,
+		struct sg_table *sgt, void *priv);
+
+	void (*destroy)(struct msm_gem_address_space *);
+};
+
+struct msm_gem_address_space {
+	const char *name;
+	struct msm_mmu *mmu;
+	const struct msm_gem_aspace_ops *ops;
+};
+
+struct msm_gem_vma {
+	/* Node used by the GPU address space, but not the SDE address space */
+	struct drm_mm_node node;
+	uint64_t iova;
+};
+
 struct msm_gem_object {
 	struct drm_gem_object base;
 
@@ -62,9 +84,7 @@
 	struct sg_table *sgt;
 	void *vaddr;
 
-	struct {
-		dma_addr_t iova;
-	} domain[NUM_DOMAINS];
+	struct msm_gem_vma domain[NUM_DOMAINS];
 
 	/* normally (resv == &_resv) except for imported bo's */
 	struct reservation_object *resv;
diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c
index 60bb290..13403c6 100644
--- a/drivers/gpu/drm/msm/msm_gem_prime.c
+++ b/drivers/gpu/drm/msm/msm_gem_prime.c
@@ -70,3 +70,10 @@
 	if (!obj->import_attach)
 		msm_gem_put_pages(obj);
 }
+
+struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj)
+{
+	struct msm_gem_object *msm_obj = to_msm_bo(obj);
+
+	return msm_obj->resv;
+}
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
new file mode 100644
index 0000000..8e56871
--- /dev/null
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2016 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msm_drv.h"
+#include "msm_gem.h"
+#include "msm_mmu.h"
+
+/* SDE address space operations */
+static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace,
+		struct msm_gem_vma *vma, struct sg_table *sgt,
+		void *priv)
+{
+	struct dma_buf *buf = priv;
+
+	if (buf)
+		aspace->mmu->funcs->unmap_dma_buf(aspace->mmu,
+			sgt, buf, DMA_BIDIRECTIONAL);
+	else
+		aspace->mmu->funcs->unmap_sg(aspace->mmu, sgt,
+			DMA_BIDIRECTIONAL);
+
+	vma->iova = 0;
+}
+
+
+static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace,
+		struct msm_gem_vma *vma, struct sg_table *sgt,
+		void *priv, unsigned int flags)
+{
+	struct dma_buf *buf = priv;
+	int ret;
+
+	if (buf)
+		ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, buf,
+			DMA_BIDIRECTIONAL, flags);
+	else
+		ret = aspace->mmu->funcs->map_sg(aspace->mmu, sgt,
+			DMA_BIDIRECTIONAL);
+
+	if (!ret)
+		vma->iova = sg_dma_address(sgt->sgl);
+
+	return ret;
+}
+
+static void smmu_aspace_destroy(struct msm_gem_address_space *aspace)
+{
+	aspace->mmu->funcs->destroy(aspace->mmu);
+}
+
+
+static const struct msm_gem_aspace_ops smmu_aspace_ops = {
+	.map = smmu_aspace_map_vma,
+	.unmap = smmu_aspace_unmap_vma,
+	.destroy = smmu_aspace_destroy
+};
+
+struct msm_gem_address_space *
+msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
+		const char *name)
+{
+	struct msm_gem_address_space *aspace;
+
+	if (!mmu)
+		return ERR_PTR(-EINVAL);
+
+	aspace = kzalloc(sizeof(*aspace), GFP_KERNEL);
+	if (!aspace)
+		return ERR_PTR(-ENOMEM);
+
+	aspace->name = name;
+	aspace->mmu = mmu;
+	aspace->ops = &smmu_aspace_ops;
+
+	return aspace;
+}
+
+/* GPU address space operations */
+struct msm_iommu_aspace {
+	struct msm_gem_address_space base;
+	struct drm_mm mm;
+};
+
+#define to_iommu_aspace(aspace) \
+	((struct msm_iommu_aspace *) \
+	 container_of(aspace, struct msm_iommu_aspace, base))
+
+static void iommu_aspace_unmap_vma(struct msm_gem_address_space *aspace,
+		struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
+{
+	if (!vma->iova)
+		return;
+
+	if (aspace->mmu)
+		aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt);
+
+	drm_mm_remove_node(&vma->node);
+
+	vma->iova = 0;
+}
+
+static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace,
+		struct msm_gem_vma *vma, struct sg_table *sgt,
+		void *priv, unsigned int flags)
+{
+	struct msm_iommu_aspace *local = to_iommu_aspace(aspace);
+	size_t size = 0;
+	struct scatterlist *sg;
+	int ret = 0, i;
+
+	if (WARN_ON(drm_mm_node_allocated(&vma->node)))
+		return 0;
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i)
+		size += sg->length + sg->offset;
+
+	ret = drm_mm_insert_node(&local->mm, &vma->node, size >> PAGE_SHIFT,
+			0, DRM_MM_SEARCH_DEFAULT);
+	if (ret)
+		return ret;
+
+	vma->iova = vma->node.start << PAGE_SHIFT;
+
+	if (aspace->mmu)
+		ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova,
+			sgt, IOMMU_READ | IOMMU_WRITE);
+
+	return ret;
+}
+
+static void iommu_aspace_destroy(struct msm_gem_address_space *aspace)
+{
+	struct msm_iommu_aspace *local = to_iommu_aspace(aspace);
+
+	drm_mm_takedown(&local->mm);
+	aspace->mmu->funcs->destroy(aspace->mmu);
+}
+
+static const struct msm_gem_aspace_ops msm_iommu_aspace_ops = {
+	.map = iommu_aspace_map_vma,
+	.unmap = iommu_aspace_unmap_vma,
+	.destroy = iommu_aspace_destroy,
+};
+
+static struct msm_gem_address_space *
+msm_gem_address_space_new(struct msm_mmu *mmu, const char *name,
+		uint64_t start, uint64_t end)
+{
+	struct msm_iommu_aspace *local;
+
+	if (!mmu)
+		return ERR_PTR(-EINVAL);
+
+	local = kzalloc(sizeof(*local), GFP_KERNEL);
+	if (!local)
+		return ERR_PTR(-ENOMEM);
+
+	drm_mm_init(&local->mm, (start >> PAGE_SHIFT),
+		(end >> PAGE_SHIFT) - 1);
+
+	local->base.name = name;
+	local->base.mmu = mmu;
+	local->base.ops = &msm_iommu_aspace_ops;
+
+	return &local->base;
+}
+
+int msm_gem_map_vma(struct msm_gem_address_space *aspace,
+		struct msm_gem_vma *vma, struct sg_table *sgt,
+		void *priv, unsigned int flags)
+{
+	if (aspace && aspace->ops->map)
+		return aspace->ops->map(aspace, vma, sgt, priv, flags);
+
+	return -EINVAL;
+}
+
+void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
+		struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
+{
+	if (aspace && aspace->ops->unmap)
+		aspace->ops->unmap(aspace, vma, sgt, priv);
+}
+
+struct msm_gem_address_space *
+msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
+		const char *name)
+{
+	struct msm_mmu *mmu = msm_iommu_new(dev, domain);
+
+	if (IS_ERR(mmu))
+		return (struct msm_gem_address_space *) mmu;
+
+	return msm_gem_address_space_new(mmu, name,
+		domain->geometry.aperture_start,
+		domain->geometry.aperture_end);
+}
+
+void
+msm_gem_address_space_destroy(struct msm_gem_address_space *aspace)
+{
+	if (aspace && aspace->ops->destroy)
+		aspace->ops->destroy(aspace);
+
+	kfree(aspace);
+}
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 5bb0983..ded4226 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -656,12 +656,17 @@
 	 */
 	iommu = iommu_domain_alloc(&platform_bus_type);
 	if (iommu) {
+		/* TODO 32b vs 64b address space.. */
+		iommu->geometry.aperture_start = 0x1000;
+		iommu->geometry.aperture_end = 0xffffffff;
+
 		dev_info(drm->dev, "%s: using IOMMU\n", name);
-		gpu->mmu = msm_iommu_new(&pdev->dev, iommu);
-		if (IS_ERR(gpu->mmu)) {
-			ret = PTR_ERR(gpu->mmu);
+		gpu->aspace = msm_gem_address_space_create(&pdev->dev,
+				iommu, "gpu");
+		if (IS_ERR(gpu->aspace)) {
+			ret = PTR_ERR(gpu->aspace);
 			dev_err(drm->dev, "failed to init iommu: %d\n", ret);
-			gpu->mmu = NULL;
+			gpu->aspace = NULL;
 			iommu_domain_free(iommu);
 			goto fail;
 		}
@@ -669,7 +674,7 @@
 	} else {
 		dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name);
 	}
-	gpu->id = msm_register_mmu(drm, gpu->mmu);
+	gpu->id = msm_register_address_space(drm, gpu->aspace);
 
 
 	/* Create ringbuffer: */
@@ -705,9 +710,9 @@
 		msm_ringbuffer_destroy(gpu->rb);
 	}
 
-	if (gpu->mmu)
-		gpu->mmu->funcs->destroy(gpu->mmu);
-
 	if (gpu->fctx)
 		msm_fence_context_free(gpu->fctx);
+
+	if (gpu->aspace)
+		msm_gem_address_space_destroy(gpu->aspace);
 }
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index d61d98a..c6bf5d6 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -98,7 +98,7 @@
 	void __iomem *mmio;
 	int irq;
 
-	struct msm_mmu *mmu;
+	struct msm_gem_address_space *aspace;
 	int id;
 
 	/* Power Control: */
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index 3a294d0..bc9877c 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -46,7 +46,7 @@
 }
 
 static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova,
-		struct sg_table *sgt, unsigned len, int prot)
+		struct sg_table *sgt, int prot)
 {
 	struct msm_iommu *iommu = to_msm_iommu(mmu);
 	struct iommu_domain *domain = iommu->domain;
@@ -85,7 +85,7 @@
 }
 
 static int msm_iommu_unmap(struct msm_mmu *mmu, uint32_t iova,
-		struct sg_table *sgt, unsigned len)
+		struct sg_table *sgt)
 {
 	struct msm_iommu *iommu = to_msm_iommu(mmu);
 	struct iommu_domain *domain = iommu->domain;
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index aa1b090..eed0f1b 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -62,6 +62,9 @@
 	/* functions to wait for atomic commit completed on each CRTC */
 	void (*wait_for_crtc_commit_done)(struct msm_kms *kms,
 					struct drm_crtc *crtc);
+	/* function pointer to wait for pixel transfer to panel to complete*/
+	void (*wait_for_tx_complete)(struct msm_kms *kms,
+					struct drm_crtc *crtc);
 	/* get msm_format w/ optional format modifiers from drm_mode_fb_cmd2 */
 	const struct msm_format *(*get_format)(struct msm_kms *kms,
 					const uint32_t format,
@@ -72,6 +75,9 @@
 			const struct msm_format *msm_fmt,
 			const struct drm_mode_fb_cmd2 *cmd,
 			struct drm_gem_object **bos);
+	/* perform complete atomic check of given atomic state */
+	int (*atomic_check)(struct msm_kms *kms,
+				    struct drm_atomic_state *state);
 	/* misc: */
 	long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
 			struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
index fbf7e7b..dc7e5a6 100644
--- a/drivers/gpu/drm/msm/msm_mmu.h
+++ b/drivers/gpu/drm/msm/msm_mmu.h
@@ -21,7 +21,6 @@
 #include <linux/iommu.h>
 
 struct msm_mmu;
-struct msm_gpu;
 
 enum msm_mmu_domain_type {
 	MSM_SMMU_DOMAIN_UNSECURE,
@@ -35,9 +34,8 @@
 	int (*attach)(struct msm_mmu *mmu, const char * const *names, int cnt);
 	void (*detach)(struct msm_mmu *mmu, const char * const *names, int cnt);
 	int (*map)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
-			unsigned int len, int prot);
-	int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
-			unsigned int len);
+			int prot);
+	int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt);
 	int (*map_sg)(struct msm_mmu *mmu, struct sg_table *sgt,
 			enum dma_data_direction dir);
 	void (*unmap_sg)(struct msm_mmu *mmu, struct sg_table *sgt,
@@ -62,7 +60,6 @@
 }
 
 struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
-struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu);
 struct msm_mmu *msm_smmu_new(struct device *dev,
 	enum msm_mmu_domain_type domain);
 
diff --git a/drivers/gpu/drm/msm/msm_prop.c b/drivers/gpu/drm/msm/msm_prop.c
index 663781f..f2996dd 100644
--- a/drivers/gpu/drm/msm/msm_prop.c
+++ b/drivers/gpu/drm/msm/msm_prop.c
@@ -371,6 +371,18 @@
 	return rc;
 }
 
+int msm_property_set_dirty(struct msm_property_info *info, int property_idx)
+{
+	if (!info) {
+		DRM_ERROR("invalid property info\n");
+		return -EINVAL;
+	}
+	mutex_lock(&info->property_lock);
+	_msm_property_set_dirty_no_lock(info, property_idx);
+	mutex_unlock(&info->property_lock);
+	return 0;
+}
+
 int msm_property_atomic_set(struct msm_property_info *info,
 		uint64_t *property_values,
 		struct drm_property_blob **property_blobs,
diff --git a/drivers/gpu/drm/msm/msm_prop.h b/drivers/gpu/drm/msm/msm_prop.h
index dbe28bd..e54c796 100644
--- a/drivers/gpu/drm/msm/msm_prop.h
+++ b/drivers/gpu/drm/msm/msm_prop.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -266,6 +266,14 @@
 		struct drm_property *property);
 
 /**
+ * msm_property_set_dirty - forcibly flag a property as dirty
+ * @info: Pointer to property info container struct
+ * @property_idx: Property index
+ * Returns: Zero on success
+ */
+int msm_property_set_dirty(struct msm_property_info *info, int property_idx);
+
+/**
  * msm_property_atomic_set - helper function for atomic property set callback
  * @info: Pointer to property info container struct
  * @property_values: Pointer to property values cache array
diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c
index 4d45898..e3d2e34 100644
--- a/drivers/gpu/drm/msm/msm_smmu.c
+++ b/drivers/gpu/drm/msm/msm_smmu.c
@@ -27,6 +27,7 @@
 #include "msm_drv.h"
 #include "msm_gem.h"
 #include "msm_mmu.h"
+#include "sde_dbg.h"
 
 #ifndef SZ_4G
 #define SZ_4G	(((size_t) SZ_1G) * 4)
@@ -108,7 +109,7 @@
 }
 
 static int msm_smmu_map(struct msm_mmu *mmu, uint32_t iova,
-		struct sg_table *sgt, unsigned int len, int prot)
+		struct sg_table *sgt, int prot)
 {
 	struct msm_smmu *smmu = to_msm_smmu(mmu);
 	struct msm_smmu_client *client = msm_smmu_to_client(smmu);
@@ -176,7 +177,7 @@
 }
 
 static int msm_smmu_unmap(struct msm_mmu *mmu, uint32_t iova,
-		struct sg_table *sgt, unsigned int len)
+		struct sg_table *sgt)
 {
 	struct msm_smmu *smmu = to_msm_smmu(mmu);
 	struct msm_smmu_client *client = msm_smmu_to_client(smmu);
@@ -238,6 +239,13 @@
 		return -ENOMEM;
 	}
 
+	if (sgt && sgt->sgl) {
+		DRM_DEBUG("%pad/0x%x/0x%x/0x%lx\n", &sgt->sgl->dma_address,
+				sgt->sgl->dma_length, dir, attrs);
+		SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length,
+				dir, attrs);
+	}
+
 	return 0;
 }
 
@@ -248,6 +256,12 @@
 	struct msm_smmu *smmu = to_msm_smmu(mmu);
 	struct msm_smmu_client *client = msm_smmu_to_client(smmu);
 
+	if (sgt && sgt->sgl) {
+		DRM_DEBUG("%pad/0x%x/0x%x\n", &sgt->sgl->dma_address,
+				sgt->sgl->dma_length, dir);
+		SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, dir);
+	}
+
 	msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf);
 }
 
@@ -386,6 +400,37 @@
 	return &smmu->base;
 }
 
+static int msm_smmu_fault_handler(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova,
+		int flags, void *token)
+{
+	struct msm_smmu_client *client;
+	int rc = -EINVAL;
+
+	if (!token) {
+		DRM_ERROR("Error: token is NULL\n");
+		return -EINVAL;
+	}
+
+	client = (struct msm_smmu_client *)token;
+
+	/* see iommu.h for fault flags definition */
+	SDE_EVT32(iova, flags);
+	DRM_ERROR("trigger dump, iova=0x%08lx, flags=0x%x\n", iova, flags);
+	DRM_ERROR("SMMU device:%s", client->dev ? client->dev->kobj.name : "");
+
+	/* generate dump, but no panic */
+	SDE_DBG_DUMP("sde", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl",
+			"dsi1_phy", "vbif", "dbg_bus",
+			"vbif_dbg_bus");
+
+	/*
+	 * return -ENOSYS to allow smmu driver to dump out useful
+	 * debug info.
+	 */
+	return rc;
+}
+
 static int _msm_smmu_create_mapping(struct msm_smmu_client *client,
 	const struct msm_smmu_domain *domain)
 {
@@ -411,6 +456,9 @@
 		}
 	}
 
+	iommu_set_fault_handler(client->mmu_mapping->domain,
+			msm_smmu_fault_handler, (void *)client);
+
 	DRM_INFO("Created domain %s [%zx,%zx] secure=%d\n",
 			domain->label, domain->va_start, domain->va_size,
 			domain->secure);
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index b410302..9c13991 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -526,7 +526,7 @@
 }
 
 static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
-				   struct sde_crtc *sde_crtc, u32 last_feature)
+				   struct sde_crtc *sde_crtc)
 {
 	struct sde_hw_cp_cfg hw_cfg;
 	struct sde_hw_mixer *hw_lm;
@@ -541,16 +541,13 @@
 	hw_cfg.num_of_mixers = sde_crtc->num_mixers;
 	hw_cfg.displayh = sde_crtc->base.mode.hdisplay;
 	hw_cfg.displayv = sde_crtc->base.mode.vdisplay;
+	hw_cfg.last_feature = 0;
 
 	for (i = 0; i < num_mixers && !ret; i++) {
 		hw_lm = sde_crtc->mixers[i].hw_lm;
 		hw_dspp = sde_crtc->mixers[i].hw_dspp;
 		hw_cfg.ctl = sde_crtc->mixers[i].hw_ctl;
 		hw_cfg.mixer_info = hw_lm;
-		if (i == num_mixers - 1)
-			hw_cfg.last_feature = last_feature;
-		else
-			hw_cfg.last_feature = 0;
 		switch (prop_node->feature) {
 		case SDE_CP_CRTC_DSPP_VLUT:
 			if (!hw_dspp || !hw_dspp->ops.setup_vlut) {
@@ -724,7 +721,6 @@
 	struct sde_hw_ctl *ctl;
 	uint32_t flush_mask = 0;
 	u32 num_mixers = 0, i = 0;
-	u32 num_of_features;
 
 	if (!crtc || !crtc->dev) {
 		DRM_ERROR("invalid crtc %pK dev %pK\n", crtc,
@@ -757,15 +753,9 @@
 		set_dspp_flush = true;
 	}
 
-	num_of_features = 0;
-	list_for_each_entry(prop_node, &sde_crtc->dirty_list, dirty_list)
-		num_of_features++;
-
 	list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
 				dirty_list) {
-		num_of_features--;
-		sde_cp_crtc_setfeature(prop_node, sde_crtc,
-				(num_of_features == 0));
+		sde_cp_crtc_setfeature(prop_node, sde_crtc);
 		/* Set the flush flag to true */
 		if (prop_node->is_dspp_feature)
 			set_dspp_flush = true;
@@ -773,16 +763,10 @@
 			set_lm_flush = true;
 	}
 
-	num_of_features = 0;
-	list_for_each_entry(prop_node, &sde_crtc->ad_dirty, dirty_list)
-		num_of_features++;
-
 	list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty,
 				dirty_list) {
-		num_of_features--;
 		set_dspp_flush = true;
-		sde_cp_crtc_setfeature(prop_node, sde_crtc,
-				(num_of_features == 0));
+		sde_cp_crtc_setfeature(prop_node, sde_crtc);
 	}
 
 	for (i = 0; i < num_mixers; i++) {
@@ -1357,7 +1341,7 @@
 	hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_BACKLIGHT, &bl);
 	event.length = sizeof(u32);
 	event.type = DRM_EVENT_AD_BACKLIGHT;
-	msm_mode_object_event_nofity(&crtc_drm->base, crtc_drm->dev,
+	msm_mode_object_event_notify(&crtc_drm->base, crtc_drm->dev,
 			&event, (u8 *)&bl);
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index f13c6c9..2970b28 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -83,7 +83,7 @@
 	if (c_conn->ops.set_backlight) {
 		event.type = DRM_EVENT_SYS_BACKLIGHT;
 		event.length = sizeof(u32);
-		msm_mode_object_event_nofity(&c_conn->base.base,
+		msm_mode_object_event_notify(&c_conn->base.base,
 				c_conn->base.dev, &event, (u8 *)&brightness);
 		c_conn->ops.set_backlight(c_conn->display, bl_lvl);
 	}
@@ -546,7 +546,7 @@
 			return rc;
 
 		c_state->rois.roi[i] = roi_v1.roi[i];
-		SDE_DEBUG_CONN(c_conn, "roi%d: roi 0x%x 0x%x 0x%x 0x%x\n", i,
+		SDE_DEBUG_CONN(c_conn, "roi%d: roi (%d,%d) (%d,%d)\n", i,
 				c_state->rois.roi[i].x1,
 				c_state->rois.roi[i].y1,
 				c_state->rois.roi[i].x2,
@@ -856,7 +856,7 @@
 
 	sde_connector = to_sde_connector(connector);
 
-	if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
+	if (!debugfs_create_bool("fb_kmap", 0600, connector->debugfs_entry,
 			&sde_connector->fb_kmap)) {
 		SDE_ERROR("failed to create connector fb_kmap\n");
 		return -ENOMEM;
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c
index 1b40161..cec2b5f 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c
@@ -195,6 +195,12 @@
 			!sde_kms->hw_intr->ops.get_interrupt_status)
 		return 0;
 
+	if (irq_idx < 0) {
+		SDE_ERROR("[%pS] invalid irq_idx=%d\n",
+				__builtin_return_address(0), irq_idx);
+		return 0;
+	}
+
 	return sde_kms->hw_intr->ops.get_interrupt_status(sde_kms->hw_intr,
 			irq_idx, clear);
 }
@@ -323,7 +329,7 @@
 int sde_debugfs_core_irq_init(struct sde_kms *sde_kms,
 		struct dentry *parent)
 {
-	sde_kms->irq_obj.debugfs_file = debugfs_create_file("core_irq", 0644,
+	sde_kms->irq_obj.debugfs_file = debugfs_create_file("core_irq", 0600,
 			parent, &sde_kms->irq_obj,
 			&sde_debugfs_core_irq_fops);
 
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 0c69886..71dfc12 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -110,6 +110,7 @@
 		struct sde_core_perf_params *perf)
 {
 	struct sde_crtc_state *sde_cstate;
+	int i;
 
 	if (!kms || !kms->catalog || !crtc || !state || !perf) {
 		SDE_ERROR("invalid parameters\n");
@@ -119,29 +120,64 @@
 	sde_cstate = to_sde_crtc_state(state);
 	memset(perf, 0, sizeof(struct sde_core_perf_params));
 
-	perf->bw_ctl = sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_AB);
-	perf->max_per_pipe_ib =
+	perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC] =
+		sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_AB);
+	perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC] =
+		sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_IB);
+
+	if (sde_cstate->bw_split_vote) {
+		perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC] =
+			sde_crtc_get_property(sde_cstate, CRTC_PROP_LLCC_AB);
+		perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC] =
+			sde_crtc_get_property(sde_cstate, CRTC_PROP_LLCC_IB);
+		perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI] =
+			sde_crtc_get_property(sde_cstate, CRTC_PROP_DRAM_AB);
+		perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI] =
+			sde_crtc_get_property(sde_cstate, CRTC_PROP_DRAM_IB);
+	} else {
+		perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC] =
+			sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_AB);
+		perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC] =
 			sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_IB);
+		perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI] =
+			sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_AB);
+		perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI] =
+			sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_IB);
+	}
+
 	perf->core_clk_rate =
 			sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_CLK);
 
 	if (!sde_cstate->bw_control) {
-		perf->bw_ctl = kms->catalog->perf.max_bw_high * 1000ULL;
-		perf->max_per_pipe_ib = perf->bw_ctl;
+		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+			perf->bw_ctl[i] = kms->catalog->perf.max_bw_high *
+					1000ULL;
+			perf->max_per_pipe_ib[i] = perf->bw_ctl[i];
+		}
 		perf->core_clk_rate = kms->perf.max_core_clk_rate;
 	} else if (kms->perf.perf_tune.mode == SDE_PERF_MODE_MINIMUM) {
-		perf->bw_ctl = 0;
-		perf->max_per_pipe_ib = 0;
+		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+			perf->bw_ctl[i] = 0;
+			perf->max_per_pipe_ib[i] = 0;
+		}
 		perf->core_clk_rate = 0;
 	} else if (kms->perf.perf_tune.mode == SDE_PERF_MODE_FIXED) {
-		perf->bw_ctl = kms->perf.fix_core_ab_vote;
-		perf->max_per_pipe_ib = kms->perf.fix_core_ib_vote;
+		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+			perf->bw_ctl[i] = kms->perf.fix_core_ab_vote;
+			perf->max_per_pipe_ib[i] = kms->perf.fix_core_ib_vote;
+		}
 		perf->core_clk_rate = kms->perf.fix_core_clk_rate;
 	}
 
-	SDE_DEBUG("crtc=%d clk_rate=%llu ib=%llu ab=%llu\n",
+	SDE_DEBUG(
+		"crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu llcc_ib=%llu llcc_ab=%llu mem_ib=%llu mem_ab=%llu\n",
 			crtc->base.id, perf->core_clk_rate,
-			perf->max_per_pipe_ib, perf->bw_ctl);
+			perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+			perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+			perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+			perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+			perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI],
+			perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI]);
 }
 
 int sde_core_perf_crtc_check(struct drm_crtc *crtc,
@@ -154,6 +190,7 @@
 	struct sde_crtc_state *sde_cstate;
 	struct drm_crtc *tmp_crtc;
 	struct sde_kms *kms;
+	int i;
 
 	if (!crtc || !state) {
 		SDE_ERROR("invalid crtc\n");
@@ -172,45 +209,49 @@
 
 	sde_cstate = to_sde_crtc_state(state);
 
-	/* swap state and obtain new values */
-	sde_cstate->cur_perf = sde_cstate->new_perf;
+	/* obtain new values */
 	_sde_core_perf_calc_crtc(kms, crtc, state, &sde_cstate->new_perf);
 
-	bw_sum_of_intfs = sde_cstate->new_perf.bw_ctl;
-	curr_client_type = sde_crtc_get_client_type(crtc);
+	for (i = SDE_POWER_HANDLE_DBUS_ID_MNOC;
+			i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+		bw_sum_of_intfs = sde_cstate->new_perf.bw_ctl[i];
+		curr_client_type = sde_crtc_get_client_type(crtc);
 
-	drm_for_each_crtc(tmp_crtc, crtc->dev) {
-		if (_sde_core_perf_crtc_is_power_on(tmp_crtc) &&
-		    (sde_crtc_get_client_type(tmp_crtc) == curr_client_type) &&
-		    (tmp_crtc != crtc)) {
-			struct sde_crtc_state *tmp_cstate =
+		drm_for_each_crtc(tmp_crtc, crtc->dev) {
+			if (_sde_core_perf_crtc_is_power_on(tmp_crtc) &&
+			    (sde_crtc_get_client_type(tmp_crtc) ==
+					    curr_client_type) &&
+			    (tmp_crtc != crtc)) {
+				struct sde_crtc_state *tmp_cstate =
 					to_sde_crtc_state(tmp_crtc->state);
 
-			bw_sum_of_intfs += tmp_cstate->new_perf.bw_ctl;
+				bw_sum_of_intfs +=
+					tmp_cstate->new_perf.bw_ctl[i];
+			}
 		}
-	}
 
-	/* convert bandwidth to kb */
-	bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000);
-	SDE_DEBUG("calculated bandwidth=%uk\n", bw);
+		/* convert bandwidth to kb */
+		bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000);
+		SDE_DEBUG("calculated bandwidth=%uk\n", bw);
 
-	is_video_mode = sde_crtc_get_intf_mode(crtc) == INTF_MODE_VIDEO;
-	threshold = (is_video_mode ||
-		_sde_core_video_mode_intf_connected(crtc)) ?
-		kms->catalog->perf.max_bw_low : kms->catalog->perf.max_bw_high;
+		is_video_mode = sde_crtc_get_intf_mode(crtc) == INTF_MODE_VIDEO;
+		threshold = (is_video_mode ||
+			_sde_core_video_mode_intf_connected(crtc)) ?
+			kms->catalog->perf.max_bw_low :
+			kms->catalog->perf.max_bw_high;
 
-	SDE_DEBUG("final threshold bw limit = %d\n", threshold);
+		SDE_DEBUG("final threshold bw limit = %d\n", threshold);
 
-	if (!sde_cstate->bw_control) {
-		SDE_DEBUG("bypass bandwidth check\n");
-	} else if (!threshold) {
-		sde_cstate->new_perf = sde_cstate->cur_perf;
-		SDE_ERROR("no bandwidth limits specified\n");
-		return -E2BIG;
-	} else if (bw > threshold) {
-		sde_cstate->new_perf = sde_cstate->cur_perf;
-		SDE_ERROR("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
-		return -E2BIG;
+		if (!sde_cstate->bw_control) {
+			SDE_DEBUG("bypass bandwidth check\n");
+		} else if (!threshold) {
+			SDE_ERROR("no bandwidth limits specified\n");
+			return -E2BIG;
+		} else if (bw > threshold) {
+			SDE_ERROR("exceeds bandwidth: %ukb > %ukb\n", bw,
+					threshold);
+			return -E2BIG;
+		}
 	}
 
 	return 0;
@@ -243,10 +284,10 @@
 }
 
 static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms,
-		struct drm_crtc *crtc)
+		struct drm_crtc *crtc, u32 bus_id)
 {
 	u64 bw_sum_of_intfs = 0, bus_ab_quota, bus_ib_quota;
-	struct sde_core_perf_params perf = {0};
+	struct sde_core_perf_params perf = { { 0 } };
 	enum sde_crtc_client_type client_vote, curr_client_type
 					= sde_crtc_get_client_type(crtc);
 	struct drm_crtc *tmp_crtc;
@@ -259,19 +300,20 @@
 								&kms->perf)) {
 			sde_cstate = to_sde_crtc_state(tmp_crtc->state);
 
-			perf.max_per_pipe_ib = max(perf.max_per_pipe_ib,
-				sde_cstate->new_perf.max_per_pipe_ib);
+			perf.max_per_pipe_ib[bus_id] =
+				max(perf.max_per_pipe_ib[bus_id],
+				sde_cstate->new_perf.max_per_pipe_ib[bus_id]);
 
-			bw_sum_of_intfs += sde_cstate->new_perf.bw_ctl;
+			bw_sum_of_intfs += sde_cstate->new_perf.bw_ctl[bus_id];
 
-			SDE_DEBUG("crtc=%d bw=%llu\n",
-				tmp_crtc->base.id,
-				sde_cstate->new_perf.bw_ctl);
+			SDE_DEBUG("crtc=%d bus_id=%d bw=%llu\n",
+				tmp_crtc->base.id, bus_id,
+				sde_cstate->new_perf.bw_ctl[bus_id]);
 		}
 	}
 
 	bus_ab_quota = max(bw_sum_of_intfs, kms->perf.perf_tune.min_bus_vote);
-	bus_ib_quota = perf.max_per_pipe_ib;
+	bus_ib_quota = perf.max_per_pipe_ib[bus_id];
 
 	if (kms->perf.perf_tune.mode == SDE_PERF_MODE_FIXED) {
 		bus_ab_quota = kms->perf.fix_core_ab_vote;
@@ -283,25 +325,25 @@
 	case NRT_CLIENT:
 		sde_power_data_bus_set_quota(&priv->phandle, kms->core_client,
 				SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT,
-				bus_ab_quota, bus_ib_quota);
-		SDE_DEBUG("client:%s ab=%llu ib=%llu\n", "nrt",
-				bus_ab_quota, bus_ib_quota);
+				bus_id, bus_ab_quota, bus_ib_quota);
+		SDE_DEBUG("client:%s bus_id=%d ab=%llu ib=%llu\n", "nrt",
+				bus_id, bus_ab_quota, bus_ib_quota);
 		break;
 
 	case RT_CLIENT:
 		sde_power_data_bus_set_quota(&priv->phandle, kms->core_client,
 				SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT,
-				bus_ab_quota, bus_ib_quota);
-		SDE_DEBUG("client:%s ab=%llu ib=%llu\n", "rt",
-				bus_ab_quota, bus_ib_quota);
+				bus_id, bus_ab_quota, bus_ib_quota);
+		SDE_DEBUG("client:%s bus_id=%d ab=%llu ib=%llu\n", "rt",
+				bus_id, bus_ab_quota, bus_ib_quota);
 		break;
 
 	case RT_RSC_CLIENT:
 		sde_cstate = to_sde_crtc_state(crtc->state);
-		sde_rsc_client_vote(sde_cstate->rsc_client, bus_ab_quota,
-					bus_ib_quota);
-		SDE_DEBUG("client:%s ab=%llu ib=%llu\n", "rt_rsc",
-				bus_ab_quota, bus_ib_quota);
+		sde_rsc_client_vote(sde_cstate->rsc_client,
+				bus_id, bus_ab_quota, bus_ib_quota);
+		SDE_DEBUG("client:%s bus_id=%d ab=%llu ib=%llu\n", "rt_rsc",
+				bus_id, bus_ab_quota, bus_ib_quota);
 		break;
 
 	default:
@@ -314,10 +356,12 @@
 		case DISP_RSC_MODE:
 			sde_power_data_bus_set_quota(&priv->phandle,
 				kms->core_client,
-				SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT, 0, 0);
+				SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT,
+				bus_id, 0, 0);
 			sde_power_data_bus_set_quota(&priv->phandle,
 				kms->core_client,
-				SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, 0, 0);
+				SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT,
+				bus_id, 0, 0);
 			kms->perf.bw_vote_mode_updated = false;
 			break;
 
@@ -325,7 +369,7 @@
 			sde_cstate = to_sde_crtc_state(crtc->state);
 			if (sde_cstate->rsc_client) {
 				sde_rsc_client_vote(sde_cstate->rsc_client,
-									0, 0);
+								bus_id, 0, 0);
 				kms->perf.bw_vote_mode_updated = false;
 			}
 			break;
@@ -347,8 +391,10 @@
 void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc)
 {
 	struct drm_crtc *tmp_crtc;
+	struct sde_crtc *sde_crtc;
 	struct sde_crtc_state *sde_cstate;
 	struct sde_kms *kms;
+	int i;
 
 	if (!crtc) {
 		SDE_ERROR("invalid crtc\n");
@@ -361,6 +407,7 @@
 		return;
 	}
 
+	sde_crtc = to_sde_crtc(crtc);
 	sde_cstate = to_sde_crtc_state(crtc->state);
 
 	/* only do this for command mode rt client (non-rsc client) */
@@ -383,10 +430,11 @@
 	/* Release the bandwidth */
 	if (kms->perf.enable_bw_release) {
 		trace_sde_cmd_release_bw(crtc->base.id);
-		sde_cstate->cur_perf.bw_ctl = 0;
-		sde_cstate->new_perf.bw_ctl = 0;
 		SDE_DEBUG("Release BW crtc=%d\n", crtc->base.id);
-		_sde_core_perf_crtc_update_bus(kms, crtc);
+		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+			sde_crtc->cur_perf.bw_ctl[i] = 0;
+			_sde_core_perf_crtc_update_bus(kms, crtc, i);
+		}
 	}
 }
 
@@ -421,7 +469,7 @@
 	u64 clk_rate = 0;
 	struct sde_crtc *sde_crtc;
 	struct sde_crtc_state *sde_cstate;
-	int ret;
+	int ret, i;
 	struct msm_drm_private *priv;
 	struct sde_kms *kms;
 
@@ -447,42 +495,56 @@
 	SDE_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n",
 			crtc->base.id, stop_req, kms->perf.core_clk_rate);
 
-	old = &sde_cstate->cur_perf;
+	old = &sde_crtc->cur_perf;
 	new = &sde_cstate->new_perf;
 
 	if (_sde_core_perf_crtc_is_power_on(crtc) && !stop_req) {
-		/*
-		 * cases for bus bandwidth update.
-		 * 1. new bandwidth vote - "ab or ib vote" is higher
-		 *    than current vote for update request.
-		 * 2. new bandwidth vote - "ab or ib vote" is lower
-		 *    than current vote at end of commit or stop.
-		 */
-		if ((params_changed && ((new->bw_ctl > old->bw_ctl) ||
-			  (new->max_per_pipe_ib > old->max_per_pipe_ib))) ||
-		    (!params_changed && ((new->bw_ctl < old->bw_ctl) ||
-			  (new->max_per_pipe_ib < old->max_per_pipe_ib)))) {
-			SDE_DEBUG("crtc=%d p=%d new_bw=%llu,old_bw=%llu\n",
-				crtc->base.id, params_changed, new->bw_ctl,
-				old->bw_ctl);
-			old->bw_ctl = new->bw_ctl;
-			old->max_per_pipe_ib = new->max_per_pipe_ib;
-			update_bus = 1;
-		}
+		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+			/*
+			 * cases for bus bandwidth update.
+			 * 1. new bandwidth vote - "ab or ib vote" is higher
+			 *    than current vote for update request.
+			 * 2. new bandwidth vote - "ab or ib vote" is lower
+			 *    than current vote at end of commit or stop.
+			 */
+			if ((params_changed && ((new->bw_ctl[i] >
+						old->bw_ctl[i]) ||
+				  (new->max_per_pipe_ib[i] >
+						old->max_per_pipe_ib[i]))) ||
+			    (!params_changed && ((new->bw_ctl[i] <
+						old->bw_ctl[i]) ||
+				  (new->max_per_pipe_ib[i] <
+						old->max_per_pipe_ib[i])))) {
+				SDE_DEBUG(
+					"crtc=%d p=%d new_bw=%llu,old_bw=%llu\n",
+					crtc->base.id, params_changed,
+					new->bw_ctl[i], old->bw_ctl[i]);
+				old->bw_ctl[i] = new->bw_ctl[i];
+				old->max_per_pipe_ib[i] =
+						new->max_per_pipe_ib[i];
+				update_bus |= BIT(i);
+			}
 
-		/* display rsc override during solver mode */
-		if (kms->perf.bw_vote_mode == DISP_RSC_MODE &&
+			/* display rsc override during solver mode */
+			if (kms->perf.bw_vote_mode == DISP_RSC_MODE &&
 				get_sde_rsc_current_state(SDE_RSC_INDEX) ==
-							    SDE_RSC_CMD_STATE) {
-			/* update new bandwdith in all cases */
-			if (params_changed && ((new->bw_ctl != old->bw_ctl) ||
-			      (new->max_per_pipe_ib != old->max_per_pipe_ib))) {
-				old->bw_ctl = new->bw_ctl;
-				old->max_per_pipe_ib = new->max_per_pipe_ib;
-				update_bus = 1;
-			/* reduce bw vote is not required in solver mode */
-			} else if (!params_changed) {
-				update_bus = 0;
+						SDE_RSC_CMD_STATE) {
+				/* update new bandwidth in all cases */
+				if (params_changed && ((new->bw_ctl[i] !=
+						old->bw_ctl[i]) ||
+				      (new->max_per_pipe_ib[i] !=
+						old->max_per_pipe_ib[i]))) {
+					old->bw_ctl[i] = new->bw_ctl[i];
+					old->max_per_pipe_ib[i] =
+							new->max_per_pipe_ib[i];
+					update_bus |= BIT(i);
+				/*
+				 * reduce bw vote is not required in solver
+				 * mode
+				 */
+				} else if (!params_changed) {
+					update_bus &= ~BIT(i);
+				}
 			}
 		}
 
@@ -497,15 +559,20 @@
 		SDE_DEBUG("crtc=%d disable\n", crtc->base.id);
 		memset(old, 0, sizeof(*old));
 		memset(new, 0, sizeof(*new));
-		update_bus = 1;
+		update_bus = ~0;
 		update_clk = 1;
 	}
-	trace_sde_perf_crtc_update(crtc->base.id, new->bw_ctl,
+	trace_sde_perf_crtc_update(crtc->base.id,
+				new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+				new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+				new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI],
 				new->core_clk_rate, stop_req,
 				update_bus, update_clk);
 
-	if (update_bus)
-		_sde_core_perf_crtc_update_bus(kms, crtc);
+	for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+		if (update_bus & BIT(i))
+			_sde_core_perf_crtc_update_bus(kms, crtc, i);
+	}
 
 	/*
 	 * Update the clock after bandwidth vote to ensure
@@ -636,27 +703,27 @@
 		return -EINVAL;
 	}
 
-	debugfs_create_u64("max_core_clk_rate", 0644, perf->debugfs_root,
+	debugfs_create_u64("max_core_clk_rate", 0600, perf->debugfs_root,
 			&perf->max_core_clk_rate);
-	debugfs_create_u64("core_clk_rate", 0644, perf->debugfs_root,
+	debugfs_create_u64("core_clk_rate", 0600, perf->debugfs_root,
 			&perf->core_clk_rate);
-	debugfs_create_u32("enable_bw_release", 0644, perf->debugfs_root,
+	debugfs_create_u32("enable_bw_release", 0600, perf->debugfs_root,
 			(u32 *)&perf->enable_bw_release);
-	debugfs_create_u32("threshold_low", 0644, perf->debugfs_root,
+	debugfs_create_u32("threshold_low", 0600, perf->debugfs_root,
 			(u32 *)&catalog->perf.max_bw_low);
-	debugfs_create_u32("threshold_high", 0644, perf->debugfs_root,
+	debugfs_create_u32("threshold_high", 0600, perf->debugfs_root,
 			(u32 *)&catalog->perf.max_bw_high);
-	debugfs_create_file("perf_mode", 0644, perf->debugfs_root,
+	debugfs_create_file("perf_mode", 0600, perf->debugfs_root,
 			(u32 *)perf, &sde_core_perf_mode_fops);
 	debugfs_create_u32("bw_vote_mode", 0600, perf->debugfs_root,
 			&perf->bw_vote_mode);
 	debugfs_create_bool("bw_vote_mode_updated", 0600, perf->debugfs_root,
 			&perf->bw_vote_mode_updated);
-	debugfs_create_u64("fix_core_clk_rate", 0644, perf->debugfs_root,
+	debugfs_create_u64("fix_core_clk_rate", 0600, perf->debugfs_root,
 			&perf->fix_core_clk_rate);
-	debugfs_create_u64("fix_core_ib_vote", 0644, perf->debugfs_root,
+	debugfs_create_u64("fix_core_ib_vote", 0600, perf->debugfs_root,
 			&perf->fix_core_ib_vote);
-	debugfs_create_u64("fix_core_ab_vote", 0644, perf->debugfs_root,
+	debugfs_create_u64("fix_core_ab_vote", 0600, perf->debugfs_root,
 			&perf->fix_core_ab_vote);
 
 	return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.h b/drivers/gpu/drm/msm/sde/sde_core_perf.h
index 4a1bdad..589415c 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.h
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.h
@@ -30,8 +30,8 @@
  * @core_clk_rate: core clock rate request
  */
 struct sde_core_perf_params {
-	u64 max_per_pipe_ib;
-	u64 bw_ctl;
+	u64 max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MAX];
+	u64 bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MAX];
 	u64 core_clk_rate;
 };
 
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index e13bcc9..923297f 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -494,12 +494,6 @@
 {
 	if (!sde_crtc)
 		return;
-
-	if (sde_crtc->event_thread) {
-		kthread_flush_worker(&sde_crtc->event_worker);
-		kthread_stop(sde_crtc->event_thread);
-		sde_crtc->event_thread = NULL;
-	}
 }
 
 static void sde_crtc_destroy(struct drm_crtc *crtc)
@@ -735,6 +729,25 @@
 	return 0;
 }
 
+static bool _sde_crtc_setup_is_3dmux_dsc(struct drm_crtc_state *state)
+{
+	int i;
+	struct sde_crtc_state *cstate;
+	bool is_3dmux_dsc = false;
+
+	cstate = to_sde_crtc_state(state);
+
+	for (i = 0; i < cstate->num_connectors; i++) {
+		struct drm_connector *conn = cstate->connectors[i];
+
+		if (sde_connector_get_topology_name(conn) ==
+				SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC)
+			is_3dmux_dsc = true;
+	}
+
+	return is_3dmux_dsc;
+}
+
 static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc,
 		struct drm_crtc_state *state)
 {
@@ -768,6 +781,12 @@
 
 		sde_conn_state = to_sde_connector_state(conn_state);
 
+		/*
+		 * current driver only supports same connector and crtc size,
+		 * but if support for different sizes is added, driver needs
+		 * to check the connector roi here to make sure is full screen
+		 * for dsc 3d-mux topology that doesn't support partial update.
+		 */
 		if (memcmp(&sde_conn_state->rois, &crtc_state->user_roi_list,
 				sizeof(crtc_state->user_roi_list))) {
 			SDE_ERROR("%s: crtc -> conn roi scaling unsupported\n",
@@ -778,6 +797,23 @@
 
 	sde_kms_rect_merge_rectangles(&crtc_state->user_roi_list, crtc_roi);
 
+	/*
+	 * for 3dmux dsc, make sure is full ROI, since current driver doesn't
+	 * support partial update for this configuration.
+	 */
+	if (!sde_kms_rect_is_null(crtc_roi) &&
+		_sde_crtc_setup_is_3dmux_dsc(state)) {
+		struct drm_display_mode *adj_mode = &state->adjusted_mode;
+
+		if (crtc_roi->w != adj_mode->hdisplay ||
+			crtc_roi->h != adj_mode->vdisplay) {
+			SDE_ERROR("%s: unsupported top roi[%d %d] wxh[%d %d]\n",
+				sde_crtc->name, crtc_roi->w, crtc_roi->h,
+				adj_mode->hdisplay, adj_mode->vdisplay);
+			return -EINVAL;
+		}
+	}
+
 	SDE_DEBUG("%s: crtc roi (%d,%d,%d,%d)\n", sde_crtc->name,
 			crtc_roi->x, crtc_roi->y, crtc_roi->w, crtc_roi->h);
 
@@ -1113,10 +1149,10 @@
 	struct sde_rect plane_crtc_roi;
 
 	u32 flush_mask, flush_sbuf, flush_tmp;
-	uint32_t lm_idx = LEFT_MIXER, stage_idx;
-	bool bg_alpha_enable[CRTC_DUAL_MIXERS] = {false};
-	int zpos_cnt[CRTC_DUAL_MIXERS][SDE_STAGE_MAX + 1] = { {0} };
+	uint32_t stage_idx, lm_idx;
+	int zpos_cnt[SDE_STAGE_MAX + 1] = { 0 };
 	int i;
+	bool bg_alpha_enable = false;
 	u32 prefill = 0;
 
 	if (!sde_crtc || !mixer) {
@@ -1166,6 +1202,8 @@
 				state->fb ? state->fb->base.id : -1);
 
 		format = to_sde_format(msm_framebuffer_format(pstate->base.fb));
+		if (pstate->stage == SDE_STAGE_BASE && format->alpha_enable)
+			bg_alpha_enable = true;
 
 		SDE_EVT32(DRMID(crtc), DRMID(plane),
 				state->fb ? state->fb->base.id : -1,
@@ -1175,46 +1213,28 @@
 				state->crtc_w, state->crtc_h,
 				cstate->sbuf_cfg.rot_op_mode);
 
-		for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
-			struct sde_rect intersect;
-
-			/* skip if the roi doesn't fall within LM's bounds */
-			sde_kms_rect_intersect(&plane_crtc_roi,
-					&cstate->lm_bounds[lm_idx],
-					&intersect);
-			if (sde_kms_rect_is_null(&intersect))
-				continue;
-
-			stage_idx = zpos_cnt[lm_idx][pstate->stage]++;
-			stage_cfg->stage[lm_idx][pstate->stage][stage_idx] =
+		stage_idx = zpos_cnt[pstate->stage]++;
+		stage_cfg->stage[pstate->stage][stage_idx] =
 					sde_plane_pipe(plane);
-			stage_cfg->multirect_index
-					[lm_idx][pstate->stage][stage_idx] =
+		stage_cfg->multirect_index[pstate->stage][stage_idx] =
 					pstate->multirect_index;
 
+		SDE_EVT32(DRMID(crtc), DRMID(plane), stage_idx,
+			sde_plane_pipe(plane) - SSPP_VIG0, pstate->stage,
+			pstate->multirect_index, pstate->multirect_mode,
+			format->base.pixel_format, fb ? fb->modifier[0] : 0);
+
+		/* blend config update */
+		for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+			_sde_crtc_setup_blend_cfg(mixer + lm_idx, pstate,
+								format);
 			mixer[lm_idx].flush_mask |= flush_mask;
 
-
-			SDE_EVT32(DRMID(plane), DRMID(crtc), lm_idx, stage_idx,
-				pstate->stage, pstate->multirect_index,
-				pstate->multirect_mode,
-				format->base.pixel_format,
-				fb ? fb->modifier[0] : 0);
-
-			/* blend config update */
-			if (pstate->stage != SDE_STAGE_BASE) {
-				_sde_crtc_setup_blend_cfg(mixer + lm_idx,
-						pstate, format);
-
-				if (bg_alpha_enable[lm_idx] &&
-						!format->alpha_enable)
-					mixer[lm_idx].mixer_op_mode = 0;
-				else
-					mixer[lm_idx].mixer_op_mode |=
+			if (bg_alpha_enable && !format->alpha_enable)
+				mixer[lm_idx].mixer_op_mode = 0;
+			else
+				mixer[lm_idx].mixer_op_mode |=
 						1 << pstate->stage;
-			} else if (format->alpha_enable) {
-				bg_alpha_enable[lm_idx] = true;
-			}
 		}
 	}
 
@@ -1377,7 +1397,7 @@
 			mixer[i].flush_mask);
 
 		ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx,
-			&sde_crtc->stage_cfg, i);
+			&sde_crtc->stage_cfg);
 	}
 
 	_sde_crtc_program_lm_output_roi(crtc);
@@ -1491,7 +1511,6 @@
 	struct sde_crtc_state *cstate;
 	struct sde_kms *sde_kms;
 	unsigned long flags;
-	bool disable_inprogress = false;
 
 	if (!work) {
 		SDE_ERROR("invalid work handle\n");
@@ -1517,9 +1536,6 @@
 
 	SDE_DEBUG("crtc%d event:%u ts:%lld\n", crtc->base.id, fevent->event,
 			ktime_to_ns(fevent->ts));
-	disable_inprogress = fevent->event &
-					SDE_ENCODER_FRAME_EVENT_DURING_DISABLE;
-	fevent->event &= ~SDE_ENCODER_FRAME_EVENT_DURING_DISABLE;
 
 	if (fevent->event == SDE_ENCODER_FRAME_EVENT_DONE ||
 			(fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) ||
@@ -1540,15 +1556,17 @@
 					ktime_to_ns(fevent->ts));
 			SDE_EVT32(DRMID(crtc), fevent->event,
 							SDE_EVTLOG_FUNC_CASE2);
-			if (!disable_inprogress)
-				sde_core_perf_crtc_release_bw(crtc);
+			sde_core_perf_crtc_release_bw(crtc);
 		} else {
 			SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event,
 							SDE_EVTLOG_FUNC_CASE3);
 		}
 
-		if (fevent->event == SDE_ENCODER_FRAME_EVENT_DONE &&
-							!disable_inprogress)
+		if (fevent->event == SDE_ENCODER_FRAME_EVENT_DONE ||
+			    (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR))
+			complete_all(&sde_crtc->frame_done_comp);
+
+		if (fevent->event == SDE_ENCODER_FRAME_EVENT_DONE)
 			sde_core_perf_crtc_update(crtc, 0, false);
 	} else {
 		SDE_ERROR("crtc%d ts:%lld unknown event %u\n", crtc->base.id,
@@ -1573,7 +1591,7 @@
 	struct msm_drm_private *priv;
 	struct sde_crtc_frame_event *fevent;
 	unsigned long flags;
-	int pipe_id;
+	u32 crtc_id;
 
 	if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
 		SDE_ERROR("invalid parameters\n");
@@ -1581,7 +1599,7 @@
 	}
 	sde_crtc = to_sde_crtc(crtc);
 	priv = crtc->dev->dev_private;
-	pipe_id = drm_crtc_index(crtc);
+	crtc_id = drm_crtc_index(crtc);
 
 	SDE_DEBUG("crtc%d\n", crtc->base.id);
 	SDE_EVT32_VERBOSE(DRMID(crtc), event);
@@ -1603,11 +1621,7 @@
 	fevent->event = event;
 	fevent->crtc = crtc;
 	fevent->ts = ktime_get();
-	if (event & SDE_ENCODER_FRAME_EVENT_DURING_DISABLE)
-		sde_crtc_frame_event_work(&fevent->work);
-	else
-		kthread_queue_work(&priv->disp_thread[pipe_id].worker,
-								&fevent->work);
+	kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
 }
 
 void sde_crtc_complete_commit(struct drm_crtc *crtc,
@@ -1626,9 +1640,10 @@
 	cstate = to_sde_crtc_state(crtc->state);
 	SDE_EVT32_VERBOSE(DRMID(crtc));
 
-	/* signal output fence(s) at end of commit */
+	/* signal release fence */
 	sde_fence_signal(&sde_crtc->output_fence, 0);
 
+	/* signal retire fence */
 	for (i = 0; i < cstate->num_connectors; ++i)
 		sde_connector_complete_commit(cstate->connectors[i]);
 }
@@ -2059,6 +2074,36 @@
 			cstate->property_values, cstate->property_blobs);
 }
 
+static int _sde_crtc_wait_for_frame_done(struct drm_crtc *crtc)
+{
+	struct sde_crtc *sde_crtc;
+	int ret, rc = 0;
+
+	if (!crtc) {
+		SDE_ERROR("invalid argument\n");
+		return -EINVAL;
+	}
+	sde_crtc = to_sde_crtc(crtc);
+
+	if (!atomic_read(&sde_crtc->frame_pending)) {
+		SDE_DEBUG("no frames pending\n");
+		return 0;
+	}
+
+	SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_ENTRY);
+	ret = wait_for_completion_timeout(&sde_crtc->frame_done_comp,
+			msecs_to_jiffies(SDE_FRAME_DONE_TIMEOUT));
+	if (!ret) {
+		SDE_ERROR("frame done completion wait timed out, ret:%d\n",
+				ret);
+		SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FATAL);
+		rc = -ETIMEDOUT;
+	}
+	SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_EXIT);
+
+	return rc;
+}
+
 void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
 {
 	struct drm_encoder *encoder;
@@ -2103,20 +2148,23 @@
 		sde_encoder_prepare_for_kickoff(encoder, &params);
 	}
 
-	if (atomic_read(&sde_crtc->frame_pending) > 2) {
-		/* framework allows only 1 outstanding + current */
-		SDE_ERROR("crtc%d invalid frame pending\n",
-				crtc->base.id);
-		SDE_EVT32(DRMID(crtc), 0);
+	/* wait for frame_event_done completion */
+	if (_sde_crtc_wait_for_frame_done(crtc)) {
+		SDE_ERROR("crtc%d wait for frame done failed;frame_pending%d\n",
+				crtc->base.id,
+				atomic_read(&sde_crtc->frame_pending));
 		goto end;
-	} else if (atomic_inc_return(&sde_crtc->frame_pending) == 1) {
+	}
+
+	if (atomic_inc_return(&sde_crtc->frame_pending) == 1) {
 		/* acquire bandwidth and other resources */
 		SDE_DEBUG("crtc%d first commit\n", crtc->base.id);
-		SDE_EVT32(DRMID(crtc), 1);
+		SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_CASE1);
 	} else {
 		SDE_DEBUG("crtc%d commit\n", crtc->base.id);
-		SDE_EVT32(DRMID(crtc), 2);
+		SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_CASE2);
 	}
+	sde_crtc->play_count++;
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 		if (encoder->crtc != crtc)
@@ -2124,6 +2172,9 @@
 
 		sde_encoder_kickoff(encoder);
 	}
+
+	reinit_completion(&sde_crtc->frame_done_comp);
+
 end:
 	SDE_ATRACE_END("crtc_commit");
 	return;
@@ -2239,7 +2290,7 @@
 		_sde_crtc_vblank_enable_nolock(sde_crtc, !enable);
 
 	sde_crtc->suspend = enable;
-	msm_mode_object_event_nofity(&crtc->base, crtc->dev, &event,
+	msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
 			(u8 *)&power_on);
 	mutex_unlock(&sde_crtc->crtc_lock);
 }
@@ -2277,6 +2328,8 @@
 
 	_sde_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp);
 
+	cstate->idle_pc = sde_crtc->idle_pc;
+
 	return &cstate->base;
 }
 
@@ -2377,6 +2430,24 @@
 			sde_encoder_virt_restore(encoder);
 		}
 
+	} else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) {
+		/*
+		 * Serialize h/w idle state update with crtc atomic check.
+		 * Grab the modeset lock to ensure that there is no on-going
+		 * atomic check, then increment the idle_pc counter. The next
+		 * atomic check will detect a new idle_pc since the counter
+		 * has advanced between the old_state and new_state, and
+		 * therefore properly reprogram all relevant drm objects'
+		 * hardware.
+		 */
+		drm_modeset_lock_crtc(crtc, NULL);
+
+		sde_crtc->idle_pc++;
+
+		SDE_DEBUG("crtc%d idle_pc:%d\n", crtc->base.id,
+				sde_crtc->idle_pc);
+		SDE_EVT32(DRMID(crtc), sde_crtc->idle_pc);
+
 	} else if (event_type == SDE_POWER_EVENT_POST_DISABLE) {
 		struct drm_plane *plane;
 
@@ -2386,6 +2457,9 @@
 		 */
 		drm_atomic_crtc_for_each_plane(plane, crtc)
 			sde_plane_set_revalidate(plane, true);
+
+		drm_modeset_unlock_crtc(crtc);
+		sde_cp_crtc_suspend(crtc);
 	}
 
 	mutex_unlock(&sde_crtc->crtc_lock);
@@ -2417,6 +2491,12 @@
 	mutex_lock(&sde_crtc->crtc_lock);
 	SDE_EVT32(DRMID(crtc));
 
+	/* wait for frame_event_done completion */
+	if (_sde_crtc_wait_for_frame_done(crtc))
+		SDE_ERROR("crtc%d wait for frame done failed;frame_pending%d\n",
+				crtc->base.id,
+				atomic_read(&sde_crtc->frame_pending));
+
 	if (atomic_read(&sde_crtc->vblank_refcount) && !sde_crtc->suspend) {
 		SDE_ERROR("crtc%d invalid vblank refcount\n",
 				crtc->base.id);
@@ -2428,8 +2508,6 @@
 	}
 
 	if (atomic_read(&sde_crtc->frame_pending)) {
-		/* release bandwidth and other resources */
-		SDE_ERROR("crtc%d invalid frame pending\n", crtc->base.id);
 		SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->frame_pending),
 							SDE_EVTLOG_FUNC_CASE2);
 		sde_core_perf_crtc_release_bw(crtc);
@@ -2455,6 +2533,7 @@
 
 	/* disable clk & bw control until clk & bw properties are set */
 	cstate->bw_control = false;
+	cstate->bw_split_vote = false;
 
 	spin_lock_irqsave(&sde_crtc->spin_lock, flags);
 	list_for_each_entry(node, &sde_crtc->user_event_list, list) {
@@ -2509,7 +2588,8 @@
 
 	sde_crtc->power_event = sde_power_handle_register_event(
 		&priv->phandle,
-		SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE,
+		SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE |
+		SDE_POWER_EVENT_PRE_DISABLE,
 		sde_crtc_handle_power_event, crtc, sde_crtc->name);
 }
 
@@ -2549,7 +2629,7 @@
 	for (i = curr_cnt; i < cnt; i++) {
 		pstate = pstates[i].drm_pstate;
 		POPULATE_RECT(&dst_rect, pstate->crtc_x, pstate->crtc_y,
-				pstate->crtc_w, pstate->crtc_h, true);
+				pstate->crtc_w, pstate->crtc_h, false);
 		sde_kms_rect_intersect(&dst_rect, excl_rect, &intersect);
 
 		if (intersect.w == excl_rect->w && intersect.h == excl_rect->h
@@ -2720,8 +2800,10 @@
 			sde_plane_clear_multirect(pipe_staged[i]);
 
 			if (is_sde_plane_virtual(pipe_staged[i]->plane)) {
-				SDE_ERROR("invalid use of virtual plane: %d\n",
+				SDE_ERROR(
+					"r1 only virt plane:%d not supported\n",
 					pipe_staged[i]->plane->base.id);
+				rc  = -EINVAL;
 				goto end;
 			}
 		}
@@ -2802,43 +2884,67 @@
 		goto end;
 	}
 
-	/*
-	 * enforce pipe priority restrictions
+	/* validate source split:
 	 * use pstates sorted by stage to check planes on same stage
 	 * we assume that all pipes are in source split so its valid to compare
 	 * without taking into account left/right mixer placement
 	 */
 	for (i = 1; i < cnt; i++) {
 		struct plane_state *prv_pstate, *cur_pstate;
-		int32_t prv_x, cur_x, prv_id, cur_id;
+		struct sde_rect left_rect, right_rect;
+		int32_t left_pid, right_pid;
+		int32_t stage;
 
 		prv_pstate = &pstates[i - 1];
 		cur_pstate = &pstates[i];
 		if (prv_pstate->stage != cur_pstate->stage)
 			continue;
 
-		prv_x = prv_pstate->drm_pstate->crtc_x;
-		cur_x = cur_pstate->drm_pstate->crtc_x;
-		prv_id = prv_pstate->sde_pstate->base.plane->base.id;
-		cur_id = cur_pstate->sde_pstate->base.plane->base.id;
+		stage = cur_pstate->stage;
 
-		/*
-		 * Planes are enumerated in pipe-priority order such that planes
-		 * with lower drm_id must be left-most in a shared blend-stage
-		 * when using source split.
+		left_pid = prv_pstate->sde_pstate->base.plane->base.id;
+		POPULATE_RECT(&left_rect, prv_pstate->drm_pstate->crtc_x,
+			prv_pstate->drm_pstate->crtc_y,
+			prv_pstate->drm_pstate->crtc_w,
+			prv_pstate->drm_pstate->crtc_h, false);
+
+		right_pid = cur_pstate->sde_pstate->base.plane->base.id;
+		POPULATE_RECT(&right_rect, cur_pstate->drm_pstate->crtc_x,
+			cur_pstate->drm_pstate->crtc_y,
+			cur_pstate->drm_pstate->crtc_w,
+			cur_pstate->drm_pstate->crtc_h, false);
+
+		if (right_rect.x < left_rect.x) {
+			swap(left_pid, right_pid);
+			swap(left_rect, right_rect);
+		}
+
+		/**
+		 * - planes are enumerated in pipe-priority order such that
+		 *   planes with lower drm_id must be left-most in a shared
+		 *   blend-stage when using source split.
+		 * - planes in source split must be contiguous in width
+		 * - planes in source split must have same dest yoff and height
 		 */
-		if (cur_x > prv_x && cur_id < prv_id) {
+		if (right_pid < left_pid) {
 			SDE_ERROR(
-				"shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n",
-				cur_pstate->stage, cur_id, cur_x,
-				prv_id, prv_x);
+				"invalid src split cfg. priority mismatch. stage: %d left: %d right: %d\n",
+				stage, left_pid, right_pid);
 			rc = -EINVAL;
 			goto end;
-		} else if (cur_x < prv_x && cur_id > prv_id) {
+		} else if (right_rect.x != (left_rect.x + left_rect.w)) {
 			SDE_ERROR(
-				"shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n",
-				cur_pstate->stage, prv_id, prv_x,
-				cur_id, cur_x);
+				"non-contiguous coordinates for src split. stage: %d left: %d - %d right: %d - %d\n",
+				stage, left_rect.x, left_rect.w,
+				right_rect.x, right_rect.w);
+			rc = -EINVAL;
+			goto end;
+		} else if ((left_rect.y != right_rect.y) ||
+				(left_rect.h != right_rect.h)) {
+			SDE_ERROR(
+				"source split at stage: %d. invalid yoff/height: l_y: %d r_y: %d l_h: %d r_h: %d\n",
+				stage, left_rect.y, right_rect.y,
+				left_rect.h, right_rect.h);
 			rc = -EINVAL;
 			goto end;
 		}
@@ -2935,13 +3041,21 @@
 			catalog->perf.max_bw_high * 1000ULL,
 			CRTC_PROP_CORE_IB);
 	msm_property_install_range(&sde_crtc->property_info,
-			"mem_ab", 0x0, 0, U64_MAX,
+			"llcc_ab", 0x0, 0, U64_MAX,
 			catalog->perf.max_bw_high * 1000ULL,
-			CRTC_PROP_MEM_AB);
+			CRTC_PROP_LLCC_AB);
 	msm_property_install_range(&sde_crtc->property_info,
-			"mem_ib", 0x0, 0, U64_MAX,
+			"llcc_ib", 0x0, 0, U64_MAX,
 			catalog->perf.max_bw_high * 1000ULL,
-			CRTC_PROP_MEM_IB);
+			CRTC_PROP_LLCC_IB);
+	msm_property_install_range(&sde_crtc->property_info,
+			"dram_ab", 0x0, 0, U64_MAX,
+			catalog->perf.max_bw_high * 1000ULL,
+			CRTC_PROP_DRAM_AB);
+	msm_property_install_range(&sde_crtc->property_info,
+			"dram_ib", 0x0, 0, U64_MAX,
+			catalog->perf.max_bw_high * 1000ULL,
+			CRTC_PROP_DRAM_IB);
 	msm_property_install_range(&sde_crtc->property_info,
 			"rot_prefill_bw", 0, 0, U64_MAX,
 			catalog->perf.max_bw_high * 1000ULL,
@@ -3023,7 +3137,7 @@
 			catalog->perf.min_prefill_lines);
 
 	msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info,
-			info->data, info->len, CRTC_PROP_INFO);
+			info->data, SDE_KMS_INFO_DATALEN(info), CRTC_PROP_INFO);
 
 	kfree(info);
 }
@@ -3069,10 +3183,15 @@
 			case CRTC_PROP_CORE_CLK:
 			case CRTC_PROP_CORE_AB:
 			case CRTC_PROP_CORE_IB:
-			case CRTC_PROP_MEM_AB:
-			case CRTC_PROP_MEM_IB:
 				cstate->bw_control = true;
 				break;
+			case CRTC_PROP_LLCC_AB:
+			case CRTC_PROP_LLCC_IB:
+			case CRTC_PROP_DRAM_AB:
+			case CRTC_PROP_DRAM_IB:
+				cstate->bw_control = true;
+				cstate->bw_split_vote = true;
+				break;
 			default:
 				/* nothing to do */
 				break;
@@ -3282,10 +3401,9 @@
 				sde_crtc->vblank_cb_count * 1000, diff_ms) : 0;
 
 		seq_printf(s,
-			"vblank fps:%lld count:%u total:%llums\n",
-				fps,
-				sde_crtc->vblank_cb_count,
-				ktime_to_ms(diff));
+			"vblank fps:%lld count:%u total:%llums total_framecount:%llu\n",
+				fps, sde_crtc->vblank_cb_count,
+				ktime_to_ms(diff), sde_crtc->play_count);
 
 		/* reset time & count for next measurement */
 		sde_crtc->vblank_cb_count = 0;
@@ -3422,16 +3540,25 @@
 static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v)
 {
 	struct drm_crtc *crtc = (struct drm_crtc *) s->private;
+	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
 	struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state);
 	struct sde_crtc_res *res;
+	int i;
 
 	seq_printf(s, "num_connectors: %d\n", cstate->num_connectors);
 	seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc));
 	seq_printf(s, "intf_mode: %d\n", sde_crtc_get_intf_mode(crtc));
-	seq_printf(s, "bw_ctl: %llu\n", cstate->cur_perf.bw_ctl);
-	seq_printf(s, "core_clk_rate: %llu\n", cstate->cur_perf.core_clk_rate);
-	seq_printf(s, "max_per_pipe_ib: %llu\n",
-			cstate->cur_perf.max_per_pipe_ib);
+	seq_printf(s, "core_clk_rate: %llu\n",
+			sde_crtc->cur_perf.core_clk_rate);
+	for (i = SDE_POWER_HANDLE_DBUS_ID_MNOC;
+			i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+		seq_printf(s, "bw_ctl[%s]: %llu\n",
+				sde_power_handle_get_dbus_name(i),
+				sde_crtc->cur_perf.bw_ctl[i]);
+		seq_printf(s, "max_per_pipe_ib[%s]: %llu\n",
+				sde_power_handle_get_dbus_name(i),
+				sde_crtc->cur_perf.max_per_pipe_ib[i]);
+	}
 
 	seq_printf(s, "rp.%d: ", cstate->rp.sequence_id);
 	list_for_each_entry(res, &cstate->rp.res_list, list)
@@ -3475,14 +3602,14 @@
 		return -ENOMEM;
 
 	/* don't error check these */
-	debugfs_create_file("status", 0444,
+	debugfs_create_file("status", 0400,
 			sde_crtc->debugfs_root,
 			sde_crtc, &debugfs_status_fops);
-	debugfs_create_file("state", 0644,
+	debugfs_create_file("state", 0600,
 			sde_crtc->debugfs_root,
 			&sde_crtc->base,
 			&sde_crtc_debugfs_state_fops);
-	debugfs_create_file("misr_data", 0644, sde_crtc->debugfs_root,
+	debugfs_create_file("misr_data", 0600, sde_crtc->debugfs_root,
 					sde_crtc, &debugfs_misr_fops);
 
 	return 0;
@@ -3572,14 +3699,18 @@
 {
 	unsigned long irq_flags;
 	struct sde_crtc *sde_crtc;
+	struct msm_drm_private *priv;
 	struct sde_crtc_event *event = NULL;
+	u32 crtc_id;
 
-	if (!crtc || !func)
+	if (!crtc || !crtc->dev || !crtc->dev->dev_private || !func) {
+		SDE_ERROR("invalid parameters\n");
 		return -EINVAL;
+	}
 	sde_crtc = to_sde_crtc(crtc);
+	priv = crtc->dev->dev_private;
+	crtc_id = drm_crtc_index(crtc);
 
-	if (!sde_crtc->event_thread)
-		return -EINVAL;
 	/*
 	 * Obtain an event struct from the private cache. This event
 	 * queue may be called from ISR contexts, so use a private
@@ -3603,7 +3734,8 @@
 
 	/* queue new event request */
 	kthread_init_work(&event->kt_work, _sde_crtc_event_cb);
-	kthread_queue_work(&sde_crtc->event_worker, &event->kt_work);
+	kthread_queue_work(&priv->event_thread[crtc_id].worker,
+			&event->kt_work);
 
 	return 0;
 }
@@ -3624,17 +3756,6 @@
 		list_add_tail(&sde_crtc->event_cache[i].list,
 				&sde_crtc->event_free_list);
 
-	kthread_init_worker(&sde_crtc->event_worker);
-	sde_crtc->event_thread = kthread_run(kthread_worker_fn,
-			&sde_crtc->event_worker, "crtc_event:%d",
-			sde_crtc->base.base.id);
-
-	if (IS_ERR_OR_NULL(sde_crtc->event_thread)) {
-		SDE_ERROR("failed to create event thread\n");
-		rc = PTR_ERR(sde_crtc->event_thread);
-		sde_crtc->event_thread = NULL;
-	}
-
 	return rc;
 }
 
@@ -3662,6 +3783,8 @@
 	spin_lock_init(&sde_crtc->spin_lock);
 	atomic_set(&sde_crtc->frame_pending, 0);
 
+	init_completion(&sde_crtc->frame_done_comp);
+
 	INIT_LIST_HEAD(&sde_crtc->frame_event_list);
 	INIT_LIST_HEAD(&sde_crtc->user_event_list);
 	for (i = 0; i < ARRAY_SIZE(sde_crtc->frame_events); i++) {
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 69a9270..f021477 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -121,9 +121,11 @@
  * @stage_cfg     : H/w mixer stage configuration
  * @debugfs_root  : Parent of debugfs node
  * @vblank_cb_count : count of vblank callback since last reset
+ * @play_count    : frame count between crtc enable and disable
  * @vblank_cb_time  : ktime at vblank count reset
  * @vblank_refcount : reference count for vblank enable request
  * @suspend         : whether or not a suspend operation is in progress
+ * @idle_pc       : count of current idle power collapse request
  * @feature_list  : list of color processing features supported on a crtc
  * @active_list   : list of color processing features are active
  * @dirty_list    : list of color processing features are dirty
@@ -134,6 +136,7 @@
  * @frame_events  : static allocation of in-flight frame events
  * @frame_event_list : available frame event list
  * @spin_lock     : spin lock for frame event, transaction status, etc...
+ * @frame_done_comp    : for frame_event_done synchronization
  * @event_thread  : Pointer to event handler thread
  * @event_worker  : Event worker queue
  * @event_cache   : Local cache of event worker structures
@@ -141,6 +144,7 @@
  * @event_lock    : Spinlock around event handling code
  * @misr_enable   : boolean entry indicates misr enable/disable status.
  * @power_event   : registered power event handle
+ * @cur_perf      : current performance committed to clock/bandwidth driver
  */
 struct sde_crtc {
 	struct drm_crtc base;
@@ -166,9 +170,11 @@
 	struct dentry *debugfs_root;
 
 	u32 vblank_cb_count;
+	u64 play_count;
 	ktime_t vblank_cb_time;
 	atomic_t vblank_refcount;
 	bool suspend;
+	u32 idle_pc;
 
 	struct list_head feature_list;
 	struct list_head active_list;
@@ -183,16 +189,17 @@
 	struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE];
 	struct list_head frame_event_list;
 	spinlock_t spin_lock;
+	struct completion frame_done_comp;
 
 	/* for handling internal event thread */
-	struct task_struct *event_thread;
-	struct kthread_worker event_worker;
 	struct sde_crtc_event event_cache[SDE_CRTC_MAX_EVENT_COUNT];
 	struct list_head event_free_list;
 	spinlock_t event_lock;
 	bool misr_enable;
 
 	struct sde_power_event *power_event;
+
+	struct sde_core_perf_params cur_perf;
 };
 
 #define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
@@ -255,7 +262,8 @@
  * @intf_mode     : Interface mode of the primary connector
  * @rsc_client    : sde rsc client when mode is valid
  * @is_ppsplit    : Whether current topology requires PPSplit special handling
- * @bw_control    : true if bw/clk controlled by bw/clk properties
+ * @bw_control    : true if bw/clk controlled by core bw/clk properties
+ * @bw_split_vote : true if bw controlled by llcc/dram bw properties
  * @crtc_roi      : Current CRTC ROI. Possibly sub-rectangle of mode.
  *                  Origin top left of CRTC.
  * @lm_bounds     : LM boundaries based on current mode full resolution, no ROI.
@@ -268,11 +276,11 @@
  * @property_blobs: Reference pointers for blob properties
  * @num_dim_layers: Number of dim layers
  * @dim_layer: Dim layer configs
- * @cur_perf: current performance state
- * @new_perf: new performance state
+ * @new_perf: new performance state being requested
  * @sbuf_cfg: stream buffer configuration
  * @sbuf_prefill_line: number of line for inline rotator prefetch
  * @sbuf_flush_mask: flush mask for inline rotator
+ * @idle_pc: count of idle power collapse request when state is duplicated
  */
 struct sde_crtc_state {
 	struct drm_crtc_state base;
@@ -283,6 +291,7 @@
 	struct sde_rsc_client *rsc_client;
 	bool rsc_update;
 	bool bw_control;
+	bool bw_split_vote;
 
 	bool is_ppsplit;
 	struct sde_rect crtc_roi;
@@ -296,12 +305,13 @@
 	uint32_t num_dim_layers;
 	struct sde_hw_dim_layer dim_layer[SDE_MAX_DIM_LAYERS];
 
-	struct sde_core_perf_params cur_perf;
 	struct sde_core_perf_params new_perf;
 	struct sde_ctl_sbuf_cfg sbuf_cfg;
 	u32 sbuf_prefill_line;
 	u32 sbuf_flush_mask;
 
+	u32 idle_pc;
+
 	struct sde_crtc_respool rp;
 };
 
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 5ccd385..2ff8c38 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -36,6 +36,7 @@
 #include "sde_hw_dsc.h"
 #include "sde_crtc.h"
 #include "sde_trace.h"
+#include "sde_core_irq.h"
 
 #define SDE_DEBUG_ENC(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\
 		(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
@@ -43,8 +44,17 @@
 #define SDE_ERROR_ENC(e, fmt, ...) SDE_ERROR("enc%d " fmt,\
 		(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
 
-/* timeout in frames waiting for frame done */
-#define SDE_ENCODER_FRAME_DONE_TIMEOUT	60
+#define SDE_DEBUG_PHYS(p, fmt, ...) SDE_DEBUG("enc%d intf%d pp%d " fmt,\
+		(p) ? (p)->parent->base.id : -1, \
+		(p) ? (p)->intf_idx - INTF_0 : -1, \
+		(p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \
+		##__VA_ARGS__)
+
+#define SDE_ERROR_PHYS(p, fmt, ...) SDE_ERROR("enc%d intf%d pp%d " fmt,\
+		(p) ? (p)->parent->base.id : -1, \
+		(p) ? (p)->intf_idx - INTF_0 : -1, \
+		(p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \
+		##__VA_ARGS__)
 
 /*
  * Two to anticipate panels that can do cmd/vid dynamic switching
@@ -160,7 +170,6 @@
  * @rsc_cfg:			rsc configuration
  * @cur_conn_roi:		current connector roi
  * @prv_conn_roi:		previous connector roi to optimize if unchanged
- * @disable_inprogress:		sde encoder disable is in progress.
  */
 struct sde_encoder_virt {
 	struct drm_encoder base;
@@ -204,7 +213,6 @@
 	struct sde_encoder_rsc_config rsc_cfg;
 	struct sde_rect cur_conn_roi;
 	struct sde_rect prv_conn_roi;
-	bool disable_inprogress;
 };
 
 #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
@@ -278,6 +286,174 @@
 									enable);
 }
 
+void sde_encoder_helper_report_irq_timeout(struct sde_encoder_phys *phys_enc,
+		enum sde_intr_idx intr_idx)
+{
+	SDE_EVT32(DRMID(phys_enc->parent),
+			phys_enc->intf_idx - INTF_0,
+			phys_enc->hw_pp->idx - PINGPONG_0,
+			intr_idx);
+	SDE_ERROR_PHYS(phys_enc, "irq %d timeout\n", intr_idx);
+
+	if (phys_enc->parent_ops.handle_frame_done)
+		phys_enc->parent_ops.handle_frame_done(
+				phys_enc->parent, phys_enc,
+				SDE_ENCODER_FRAME_EVENT_ERROR);
+}
+
+int sde_encoder_helper_wait_for_irq(struct sde_encoder_phys *phys_enc,
+		enum sde_intr_idx intr_idx,
+		struct sde_encoder_wait_info *wait_info)
+{
+	struct sde_encoder_irq *irq;
+	u32 irq_status;
+	int ret;
+
+	if (!phys_enc || !wait_info || intr_idx >= INTR_IDX_MAX) {
+		SDE_ERROR("invalid params\n");
+		return -EINVAL;
+	}
+	irq = &phys_enc->irq[intr_idx];
+
+	/* note: do master / slave checking outside */
+
+	/* return EWOULDBLOCK since we know the wait isn't necessary */
+	if (phys_enc->enable_state == SDE_ENC_DISABLED) {
+		SDE_ERROR_PHYS(phys_enc, "encoder is disabled\n");
+		return -EWOULDBLOCK;
+	}
+
+	if (irq->irq_idx < 0) {
+		SDE_DEBUG_PHYS(phys_enc, "irq %s hw %d disabled, skip wait\n",
+				irq->name, irq->hw_idx);
+		SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+				irq->irq_idx);
+		return 0;
+	}
+
+	SDE_DEBUG_PHYS(phys_enc, "pending_cnt %d\n",
+			atomic_read(wait_info->atomic_cnt));
+	SDE_EVT32(DRMID(phys_enc->parent), irq->hw_idx,
+			atomic_read(wait_info->atomic_cnt),
+			SDE_EVTLOG_FUNC_ENTRY);
+
+	ret = sde_encoder_helper_wait_event_timeout(
+			DRMID(phys_enc->parent),
+			irq->hw_idx,
+			wait_info);
+
+	if (ret <= 0) {
+		irq_status = sde_core_irq_read(phys_enc->sde_kms,
+				irq->irq_idx, true);
+		if (irq_status) {
+			unsigned long flags;
+
+			SDE_EVT32(DRMID(phys_enc->parent),
+					irq->hw_idx,
+					atomic_read(wait_info->atomic_cnt));
+			SDE_DEBUG_PHYS(phys_enc,
+					"done but irq %d not triggered\n",
+					irq->irq_idx);
+			local_irq_save(flags);
+			irq->cb.func(phys_enc, irq->irq_idx);
+			local_irq_restore(flags);
+			ret = 0;
+		} else {
+			ret = -ETIMEDOUT;
+		}
+	} else {
+		ret = 0;
+	}
+
+	SDE_EVT32(DRMID(phys_enc->parent), irq->hw_idx, ret,
+			SDE_EVTLOG_FUNC_EXIT);
+
+	return ret;
+}
+
+int sde_encoder_helper_register_irq(struct sde_encoder_phys *phys_enc,
+		enum sde_intr_idx intr_idx)
+{
+	struct sde_encoder_irq *irq;
+	int ret = 0;
+
+	if (!phys_enc || intr_idx >= INTR_IDX_MAX) {
+		SDE_ERROR("invalid params\n");
+		return -EINVAL;
+	}
+	irq = &phys_enc->irq[intr_idx];
+
+	if (irq->irq_idx >= 0) {
+		SDE_ERROR_PHYS(phys_enc,
+				"skipping already registered irq %s type %d\n",
+				irq->name, irq->intr_type);
+		return 0;
+	}
+
+	irq->irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms,
+			irq->intr_type, irq->hw_idx);
+	if (irq->irq_idx < 0) {
+		SDE_ERROR_PHYS(phys_enc,
+			"failed to lookup IRQ index for %s type:%d\n",
+			irq->name, irq->intr_type);
+		return -EINVAL;
+	}
+
+	ret = sde_core_irq_register_callback(phys_enc->sde_kms, irq->irq_idx,
+			&irq->cb);
+	if (ret) {
+		SDE_ERROR_PHYS(phys_enc,
+			"failed to register IRQ callback for %s\n",
+			irq->name);
+		irq->irq_idx = -EINVAL;
+		return ret;
+	}
+
+	ret = sde_core_irq_enable(phys_enc->sde_kms, &irq->irq_idx, 1);
+	if (ret) {
+		SDE_ERROR_PHYS(phys_enc,
+			"enable IRQ for intr:%s failed, irq_idx %d\n",
+			irq->name, irq->irq_idx);
+
+		sde_core_irq_unregister_callback(phys_enc->sde_kms,
+				irq->irq_idx, &irq->cb);
+		irq->irq_idx = -EINVAL;
+		return ret;
+	}
+
+	SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, irq->irq_idx);
+	SDE_DEBUG_PHYS(phys_enc, "registered irq %s idx: %d\n",
+			irq->name, irq->irq_idx);
+
+	return ret;
+}
+
+int sde_encoder_helper_unregister_irq(struct sde_encoder_phys *phys_enc,
+		enum sde_intr_idx intr_idx)
+{
+	struct sde_encoder_irq *irq;
+
+	if (!phys_enc) {
+		SDE_ERROR("invalid encoder\n");
+		return -EINVAL;
+	}
+	irq = &phys_enc->irq[intr_idx];
+
+	/* silently skip irqs that weren't registered */
+	if (irq->irq_idx < 0)
+		return 0;
+
+	sde_core_irq_disable(phys_enc->sde_kms, &irq->irq_idx, 1);
+	sde_core_irq_unregister_callback(phys_enc->sde_kms, irq->irq_idx,
+			&irq->cb);
+	irq->irq_idx = -EINVAL;
+
+	SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, irq->irq_idx);
+	SDE_DEBUG_PHYS(phys_enc, "unregistered %d\n", irq->irq_idx);
+
+	return 0;
+}
+
 void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
 		struct sde_encoder_hw_resources *hw_res,
 		struct drm_connector_state *conn_state)
@@ -354,6 +530,7 @@
 	struct split_pipe_cfg cfg = { 0 };
 	struct sde_hw_mdp *hw_mdptop;
 	enum sde_rm_topology_name topology;
+	struct msm_display_info *disp_info;
 
 	if (!phys_enc || !phys_enc->hw_mdptop || !phys_enc->parent) {
 		SDE_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0);
@@ -362,6 +539,10 @@
 
 	sde_enc = to_sde_encoder_virt(phys_enc->parent);
 	hw_mdptop = phys_enc->hw_mdptop;
+	disp_info = &sde_enc->disp_info;
+
+	if (disp_info->intf_type != DRM_MODE_CONNECTOR_DSI)
+		return;
 
 	/**
 	 * disable split modes since encoder will be operating in as the only
@@ -651,7 +832,7 @@
 	sde_kms_rect_merge_rectangles(&c_state->rois, merged_conn_roi);
 }
 
-static int _sde_encoder_dsc_1_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_dsc_n_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc)
 {
 	int this_frame_slices;
 	int intf_ip_w, enc_ip_w;
@@ -692,6 +873,7 @@
 
 	return 0;
 }
+
 static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc,
 		struct sde_encoder_kickoff_params *params)
 {
@@ -892,7 +1074,7 @@
 		return -EINVAL;
 	}
 
-	SDE_DEBUG_ENC(sde_enc, "\n");
+	SDE_DEBUG_ENC(sde_enc, "topology:%d\n", topology);
 	SDE_EVT32(DRMID(&sde_enc->base));
 
 	if (sde_kms_rect_is_equal(&sde_enc->cur_conn_roi,
@@ -901,7 +1083,8 @@
 
 	switch (topology) {
 	case SDE_RM_TOPOLOGY_SINGLEPIPE_DSC:
-		ret = _sde_encoder_dsc_1_lm_1_enc_1_intf(sde_enc);
+	case SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC:
+		ret = _sde_encoder_dsc_n_lm_1_enc_1_intf(sde_enc);
 		break;
 	case SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE:
 		ret = _sde_encoder_dsc_2_lm_2_enc_1_intf(sde_enc, params);
@@ -986,15 +1169,11 @@
 struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *drm_enc)
 {
 	struct sde_encoder_virt *sde_enc;
-	struct msm_display_info *disp_info;
 
 	if (!drm_enc)
 		return NULL;
-
 	sde_enc = to_sde_encoder_virt(drm_enc);
-	disp_info = &sde_enc->disp_info;
-
-	return disp_info->is_primary ? sde_enc->rsc_client : NULL;
+	return sde_enc->rsc_client;
 }
 
 static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
@@ -1416,6 +1595,9 @@
 		hw_mdptop->ops.setup_vsync_sel(hw_mdptop, &te_cfg,
 				sde_enc->disp_info.is_te_using_watchdog_timer);
 	}
+
+	memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi));
+	memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi));
 }
 
 void sde_encoder_virt_restore(struct drm_encoder *drm_enc)
@@ -1457,7 +1639,6 @@
 	SDE_EVT32(DRMID(drm_enc));
 
 	sde_enc->cur_master = NULL;
-	sde_enc->disable_inprogress = false;
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
@@ -1516,7 +1697,6 @@
 
 	priv = drm_enc->dev->dev_private;
 	sde_kms = to_sde_kms(priv->kms);
-	sde_enc->disable_inprogress = true;
 
 	SDE_EVT32(DRMID(drm_enc));
 
@@ -1667,6 +1847,12 @@
 	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
 	unsigned int i;
 
+	if (!sde_enc->frame_busy_mask[0]) {
+		/* suppress frame_done without waiter, likely autorefresh */
+		SDE_EVT32(DRMID(drm_enc), event, ready_phys->intf_idx);
+		return;
+	}
+
 	/* One of the physical encoders has become idle */
 	for (i = 0; i < sde_enc->num_phys_encs; i++)
 		if (sde_enc->phys_encs[i] == ready_phys) {
@@ -1682,9 +1868,6 @@
 		sde_encoder_resource_control(drm_enc,
 				SDE_ENC_RC_EVENT_FRAME_DONE);
 
-		if (sde_enc->disable_inprogress)
-			event |= SDE_ENCODER_FRAME_EVENT_DURING_DISABLE;
-
 		if (sde_enc->crtc_frame_event_cb)
 			sde_enc->crtc_frame_event_cb(
 				sde_enc->crtc_frame_event_cb_data, event);
@@ -1782,23 +1965,23 @@
 int sde_encoder_helper_wait_event_timeout(
 		int32_t drm_id,
 		int32_t hw_id,
-		wait_queue_head_t *wq,
-		atomic_t *cnt,
-		s64 timeout_ms)
+		struct sde_encoder_wait_info *info)
 {
 	int rc = 0;
-	s64 expected_time = ktime_to_ms(ktime_get()) + timeout_ms;
-	s64 jiffies = msecs_to_jiffies(timeout_ms);
+	s64 expected_time = ktime_to_ms(ktime_get()) + info->timeout_ms;
+	s64 jiffies = msecs_to_jiffies(info->timeout_ms);
 	s64 time;
 
 	do {
-		rc = wait_event_timeout(*wq, atomic_read(cnt) == 0, jiffies);
+		rc = wait_event_timeout(*(info->wq),
+				atomic_read(info->atomic_cnt) == 0, jiffies);
 		time = ktime_to_ms(ktime_get());
 
 		SDE_EVT32(drm_id, hw_id, rc, time, expected_time,
-				atomic_read(cnt));
+				atomic_read(info->atomic_cnt));
 	/* If we timed out, counter is valid and time is less, wait again */
-	} while (atomic_read(cnt) && (rc == 0) && (time < expected_time));
+	} while (atomic_read(info->atomic_cnt) && (rc == 0) &&
+			(time < expected_time));
 
 	return rc;
 }
@@ -2038,6 +2221,22 @@
 	}
 }
 
+bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc)
+{
+	struct sde_encoder_virt *sde_enc;
+	struct msm_display_info *disp_info;
+
+	if (!drm_enc) {
+		SDE_ERROR("invalid encoder\n");
+		return false;
+	}
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+	disp_info = &sde_enc->disp_info;
+
+	return (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE);
+}
+
 void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc)
 {
 	struct sde_encoder_virt *sde_enc;
@@ -2146,7 +2345,7 @@
 	SDE_DEBUG_ENC(sde_enc, "\n");
 
 	atomic_set(&sde_enc->frame_done_timeout,
-			SDE_ENCODER_FRAME_DONE_TIMEOUT * 1000 /
+			SDE_FRAME_DONE_TIMEOUT * 1000 /
 			drm_enc->crtc->state->adjusted_mode.vrefresh);
 	mod_timer(&sde_enc->frame_done_timer, jiffies +
 		((atomic_read(&sde_enc->frame_done_timeout) * HZ) / 1000));
@@ -2217,8 +2416,7 @@
 		/* only enable border color on LM */
 		if (phys_enc->hw_ctl->ops.setup_blendstage)
 			phys_enc->hw_ctl->ops.setup_blendstage(
-					phys_enc->hw_ctl,
-					hw_lm->idx, 0, 0);
+					phys_enc->hw_ctl, hw_lm->idx, NULL);
 	}
 
 	if (!lm_valid) {
@@ -2228,6 +2426,25 @@
 	return 0;
 }
 
+void sde_encoder_prepare_commit(struct drm_encoder *drm_enc)
+{
+	struct sde_encoder_virt *sde_enc;
+	struct sde_encoder_phys *phys;
+	int i;
+
+	if (!drm_enc) {
+		SDE_ERROR("invalid encoder\n");
+		return;
+	}
+	sde_enc = to_sde_encoder_virt(drm_enc);
+
+	for (i = 0; i < sde_enc->num_phys_encs; i++) {
+		phys = sde_enc->phys_encs[i];
+		if (phys && phys->ops.prepare_commit)
+			phys->ops.prepare_commit(phys);
+	}
+}
+
 #ifdef CONFIG_DEBUG_FS
 static int _sde_encoder_status_show(struct seq_file *s, void *data)
 {
@@ -2425,10 +2642,10 @@
 		return -ENOMEM;
 
 	/* don't error check these */
-	debugfs_create_file("status", 0644,
+	debugfs_create_file("status", 0600,
 		sde_enc->debugfs_root, sde_enc, &debugfs_status_fops);
 
-	debugfs_create_file("misr_data", 0644,
+	debugfs_create_file("misr_data", 0600,
 		sde_enc->debugfs_root, sde_enc, &debugfs_misr_fops);
 
 	for (i = 0; i < sde_enc->num_phys_encs; i++)
@@ -2708,10 +2925,7 @@
 
 	SDE_ERROR_ENC(sde_enc, "frame done timeout\n");
 
-	event =	SDE_ENCODER_FRAME_EVENT_ERROR;
-	if (sde_enc->disable_inprogress)
-		event |= SDE_ENCODER_FRAME_EVENT_DURING_DISABLE;
-
+	event = SDE_ENCODER_FRAME_EVENT_ERROR;
 	SDE_EVT32(DRMID(drm_enc), event);
 	sde_enc->crtc_frame_event_cb(sde_enc->crtc_frame_event_cb_data, event);
 }
@@ -2789,8 +3003,10 @@
 	return ERR_PTR(ret);
 }
 
-int sde_encoder_wait_for_commit_done(struct drm_encoder *drm_enc)
+int sde_encoder_wait_for_event(struct drm_encoder *drm_enc,
+	enum msm_event_wait event)
 {
+	int (*fn_wait)(struct sde_encoder_phys *phys_enc) = NULL;
 	struct sde_encoder_virt *sde_enc = NULL;
 	int i, ret = 0;
 
@@ -2804,8 +3020,17 @@
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
-		if (phys && phys->ops.wait_for_commit_done) {
-			ret = phys->ops.wait_for_commit_done(phys);
+		switch (event) {
+		case MSM_ENC_COMMIT_DONE:
+			fn_wait = phys->ops.wait_for_commit_done;
+			break;
+		case MSM_ENC_TX_COMPLETE:
+			fn_wait = phys->ops.wait_for_tx_complete;
+			break;
+		};
+
+		if (phys && fn_wait) {
+			ret = fn_wait(phys);
 			if (ret)
 				return ret;
 		}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index d3a9bb4..9c2d3e9 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -27,7 +27,6 @@
 #define SDE_ENCODER_FRAME_EVENT_DONE		BIT(0)
 #define SDE_ENCODER_FRAME_EVENT_ERROR		BIT(1)
 #define SDE_ENCODER_FRAME_EVENT_PANEL_DEAD	BIT(2)
-#define SDE_ENCODER_FRAME_EVENT_DURING_DISABLE	BIT(3)
 
 /**
  * Encoder functions and data types
@@ -128,14 +127,24 @@
 void sde_encoder_kickoff(struct drm_encoder *encoder);
 
 /**
- * sde_encoder_wait_nxt_committed - Wait for hardware to have flushed the
- *	current pending frames to hardware at a vblank or ctl_start
- *	Encoders will map this differently depending on irqs
- *	vid mode -> vsync_irq
+ * sde_encoder_wait_for_event - Waits for encoder events
  * @encoder:	encoder pointer
+ * @event:      event to wait for
+ * MSM_ENC_COMMIT_DONE -  Wait for hardware to have flushed the current pending
+ *                        frames to hardware at a vblank or ctl_start
+ *                        Encoders will map this differently depending on the
+ *                        panel type.
+ *	                  vid mode -> vsync_irq
+ *                        cmd mode -> ctl_start
+ * MSM_ENC_TX_COMPLETE -  Wait for the hardware to transfer all the pixels to
+ *                        the panel. Encoders will map this differently
+ *                        depending on the panel type.
+ *                        vid mode -> vsync_irq
+ *                        cmd mode -> pp_done
  * Returns: 0 on success, -EWOULDBLOCK if already signaled, error otherwise
  */
-int sde_encoder_wait_for_commit_done(struct drm_encoder *drm_encoder);
+int sde_encoder_wait_for_event(struct drm_encoder *drm_encoder,
+						enum msm_event_wait event);
 
 /*
  * sde_encoder_get_intf_mode - get interface mode of the given encoder
@@ -164,6 +173,13 @@
 bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc);
 
 /**
+ * sde_encoder_is_cmd_mode - check if it is cmd mode
+ * @drm_enc: Pointer to drm encoder object
+ * @Return: true if it is cmd mode
+ */
+bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc);
+
+/**
  * sde_encoder_init - initialize virtual encoder object
  * @dev:        Pointer to drm device structure
  * @disp_info:  Pointer to display information structure
@@ -179,4 +195,11 @@
  */
 void sde_encoder_destroy(struct drm_encoder *drm_enc);
 
+/**
+ * sde_encoder_prepare_commit - prepare encoder at the very beginning of an
+ *	atomic commit, before any registers are written
+ * @drm_enc:    Pointer to previously created drm encoder structure
+ */
+void sde_encoder_prepare_commit(struct drm_encoder *drm_enc);
+
 #endif /* __SDE_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index c2ef28d..b173876 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -94,6 +94,7 @@
  * struct sde_encoder_phys_ops - Interface the physical encoders provide to
  *	the containing virtual encoder.
  * @late_register:		DRM Call. Add Userspace interfaces, debugfs.
+ * @prepare_commit:		MSM Atomic Call, start of atomic commit sequence
  * @is_master:			Whether this phys_enc is the current master
  *				encoder. Can be switched at enable time. Based
  *				on split_role and current mode (CMD/VID).
@@ -110,6 +111,8 @@
  * @control_vblank_irq		Register/Deregister for VBLANK IRQ
  * @wait_for_commit_done:	Wait for hardware to have flushed the
  *				current pending frames to hardware
+ * @wait_for_tx_complete:	Wait for hardware to transfer the pixels
+ *				to the panel
  * @prepare_for_kickoff:	Do any work necessary prior to a kickoff
  *				For CMD encoder, may wait for previous tx done
  * @handle_post_kickoff:	Do any work necessary post-kickoff work
@@ -127,6 +130,7 @@
 struct sde_encoder_phys_ops {
 	int (*late_register)(struct sde_encoder_phys *encoder,
 			struct dentry *debugfs_root);
+	void (*prepare_commit)(struct sde_encoder_phys *encoder);
 	bool (*is_master)(struct sde_encoder_phys *encoder);
 	bool (*mode_fixup)(struct sde_encoder_phys *encoder,
 			const struct drm_display_mode *mode,
@@ -145,6 +149,7 @@
 			struct drm_connector_state *conn_state);
 	int (*control_vblank_irq)(struct sde_encoder_phys *enc, bool enable);
 	int (*wait_for_commit_done)(struct sde_encoder_phys *phys_enc);
+	int (*wait_for_tx_complete)(struct sde_encoder_phys *phys_enc);
 	void (*prepare_for_kickoff)(struct sde_encoder_phys *phys_enc,
 			struct sde_encoder_kickoff_params *params);
 	void (*handle_post_kickoff)(struct sde_encoder_phys *phys_enc);
@@ -167,6 +172,8 @@
  * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel
  * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel
  * @INTR_IDX_RDPTR:    Readpointer done unterrupt for cmd mode panel
+ * @INTR_IDX_AUTOREFRESH_DONE:  Autorefresh done for cmd mode panel meaning
+ *                              autorefresh has triggered a double buffer flip
  */
 enum sde_intr_idx {
 	INTR_IDX_VSYNC,
@@ -174,10 +181,30 @@
 	INTR_IDX_UNDERRUN,
 	INTR_IDX_CTL_START,
 	INTR_IDX_RDPTR,
+	INTR_IDX_AUTOREFRESH_DONE,
 	INTR_IDX_MAX,
 };
 
 /**
+ * sde_encoder_irq - tracking structure for interrupts
+ * @name:		string name of interrupt
+ * @intr_type:		Encoder interrupt type
+ * @intr_idx:		Encoder interrupt enumeration
+ * @hw_idx:		HW Block ID
+ * @irq_idx:		IRQ interface lookup index from SDE IRQ framework
+ *			will be -EINVAL if IRQ is not registered
+ * @irq_cb:		interrupt callback
+ */
+struct sde_encoder_irq {
+	const char *name;
+	enum sde_intr_type intr_type;
+	enum sde_intr_idx intr_idx;
+	int hw_idx;
+	int irq_idx;
+	struct sde_irq_callback cb;
+};
+
+/**
  * struct sde_encoder_phys - physical encoder that drives a single INTF block
  *	tied to a specific panel / sub-panel. Abstract type, sub-classed by
  *	phys_vid or phys_cmd for video mode or command mode encs respectively.
@@ -209,6 +236,7 @@
  * @pending_ctlstart_cnt:	Atomic counter tracking the number of ctl start
  *                              pending.
  * @pending_kickoff_wq:		Wait queue for blocking until kickoff completes
+ * @irq:			IRQ tracking structures
  */
 struct sde_encoder_phys {
 	struct drm_encoder *parent;
@@ -234,6 +262,7 @@
 	atomic_t pending_ctlstart_cnt;
 	atomic_t pending_kickoff_cnt;
 	wait_queue_head_t pending_kickoff_wq;
+	struct sde_encoder_irq irq[INTR_IDX_MAX];
 };
 
 static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys)
@@ -246,42 +275,46 @@
  * struct sde_encoder_phys_vid - sub-class of sde_encoder_phys to handle video
  *	mode specific operations
  * @base:	Baseclass physical encoder structure
- * @irq_idx:	IRQ interface lookup index
- * @irq_cb:	interrupt callback
  * @hw_intf:	Hardware interface to the intf registers
  * @timing_params: Current timing parameter
  * @rot_prefill_line: number of line to prefill for inline rotation; 0 disable
  */
 struct sde_encoder_phys_vid {
 	struct sde_encoder_phys base;
-	int irq_idx[INTR_IDX_MAX];
-	struct sde_irq_callback irq_cb[INTR_IDX_MAX];
 	struct sde_hw_intf *hw_intf;
 	struct intf_timing_params timing_params;
 	u64 rot_prefill_line;
 };
 
 /**
+ * struct sde_encoder_phys_cmd_autorefresh - autorefresh state tracking
+ * @cfg: current active autorefresh configuration
+ * @kickoff_cnt: atomic count tracking autorefresh done irq kickoffs pending
+ * @kickoff_wq:	wait queue for waiting on autorefresh done irq
+ */
+struct sde_encoder_phys_cmd_autorefresh {
+	struct sde_hw_autorefresh cfg;
+	atomic_t kickoff_cnt;
+	wait_queue_head_t kickoff_wq;
+};
+
+/**
  * struct sde_encoder_phys_cmd - sub-class of sde_encoder_phys to handle command
  *	mode specific operations
  * @base:	Baseclass physical encoder structure
  * @intf_idx:	Intf Block index used by this phys encoder
  * @stream_sel:	Stream selection for multi-stream interfaces
- * @pp_rd_ptr_irq_idx:	IRQ signifying panel's frame read pointer
- *			For CMD encoders, VBLANK is driven by the PP RD Done IRQ
- * @pp_tx_done_irq_idx:	IRQ signifying frame transmission to panel complete
- * @irq_cb:		interrupt callback
  * @serialize_wait4pp:	serialize wait4pp feature waits for pp_done interrupt
  *			after ctl_start instead of before next frame kickoff
  * @pp_timeout_report_cnt: number of pingpong done irq timeout errors
+ * @autorefresh: autorefresh feature state
  */
 struct sde_encoder_phys_cmd {
 	struct sde_encoder_phys base;
 	int stream_sel;
-	int irq_idx[INTR_IDX_MAX];
-	struct sde_irq_callback irq_cb[INTR_IDX_MAX];
 	bool serialize_wait4pp;
 	int pp_timeout_report_cnt;
+	struct sde_encoder_phys_cmd_autorefresh autorefresh;
 };
 
 /**
@@ -353,6 +386,18 @@
 };
 
 /**
+ * sde_encoder_wait_info - container for passing arguments to irq wait functions
+ * @wq: wait queue structure
+ * @atomic_cnt: wait until atomic_cnt equals zero
+ * @timeout_ms: timeout value in milliseconds
+ */
+struct sde_encoder_wait_info {
+	wait_queue_head_t *wq;
+	atomic_t *atomic_cnt;
+	s64 timeout_ms;
+};
+
+/**
  * sde_encoder_phys_vid_init - Construct a new video mode physical encoder
  * @p:	Pointer to init params structure
  * Return: Error code or newly allocated encoder
@@ -404,16 +449,12 @@
  *	making sure that elapsed time during wait is valid.
  * @drm_id: drm object id for logging
  * @hw_id: hw instance id for logging
- * @wq: wait queue structure
- * @cnt: atomic counter to wait on
- * @timeout_ms: timeout value in milliseconds
+ * @info: wait info structure
  */
 int sde_encoder_helper_wait_event_timeout(
 		int32_t drm_id,
 		int32_t hw_id,
-		wait_queue_head_t *wq,
-		atomic_t *cnt,
-		s64 timeout_ms);
+		struct sde_encoder_wait_info *info);
 
 /**
  * sde_encoder_helper_hw_reset - issue ctl hw reset
@@ -434,7 +475,8 @@
 
 	topology = sde_connector_get_topology_name(phys_enc->connector);
 	if (phys_enc->split_role == ENC_ROLE_SOLO &&
-			topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE)
+			(topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE ||
+			 topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC))
 		return BLEND_3D_H_ROW_INT;
 
 	return BLEND_3D_NONE;
@@ -460,4 +502,43 @@
 int sde_encoder_helper_hw_release(struct sde_encoder_phys *phys_enc,
 		struct drm_framebuffer *fb);
 
+/**
+ * sde_encoder_helper_report_irq_timeout - utility to report error that irq has
+ *	timed out, including reporting frame error event to crtc and debug dump
+ * @phys_enc: Pointer to physical encoder structure
+ * @intr_idx: Failing interrupt index
+ */
+void sde_encoder_helper_report_irq_timeout(struct sde_encoder_phys *phys_enc,
+		enum sde_intr_idx intr_idx);
+
+/**
+ * sde_encoder_helper_wait_for_irq - utility to wait on an irq.
+ *	note: will call sde_encoder_helper_wait_for_irq on timeout
+ * @phys_enc: Pointer to physical encoder structure
+ * @intr_idx: encoder interrupt index
+ * @wait_info: wait info struct
+ * @Return: 0 or -ERROR
+ */
+int sde_encoder_helper_wait_for_irq(struct sde_encoder_phys *phys_enc,
+		enum sde_intr_idx intr_idx,
+		struct sde_encoder_wait_info *wait_info);
+
+/**
+ * sde_encoder_helper_register_irq - register and enable an irq
+ * @phys_enc: Pointer to physical encoder structure
+ * @intr_idx: encoder interrupt index
+ * @Return: 0 or -ERROR
+ */
+int sde_encoder_helper_register_irq(struct sde_encoder_phys *phys_enc,
+		enum sde_intr_idx intr_idx);
+
+/**
+ * sde_encoder_helper_unregister_irq - unregister and disable an irq
+ * @phys_enc: Pointer to physical encoder structure
+ * @intr_idx: encoder interrupt index
+ * @Return: 0 or -ERROR
+ */
+int sde_encoder_helper_unregister_irq(struct sde_encoder_phys *phys_enc,
+		enum sde_intr_idx intr_idx);
+
 #endif /* __sde_encoder_phys_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 7adab09..9880ab1 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -44,6 +44,16 @@
 #define DEFAULT_TEARCHECK_SYNC_THRESH_START	4
 #define DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE	4
 
+#define SDE_ENC_WR_PTR_START_TIMEOUT_US 20000
+
+static inline int _sde_encoder_phys_cmd_get_idle_timeout(
+		struct sde_encoder_phys_cmd *cmd_enc)
+{
+	return cmd_enc->autorefresh.cfg.frame_count ?
+			cmd_enc->autorefresh.cfg.frame_count *
+			KICKOFF_TIMEOUT_MS : KICKOFF_TIMEOUT_MS;
+}
+
 static inline bool sde_encoder_phys_cmd_is_master(
 		struct sde_encoder_phys *phys_enc)
 {
@@ -60,6 +70,52 @@
 	return true;
 }
 
+static uint64_t _sde_encoder_phys_cmd_get_autorefresh_property(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct drm_connector *conn = phys_enc->connector;
+
+	if (!conn || !conn->state)
+		return 0;
+
+	return sde_connector_get_property(conn->state,
+				CONNECTOR_PROP_AUTOREFRESH);
+}
+
+static void _sde_encoder_phys_cmd_config_autorefresh(
+		struct sde_encoder_phys *phys_enc,
+		u32 new_frame_count)
+{
+	struct sde_encoder_phys_cmd *cmd_enc =
+			to_sde_encoder_phys_cmd(phys_enc);
+	struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp;
+	struct drm_connector *conn = phys_enc->connector;
+	struct sde_hw_autorefresh *cfg_cur, cfg_nxt;
+
+	if (!conn || !conn->state || !hw_pp)
+		return;
+
+	cfg_cur = &cmd_enc->autorefresh.cfg;
+
+	/* autorefresh property value should be validated already */
+	memset(&cfg_nxt, 0, sizeof(cfg_nxt));
+	cfg_nxt.frame_count = new_frame_count;
+	cfg_nxt.enable = (cfg_nxt.frame_count != 0);
+
+	SDE_DEBUG_CMDENC(cmd_enc, "autorefresh state %d->%d framecount %d\n",
+			cfg_cur->enable, cfg_nxt.enable, cfg_nxt.frame_count);
+	SDE_EVT32(DRMID(phys_enc->parent), hw_pp->idx, cfg_cur->enable,
+			cfg_nxt.enable, cfg_nxt.frame_count);
+
+	/* only proceed on state changes */
+	if (cfg_nxt.enable == cfg_cur->enable)
+		return;
+
+	memcpy(cfg_cur, &cfg_nxt, sizeof(*cfg_cur));
+	if (hw_pp->ops.setup_autorefresh)
+		hw_pp->ops.setup_autorefresh(hw_pp, cfg_cur);
+}
+
 static void _sde_encoder_phys_cmd_update_flush_mask(
 		struct sde_encoder_phys *phys_enc)
 {
@@ -99,6 +155,125 @@
 	ctl->ops.setup_intf_cfg(ctl, &intf_cfg);
 }
 
+static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
+{
+	struct sde_encoder_phys *phys_enc = arg;
+	unsigned long lock_flags;
+	int new_cnt;
+
+	if (!phys_enc)
+		return;
+
+	/* notify all synchronous clients first, then asynchronous clients */
+	if (phys_enc->parent_ops.handle_frame_done)
+		phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
+				phys_enc, SDE_ENCODER_FRAME_EVENT_DONE);
+
+	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+	new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
+	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+
+	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
+			phys_enc->hw_pp->idx - PINGPONG_0, new_cnt);
+
+	/* Signal any waiting atomic commit thread */
+	wake_up_all(&phys_enc->pending_kickoff_wq);
+}
+
+static void sde_encoder_phys_cmd_autorefresh_done_irq(void *arg, int irq_idx)
+{
+	struct sde_encoder_phys *phys_enc = arg;
+	struct sde_encoder_phys_cmd *cmd_enc =
+			to_sde_encoder_phys_cmd(phys_enc);
+	unsigned long lock_flags;
+	int new_cnt;
+
+	if (!cmd_enc)
+		return;
+
+	phys_enc = &cmd_enc->base;
+	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+	new_cnt = atomic_add_unless(&cmd_enc->autorefresh.kickoff_cnt, -1, 0);
+	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+
+	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
+			phys_enc->hw_pp->idx - PINGPONG_0, new_cnt);
+
+	/* Signal any waiting atomic commit thread */
+	wake_up_all(&cmd_enc->autorefresh.kickoff_wq);
+}
+
+static void sde_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx)
+{
+	struct sde_encoder_phys *phys_enc = arg;
+
+	if (!phys_enc)
+		return;
+
+	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
+			phys_enc->hw_pp->idx - PINGPONG_0, 0xfff);
+
+	if (phys_enc->parent_ops.handle_vblank_virt)
+		phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
+			phys_enc);
+}
+
+static void sde_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx)
+{
+	struct sde_encoder_phys *phys_enc = arg;
+	struct sde_hw_ctl *ctl;
+
+	if (!phys_enc)
+		return;
+
+	if (!phys_enc->hw_ctl)
+		return;
+
+	ctl = phys_enc->hw_ctl;
+	SDE_EVT32_IRQ(DRMID(phys_enc->parent), ctl->idx - CTL_0, 0xfff);
+	atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
+
+	/* Signal any waiting ctl start interrupt */
+	wake_up_all(&phys_enc->pending_kickoff_wq);
+}
+
+static void sde_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx)
+{
+	struct sde_encoder_phys *phys_enc = arg;
+
+	if (!phys_enc)
+		return;
+
+	if (phys_enc->parent_ops.handle_underrun_virt)
+		phys_enc->parent_ops.handle_underrun_virt(phys_enc->parent,
+			phys_enc);
+}
+
+static void _sde_encoder_phys_cmd_setup_irq_hw_idx(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_irq *irq;
+
+	irq = &phys_enc->irq[INTR_IDX_CTL_START];
+	irq->hw_idx = phys_enc->hw_ctl->idx;
+	irq->irq_idx = -EINVAL;
+
+	irq = &phys_enc->irq[INTR_IDX_PINGPONG];
+	irq->hw_idx = phys_enc->hw_pp->idx;
+	irq->irq_idx = -EINVAL;
+
+	irq = &phys_enc->irq[INTR_IDX_RDPTR];
+	irq->hw_idx = phys_enc->hw_pp->idx;
+	irq->irq_idx = -EINVAL;
+
+	irq = &phys_enc->irq[INTR_IDX_UNDERRUN];
+	irq->hw_idx = phys_enc->intf_idx;
+	irq->irq_idx = -EINVAL;
+
+	irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE];
+	irq->hw_idx = phys_enc->hw_pp->idx;
+	irq->irq_idx = -EINVAL;
+}
 
 static void sde_encoder_phys_cmd_mode_set(
 		struct sde_encoder_phys *phys_enc,
@@ -112,8 +287,7 @@
 	int i, instance;
 
 	if (!phys_enc || !mode || !adj_mode) {
-		SDE_ERROR("invalid arg(s), enc %d mode %d adj_mode %d\n",
-				phys_enc != 0, mode != 0, adj_mode != 0);
+		SDE_ERROR("invalid args\n");
 		return;
 	}
 	phys_enc->cached_mode = *adj_mode;
@@ -135,71 +309,8 @@
 		phys_enc->hw_ctl = NULL;
 		return;
 	}
-}
 
-static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
-{
-	struct sde_encoder_phys_cmd *cmd_enc = arg;
-	struct sde_encoder_phys *phys_enc;
-	unsigned long lock_flags;
-	int new_cnt;
-
-	if (!cmd_enc)
-		return;
-
-	phys_enc = &cmd_enc->base;
-
-	/* notify all synchronous clients first, then asynchronous clients */
-	if (phys_enc->parent_ops.handle_frame_done)
-		phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
-				phys_enc, SDE_ENCODER_FRAME_EVENT_DONE);
-
-	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
-	new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
-	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
-
-	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
-			phys_enc->hw_pp->idx - PINGPONG_0, new_cnt);
-
-	/* Signal any waiting atomic commit thread */
-	wake_up_all(&phys_enc->pending_kickoff_wq);
-}
-
-static void sde_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx)
-{
-	struct sde_encoder_phys_cmd *cmd_enc = arg;
-	struct sde_encoder_phys *phys_enc = &cmd_enc->base;
-
-	if (!cmd_enc)
-		return;
-
-	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
-			phys_enc->hw_pp->idx - PINGPONG_0, 0xfff);
-
-	if (phys_enc->parent_ops.handle_vblank_virt)
-		phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
-			phys_enc);
-}
-
-static void sde_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx)
-{
-	struct sde_encoder_phys_cmd *cmd_enc = arg;
-	struct sde_encoder_phys *phys_enc;
-	struct sde_hw_ctl *ctl;
-
-	if (!cmd_enc)
-		return;
-
-	phys_enc = &cmd_enc->base;
-	if (!phys_enc->hw_ctl)
-		return;
-
-	ctl = phys_enc->hw_ctl;
-	SDE_EVT32_IRQ(DRMID(phys_enc->parent), ctl->idx - CTL_0, 0xfff);
-	atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
-
-	/* Signal any waiting ctl start interrupt */
-	wake_up_all(&phys_enc->pending_kickoff_wq);
+	_sde_encoder_phys_cmd_setup_irq_hw_idx(phys_enc);
 }
 
 static bool _sde_encoder_phys_is_ppsplit(struct sde_encoder_phys *phys_enc)
@@ -274,12 +385,80 @@
 			phys_enc->split_role == ENC_ROLE_SLAVE;
 }
 
+static int _sde_encoder_phys_cmd_poll_write_pointer_started(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_phys_cmd *cmd_enc =
+			to_sde_encoder_phys_cmd(phys_enc);
+	struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp;
+	struct sde_hw_pp_vsync_info info;
+	u32 timeout_us = SDE_ENC_WR_PTR_START_TIMEOUT_US;
+	int ret;
+
+	if (!hw_pp || !hw_pp->ops.get_vsync_info ||
+			!hw_pp->ops.poll_timeout_wr_ptr)
+		return 0;
+
+	ret = hw_pp->ops.get_vsync_info(hw_pp, &info);
+	if (ret)
+		return ret;
+
+	SDE_DEBUG_CMDENC(cmd_enc,
+			"pp:%d rd_ptr %d wr_ptr %d\n",
+			phys_enc->hw_pp->idx - PINGPONG_0,
+			info.rd_ptr_line_count,
+			info.wr_ptr_line_count);
+	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
+			info.wr_ptr_line_count);
+
+	ret = hw_pp->ops.poll_timeout_wr_ptr(hw_pp, timeout_us);
+	if (ret) {
+		SDE_EVT32(DRMID(phys_enc->parent),
+				phys_enc->hw_pp->idx - PINGPONG_0,
+				timeout_us,
+				ret);
+		SDE_DBG_DUMP("sde", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl",
+				"dsi1_phy", "vbif_rt", "dbg_bus",
+				"vbif_dbg_bus", "panic");
+	}
+
+	return ret;
+}
+
+static bool _sde_encoder_phys_cmd_is_ongoing_pptx(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct sde_hw_pingpong *hw_pp;
+	struct sde_hw_pp_vsync_info info;
+
+	if (!phys_enc)
+		return false;
+
+	hw_pp = phys_enc->hw_pp;
+	if (!hw_pp || !hw_pp->ops.get_vsync_info)
+		return false;
+
+	hw_pp->ops.get_vsync_info(hw_pp, &info);
+
+	SDE_EVT32(DRMID(phys_enc->parent),
+			phys_enc->hw_pp->idx - PINGPONG_0,
+			atomic_read(&phys_enc->pending_kickoff_cnt),
+			info.wr_ptr_line_count,
+			phys_enc->cached_mode.vdisplay);
+
+	if (info.wr_ptr_line_count > 0 && info.wr_ptr_line_count <
+			phys_enc->cached_mode.vdisplay)
+		return true;
+
+	return false;
+}
+
 static int _sde_encoder_phys_cmd_wait_for_idle(
 		struct sde_encoder_phys *phys_enc)
 {
 	struct sde_encoder_phys_cmd *cmd_enc =
 			to_sde_encoder_phys_cmd(phys_enc);
-	u32 irq_status;
+	struct sde_encoder_wait_info wait_info;
 	int ret;
 
 	if (!phys_enc) {
@@ -287,74 +466,30 @@
 		return -EINVAL;
 	}
 
+	wait_info.wq = &phys_enc->pending_kickoff_wq;
+	wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
+	wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
+
 	/* slave encoder doesn't enable for ppsplit */
 	if (_sde_encoder_phys_is_ppsplit_slave(phys_enc))
 		return 0;
 
-	/* return EWOULDBLOCK since we know the wait isn't necessary */
-	if (phys_enc->enable_state == SDE_ENC_DISABLED) {
-		SDE_ERROR_CMDENC(cmd_enc, "encoder is disabled\n");
-		return -EWOULDBLOCK;
-	}
-
-	/* wait for previous kickoff to complete */
-	ret = sde_encoder_helper_wait_event_timeout(
-			DRMID(phys_enc->parent),
-			phys_enc->hw_pp->idx - PINGPONG_0,
-			&phys_enc->pending_kickoff_wq,
-			&phys_enc->pending_kickoff_cnt,
-			KICKOFF_TIMEOUT_MS);
-	if (ret <= 0) {
-		/* read and clear interrupt */
-		irq_status = sde_core_irq_read(phys_enc->sde_kms,
-				cmd_enc->irq_idx[INTR_IDX_PINGPONG], true);
-		if (irq_status) {
-			unsigned long flags;
-			SDE_EVT32(DRMID(phys_enc->parent),
-					phys_enc->hw_pp->idx - PINGPONG_0);
-			SDE_DEBUG_CMDENC(cmd_enc,
-					"pp:%d done but irq not triggered\n",
-					phys_enc->hw_pp->idx - PINGPONG_0);
-			local_irq_save(flags);
-			sde_encoder_phys_cmd_pp_tx_done_irq(cmd_enc,
-					INTR_IDX_PINGPONG);
-			local_irq_restore(flags);
-			ret = 0;
-		} else {
-			ret = _sde_encoder_phys_cmd_handle_ppdone_timeout(
-					phys_enc);
-		}
-	} else {
-		ret = 0;
-	}
-
-	if (!ret)
+	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG,
+			&wait_info);
+	if (ret == -ETIMEDOUT)
+		_sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc);
+	else if (!ret)
 		cmd_enc->pp_timeout_report_cnt = 0;
 
 	return ret;
 }
 
-static void sde_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx)
-{
-	struct sde_encoder_phys_cmd *cmd_enc = arg;
-	struct sde_encoder_phys *phys_enc;
-
-	if (!cmd_enc)
-		return;
-
-	phys_enc = &cmd_enc->base;
-	if (phys_enc->parent_ops.handle_underrun_virt)
-		phys_enc->parent_ops.handle_underrun_virt(phys_enc->parent,
-			phys_enc);
-}
-
-static int sde_encoder_phys_cmd_register_irq(struct sde_encoder_phys *phys_enc,
-	enum sde_intr_type intr_type, int idx,
-	void (*irq_func)(void *, int), const char *irq_name)
+static int _sde_encoder_phys_cmd_wait_for_autorefresh_done(
+		struct sde_encoder_phys *phys_enc)
 {
 	struct sde_encoder_phys_cmd *cmd_enc =
 			to_sde_encoder_phys_cmd(phys_enc);
-	int idx_lookup = 0;
+	struct sde_encoder_wait_info wait_info;
 	int ret = 0;
 
 	if (!phys_enc) {
@@ -362,79 +497,29 @@
 		return -EINVAL;
 	}
 
-	if (intr_type == SDE_IRQ_TYPE_INTF_UNDER_RUN)
-		idx_lookup = phys_enc->intf_idx;
-	else if (intr_type == SDE_IRQ_TYPE_CTL_START)
-		idx_lookup = phys_enc->hw_ctl ? phys_enc->hw_ctl->idx : -1;
+	/* only master deals with autorefresh */
+	if (!sde_encoder_phys_cmd_is_master(phys_enc))
+		return 0;
+
+	wait_info.wq = &cmd_enc->autorefresh.kickoff_wq;
+	wait_info.atomic_cnt = &cmd_enc->autorefresh.kickoff_cnt;
+	wait_info.timeout_ms = _sde_encoder_phys_cmd_get_idle_timeout(cmd_enc);
+
+	/* wait for autorefresh kickoff to start */
+	ret = sde_encoder_helper_wait_for_irq(phys_enc,
+			INTR_IDX_AUTOREFRESH_DONE, &wait_info);
+
+	/* double check that kickoff has started by reading write ptr reg */
+	if (!ret)
+		ret = _sde_encoder_phys_cmd_poll_write_pointer_started(
+			phys_enc);
 	else
-		idx_lookup = phys_enc->hw_pp->idx;
-
-	cmd_enc->irq_idx[idx] = sde_core_irq_idx_lookup(phys_enc->sde_kms,
-			intr_type, idx_lookup);
-	if (cmd_enc->irq_idx[idx] < 0) {
-		SDE_ERROR_CMDENC(cmd_enc,
-			"failed to lookup IRQ index for %s with pp=%d\n",
-			irq_name,
-			phys_enc->hw_pp->idx - PINGPONG_0);
-		return -EINVAL;
-	}
-
-	cmd_enc->irq_cb[idx].func = irq_func;
-	cmd_enc->irq_cb[idx].arg = cmd_enc;
-	ret = sde_core_irq_register_callback(phys_enc->sde_kms,
-			cmd_enc->irq_idx[idx], &cmd_enc->irq_cb[idx]);
-	if (ret) {
-		SDE_ERROR_CMDENC(cmd_enc,
-				"failed to register IRQ callback %s\n",
-				irq_name);
-		return ret;
-	}
-
-	ret = sde_core_irq_enable(phys_enc->sde_kms, &cmd_enc->irq_idx[idx], 1);
-	if (ret) {
-		SDE_ERROR_CMDENC(cmd_enc,
-			"failed to enable IRQ for %s, pp %d, irq_idx %d\n",
-			irq_name,
-			phys_enc->hw_pp->idx - PINGPONG_0,
-			cmd_enc->irq_idx[idx]);
-		cmd_enc->irq_idx[idx] = -EINVAL;
-
-		/* Unregister callback on IRQ enable failure */
-		sde_core_irq_unregister_callback(phys_enc->sde_kms,
-				cmd_enc->irq_idx[idx], &cmd_enc->irq_cb[idx]);
-		return ret;
-	}
-
-	SDE_DEBUG_CMDENC(cmd_enc, "registered IRQ %s for pp %d, irq_idx %d\n",
-			irq_name,
-			phys_enc->hw_pp->idx - PINGPONG_0,
-			cmd_enc->irq_idx[idx]);
+		sde_encoder_helper_report_irq_timeout(phys_enc,
+				INTR_IDX_AUTOREFRESH_DONE);
 
 	return ret;
 }
 
-static int sde_encoder_phys_cmd_unregister_irq(
-		struct sde_encoder_phys *phys_enc, int idx)
-{
-	struct sde_encoder_phys_cmd *cmd_enc =
-			to_sde_encoder_phys_cmd(phys_enc);
-
-	if (!phys_enc) {
-		SDE_ERROR("invalid encoder\n");
-		return -EINVAL;
-	}
-
-	sde_core_irq_disable(phys_enc->sde_kms, &cmd_enc->irq_idx[idx], 1);
-	sde_core_irq_unregister_callback(phys_enc->sde_kms,
-			cmd_enc->irq_idx[idx], &cmd_enc->irq_cb[idx]);
-
-	SDE_DEBUG_CMDENC(cmd_enc, "unregistered IRQ for pp %d, irq_idx %d\n",
-			phys_enc->hw_pp->idx - PINGPONG_0,
-			cmd_enc->irq_idx[idx]);
-
-	return 0;
-}
-
 static int sde_encoder_phys_cmd_control_vblank_irq(
 		struct sde_encoder_phys *phys_enc,
 		bool enable)
@@ -460,13 +545,9 @@
 			enable, atomic_read(&phys_enc->vblank_refcount));
 
 	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
-		ret = sde_encoder_phys_cmd_register_irq(phys_enc,
-				SDE_IRQ_TYPE_PING_PONG_RD_PTR,
-				INTR_IDX_RDPTR,
-				sde_encoder_phys_cmd_pp_rd_ptr_irq,
-				"pp_rd_ptr");
+		ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR);
 	else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
-		ret = sde_encoder_phys_cmd_unregister_irq(phys_enc,
+		ret = sde_encoder_helper_unregister_irq(phys_enc,
 				INTR_IDX_RDPTR);
 
 end:
@@ -489,35 +570,28 @@
 	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
 
 	if (enable) {
-		sde_encoder_phys_cmd_register_irq(phys_enc,
-				SDE_IRQ_TYPE_PING_PONG_COMP,
-				INTR_IDX_PINGPONG,
-				sde_encoder_phys_cmd_pp_tx_done_irq,
-				"pp_tx_done");
-
+		sde_encoder_helper_register_irq(phys_enc, INTR_IDX_PINGPONG);
+		sde_encoder_helper_register_irq(phys_enc, INTR_IDX_UNDERRUN);
 		sde_encoder_phys_cmd_control_vblank_irq(phys_enc, true);
 
-		sde_encoder_phys_cmd_register_irq(phys_enc,
-				SDE_IRQ_TYPE_INTF_UNDER_RUN,
-				INTR_IDX_UNDERRUN,
-				sde_encoder_phys_cmd_underrun_irq,
-				"underrun");
+		if (sde_encoder_phys_cmd_is_master(phys_enc)) {
+			sde_encoder_helper_register_irq(phys_enc,
+					INTR_IDX_CTL_START);
+			sde_encoder_helper_register_irq(phys_enc,
+					INTR_IDX_AUTOREFRESH_DONE);
+		}
 
-		if (sde_encoder_phys_cmd_is_master(phys_enc))
-			sde_encoder_phys_cmd_register_irq(phys_enc,
-				SDE_IRQ_TYPE_CTL_START,
-				INTR_IDX_CTL_START,
-				sde_encoder_phys_cmd_ctl_start_irq,
-				"ctl_start");
 	} else {
-		if (sde_encoder_phys_cmd_is_master(phys_enc))
-			sde_encoder_phys_cmd_unregister_irq(
-				phys_enc, INTR_IDX_CTL_START);
-		sde_encoder_phys_cmd_unregister_irq(
-				phys_enc, INTR_IDX_UNDERRUN);
+		if (sde_encoder_phys_cmd_is_master(phys_enc)) {
+			sde_encoder_helper_unregister_irq(phys_enc,
+					INTR_IDX_CTL_START);
+			sde_encoder_helper_unregister_irq(phys_enc,
+					INTR_IDX_AUTOREFRESH_DONE);
+		}
+
+		sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_UNDERRUN);
 		sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false);
-		sde_encoder_phys_cmd_unregister_irq(
-				phys_enc, INTR_IDX_PINGPONG);
+		sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_PINGPONG);
 	}
 }
 
@@ -564,7 +638,9 @@
 	}
 
 	tc_cfg.vsync_count = vsync_hz / (mode->vtotal * mode->vrefresh);
-	tc_cfg.hw_vsync_mode = 1;
+
+	/* enable external TE after kickoff to avoid premature autorefresh */
+	tc_cfg.hw_vsync_mode = 0;
 
 	/*
 	 * By setting sync_cfg_height to near max register value, we essentially
@@ -644,9 +720,20 @@
 
 	_sde_encoder_phys_cmd_pingpong_config(phys_enc);
 
+	/*
+	 * For pp-split, skip setting the flush bit for the slave intf, since
+	 * both intfs use same ctl and HW will only flush the master.
+	 */
+	if (_sde_encoder_phys_is_ppsplit(phys_enc) &&
+		!sde_encoder_phys_cmd_is_master(phys_enc))
+		goto skip_flush;
+
 	ctl = phys_enc->hw_ctl;
 	ctl->ops.get_bitmask_intf(ctl, &flush_mask, phys_enc->intf_idx);
 	ctl->ops.update_pending_flush(ctl, flush_mask);
+
+skip_flush:
+	return;
 }
 
 static void sde_encoder_phys_cmd_enable(struct sde_encoder_phys *phys_enc)
@@ -669,6 +756,41 @@
 	phys_enc->enable_state = SDE_ENC_ENABLED;
 }
 
+static bool _sde_encoder_phys_cmd_is_autorefresh_enabled(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct sde_hw_pingpong *hw_pp;
+	struct sde_hw_autorefresh cfg;
+	int ret;
+
+	if (!phys_enc || !phys_enc->hw_pp)
+		return 0;
+
+	if (!sde_encoder_phys_cmd_is_master(phys_enc))
+		return 0;
+
+	hw_pp = phys_enc->hw_pp;
+	if (!hw_pp->ops.get_autorefresh)
+		return 0;
+
+	ret = hw_pp->ops.get_autorefresh(hw_pp, &cfg);
+	if (ret)
+		return 0;
+
+	return cfg.enable;
+}
+
+static void _sde_encoder_phys_cmd_connect_te(
+		struct sde_encoder_phys *phys_enc, bool enable)
+{
+	if (!phys_enc || !phys_enc->hw_pp ||
+			!phys_enc->hw_pp->ops.connect_external_te)
+		return;
+
+	SDE_EVT32(DRMID(phys_enc->parent), enable);
+	phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable);
+}
+
 static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
 {
 	struct sde_encoder_phys_cmd *cmd_enc =
@@ -746,7 +868,10 @@
 		return;
 	}
 	SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
-	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0);
+
+	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
+			atomic_read(&phys_enc->pending_kickoff_cnt),
+			atomic_read(&cmd_enc->autorefresh.kickoff_cnt));
 
 	/*
 	 * Mark kickoff request as outstanding. If there are more than one,
@@ -760,50 +885,60 @@
 				phys_enc->hw_pp->idx - PINGPONG_0);
 		SDE_ERROR("failed wait_for_idle: %d\n", ret);
 	}
+
+	SDE_DEBUG_CMDENC(cmd_enc, "pp:%d pending_cnt %d\n",
+			phys_enc->hw_pp->idx - PINGPONG_0,
+			atomic_read(&phys_enc->pending_kickoff_cnt));
 }
 
 static int _sde_encoder_phys_cmd_wait_for_ctl_start(
 		struct sde_encoder_phys *phys_enc)
 {
-	int rc = 0;
-	struct sde_hw_ctl *ctl;
-	u32 irq_status;
-	struct sde_encoder_phys_cmd *cmd_enc;
+	struct sde_encoder_phys_cmd *cmd_enc =
+			to_sde_encoder_phys_cmd(phys_enc);
+	struct sde_encoder_wait_info wait_info;
+	int ret;
 
-	if (!phys_enc->hw_ctl) {
-		SDE_ERROR("invalid ctl\n");
+	if (!phys_enc) {
+		SDE_ERROR("invalid encoder\n");
 		return -EINVAL;
 	}
 
-	ctl = phys_enc->hw_ctl;
-	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
-	rc = sde_encoder_helper_wait_event_timeout(DRMID(phys_enc->parent),
-			ctl->idx - CTL_0,
-			&phys_enc->pending_kickoff_wq,
-			&phys_enc->pending_ctlstart_cnt,
-			CTL_START_TIMEOUT_MS);
-	if (rc <= 0) {
-		/* read and clear interrupt */
-		irq_status = sde_core_irq_read(phys_enc->sde_kms,
-				cmd_enc->irq_idx[INTR_IDX_CTL_START], true);
-		if (irq_status) {
-			unsigned long flags;
+	wait_info.wq = &phys_enc->pending_kickoff_wq;
+	wait_info.atomic_cnt = &phys_enc->pending_ctlstart_cnt;
+	wait_info.timeout_ms = CTL_START_TIMEOUT_MS;
 
-			SDE_EVT32(DRMID(phys_enc->parent), ctl->idx - CTL_0);
-			SDE_DEBUG_CMDENC(cmd_enc,
-					"ctl:%d start done but irq not triggered\n",
-					ctl->idx - CTL_0);
-			local_irq_save(flags);
-			sde_encoder_phys_cmd_ctl_start_irq(cmd_enc,
-					INTR_IDX_CTL_START);
-			local_irq_restore(flags);
-			rc = 0;
-		} else {
-			SDE_ERROR("ctl start interrupt wait failed\n");
-			rc = -EINVAL;
-		}
-	} else {
-		rc = 0;
+	/* slave encoder doesn't enable for ppsplit */
+	if (_sde_encoder_phys_is_ppsplit_slave(phys_enc))
+		return 0;
+
+	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_CTL_START,
+			&wait_info);
+	if (ret == -ETIMEDOUT) {
+		SDE_ERROR_CMDENC(cmd_enc, "ctl start interrupt wait failed\n");
+		ret = -EINVAL;
+	} else if (!ret)
+		ret = 0;
+
+	return ret;
+}
+
+static int sde_encoder_phys_cmd_wait_for_tx_complete(
+		struct sde_encoder_phys *phys_enc)
+{
+	int rc;
+	struct sde_encoder_phys_cmd *cmd_enc;
+
+	if (!phys_enc)
+		return -EINVAL;
+
+	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
+
+	rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc);
+	if (rc) {
+		SDE_EVT32(DRMID(phys_enc->parent),
+				phys_enc->intf_idx - INTF_0);
+		SDE_ERROR("failed wait_for_idle: %d\n", rc);
 	}
 
 	return rc;
@@ -824,6 +959,10 @@
 	if (sde_encoder_phys_cmd_is_master(phys_enc))
 		rc = _sde_encoder_phys_cmd_wait_for_ctl_start(phys_enc);
 
+	if (!rc && sde_encoder_phys_cmd_is_master(phys_enc) &&
+			cmd_enc->autorefresh.cfg.enable)
+		rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(phys_enc);
+
 	/* required for both controllers */
 	if (!rc && cmd_enc->serialize_wait4pp)
 		sde_encoder_phys_cmd_prepare_for_kickoff(phys_enc, NULL);
@@ -864,9 +1003,117 @@
 	_sde_encoder_phys_cmd_update_flush_mask(phys_enc);
 }
 
+static void sde_encoder_phys_cmd_prepare_commit(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_phys_cmd *cmd_enc =
+		to_sde_encoder_phys_cmd(phys_enc);
+
+	if (!phys_enc)
+		return;
+
+	if (sde_encoder_phys_cmd_is_master(phys_enc)) {
+		unsigned long lock_flags;
+
+
+		SDE_EVT32(DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0,
+				cmd_enc->autorefresh.cfg.enable);
+
+		if (!_sde_encoder_phys_cmd_is_autorefresh_enabled(phys_enc))
+			return;
+
+		/**
+		 * Autorefresh must be disabled carefully:
+		 *  - Must disable while there is no ongoing transmission
+		 *  - Receiving a TE will trigger the next Autorefresh TX
+		 *  - Only safe to disable Autorefresh between PPDone and TE
+		 *  - However, that is a small time window
+		 *  - Disabling External TE gives large safe window, assuming
+		 *    internally generated TE is set to a large counter value
+		 *
+		 * If Autorefresh is active:
+		 * 1. Disable external TE
+		 *   - TE will run on an SDE counter set to large value (~200ms)
+		 *
+		 * 2. Check for ongoing TX
+		 *   - If ongoing TX, set pending_kickoff_cnt if not set already
+		 *   - We don't want to wait for a ppdone that will never
+		 *     arrive, so verify ongoing TX
+		 *
+		 * 3. Wait for TX to Complete
+		 *  - Wait for PPDone pending count to reach 0
+		 *
+		 * 4. Leave Autorefresh Disabled
+		 *   - Assume disable of Autorefresh since it is now safe
+		 *   - Can now safely Disable Encoder, do debug printing, etc.
+		 *     without worrying that Autorefresh will kickoff
+		 */
+
+		spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+
+		/* disable external TE to prevent next autorefresh */
+		_sde_encoder_phys_cmd_connect_te(phys_enc, false);
+
+		/* verify that we disabled TE during outstanding TX */
+		if (_sde_encoder_phys_cmd_is_ongoing_pptx(phys_enc))
+			atomic_add_unless(&phys_enc->pending_kickoff_cnt, 1, 1);
+
+		spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+
+		/* wait for ppdone if necessary due to catching ongoing TX */
+		if (_sde_encoder_phys_cmd_wait_for_idle(phys_enc))
+			SDE_ERROR_CMDENC(cmd_enc,
+					"pp:%d kickoff timed out\n",
+					phys_enc->hw_pp->idx - PINGPONG_0);
+
+		/*
+		 * not strictly necessary for kickoff, but simplifies disable
+		 * callflow since our disable is split across multiple phys_encs
+		 */
+		_sde_encoder_phys_cmd_config_autorefresh(phys_enc, 0);
+
+		SDE_DEBUG_CMDENC(cmd_enc, "disabled autorefresh & ext TE\n");
+
+	}
+}
+
+static void sde_encoder_phys_cmd_handle_post_kickoff(
+		struct sde_encoder_phys *phys_enc)
+{
+	if (!phys_enc)
+		return;
+
+	/**
+	 * re-enable external TE, either for the first time after enabling
+	 * or if disabled for Autorefresh
+	 */
+	_sde_encoder_phys_cmd_connect_te(phys_enc, true);
+}
+
+static void sde_encoder_phys_cmd_trigger_start(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_phys_cmd *cmd_enc =
+			to_sde_encoder_phys_cmd(phys_enc);
+	u32 frame_cnt;
+
+	if (!phys_enc)
+		return;
+
+	/* we don't issue CTL_START when using autorefresh */
+	frame_cnt = _sde_encoder_phys_cmd_get_autorefresh_property(phys_enc);
+	if (frame_cnt) {
+		_sde_encoder_phys_cmd_config_autorefresh(phys_enc, frame_cnt);
+		atomic_inc(&cmd_enc->autorefresh.kickoff_cnt);
+	} else {
+		sde_encoder_helper_trigger_start(phys_enc);
+	}
+}
+
 static void sde_encoder_phys_cmd_init_ops(
 		struct sde_encoder_phys_ops *ops)
 {
+	ops->prepare_commit = sde_encoder_phys_cmd_prepare_commit;
 	ops->is_master = sde_encoder_phys_cmd_is_master;
 	ops->mode_set = sde_encoder_phys_cmd_mode_set;
 	ops->mode_fixup = sde_encoder_phys_cmd_mode_fixup;
@@ -877,7 +1124,9 @@
 	ops->control_vblank_irq = sde_encoder_phys_cmd_control_vblank_irq;
 	ops->wait_for_commit_done = sde_encoder_phys_cmd_wait_for_commit_done;
 	ops->prepare_for_kickoff = sde_encoder_phys_cmd_prepare_for_kickoff;
-	ops->trigger_start = sde_encoder_helper_trigger_start;
+	ops->wait_for_tx_complete = sde_encoder_phys_cmd_wait_for_tx_complete;
+	ops->handle_post_kickoff = sde_encoder_phys_cmd_handle_post_kickoff;
+	ops->trigger_start = sde_encoder_phys_cmd_trigger_start;
 	ops->needs_single_flush = sde_encoder_phys_cmd_needs_single_flush;
 	ops->hw_reset = sde_encoder_helper_hw_reset;
 	ops->irq_control = sde_encoder_phys_cmd_irq_control;
@@ -891,6 +1140,7 @@
 	struct sde_encoder_phys *phys_enc = NULL;
 	struct sde_encoder_phys_cmd *cmd_enc = NULL;
 	struct sde_hw_mdp *hw_mdp;
+	struct sde_encoder_irq *irq;
 	int i, ret = 0;
 
 	SDE_DEBUG("intf %d\n", p->intf_idx - INTF_0);
@@ -922,12 +1172,50 @@
 	cmd_enc->stream_sel = 0;
 	phys_enc->enable_state = SDE_ENC_DISABLED;
 	phys_enc->comp_type = p->comp_type;
-	for (i = 0; i < INTR_IDX_MAX; i++)
-		INIT_LIST_HEAD(&cmd_enc->irq_cb[i].list);
+	for (i = 0; i < INTR_IDX_MAX; i++) {
+		irq = &phys_enc->irq[i];
+		INIT_LIST_HEAD(&irq->cb.list);
+		irq->irq_idx = -EINVAL;
+		irq->hw_idx = -EINVAL;
+		irq->cb.arg = phys_enc;
+	}
+
+	irq = &phys_enc->irq[INTR_IDX_CTL_START];
+	irq->name = "ctl_start";
+	irq->intr_type = SDE_IRQ_TYPE_CTL_START;
+	irq->intr_idx = INTR_IDX_CTL_START;
+	irq->cb.func = sde_encoder_phys_cmd_ctl_start_irq;
+
+	irq = &phys_enc->irq[INTR_IDX_PINGPONG];
+	irq->name = "pp_done";
+	irq->intr_type = SDE_IRQ_TYPE_PING_PONG_COMP;
+	irq->intr_idx = INTR_IDX_PINGPONG;
+	irq->cb.func = sde_encoder_phys_cmd_pp_tx_done_irq;
+
+	irq = &phys_enc->irq[INTR_IDX_RDPTR];
+	irq->name = "pp_rd_ptr";
+	irq->intr_type = SDE_IRQ_TYPE_PING_PONG_RD_PTR;
+	irq->intr_idx = INTR_IDX_RDPTR;
+	irq->cb.func = sde_encoder_phys_cmd_pp_rd_ptr_irq;
+
+	irq = &phys_enc->irq[INTR_IDX_UNDERRUN];
+	irq->name = "underrun";
+	irq->intr_type = SDE_IRQ_TYPE_INTF_UNDER_RUN;
+	irq->intr_idx = INTR_IDX_UNDERRUN;
+	irq->cb.func = sde_encoder_phys_cmd_underrun_irq;
+
+	irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE];
+	irq->name = "autorefresh_done";
+	irq->intr_type = SDE_IRQ_TYPE_PING_PONG_AUTO_REF;
+	irq->intr_idx = INTR_IDX_AUTOREFRESH_DONE;
+	irq->cb.func = sde_encoder_phys_cmd_autorefresh_done_irq;
+
 	atomic_set(&phys_enc->vblank_refcount, 0);
 	atomic_set(&phys_enc->pending_kickoff_cnt, 0);
 	atomic_set(&phys_enc->pending_ctlstart_cnt, 0);
 	init_waitqueue_head(&phys_enc->pending_kickoff_wq);
+	atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0);
+	init_waitqueue_head(&cmd_enc->autorefresh.kickoff_wq);
 
 	SDE_DEBUG_CMDENC(cmd_enc, "created\n");
 
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 488f5c0..007738a6 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -345,17 +345,17 @@
 
 static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
 {
-	struct sde_encoder_phys_vid *vid_enc = arg;
-	struct sde_encoder_phys *phys_enc;
+	struct sde_encoder_phys *phys_enc = arg;
+	struct sde_encoder_phys_vid *vid_enc =
+			to_sde_encoder_phys_vid(phys_enc);
 	struct sde_hw_ctl *hw_ctl;
 	unsigned long lock_flags;
 	u32 flush_register = 0;
 	int new_cnt = -1, old_cnt = -1;
 
-	if (!vid_enc)
+	if (!phys_enc)
 		return;
 
-	phys_enc = &vid_enc->base;
 	hw_ctl = phys_enc->hw_ctl;
 
 	if (phys_enc->parent_ops.handle_vblank_virt)
@@ -387,13 +387,11 @@
 
 static void sde_encoder_phys_vid_underrun_irq(void *arg, int irq_idx)
 {
-	struct sde_encoder_phys_vid *vid_enc = arg;
-	struct sde_encoder_phys *phys_enc;
+	struct sde_encoder_phys *phys_enc = arg;
 
-	if (!vid_enc)
+	if (!phys_enc)
 		return;
 
-	phys_enc = &vid_enc->base;
 	if (phys_enc->parent_ops.handle_underrun_virt)
 		phys_enc->parent_ops.handle_underrun_virt(phys_enc->parent,
 			phys_enc);
@@ -419,77 +417,18 @@
 	return phys_enc && _sde_encoder_phys_is_ppsplit(phys_enc);
 }
 
-static int sde_encoder_phys_vid_register_irq(struct sde_encoder_phys *phys_enc,
-	enum sde_intr_type intr_type, int idx,
-	void (*irq_func)(void *, int), const char *irq_name)
+static void _sde_encoder_phys_vid_setup_irq_hw_idx(
+		struct sde_encoder_phys *phys_enc)
 {
-	struct sde_encoder_phys_vid *vid_enc;
-	int ret = 0;
+	struct sde_encoder_irq *irq;
 
-	if (!phys_enc) {
-		SDE_ERROR("invalid encoder\n");
-		return -EINVAL;
-	}
+	irq = &phys_enc->irq[INTR_IDX_VSYNC];
+	irq->hw_idx = phys_enc->intf_idx;
+	irq->irq_idx = -EINVAL;
 
-	vid_enc = to_sde_encoder_phys_vid(phys_enc);
-	vid_enc->irq_idx[idx] = sde_core_irq_idx_lookup(phys_enc->sde_kms,
-			intr_type, vid_enc->hw_intf->idx);
-	if (vid_enc->irq_idx[idx] < 0) {
-		SDE_ERROR_VIDENC(vid_enc,
-			"failed to lookup IRQ index for %s type:%d\n", irq_name,
-			intr_type);
-		return -EINVAL;
-	}
-
-	vid_enc->irq_cb[idx].func = irq_func;
-	vid_enc->irq_cb[idx].arg = vid_enc;
-	ret = sde_core_irq_register_callback(phys_enc->sde_kms,
-			vid_enc->irq_idx[idx], &vid_enc->irq_cb[idx]);
-	if (ret) {
-		SDE_ERROR_VIDENC(vid_enc,
-			"failed to register IRQ callback for %s\n", irq_name);
-		return ret;
-	}
-
-	ret = sde_core_irq_enable(phys_enc->sde_kms, &vid_enc->irq_idx[idx], 1);
-	if (ret) {
-		SDE_ERROR_VIDENC(vid_enc,
-			"enable IRQ for intr:%s failed, irq_idx %d\n",
-			irq_name, vid_enc->irq_idx[idx]);
-		vid_enc->irq_idx[idx] = -EINVAL;
-
-		/* unregister callback on IRQ enable failure */
-		sde_core_irq_unregister_callback(phys_enc->sde_kms,
-				vid_enc->irq_idx[idx], &vid_enc->irq_cb[idx]);
-		return ret;
-	}
-
-	SDE_DEBUG_VIDENC(vid_enc, "registered irq %s idx: %d\n",
-			irq_name, vid_enc->irq_idx[idx]);
-
-	return ret;
-}
-
-static int sde_encoder_phys_vid_unregister_irq(
-	struct sde_encoder_phys *phys_enc, int idx)
-{
-	struct sde_encoder_phys_vid *vid_enc;
-
-	if (!phys_enc) {
-		SDE_ERROR("invalid encoder\n");
-		goto end;
-	}
-
-	vid_enc = to_sde_encoder_phys_vid(phys_enc);
-	sde_core_irq_disable(phys_enc->sde_kms, &vid_enc->irq_idx[idx], 1);
-
-	sde_core_irq_unregister_callback(phys_enc->sde_kms,
-			vid_enc->irq_idx[idx], &vid_enc->irq_cb[idx]);
-
-	SDE_DEBUG_VIDENC(vid_enc, "unregistered %d\n", vid_enc->irq_idx[idx]);
-
-end:
-	return 0;
+	irq = &phys_enc->irq[INTR_IDX_UNDERRUN];
+	irq->hw_idx = phys_enc->intf_idx;
+	irq->irq_idx = -EINVAL;
 }
 
 static void sde_encoder_phys_vid_mode_set(
@@ -527,6 +466,8 @@
 		phys_enc->hw_ctl = NULL;
 		return;
 	}
+
+	_sde_encoder_phys_vid_setup_irq_hw_idx(phys_enc);
 }
 
 static int sde_encoder_phys_vid_control_vblank_irq(
@@ -555,13 +496,10 @@
 			atomic_read(&phys_enc->vblank_refcount));
 
 	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
-		ret = sde_encoder_phys_vid_register_irq(phys_enc,
-			SDE_IRQ_TYPE_INTF_VSYNC,
-			INTR_IDX_VSYNC,
-			sde_encoder_phys_vid_vblank_irq, "vsync_irq");
+		ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_VSYNC);
 	else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
-		ret = sde_encoder_phys_vid_unregister_irq(phys_enc,
-			INTR_IDX_VSYNC);
+		ret = sde_encoder_helper_unregister_irq(phys_enc,
+				INTR_IDX_VSYNC);
 
 	if (ret)
 		SDE_ERROR_VIDENC(vid_enc,
@@ -608,18 +546,24 @@
 	if (ret)
 		goto end;
 
-	ret = sde_encoder_phys_vid_register_irq(phys_enc,
-		SDE_IRQ_TYPE_INTF_UNDER_RUN,
-		INTR_IDX_UNDERRUN,
-		sde_encoder_phys_vid_underrun_irq, "underrun");
+	ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_UNDERRUN);
 	if (ret) {
 		sde_encoder_phys_vid_control_vblank_irq(phys_enc, false);
 		goto end;
 	}
 
+	/*
+	 * For pp-split, skip setting the flush bit for the slave intf, since
+	 * both intfs use same ctl and HW will only flush the master.
+	 */
+	if (_sde_encoder_phys_is_ppsplit(phys_enc) &&
+		!sde_encoder_phys_vid_is_master(phys_enc))
+		goto skip_flush;
+
 	ctl->ops.get_bitmask_intf(ctl, &flush_mask, intf->idx);
 	ctl->ops.update_pending_flush(ctl, flush_mask);
 
+skip_flush:
 	SDE_DEBUG_VIDENC(vid_enc, "update pending flush ctl %d flush_mask %x\n",
 		ctl->idx - CTL_0, flush_mask);
 
@@ -671,68 +615,35 @@
 static int sde_encoder_phys_vid_wait_for_vblank(
 		struct sde_encoder_phys *phys_enc, bool notify)
 {
-	struct sde_encoder_phys_vid *vid_enc =
-			to_sde_encoder_phys_vid(phys_enc);
-	u32 irq_status;
+	struct sde_encoder_wait_info wait_info = {
+		.wq = &phys_enc->pending_kickoff_wq,
+		.atomic_cnt = &phys_enc->pending_kickoff_cnt,
+		.timeout_ms = KICKOFF_TIMEOUT_MS,
+	};
 	int ret;
 
 	if (!sde_encoder_phys_vid_is_master(phys_enc)) {
-		/* always signal done for slave video encoder */
-		if (notify && phys_enc->parent_ops.handle_frame_done)
+		/* signal done for slave video encoder, unless it is pp-split */
+		if (!_sde_encoder_phys_is_ppsplit(phys_enc) &&
+			notify && phys_enc->parent_ops.handle_frame_done)
 			phys_enc->parent_ops.handle_frame_done(
 					phys_enc->parent, phys_enc,
 					SDE_ENCODER_FRAME_EVENT_DONE);
 		return 0;
 	}
 
-	if (phys_enc->enable_state != SDE_ENC_ENABLED) {
-		SDE_ERROR("encoder not enabled\n");
-		return -EWOULDBLOCK;
-	}
-
-	SDE_EVT32(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0,
-			SDE_EVTLOG_FUNC_ENTRY);
-
 	/* Wait for kickoff to complete */
-	ret = sde_encoder_helper_wait_event_timeout(
-			DRMID(phys_enc->parent),
-			vid_enc->hw_intf->idx - INTF_0,
-			&phys_enc->pending_kickoff_wq,
-			&phys_enc->pending_kickoff_cnt,
-			KICKOFF_TIMEOUT_MS);
-	if (ret <= 0) {
-		irq_status = sde_core_irq_read(phys_enc->sde_kms,
-				vid_enc->irq_idx[INTR_IDX_VSYNC], true);
-		if (irq_status) {
-			SDE_EVT32(DRMID(phys_enc->parent),
-					vid_enc->hw_intf->idx - INTF_0);
-			SDE_DEBUG_VIDENC(vid_enc, "done, irq not triggered\n");
-			if (notify && phys_enc->parent_ops.handle_frame_done)
-				phys_enc->parent_ops.handle_frame_done(
-						phys_enc->parent, phys_enc,
-						SDE_ENCODER_FRAME_EVENT_DONE);
-			sde_encoder_phys_vid_vblank_irq(vid_enc,
-					INTR_IDX_VSYNC);
-			ret = 0;
-		} else {
-			SDE_EVT32(DRMID(phys_enc->parent),
-					vid_enc->hw_intf->idx - INTF_0);
-			SDE_ERROR_VIDENC(vid_enc, "kickoff timed out\n");
-			if (notify && phys_enc->parent_ops.handle_frame_done)
-				phys_enc->parent_ops.handle_frame_done(
-						phys_enc->parent, phys_enc,
-						SDE_ENCODER_FRAME_EVENT_ERROR);
-			ret = -ETIMEDOUT;
-		}
-	} else {
-		if (notify && phys_enc->parent_ops.handle_frame_done)
-			phys_enc->parent_ops.handle_frame_done(
-					phys_enc->parent, phys_enc,
-					SDE_ENCODER_FRAME_EVENT_DONE);
-		ret = 0;
-	}
+	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC,
+			&wait_info);
 
-	return 0;
+	if (ret == -ETIMEDOUT) {
+		sde_encoder_helper_report_irq_timeout(phys_enc, INTR_IDX_VSYNC);
+	} else if (!ret && notify && phys_enc->parent_ops.handle_frame_done)
+		phys_enc->parent_ops.handle_frame_done(
+				phys_enc->parent, phys_enc,
+				SDE_ENCODER_FRAME_EVENT_DONE);
+
+	return ret;
 }
 
 static int sde_encoder_phys_vid_wait_for_commit_done(
@@ -835,6 +746,8 @@
 		sde_encoder_phys_vid_control_vblank_irq(phys_enc, false);
 	}
 
+	sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_UNDERRUN);
+
 	if (atomic_read(&phys_enc->vblank_refcount))
 		SDE_ERROR_VIDENC(vid_enc, "invalid vblank refcount %d\n",
 				atomic_read(&phys_enc->vblank_refcount));
@@ -922,6 +835,7 @@
 	struct sde_encoder_phys_vid *vid_enc = NULL;
 	struct sde_rm_hw_iter iter;
 	struct sde_hw_mdp *hw_mdp;
+	struct sde_encoder_irq *irq;
 	int i, ret = 0;
 
 	if (!p) {
@@ -976,8 +890,26 @@
 	phys_enc->intf_mode = INTF_MODE_VIDEO;
 	phys_enc->enc_spinlock = p->enc_spinlock;
 	phys_enc->comp_type = p->comp_type;
-	for (i = 0; i < INTR_IDX_MAX; i++)
-		INIT_LIST_HEAD(&vid_enc->irq_cb[i].list);
+	for (i = 0; i < INTR_IDX_MAX; i++) {
+		irq = &phys_enc->irq[i];
+		INIT_LIST_HEAD(&irq->cb.list);
+		irq->irq_idx = -EINVAL;
+		irq->hw_idx = -EINVAL;
+		irq->cb.arg = phys_enc;
+	}
+
+	irq = &phys_enc->irq[INTR_IDX_VSYNC];
+	irq->name = "vsync_irq";
+	irq->intr_type = SDE_IRQ_TYPE_INTF_VSYNC;
+	irq->intr_idx = INTR_IDX_VSYNC;
+	irq->cb.func = sde_encoder_phys_vid_vblank_irq;
+
+	irq = &phys_enc->irq[INTR_IDX_UNDERRUN];
+	irq->name = "underrun";
+	irq->intr_type = SDE_IRQ_TYPE_INTF_UNDER_RUN;
+	irq->intr_idx = INTR_IDX_UNDERRUN;
+	irq->cb.func = sde_encoder_phys_vid_underrun_irq;
+
 	atomic_set(&phys_enc->vblank_refcount, 0);
 	atomic_set(&phys_enc->pending_kickoff_cnt, 0);
 	init_waitqueue_head(&phys_enc->pending_kickoff_wq);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 1657b9b..54c1397 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -342,8 +342,20 @@
 		hw_wb->ops.setup_cdp(hw_wb, cdp_cfg);
 	}
 
-	if (hw_wb->ops.setup_outaddress)
+	if (hw_wb->ops.setup_outaddress) {
+		SDE_EVT32(hw_wb->idx,
+				wb_cfg->dest.width,
+				wb_cfg->dest.height,
+				wb_cfg->dest.plane_addr[0],
+				wb_cfg->dest.plane_size[0],
+				wb_cfg->dest.plane_addr[1],
+				wb_cfg->dest.plane_size[1],
+				wb_cfg->dest.plane_addr[2],
+				wb_cfg->dest.plane_size[2],
+				wb_cfg->dest.plane_addr[3],
+				wb_cfg->dest.plane_size[3]);
 		hw_wb->ops.setup_outaddress(hw_wb, wb_cfg);
+	}
 }
 
 /**
@@ -1121,13 +1133,13 @@
 	if (!phys_enc || !wb_enc->hw_wb || !debugfs_root)
 		return -EINVAL;
 
-	if (!debugfs_create_u32("wbdone_timeout", 0644,
+	if (!debugfs_create_u32("wbdone_timeout", 0600,
 			debugfs_root, &wb_enc->wbdone_timeout)) {
 		SDE_ERROR("failed to create debugfs/wbdone_timeout\n");
 		return -ENOMEM;
 	}
 
-	if (!debugfs_create_u32("bypass_irqreg", 0644,
+	if (!debugfs_create_u32("bypass_irqreg", 0600,
 			debugfs_root, &wb_enc->bypass_irqreg)) {
 		SDE_ERROR("failed to create debugfs/bypass_irqreg\n");
 		return -ENOMEM;
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c
index c83472a..bd9fdac 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.c
+++ b/drivers/gpu/drm/msm/sde/sde_fence.c
@@ -138,12 +138,16 @@
 {
 	struct sde_fence *f = to_sde_fence(fence);
 	struct sde_fence *fc, *next;
-	struct sde_fence_context *ctx = f->ctx;
+	struct sde_fence_context *ctx;
 	bool release_kref = false;
 
+	if (!fence || !f->ctx)
+		return;
+
+	ctx = f->ctx;
+
 	spin_lock(&ctx->list_lock);
-	list_for_each_entry_safe(fc, next, &ctx->fence_list_head,
-				 fence_list) {
+	list_for_each_entry_safe(fc, next, &ctx->fence_list_head, fence_list) {
 		/* fence release called before signal */
 		if (f == fc) {
 			list_del_init(&fc->fence_list);
@@ -156,20 +160,25 @@
 	/* keep kput outside spin_lock because it may release ctx */
 	if (release_kref)
 		kref_put(&ctx->kref, sde_fence_destroy);
-	kfree_rcu(f, base.rcu);
+	kfree(f);
 }
 
-static void sde_fence_value_str(struct fence *fence,
-				    char *str, int size)
+static void sde_fence_value_str(struct fence *fence, char *str, int size)
 {
+	if (!fence || !str)
+		return;
+
 	snprintf(str, size, "%d", fence->seqno);
 }
 
-static void sde_fence_timeline_value_str(struct fence *fence,
-					     char *str, int size)
+static void sde_fence_timeline_value_str(struct fence *fence, char *str,
+		int size)
 {
 	struct sde_fence *f = to_sde_fence(fence);
 
+	if (!fence || !f->ctx || !str)
+		return;
+
 	snprintf(str, size, "%d", f->ctx->done_count);
 }
 
@@ -226,6 +235,7 @@
 	sync_file = sync_file_create(&sde_fence->base);
 	if (sync_file == NULL) {
 		put_unused_fd(fd);
+		fd = -EINVAL;
 		fence_put(&sde_fence->base);
 		SDE_ERROR("couldn't create fence, %s\n", sde_fence->name);
 		goto exit;
@@ -244,16 +254,15 @@
 }
 
 int sde_fence_init(struct sde_fence_context *ctx,
-		const char *name,
-		uint32_t drm_id)
+		const char *name, uint32_t drm_id)
 {
-	if (!ctx) {
+	if (!ctx || !name) {
 		SDE_ERROR("invalid argument(s)\n");
 		return -EINVAL;
 	}
 	memset(ctx, 0, sizeof(*ctx));
 
-	strlcpy(ctx->name, name, SDE_FENCE_NAME_SIZE);
+	strlcpy(ctx->name, name, ARRAY_SIZE(ctx->name));
 	ctx->drm_id = drm_id;
 	kref_init(&ctx->kref);
 	ctx->context = fence_context_alloc(1);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
index b02cc06..35fc2b5 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
@@ -202,7 +202,7 @@
 	} else {
 		info[dspp->idx].state = ad4_state_run;
 		SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
-				0);
+				0x100);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 306bb86..1cbbe1e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -302,6 +302,13 @@
 	REG_DMA_PROP_MAX
 };
 
+enum {
+	INLINE_ROT_XIN,
+	INLINE_ROT_XIN_TYPE,
+	INLINE_ROT_CLK_CTRL,
+	INLINE_ROT_PROP_MAX
+};
+
 /*************************************************************
  * dts property definition
  *************************************************************/
@@ -546,6 +553,15 @@
 		PROP_TYPE_U32},
 };
 
+static struct sde_prop_type inline_rot_prop[INLINE_ROT_PROP_MAX] = {
+	{INLINE_ROT_XIN, "qcom,sde-inline-rot-xin", false,
+							PROP_TYPE_U32_ARRAY},
+	{INLINE_ROT_XIN_TYPE, "qcom,sde-inline-rot-xin-type", false,
+							PROP_TYPE_STRING_ARRAY},
+	{INLINE_ROT_CLK_CTRL, "qcom,sde-inline-rot-clk-ctrl", false,
+						PROP_TYPE_BIT_OFFSET_ARRAY},
+};
+
 /*************************************************************
  * static API list
  *************************************************************/
@@ -1407,6 +1423,8 @@
 			intf->len = DEFAULT_SDE_HW_BLOCK_LEN;
 
 		intf->prog_fetch_lines_worst_case =
+				!prop_exists[INTF_PREFETCH] ?
+				sde_cfg->perf.min_prefill_lines :
 				PROP_VALUE_ACCESS(prop_value, INTF_PREFETCH, i);
 
 		of_property_read_string_index(np,
@@ -1648,6 +1666,87 @@
 	}
 }
 
+static void _sde_inline_rot_parse_dt(struct device_node *np,
+		struct sde_mdss_cfg *sde_cfg, struct sde_rot_cfg *rot)
+{
+	int rc, prop_count[INLINE_ROT_PROP_MAX], i, j, index;
+	struct sde_prop_value *prop_value = NULL;
+	bool prop_exists[INLINE_ROT_PROP_MAX];
+	u32 off_count, sspp_count = 0, wb_count = 0;
+	const char *type;
+
+	prop_value = kzalloc(INLINE_ROT_PROP_MAX *
+			sizeof(struct sde_prop_value), GFP_KERNEL);
+	if (!prop_value)
+		return;
+
+	rc = _validate_dt_entry(np, inline_rot_prop,
+			ARRAY_SIZE(inline_rot_prop), prop_count, &off_count);
+	if (rc)
+		goto end;
+
+	rc = _read_dt_entry(np, inline_rot_prop, ARRAY_SIZE(inline_rot_prop),
+			prop_count, prop_exists, prop_value);
+	if (rc)
+		goto end;
+
+	for (i = 0; i < off_count; i++) {
+		rot->vbif_cfg[i].xin_id = PROP_VALUE_ACCESS(prop_value,
+							INLINE_ROT_XIN, i);
+		of_property_read_string_index(np,
+				inline_rot_prop[INLINE_ROT_XIN_TYPE].prop_name,
+				i, &type);
+
+		if (!strcmp(type, "sspp")) {
+			rot->vbif_cfg[i].num = INLINE_ROT0_SSPP + sspp_count;
+			rot->vbif_cfg[i].is_read = true;
+			rot->vbif_cfg[i].clk_ctrl =
+					SDE_CLK_CTRL_INLINE_ROT0_SSPP
+					+ sspp_count;
+			sspp_count++;
+		} else if (!strcmp(type, "wb")) {
+			rot->vbif_cfg[i].num = INLINE_ROT0_WB + wb_count;
+			rot->vbif_cfg[i].is_read = false;
+			rot->vbif_cfg[i].clk_ctrl =
+					SDE_CLK_CTRL_INLINE_ROT0_WB
+					+ wb_count;
+			wb_count++;
+		} else {
+			SDE_ERROR("invalid rotator vbif type:%s\n", type);
+			goto end;
+		}
+
+		index = rot->vbif_cfg[i].clk_ctrl;
+		if (index < 0 || index >= SDE_CLK_CTRL_MAX) {
+			SDE_ERROR("invalid clk_ctrl enum:%d\n", index);
+			goto end;
+		}
+
+		for (j = 0; j < sde_cfg->mdp_count; j++) {
+			sde_cfg->mdp[j].clk_ctrls[index].reg_off =
+				PROP_BITVALUE_ACCESS(prop_value,
+						INLINE_ROT_CLK_CTRL, i, 0);
+			sde_cfg->mdp[j].clk_ctrls[index].bit_off =
+				PROP_BITVALUE_ACCESS(prop_value,
+						INLINE_ROT_CLK_CTRL, i, 1);
+		}
+
+		SDE_DEBUG("rot- xin:%d, num:%d, rd:%d, clk:%d:0x%x/%d\n",
+				rot->vbif_cfg[i].xin_id,
+				rot->vbif_cfg[i].num,
+				rot->vbif_cfg[i].is_read,
+				rot->vbif_cfg[i].clk_ctrl,
+				sde_cfg->mdp[0].clk_ctrls[index].reg_off,
+				sde_cfg->mdp[0].clk_ctrls[index].bit_off);
+	}
+
+	rot->vbif_idx = VBIF_RT;
+	rot->xin_count = off_count;
+
+end:
+	kfree(prop_value);
+}
+
 static int sde_rot_parse_dt(struct device_node *np,
 		struct sde_mdss_cfg *sde_cfg)
 {
@@ -1693,10 +1792,11 @@
 				rot->slice_size = llcc_get_slice_size(slice);
 				rot->pdev = pdev;
 				llcc_slice_putd(slice);
-				sde_cfg->rot_count++;
 				SDE_DEBUG("rot:%d scid:%d slice_size:%zukb\n",
 						rot->id, rot->scid,
 						rot->slice_size);
+				_sde_inline_rot_parse_dt(np, sde_cfg, rot);
+				sde_cfg->rot_count++;
 			}
 		} else {
 			rot->pdev = NULL;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index beff43c..74fa8f9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -488,6 +488,8 @@
 	SDE_CLK_CTRL_WB0,
 	SDE_CLK_CTRL_WB1,
 	SDE_CLK_CTRL_WB2,
+	SDE_CLK_CTRL_INLINE_ROT0_SSPP,
+	SDE_CLK_CTRL_INLINE_ROT0_WB,
 	SDE_CLK_CTRL_MAX,
 };
 
@@ -648,6 +650,20 @@
 };
 
 /**
+ * struct sde_rot_vbif_cfg - inline rotator vbif configs
+ * @xin_id             xin client id
+ * @num                enum identifying this block
+ * @is_read            indicates read/write client
+ * @clk_ctrl           index to clk control
+ */
+struct sde_rot_vbif_cfg {
+	u32 xin_id;
+	u32 num;
+	bool is_read;
+	enum sde_clk_ctrl_type clk_ctrl;
+};
+
+/**
  * struct sde_rot_cfg - information of rotator blocks
  * @id                 enum identifying this block
  * @base               register offset of this block
@@ -656,12 +672,19 @@
  * @pdev               private device handle
  * @scid               subcache identifier
  * @slice_size         subcache slice size
+ * @vbif_idx           vbif identifier
+ * @xin_count          number of xin clients
+ * @vbif_cfg           vbif settings related to rotator
  */
 struct sde_rot_cfg {
 	SDE_HW_BLK_INFO;
 	void *pdev;
 	int scid;
 	size_t slice_size;
+	u32 vbif_idx;
+
+	u32 xin_count;
+	struct sde_rot_vbif_cfg vbif_cfg[MAX_BLOCKS];
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
index ad2910e..304106d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
@@ -15,6 +15,7 @@
 #include "sde_hw_catalog.h"
 #include "sde_hw_cdm.h"
 #include "sde_dbg.h"
+#include "sde_kms.h"
 
 #define CDM_CSC_10_OPMODE                  0x000
 #define CDM_CSC_10_BASE                    0x004
@@ -267,6 +268,11 @@
 	ops->disable = sde_hw_cdm_disable;
 }
 
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
+};
+
 struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx,
 		void __iomem *addr,
 		struct sde_mdss_cfg *m,
@@ -274,6 +280,7 @@
 {
 	struct sde_hw_cdm *c;
 	struct sde_cdm_cfg *cfg;
+	int rc;
 
 	c = kzalloc(sizeof(*c), GFP_KERNEL);
 	if (!c)
@@ -286,12 +293,19 @@
 	}
 
 	c->idx = idx;
-	c->cdm_hw_cap = cfg;
-	_setup_cdm_ops(&c->ops, c->cdm_hw_cap->features);
+	c->caps = cfg;
+	_setup_cdm_ops(&c->ops, c->caps->features);
 	c->hw_mdp = hw_mdp;
 
+	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_CDM, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
+
 	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
 			c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
 	/*
 	 * Perform any default initialization for the chroma down module
 	 * @setup default csc coefficients
@@ -299,9 +313,16 @@
 	sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg);
 
 	return c;
+
+blk_init_error:
+	kzfree(c);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_cdm_destroy(struct sde_hw_cdm *cdm)
 {
+	if (cdm)
+		sde_hw_blk_destroy(&cdm->base);
 	kfree(cdm);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.h b/drivers/gpu/drm/msm/sde/sde_hw_cdm.h
index a0afd89..2b3683d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.h
@@ -15,6 +15,7 @@
 
 #include "sde_hw_mdss.h"
 #include "sde_hw_top.h"
+#include "sde_hw_blk.h"
 
 struct sde_hw_cdm;
 
@@ -92,11 +93,11 @@
 };
 
 struct sde_hw_cdm {
-	/* base */
+	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
 
 	/* chroma down */
-	const struct sde_cdm_cfg   *cdm_hw_cap;
+	const struct sde_cdm_cfg *caps;
 	enum  sde_cdm  idx;
 
 	/* mdp top hw driver */
@@ -107,6 +108,16 @@
 };
 
 /**
+ * sde_hw_cdm - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_cdm *to_sde_hw_cdm(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_cdm, base);
+}
+
+/**
  * sde_hw_cdm_init - initializes the cdm hw driver object.
  * should be called once before accessing every cdm.
  * @idx:  cdm index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index a62aa6e..0b3432b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -14,6 +14,8 @@
 #include "sde_hwio.h"
 #include "sde_hw_ctl.h"
 #include "sde_dbg.h"
+#include "sde_kms.h"
+#include "sde_reg_dma.h"
 
 #define   CTL_LAYER(lm)                 \
 	(((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004))
@@ -110,6 +112,11 @@
 
 static inline void sde_hw_ctl_trigger_flush(struct sde_hw_ctl *ctx)
 {
+	struct sde_hw_reg_dma_ops *ops = sde_reg_dma_get_ops();
+
+	if (ops && ops->last_command)
+		ops->last_command(ctx, DMA_CTL_QUEUE0);
+
 	SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
 }
 
@@ -354,7 +361,7 @@
 }
 
 static void sde_hw_ctl_setup_blendstage(struct sde_hw_ctl *ctx,
-	enum sde_lm lm, struct sde_hw_stage_cfg *stage_cfg, u32 index)
+	enum sde_lm lm, struct sde_hw_stage_cfg *stage_cfg)
 {
 	struct sde_hw_blk_reg_map *c = &ctx->hw;
 	u32 mixercfg = 0, mixercfg_ext = 0, mix, ext;
@@ -363,9 +370,6 @@
 	u8 stages;
 	int pipes_per_stage;
 
-	if (index >= CRTC_DUAL_MIXERS)
-		return;
-
 	stages = _mixer_stages(ctx->mixer_hw_caps, ctx->mixer_count, lm);
 	if (stages < 0)
 		return;
@@ -388,9 +392,9 @@
 
 		for (j = 0 ; j < pipes_per_stage; j++) {
 			enum sde_sspp_multirect_index rect_index =
-				stage_cfg->multirect_index[index][i][j];
+				stage_cfg->multirect_index[i][j];
 
-			switch (stage_cfg->stage[index][i][j]) {
+			switch (stage_cfg->stage[i][j]) {
 			case SSPP_VIG0:
 				if (rect_index == SDE_SSPP_RECT_1) {
 					mixercfg_ext3 |= ((i + 1) & 0xF) << 0;
@@ -562,12 +566,18 @@
 	}
 };
 
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
+};
+
 struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx,
 		void __iomem *addr,
 		struct sde_mdss_cfg *m)
 {
 	struct sde_hw_ctl *c;
 	struct sde_ctl_cfg *cfg;
+	int rc;
 
 	c = kzalloc(sizeof(*c), GFP_KERNEL);
 	if (!c)
@@ -586,13 +596,26 @@
 	c->mixer_count = m->mixer_count;
 	c->mixer_hw_caps = m->mixer;
 
+	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_CTL, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
+
 	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
 			c->hw.blk_off + c->hw.length, c->hw.xin_id);
 
 	return c;
+
+blk_init_error:
+	kzfree(c);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_ctl_destroy(struct sde_hw_ctl *ctx)
 {
+	if (ctx)
+		sde_hw_blk_destroy(&ctx->base);
 	kfree(ctx);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index ace05e8..a111916 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -17,6 +17,7 @@
 #include "sde_hw_util.h"
 #include "sde_hw_catalog.h"
 #include "sde_hw_sspp.h"
+#include "sde_hw_blk.h"
 
 /**
  * sde_ctl_mode_sel: Interface mode selection
@@ -49,8 +50,8 @@
  * @multirect_index: index of the rectangle of SSPP.
  */
 struct sde_hw_stage_cfg {
-	enum sde_sspp stage[CRTC_DUAL_MIXERS][SDE_STAGE_MAX][PIPES_PER_STAGE];
-	enum sde_sspp_multirect_index multirect_index[CRTC_DUAL_MIXERS]
+	enum sde_sspp stage[SDE_STAGE_MAX][PIPES_PER_STAGE];
+	enum sde_sspp_multirect_index multirect_index
 					[SDE_STAGE_MAX][PIPES_PER_STAGE];
 };
 
@@ -201,7 +202,7 @@
 	 * @cfg       : blend stage configuration
 	 */
 	void (*setup_blendstage)(struct sde_hw_ctl *ctx,
-		enum sde_lm lm, struct sde_hw_stage_cfg *cfg, u32 index);
+		enum sde_lm lm, struct sde_hw_stage_cfg *cfg);
 
 	void (*setup_sbuf_cfg)(struct sde_hw_ctl *ctx,
 		struct sde_ctl_sbuf_cfg *cfg);
@@ -209,16 +210,17 @@
 
 /**
  * struct sde_hw_ctl : CTL PATH driver object
+ * @base: hardware block base structure
  * @hw: block register map object
  * @idx: control path index
- * @ctl_hw_caps: control path capabilities
+ * @caps: control path capabilities
  * @mixer_count: number of mixers
  * @mixer_hw_caps: mixer hardware capabilities
  * @pending_flush_mask: storage for pending ctl_flush managed via ops
  * @ops: operation list
  */
 struct sde_hw_ctl {
-	/* base */
+	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
 
 	/* ctl path */
@@ -233,6 +235,16 @@
 };
 
 /**
+ * sde_hw_ctl - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_ctl *to_sde_hw_ctl(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_ctl, base);
+}
+
+/**
  * sde_hw_ctl_init(): Initializes the ctl_path hw driver object.
  * should be called before accessing every ctl path registers.
  * @idx:  ctl_path index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c
index 62193f9..1a346f0 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c
@@ -16,6 +16,7 @@
 #include "sde_hw_dsc.h"
 #include "sde_hw_pingpong.h"
 #include "sde_dbg.h"
+#include "sde_kms.h"
 
 #define DSC_COMMON_MODE	                0x000
 #define DSC_ENC                         0X004
@@ -200,12 +201,18 @@
 	ops->dsc_config_thresh = sde_hw_dsc_config_thresh;
 };
 
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
+};
+
 struct sde_hw_dsc *sde_hw_dsc_init(enum sde_dsc idx,
 		void __iomem *addr,
 		struct sde_mdss_cfg *m)
 {
 	struct sde_hw_dsc *c;
 	struct sde_dsc_cfg *cfg;
+	int rc;
 
 	c = kzalloc(sizeof(*c), GFP_KERNEL);
 	if (!c)
@@ -218,16 +225,29 @@
 	}
 
 	c->idx = idx;
-	c->dsc_hw_cap = cfg;
-	_setup_dsc_ops(&c->ops, c->dsc_hw_cap->features);
+	c->caps = cfg;
+	_setup_dsc_ops(&c->ops, c->caps->features);
+
+	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_DSC, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
 
 	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
 		c->hw.blk_off + c->hw.length, c->hw.xin_id);
 
 	return c;
+
+blk_init_error:
+	kzfree(c);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_dsc_destroy(struct sde_hw_dsc *dsc)
 {
+	if (dsc)
+		sde_hw_blk_destroy(&dsc->base);
 	kfree(dsc);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dsc.h b/drivers/gpu/drm/msm/sde/sde_hw_dsc.h
index 0703531..d1678f4 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dsc.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dsc.h
@@ -13,6 +13,11 @@
 #ifndef _SDE_HW_DSC_H
 #define _SDE_HW_DSC_H
 
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+#include "sde_hw_util.h"
+#include "sde_hw_blk.h"
+
 struct sde_hw_dsc;
 struct msm_display_dsc_info;
 
@@ -52,18 +57,28 @@
 };
 
 struct sde_hw_dsc {
-	/* base */
+	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
 
 	/* dsc */
 	enum sde_dsc idx;
-	const struct sde_dsc_cfg *dsc_hw_cap;
+	const struct sde_dsc_cfg *caps;
 
 	/* ops */
 	struct sde_hw_dsc_ops ops;
 };
 
 /**
+ * sde_hw_dsc - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_dsc *to_sde_hw_dsc(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_dsc, base);
+}
+
+/**
  * sde_hw_dsc_init - initializes the dsc block for the passed
  *                   dsc idx.
  * @idx:  DSC index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index 586d1f1..e766cdb 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -17,6 +17,7 @@
 #include "sde_hw_color_processing.h"
 #include "sde_dbg.h"
 #include "sde_ad4.h"
+#include "sde_kms.h"
 
 static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
 		struct sde_mdss_cfg *m,
@@ -118,12 +119,18 @@
 	}
 }
 
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
+};
+
 struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
 			void __iomem *addr,
 			struct sde_mdss_cfg *m)
 {
 	struct sde_hw_dspp *c;
 	struct sde_dspp_cfg *cfg;
+	int rc;
 
 	if (!addr || !m)
 		return ERR_PTR(-EINVAL);
@@ -143,15 +150,28 @@
 	c->cap = cfg;
 	_setup_dspp_ops(c, c->cap->features);
 
+	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_DSPP, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
+
 	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
 			c->hw.blk_off + c->hw.length, c->hw.xin_id);
 
 	return c;
+
+blk_init_error:
+	kzfree(c);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_dspp_destroy(struct sde_hw_dspp *dspp)
 {
-	if (dspp)
+	if (dspp) {
 		reg_dmav1_deinit_dspp_ops(dspp->idx);
+		sde_hw_blk_destroy(&dspp->base);
+	}
 	kfree(dspp);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
index 70b3e56..0baa970 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
@@ -13,6 +13,8 @@
 #ifndef _SDE_HW_DSPP_H
 #define _SDE_HW_DSPP_H
 
+#include "sde_hw_blk.h"
+
 struct sde_hw_dspp;
 
 /**
@@ -166,17 +168,14 @@
 
 /**
  * struct sde_hw_dspp - dspp description
- * @base_off:     MDP register mapped offset
- * @blk_off:      DSPP offset relative to mdss offset
- * @length        Length of register block offset
- * @hwversion     Mdss hw version number
- * @idx:          DSPP index
- * @dspp_hw_cap:  Pointer to layer_cfg
- * @highest_bank_bit:
- * @ops:          Pointer to operations possible for this dspp
+ * @base: Hardware block base structure
+ * @hw: Block hardware details
+ * @idx: DSPP index
+ * @cap: Pointer to layer_cfg
+ * @ops: Pointer to operations possible for this DSPP
  */
 struct sde_hw_dspp {
-	/* base */
+	struct sde_hw_blk base;
 	 struct sde_hw_blk_reg_map hw;
 
 	/* dspp */
@@ -188,6 +187,16 @@
 };
 
 /**
+ * sde_hw_dspp - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_dspp *to_sde_hw_dspp(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_dspp, base);
+}
+
+/**
  * sde_hw_dspp_init - initializes the dspp hw driver object.
  * should be called once before accessing every dspp.
  * @idx:  DSPP index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
index 53a48c8..8c3d4fc 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
@@ -974,6 +974,11 @@
 	if (!intr)
 		return 0;
 
+	if (irq_idx >= ARRAY_SIZE(sde_irq_map) || irq_idx < 0) {
+		pr_err("invalid IRQ index: [%d]\n", irq_idx);
+		return 0;
+	}
+
 	spin_lock_irqsave(&intr->mask_lock, irq_flags);
 
 	reg_idx = sde_irq_map[irq_idx].reg_idx;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index be83afe..35f1800 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -14,6 +14,7 @@
 #include "sde_hw_catalog.h"
 #include "sde_hw_intf.h"
 #include "sde_dbg.h"
+#include "sde_kms.h"
 
 #define INTF_TIMING_ENGINE_EN           0x000
 #define INTF_CONFIG                     0x004
@@ -301,12 +302,18 @@
 		ops->setup_rot_start = sde_hw_intf_setup_rot_start;
 }
 
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
+};
+
 struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx,
 		void __iomem *addr,
 		struct sde_mdss_cfg *m)
 {
 	struct sde_hw_intf *c;
 	struct sde_intf_cfg *cfg;
+	int rc;
 
 	c = kzalloc(sizeof(*c), GFP_KERNEL);
 	if (!c)
@@ -327,14 +334,27 @@
 	c->mdss = m;
 	_setup_intf_ops(&c->ops, c->cap->features);
 
+	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_INTF, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
+
 	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
 			c->hw.blk_off + c->hw.length, c->hw.xin_id);
 
 	return c;
+
+blk_init_error:
+	kzfree(c);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_intf_destroy(struct sde_hw_intf *intf)
 {
+	if (intf)
+		sde_hw_blk_destroy(&intf->base);
 	kfree(intf);
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.h b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
index d24e83a..83e206d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
@@ -16,6 +16,7 @@
 #include "sde_hw_catalog.h"
 #include "sde_hw_mdss.h"
 #include "sde_hw_util.h"
+#include "sde_hw_blk.h"
 
 struct sde_hw_intf;
 
@@ -86,7 +87,7 @@
 };
 
 struct sde_hw_intf {
-	/* base */
+	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
 
 	/* intf */
@@ -99,6 +100,16 @@
 };
 
 /**
+ * to_sde_hw_intf - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_intf *to_sde_hw_intf(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_intf, base);
+}
+
+/**
  * sde_hw_intf_init(): Initializes the intf driver for the passed
  * interface idx.
  * @idx:  interface index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index fedc72c..3d282ee 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -16,6 +16,7 @@
 #include "sde_hw_lm.h"
 #include "sde_hw_mdss.h"
 #include "sde_dbg.h"
+#include "sde_kms.h"
 
 #define LM_OP_MODE                        0x00
 #define LM_OUT_SIZE                       0x04
@@ -277,12 +278,18 @@
 	}
 };
 
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
+};
+
 struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx,
 		void __iomem *addr,
 		struct sde_mdss_cfg *m)
 {
 	struct sde_hw_mixer *c;
 	struct sde_lm_cfg *cfg;
+	int rc;
 
 	c = kzalloc(sizeof(*c), GFP_KERNEL);
 	if (!c)
@@ -299,13 +306,26 @@
 	c->cap = cfg;
 	_setup_mixer_ops(m, &c->ops, c->cap->features);
 
+	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_LM, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
+
 	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
 			c->hw.blk_off + c->hw.length, c->hw.xin_id);
 
 	return c;
+
+blk_init_error:
+	kzfree(c);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_lm_destroy(struct sde_hw_mixer *lm)
 {
+	if (lm)
+		sde_hw_blk_destroy(&lm->base);
 	kfree(lm);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.h b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
index 45c0fc9..8a146bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
@@ -15,6 +15,7 @@
 
 #include "sde_hw_mdss.h"
 #include "sde_hw_util.h"
+#include "sde_hw_blk.h"
 
 struct sde_hw_mixer;
 
@@ -89,7 +90,7 @@
 };
 
 struct sde_hw_mixer {
-	/* base */
+	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
 
 	/* lm */
@@ -106,6 +107,16 @@
 };
 
 /**
+ * to_sde_hw_mixer - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_mixer *to_sde_hw_mixer(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_mixer, base);
+}
+
+/**
  * sde_hw_lm_init(): Initializes the mixer hw driver object.
  * should be called once before accessing every mixer.
  * @idx:  mixer index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index 31aa031..582ab5a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -283,6 +283,13 @@
 	ROT_MAX
 };
 
+enum sde_inline_rot {
+	INLINE_ROT_NONE,
+	INLINE_ROT0_SSPP,
+	INLINE_ROT0_WB,
+	INLINE_ROT_MAX
+};
+
 /**
  * SDE HW,Component order color map
  */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index a77b8d3..37b74df 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -10,11 +10,14 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/iopoll.h>
+
 #include "sde_hw_mdss.h"
 #include "sde_hwio.h"
 #include "sde_hw_catalog.h"
 #include "sde_hw_pingpong.h"
 #include "sde_dbg.h"
+#include "sde_kms.h"
 
 #define PP_TEAR_CHECK_EN                0x000
 #define PP_SYNC_CONFIG_VSYNC            0x004
@@ -84,38 +87,76 @@
 	return 0;
 }
 
-int sde_hw_pp_setup_autorefresh_config(struct sde_hw_pingpong *pp,
+static int sde_hw_pp_setup_autorefresh_config(struct sde_hw_pingpong *pp,
 		struct sde_hw_autorefresh *cfg)
 {
-	struct sde_hw_blk_reg_map *c = &pp->hw;
+	struct sde_hw_blk_reg_map *c;
 	u32 refresh_cfg;
 
+	if (!pp || !cfg)
+		return -EINVAL;
+	c = &pp->hw;
+
 	if (cfg->enable)
 		refresh_cfg = BIT(31) | cfg->frame_count;
 	else
 		refresh_cfg = 0;
 
-	SDE_REG_WRITE(c, PP_AUTOREFRESH_CONFIG,
-			refresh_cfg);
+	SDE_REG_WRITE(c, PP_AUTOREFRESH_CONFIG, refresh_cfg);
+	SDE_EVT32(pp->idx - PINGPONG_0, refresh_cfg);
 
 	return 0;
 }
 
-void sde_hw_pp_dsc_enable(struct sde_hw_pingpong *pp)
+static int sde_hw_pp_get_autorefresh_config(struct sde_hw_pingpong *pp,
+		struct sde_hw_autorefresh *cfg)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 val;
+
+	if (!pp || !cfg)
+		return -EINVAL;
+
+	c = &pp->hw;
+	val = SDE_REG_READ(c, PP_AUTOREFRESH_CONFIG);
+	cfg->enable = (val & BIT(31)) >> 31;
+	cfg->frame_count = val & 0xffff;
+
+	return 0;
+}
+
+static int sde_hw_pp_poll_timeout_wr_ptr(struct sde_hw_pingpong *pp,
+		u32 timeout_us)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 val;
+	int rc;
+
+	if (!pp)
+		return -EINVAL;
+
+	c = &pp->hw;
+	rc = readl_poll_timeout(c->base_off + c->blk_off + PP_LINE_COUNT,
+			val, (val & 0xffff) >= 1, 10, timeout_us);
+
+	return rc;
+}
+
+static void sde_hw_pp_dsc_enable(struct sde_hw_pingpong *pp)
 {
 	struct sde_hw_blk_reg_map *c = &pp->hw;
 
 	SDE_REG_WRITE(c, PP_DSC_MODE, 1);
 }
 
-void sde_hw_pp_dsc_disable(struct sde_hw_pingpong *pp)
+static void sde_hw_pp_dsc_disable(struct sde_hw_pingpong *pp)
 {
 	struct sde_hw_blk_reg_map *c = &pp->hw;
 
 	SDE_REG_WRITE(c, PP_DSC_MODE, 0);
 }
 
-int sde_hw_pp_setup_dsc(struct sde_hw_pingpong *pp)
+static int sde_hw_pp_setup_dsc(struct sde_hw_pingpong *pp)
 {
 	struct sde_hw_blk_reg_map *pp_c = &pp->hw;
 	int data;
@@ -126,7 +167,7 @@
 	return 0;
 }
 
-int sde_hw_pp_enable_te(struct sde_hw_pingpong *pp, bool enable)
+static int sde_hw_pp_enable_te(struct sde_hw_pingpong *pp, bool enable)
 {
 	struct sde_hw_blk_reg_map *c = &pp->hw;
 
@@ -134,18 +175,44 @@
 	return 0;
 }
 
-int sde_hw_pp_get_vsync_info(struct sde_hw_pingpong *pp,
+static int sde_hw_pp_connect_external_te(struct sde_hw_pingpong *pp,
+		bool enable_external_te)
+{
+	struct sde_hw_blk_reg_map *c = &pp->hw;
+	u32 cfg;
+	int orig;
+
+	if (!pp)
+		return -EINVAL;
+
+	c = &pp->hw;
+	cfg = SDE_REG_READ(c, PP_SYNC_CONFIG_VSYNC);
+	orig = (bool)(cfg & BIT(20));
+	if (enable_external_te)
+		cfg |= BIT(20);
+	else
+		cfg &= ~BIT(20);
+	SDE_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg);
+	SDE_EVT32(pp->idx - PINGPONG_0, cfg);
+
+	return orig;
+}
+
+static int sde_hw_pp_get_vsync_info(struct sde_hw_pingpong *pp,
 		struct sde_hw_pp_vsync_info *info)
 {
 	struct sde_hw_blk_reg_map *c = &pp->hw;
 	u32 val;
 
 	val = SDE_REG_READ(c, PP_VSYNC_INIT_VAL);
-	info->init_val = val & 0xffff;
+	info->rd_ptr_init_val = val & 0xffff;
 
 	val = SDE_REG_READ(c, PP_INT_COUNT_VAL);
-	info->vsync_count = (val & 0xffff0000) >> 16;
-	info->line_count = val & 0xffff;
+	info->rd_ptr_frame_count = (val & 0xffff0000) >> 16;
+	info->rd_ptr_line_count = val & 0xffff;
+
+	val = SDE_REG_READ(c, PP_LINE_COUNT);
+	info->wr_ptr_line_count = val & 0xffff;
 
 	return 0;
 }
@@ -155,11 +222,19 @@
 {
 	ops->setup_tearcheck = sde_hw_pp_setup_te_config;
 	ops->enable_tearcheck = sde_hw_pp_enable_te;
+	ops->connect_external_te = sde_hw_pp_connect_external_te;
 	ops->get_vsync_info = sde_hw_pp_get_vsync_info;
 	ops->setup_autorefresh = sde_hw_pp_setup_autorefresh_config;
 	ops->setup_dsc = sde_hw_pp_setup_dsc;
 	ops->enable_dsc = sde_hw_pp_dsc_enable;
 	ops->disable_dsc = sde_hw_pp_dsc_disable;
+	ops->get_autorefresh = sde_hw_pp_get_autorefresh_config;
+	ops->poll_timeout_wr_ptr = sde_hw_pp_poll_timeout_wr_ptr;
+};
+
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
 };
 
 struct sde_hw_pingpong *sde_hw_pingpong_init(enum sde_pingpong idx,
@@ -168,6 +243,7 @@
 {
 	struct sde_hw_pingpong *c;
 	struct sde_pingpong_cfg *cfg;
+	int rc;
 
 	c = kzalloc(sizeof(*c), GFP_KERNEL);
 	if (!c)
@@ -180,16 +256,29 @@
 	}
 
 	c->idx = idx;
-	c->pingpong_hw_cap = cfg;
-	_setup_pingpong_ops(&c->ops, c->pingpong_hw_cap->features);
+	c->caps = cfg;
+	_setup_pingpong_ops(&c->ops, c->caps->features);
+
+	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_PINGPONG, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
 
 	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
 			c->hw.blk_off + c->hw.length, c->hw.xin_id);
 
 	return c;
+
+blk_init_error:
+	kzfree(c);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_pingpong_destroy(struct sde_hw_pingpong *pp)
 {
+	if (pp)
+		sde_hw_blk_destroy(&pp->base);
 	kfree(pp);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
index 90f6171..6dbf4aa 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
@@ -13,6 +13,11 @@
 #ifndef _SDE_HW_PINGPONG_H
 #define _SDE_HW_PINGPONG_H
 
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+#include "sde_hw_util.h"
+#include "sde_hw_blk.h"
+
 struct sde_hw_pingpong;
 
 struct sde_hw_tear_check {
@@ -36,9 +41,10 @@
 };
 
 struct sde_hw_pp_vsync_info {
-	u32 init_val; /* value of rd pointer at vsync edge */
-	u32 vsync_count;    /* mdp clocks to complete one line */
-	u32 line_count;   /* current line count */
+	u32 rd_ptr_init_val;	/* value of rd pointer at vsync edge */
+	u32 rd_ptr_frame_count;	/* num frames sent since enabling interface */
+	u32 rd_ptr_line_count;	/* current line on panel (rd ptr) */
+	u32 wr_ptr_line_count;	/* current line within pp fifo (wr ptr) */
 };
 
 struct sde_hw_dsc_cfg {
@@ -72,6 +78,13 @@
 			bool enable);
 
 	/**
+	 * read, modify, write to either set or clear listening to external TE
+	 * @Return: 1 if TE was originally connected, 0 if not, or -ERROR
+	 */
+	int (*connect_external_te)(struct sde_hw_pingpong *pp,
+			bool enable_external_te);
+
+	/**
 	 * provides the programmed and current
 	 * line_count
 	 */
@@ -85,6 +98,18 @@
 			struct sde_hw_autorefresh *cfg);
 
 	/**
+	 * retrieve autorefresh config from hardware
+	 */
+	int (*get_autorefresh)(struct sde_hw_pingpong *pp,
+			struct sde_hw_autorefresh *cfg);
+
+	/**
+	 * poll until write pointer transmission starts
+	 * @Return: 0 on success, -ETIMEDOUT on timeout
+	 */
+	int (*poll_timeout_wr_ptr)(struct sde_hw_pingpong *pp, u32 timeout_us);
+
+	/**
 	 * Program the dsc compression block
 	 */
 	int (*setup_dsc)(struct sde_hw_pingpong *pp);
@@ -101,18 +126,28 @@
 };
 
 struct sde_hw_pingpong {
-	/* base */
+	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
 
 	/* pingpong */
 	enum sde_pingpong idx;
-	const struct sde_pingpong_cfg *pingpong_hw_cap;
+	const struct sde_pingpong_cfg *caps;
 
 	/* ops */
 	struct sde_hw_pingpong_ops ops;
 };
 
 /**
+ * sde_hw_pingpong - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_pingpong *to_sde_hw_pingpong(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_pingpong, base);
+}
+
+/**
  * sde_hw_pingpong_init - initializes the pingpong driver for the passed
  *	pingpong idx.
  * @idx:  Pingpong index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 678c84a..dbd435b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -49,6 +49,7 @@
 			(cfg)->dma_buf->index)
 
 #define REG_DMA_DECODE_SEL 0x180AC060
+#define REG_DMA_LAST_CMD 0x180AC004
 #define SINGLE_REG_WRITE_OPCODE (BIT(28))
 #define REL_ADDR_OPCODE (BIT(27))
 #define HW_INDEX_REG_WRITE_OPCODE (BIT(28) | BIT(29))
@@ -58,6 +59,7 @@
 #define WRAP_MIN_SIZE 2
 #define WRAP_MAX_SIZE (BIT(4) - 1)
 #define MAX_DWORDS_SZ (BIT(14) - 1)
+#define REG_DMA_HEADERS_BUFFER_SZ (sizeof(u32) * 128)
 
 typedef int (*reg_dma_internal_ops) (struct sde_reg_dma_setup_ops_cfg *cfg);
 
@@ -93,17 +95,20 @@
 static int validate_write_decode_sel(struct sde_reg_dma_setup_ops_cfg *cfg);
 static int validate_write_reg(struct sde_reg_dma_setup_ops_cfg *cfg);
 static int validate_write_multi_lut_reg(struct sde_reg_dma_setup_ops_cfg *cfg);
+static int validate_last_cmd(struct sde_reg_dma_setup_ops_cfg *cfg);
 static int write_decode_sel(struct sde_reg_dma_setup_ops_cfg *cfg);
 static int write_single_reg(struct sde_reg_dma_setup_ops_cfg *cfg);
 static int write_multi_reg_index(struct sde_reg_dma_setup_ops_cfg *cfg);
 static int write_multi_reg_inc(struct sde_reg_dma_setup_ops_cfg *cfg);
 static int write_multi_lut_reg(struct sde_reg_dma_setup_ops_cfg *cfg);
+static int write_last_cmd(struct sde_reg_dma_setup_ops_cfg *cfg);
 static int reset_reg_dma_buffer_v1(struct sde_reg_dma_buffer *lut_buf);
 static int check_support_v1(enum sde_reg_dma_features feature,
 		enum sde_reg_dma_blk blk, bool *is_supported);
 static int setup_payload_v1(struct sde_reg_dma_setup_ops_cfg *cfg);
 static int kick_off_v1(struct sde_reg_dma_kickoff_cfg *cfg);
 static int reset_v1(struct sde_hw_ctl *ctl);
+static int last_cmd_v1(struct sde_hw_ctl *ctl, enum sde_reg_dma_queue q);
 static struct sde_reg_dma_buffer *alloc_reg_dma_buf_v1(u32 size);
 static int dealloc_reg_dma_v1(struct sde_reg_dma_buffer *lut_buf);
 
@@ -123,6 +128,8 @@
 	[REG_BLK_WRITE_MULTIPLE] = validate_write_multi_lut_reg,
 };
 
+static struct sde_reg_dma_buffer *last_cmd_buf;
+
 static void get_decode_sel(unsigned long blk, u32 *decode_sel)
 {
 	int i = 0;
@@ -474,6 +481,11 @@
 		return -EINVAL;
 
 	reg_dma = cfg;
+	if (!last_cmd_buf) {
+		last_cmd_buf = alloc_reg_dma_buf_v1(REG_DMA_HEADERS_BUFFER_SZ);
+		if (IS_ERR_OR_NULL(last_cmd_buf))
+			return -EINVAL;
+	}
 	reg_dma->ops.check_support = check_support_v1;
 	reg_dma->ops.setup_payload = setup_payload_v1;
 	reg_dma->ops.kick_off = kick_off_v1;
@@ -481,6 +493,7 @@
 	reg_dma->ops.alloc_reg_dma_buf = alloc_reg_dma_buf_v1;
 	reg_dma->ops.dealloc_reg_dma = dealloc_reg_dma_v1;
 	reg_dma->ops.reset_reg_dma_buf = reset_reg_dma_buffer_v1;
+	reg_dma->ops.last_command = last_cmd_v1;
 
 	reg_dma_ctl_queue_off[CTL_0] = REG_DMA_CTL0_QUEUE_0_CMD0_OFF;
 	for (i = CTL_1; i < ARRAY_SIZE(reg_dma_ctl_queue_off); i++)
@@ -648,3 +661,76 @@
 	lut_buf->next_op_allowed = DECODE_SEL_OP;
 	return 0;
 }
+
+static int validate_last_cmd(struct sde_reg_dma_setup_ops_cfg *cfg)
+{
+	u32 remain_len, write_len;
+
+	remain_len = BUFFER_SPACE_LEFT(cfg);
+	write_len = sizeof(u32);
+	if (remain_len < write_len) {
+		DRM_ERROR("buffer is full sz %d needs %d bytes\n",
+				remain_len, write_len);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int write_last_cmd(struct sde_reg_dma_setup_ops_cfg *cfg)
+{
+	u32 *loc = NULL;
+
+	loc =  (u32 *)((u8 *)cfg->dma_buf->vaddr +
+			cfg->dma_buf->index);
+	loc[0] = REG_DMA_LAST_CMD;
+	loc[1] = BIT(0);
+	cfg->dma_buf->index = sizeof(u32) * 2;
+	cfg->dma_buf->ops_completed = REG_WRITE_OP | DECODE_SEL_OP;
+	cfg->dma_buf->next_op_allowed = REG_WRITE_OP;
+
+	return 0;
+}
+
+static int last_cmd_v1(struct sde_hw_ctl *ctl, enum sde_reg_dma_queue q)
+{
+	struct sde_reg_dma_setup_ops_cfg cfg;
+	struct sde_reg_dma_kickoff_cfg kick_off;
+
+	if (!last_cmd_buf || !ctl || q >= DMA_CTL_QUEUE_MAX) {
+		DRM_ERROR("invalid param buf %pK ctl %pK q %d\n", last_cmd_buf,
+				ctl, q);
+		return -EINVAL;
+	}
+
+	cfg.dma_buf = last_cmd_buf;
+	reset_reg_dma_buffer_v1(last_cmd_buf);
+	if (validate_last_cmd(&cfg)) {
+		DRM_ERROR("validate buf failed\n");
+		return -EINVAL;
+	}
+
+	if (write_last_cmd(&cfg)) {
+		DRM_ERROR("write buf failed\n");
+		return -EINVAL;
+	}
+
+	kick_off.ctl = ctl;
+	kick_off.queue_select = q;
+	kick_off.trigger_mode = WRITE_IMMEDIATE;
+	kick_off.last_command = 1;
+	kick_off.op = REG_DMA_WRITE;
+	kick_off.dma_buf = last_cmd_buf;
+	if (kick_off_v1(&kick_off)) {
+		DRM_ERROR("kick off last cmd failed\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void deinit_v1(void)
+{
+	if (last_cmd_buf)
+		dealloc_reg_dma_v1(last_cmd_buf);
+	last_cmd_buf = NULL;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.h b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.h
index 8e37d38..4f9ab4e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.h
@@ -20,4 +20,8 @@
  */
 int init_v1(struct sde_hw_reg_dma *reg_dma);
 
+/**
+ * deinit_v1() - free up any resources allocated during the v1 reg dma init
+ */
+void deinit_v1(void);
 #endif /* _SDE_HW_REG_DMA_V1_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
index 0dcbb7e..285ef11 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
@@ -408,7 +408,6 @@
 
 	REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[GAMUT][ctx->idx],
 			REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
-	kick_off.last_command = hw_cfg->last_feature;
 	rc = dma_ops->kick_off(&kick_off);
 	if (rc)
 		DRM_ERROR("failed to kick off ret %d\n", rc);
@@ -505,7 +504,6 @@
 
 	REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[GAMUT][ctx->idx],
 			REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
-	kick_off.last_command = hw_cfg->last_feature;
 	rc = dma_ops->kick_off(&kick_off);
 	if (rc)
 		DRM_ERROR("failed to kick off ret %d\n", rc);
@@ -598,7 +596,6 @@
 
 	REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[GC][ctx->idx],
 			REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
-	kick_off.last_command = hw_cfg->last_feature;
 	rc = dma_ops->kick_off(&kick_off);
 	if (rc) {
 		DRM_ERROR("failed to kick off ret %d\n", rc);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index d5f03a6a..bbd5931 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -900,8 +900,7 @@
 	c->caps = cfg;
 	_setup_rot_ops(&c->ops, c->caps->features);
 
-	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx,
-			&sde_hw_rot_ops);
+	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx, &sde_hw_rot_ops);
 	if (rc) {
 		SDE_ERROR("failed to init hw blk %d\n", rc);
 		goto blk_init_error;
@@ -922,9 +921,11 @@
  */
 void sde_hw_rot_destroy(struct sde_hw_rot *hw_rot)
 {
-	sde_hw_blk_destroy(&hw_rot->base);
-	kfree(hw_rot->downscale_caps);
-	kfree(hw_rot->format_caps);
+	if (hw_rot) {
+		sde_hw_blk_destroy(&hw_rot->base);
+		kfree(hw_rot->downscale_caps);
+		kfree(hw_rot->format_caps);
+	}
 	kfree(hw_rot);
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index bb9f9c0..9fd5992 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -16,6 +16,7 @@
 #include "sde_hw_sspp.h"
 #include "sde_hw_color_processing.h"
 #include "sde_dbg.h"
+#include "sde_kms.h"
 
 #define SDE_FETCH_CONFIG_RESET_VALUE   0x00000087
 
@@ -1216,12 +1217,18 @@
 	return ERR_PTR(-ENOMEM);
 }
 
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
+};
+
 struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx,
-			void __iomem *addr,
-			struct sde_mdss_cfg *catalog)
+		void __iomem *addr, struct sde_mdss_cfg *catalog,
+		bool is_virtual_pipe)
 {
 	struct sde_hw_pipe *hw_pipe;
 	struct sde_sspp_cfg *cfg;
+	int rc;
 
 	if (!addr || !catalog)
 		return ERR_PTR(-EINVAL);
@@ -1243,12 +1250,19 @@
 	hw_pipe->cap = cfg;
 	_setup_layer_ops(hw_pipe, hw_pipe->cap->features);
 
-	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
+	rc = sde_hw_blk_init(&hw_pipe->base, SDE_HW_BLK_SSPP, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
+
+	if (!is_virtual_pipe)
+		sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
 			hw_pipe->hw.blk_off,
 			hw_pipe->hw.blk_off + hw_pipe->hw.length,
 			hw_pipe->hw.xin_id);
 
-	if (cfg->sblk->scaler_blk.len)
+	if (cfg->sblk->scaler_blk.len && !is_virtual_pipe)
 		sde_dbg_reg_register_dump_range(SDE_DBG_NAME,
 			cfg->sblk->scaler_blk.name,
 			hw_pipe->hw.blk_off + cfg->sblk->scaler_blk.base,
@@ -1257,10 +1271,17 @@
 			hw_pipe->hw.xin_id);
 
 	return hw_pipe;
+
+blk_init_error:
+	kzfree(hw_pipe);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx)
 {
+	if (ctx)
+		sde_hw_blk_destroy(&ctx->base);
 	kfree(ctx);
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index d52c0e5..8d14715 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -16,6 +16,7 @@
 #include "sde_hw_catalog.h"
 #include "sde_hw_mdss.h"
 #include "sde_hw_util.h"
+#include "sde_hw_blk.h"
 #include "sde_formats.h"
 #include "sde_color_processing.h"
 
@@ -610,20 +611,16 @@
 
 /**
  * struct sde_hw_pipe - pipe description
- * @base_off:     mdp register mapped offset
- * @blk_off:      pipe offset relative to mdss offset
- * @length        length of register block offset
- * @hwversion     mdss hw version number
- * @catalog:      back pointer to catalog
- * @mdp:          pointer to associated mdp portion of the catalog
- * @idx:          pipe index
- * @type :        pipe type, VIG/DMA/RGB/CURSOR, certain operations are not
- *                supported for each pipe type
- * @pipe_hw_cap:  pointer to layer_cfg
- * @ops:          pointer to operations possible for this pipe
+ * @base: hardware block base structure
+ * @hw: block hardware details
+ * @catalog: back pointer to catalog
+ * @mdp: pointer to associated mdp portion of the catalog
+ * @idx: pipe index
+ * @cap: pointer to layer_cfg
+ * @ops: pointer to operations possible for this pipe
  */
 struct sde_hw_pipe {
-	/* base */
+	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
 	struct sde_mdss_cfg *catalog;
 	struct sde_mdp_cfg *mdp;
@@ -637,15 +634,26 @@
 };
 
 /**
+ * sde_hw_pipe - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_pipe *to_sde_hw_pipe(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_pipe, base);
+}
+
+/**
  * sde_hw_sspp_init - initializes the sspp hw driver object.
  * Should be called once before accessing every pipe.
  * @idx:  Pipe index for which driver object is required
  * @addr: Mapped register io address of MDP
  * @catalog : Pointer to mdss catalog data
+ * @is_virtual_pipe: is this pipe virtual pipe
  */
 struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx,
-			void __iomem *addr,
-			struct sde_mdss_cfg *catalog);
+		void __iomem *addr, struct sde_mdss_cfg *catalog,
+		bool is_virtual_pipe);
 
 /**
  * sde_hw_sspp_destroy(): Destroys SSPP driver context
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index 19f999e..b773187 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -14,6 +14,7 @@
 #include "sde_hw_catalog.h"
 #include "sde_hw_top.h"
 #include "sde_dbg.h"
+#include "sde_kms.h"
 
 #define SSPP_SPARE                        0x28
 #define UBWC_STATIC                       0x144
@@ -152,8 +153,8 @@
 	if (clk_ctrl <= SDE_CLK_CTRL_NONE || clk_ctrl >= SDE_CLK_CTRL_MAX)
 		return false;
 
-	reg_off = mdp->cap->clk_ctrls[clk_ctrl].reg_off;
-	bit_off = mdp->cap->clk_ctrls[clk_ctrl].bit_off;
+	reg_off = mdp->caps->clk_ctrls[clk_ctrl].reg_off;
+	bit_off = mdp->caps->clk_ctrls[clk_ctrl].bit_off;
 
 	reg_val = SDE_REG_READ(c, reg_off);
 
@@ -337,12 +338,18 @@
 	return ERR_PTR(-EINVAL);
 }
 
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
+};
+
 struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
 		void __iomem *addr,
 		const struct sde_mdss_cfg *m)
 {
 	struct sde_hw_mdp *mdp;
 	const struct sde_mdp_cfg *cfg;
+	int rc;
 
 	if (!addr || !m)
 		return ERR_PTR(-EINVAL);
@@ -361,8 +368,14 @@
 	 * Assign ops
 	 */
 	mdp->idx = idx;
-	mdp->cap = cfg;
-	_setup_mdp_ops(&mdp->ops, mdp->cap->features);
+	mdp->caps = cfg;
+	_setup_mdp_ops(&mdp->ops, mdp->caps->features);
+
+	rc = sde_hw_blk_init(&mdp->base, SDE_HW_BLK_TOP, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
 
 	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
 			mdp->hw.blk_off, mdp->hw.blk_off + mdp->hw.length,
@@ -370,10 +383,17 @@
 	sde_dbg_set_sde_top_offset(mdp->hw.blk_off);
 
 	return mdp;
+
+blk_init_error:
+	kzfree(mdp);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp)
 {
+	if (mdp)
+		sde_hw_blk_destroy(&mdp->base);
 	kfree(mdp);
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index faf25c7..573780e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -16,6 +16,7 @@
 #include "sde_hw_catalog.h"
 #include "sde_hw_mdss.h"
 #include "sde_hw_util.h"
+#include "sde_hw_blk.h"
 
 struct sde_hw_mdp;
 
@@ -179,19 +180,29 @@
 };
 
 struct sde_hw_mdp {
-	/* base */
+	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
 
-	/* intf */
+	/* top */
 	enum sde_mdp idx;
-	const struct sde_mdp_cfg *cap;
+	const struct sde_mdp_cfg *caps;
 
 	/* ops */
 	struct sde_hw_mdp_ops ops;
 };
 
 /**
- * sde_hw_intf_init - initializes the intf driver for the passed interface idx
+ * to_sde_hw_mdp - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_mdp *to_sde_hw_mdp(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_mdp, base);
+}
+
+/**
+ * sde_hw_mdptop_init - initializes the top driver for the passed idx
  * @idx:  Interface index for which driver object is required
  * @addr: Mapped register io address of MDP
  * @m:    Pointer to mdss catalog data
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.c b/drivers/gpu/drm/msm/sde/sde_hw_wb.c
index 378b904..e1bd841 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_wb.c
@@ -16,6 +16,7 @@
 #include "sde_hw_wb.h"
 #include "sde_formats.h"
 #include "sde_dbg.h"
+#include "sde_kms.h"
 
 #define WB_DST_FORMAT			0x000
 #define WB_DST_OP_MODE			0x004
@@ -262,6 +263,11 @@
 		ops->setup_cdp = sde_hw_wb_setup_cdp;
 }
 
+static struct sde_hw_blk_ops sde_hw_ops = {
+	.start = NULL,
+	.stop = NULL,
+};
+
 struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx,
 		void __iomem *addr,
 		struct sde_mdss_cfg *m,
@@ -269,6 +275,7 @@
 {
 	struct sde_hw_wb *c;
 	struct sde_wb_cfg *cfg;
+	int rc;
 
 	if (!addr || !m || !hw_mdp)
 		return ERR_PTR(-EINVAL);
@@ -292,13 +299,26 @@
 	_setup_wb_ops(&c->ops, c->caps->features);
 	c->hw_mdp = hw_mdp;
 
+	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_WB, idx, &sde_hw_ops);
+	if (rc) {
+		SDE_ERROR("failed to init hw blk %d\n", rc);
+		goto blk_init_error;
+	}
+
 	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
 			c->hw.blk_off + c->hw.length, c->hw.xin_id);
 
 	return c;
+
+blk_init_error:
+	kzfree(c);
+
+	return ERR_PTR(rc);
 }
 
 void sde_hw_wb_destroy(struct sde_hw_wb *hw_wb)
 {
+	if (hw_wb)
+		sde_hw_blk_destroy(&hw_wb->base);
 	kfree(hw_wb);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.h b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
index ca3c386..70fe8a5 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_wb.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
@@ -131,16 +131,17 @@
 
 /**
  * struct sde_hw_wb : WB driver object
- * @struct sde_hw_blk_reg_map *hw;
+ * @base: hardware block base structure
+ * @hw: block hardware details
  * @catalog: back pointer to catalog
- * @mdp:          pointer to associated mdp portion of the catalog
- * @idx
- * @wb_hw_caps
- * @ops
+ * @mdp: pointer to associated mdp portion of the catalog
+ * @idx: hardware index number within type
+ * @wb_hw_caps: hardware capabilities
+ * @ops: function pointers
  * @hw_mdp: MDP top level hardware block
  */
 struct sde_hw_wb {
-	/* base */
+	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
 	struct sde_mdss_cfg *catalog;
 	struct sde_mdp_cfg *mdp;
@@ -156,6 +157,16 @@
 };
 
 /**
+ * sde_hw_wb - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_wb *to_sde_hw_wb(struct sde_hw_blk *hw)
+{
+	return container_of(hw, struct sde_hw_wb, base);
+}
+
+/**
  * sde_hw_wb_init(): Initializes and return writeback hw driver object.
  * @idx:  wb_path index for which driver object is required
  * @addr: mapped register io address of MDP
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index c783ab0..78ea685 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -178,9 +178,9 @@
 		return -EINVAL;
 	}
 
-	debugfs_create_file("danger_status", 0644, sde_kms->debugfs_danger,
+	debugfs_create_file("danger_status", 0600, sde_kms->debugfs_danger,
 			sde_kms, &sde_debugfs_danger_stats_fops);
-	debugfs_create_file("safe_status", 0644, sde_kms->debugfs_danger,
+	debugfs_create_file("safe_status", 0600, sde_kms->debugfs_danger,
 			sde_kms, &sde_debugfs_safe_stats_fops);
 
 	return 0;
@@ -303,7 +303,7 @@
 		return -EINVAL;
 
 	/* allow debugfs_root to be NULL */
-	debugfs_create_x32(SDE_DEBUGFS_HWMASKNAME, 0644, debugfs_root, p);
+	debugfs_create_x32(SDE_DEBUGFS_HWMASKNAME, 0600, debugfs_root, p);
 
 	(void) sde_debugfs_danger_init(sde_kms, debugfs_root);
 	(void) sde_debugfs_vbif_init(sde_kms, debugfs_root);
@@ -353,16 +353,24 @@
 {
 	struct sde_kms *sde_kms;
 	struct msm_drm_private *priv;
+	struct drm_device *dev;
+	struct drm_encoder *encoder;
 
 	if (!kms)
 		return;
 	sde_kms = to_sde_kms(kms);
+	dev = sde_kms->dev;
 
-	if (!sde_kms->dev || !sde_kms->dev->dev_private)
+	if (!dev || !dev->dev_private)
 		return;
-	priv = sde_kms->dev->dev_private;
+	priv = dev->dev_private;
 
 	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+		if (encoder->crtc != NULL)
+			sde_encoder_prepare_commit(encoder);
+
 }
 
 static void sde_kms_commit(struct msm_kms *kms,
@@ -404,6 +412,49 @@
 	SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
 }
 
+static void sde_kms_wait_for_tx_complete(struct msm_kms *kms,
+		struct drm_crtc *crtc)
+{
+	struct drm_encoder *encoder;
+	struct drm_device *dev;
+	int ret;
+
+	if (!kms || !crtc || !crtc->state || !crtc->dev) {
+		SDE_ERROR("invalid params\n");
+		return;
+	}
+
+	if (!crtc->state->enable) {
+		SDE_DEBUG("[crtc:%d] not enable\n", crtc->base.id);
+		return;
+	}
+
+	if (!crtc->state->active) {
+		SDE_DEBUG("[crtc:%d] not active\n", crtc->base.id);
+		return;
+	}
+
+	dev = crtc->dev;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+		if (encoder->crtc != crtc)
+			continue;
+		/*
+		 * Video Mode - Wait for VSYNC
+		 * Cmd Mode   - Wait for PP_DONE. Will be no-op if transfer is
+		 *              complete
+		 */
+		SDE_EVT32_VERBOSE(DRMID(crtc));
+		ret = sde_encoder_wait_for_event(encoder, MSM_ENC_TX_COMPLETE);
+		if (ret && ret != -EWOULDBLOCK) {
+			SDE_ERROR(
+			"[crtc: %d][enc: %d] wait for commit done returned %d\n",
+			crtc->base.id, encoder->base.id, ret);
+			break;
+		}
+	}
+}
+
 static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
 		struct drm_crtc *crtc)
 {
@@ -435,7 +486,7 @@
 		 * mode panels. This may be a no-op for command mode panels.
 		 */
 		SDE_EVT32_VERBOSE(DRMID(crtc));
-		ret = sde_encoder_wait_for_commit_done(encoder);
+		ret = sde_encoder_wait_for_event(encoder, MSM_ENC_COMMIT_DONE);
 		if (ret && ret != -EWOULDBLOCK) {
 			SDE_ERROR("wait for commit done returned %d\n", ret);
 			break;
@@ -1285,6 +1336,8 @@
 	if (sde_kms->mmio)
 		msm_iounmap(pdev, sde_kms->mmio);
 	sde_kms->mmio = NULL;
+
+	sde_reg_dma_deinit();
 }
 
 static void sde_kms_destroy(struct msm_kms *kms)
@@ -1319,6 +1372,48 @@
 		sde_crtc_cancel_pending_flip(priv->crtcs[i], file);
 }
 
+static int sde_kms_atomic_check(struct msm_kms *kms,
+		struct drm_atomic_state *state)
+{
+	struct sde_kms *sde_kms = to_sde_kms(kms);
+	struct drm_device *dev = sde_kms->dev;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	int rc, i;
+
+	if (!kms || !state)
+		return -EINVAL;
+
+	/*
+	 * Add planes (and other affected DRM objects, if any) to new state
+	 * if idle power collapse occurred since previous commit.
+	 * Since atomic state is a delta from the last, if the user-space
+	 * did not request any changes on a plane/connector, that object
+	 * will not be included in the new atomic state. Idle power collapse
+	 * is driver-autonomous, so the driver needs to ensure that all
+	 * hardware is reprogrammed as the power comes back on by forcing
+	 * the drm objects attached to the CRTC into the new atomic state.
+	 */
+	for_each_crtc_in_state(state, crtc, crtc_state, i) {
+		struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state);
+		struct sde_crtc_state *old_cstate =
+				to_sde_crtc_state(crtc->state);
+
+		if (cstate->idle_pc != old_cstate->idle_pc) {
+			SDE_DEBUG("crtc%d idle_pc:%d/%d\n",
+					crtc->base.id, cstate->idle_pc,
+					old_cstate->idle_pc);
+			SDE_EVT32(DRMID(crtc), cstate->idle_pc,
+					old_cstate->idle_pc);
+			rc = drm_atomic_add_affected_planes(state, crtc);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return drm_atomic_helper_check(dev, state);
+}
+
 static const struct msm_kms_funcs kms_funcs = {
 	.hw_init         = sde_kms_hw_init,
 	.postinit        = sde_kms_postinit,
@@ -1332,9 +1427,11 @@
 	.commit          = sde_kms_commit,
 	.complete_commit = sde_kms_complete_commit,
 	.wait_for_crtc_commit_done = sde_kms_wait_for_commit_done,
+	.wait_for_tx_complete = sde_kms_wait_for_tx_complete,
 	.enable_vblank   = sde_kms_enable_vblank,
 	.disable_vblank  = sde_kms_disable_vblank,
 	.check_modified_format = sde_format_check_modified_format,
+	.atomic_check    = sde_kms_atomic_check,
 	.get_format      = sde_get_msm_format,
 	.round_pixclk    = sde_kms_round_pixclk,
 	.destroy         = sde_kms_destroy,
@@ -1353,15 +1450,15 @@
 	int i;
 
 	for (i = ARRAY_SIZE(sde_kms->mmu_id) - 1; i >= 0; i--) {
-		if (!sde_kms->mmu[i])
+		mmu = sde_kms->aspace[i]->mmu;
+
+		if (!mmu)
 			continue;
 
-		mmu = sde_kms->mmu[i];
-		msm_unregister_mmu(sde_kms->dev, mmu);
 		mmu->funcs->detach(mmu, (const char **)iommu_ports,
 				ARRAY_SIZE(iommu_ports));
-		mmu->funcs->destroy(mmu);
-		sde_kms->mmu[i] = 0;
+		msm_gem_address_space_destroy(sde_kms->aspace[i]);
+
 		sde_kms->mmu_id[i] = 0;
 	}
 
@@ -1374,6 +1471,8 @@
 	int i, ret;
 
 	for (i = 0; i < MSM_SMMU_DOMAIN_MAX; i++) {
+		struct msm_gem_address_space *aspace;
+
 		mmu = msm_smmu_new(sde_kms->dev->dev, i);
 		if (IS_ERR(mmu)) {
 			ret = PTR_ERR(mmu);
@@ -1382,25 +1481,35 @@
 			continue;
 		}
 
+		aspace = msm_gem_smmu_address_space_create(sde_kms->dev->dev,
+			mmu, "sde");
+		if (IS_ERR(aspace)) {
+			ret = PTR_ERR(aspace);
+			mmu->funcs->destroy(mmu);
+			goto fail;
+		}
+
+		sde_kms->aspace[i] = aspace;
+
 		ret = mmu->funcs->attach(mmu, (const char **)iommu_ports,
 				ARRAY_SIZE(iommu_ports));
 		if (ret) {
 			SDE_ERROR("failed to attach iommu %d: %d\n", i, ret);
-			mmu->funcs->destroy(mmu);
-			continue;
+			msm_gem_address_space_destroy(aspace);
+			goto fail;
 		}
 
-		sde_kms->mmu_id[i] = msm_register_mmu(sde_kms->dev, mmu);
+		sde_kms->mmu_id[i] = msm_register_address_space(sde_kms->dev,
+			aspace);
 		if (sde_kms->mmu_id[i] < 0) {
 			ret = sde_kms->mmu_id[i];
 			SDE_ERROR("failed to register sde iommu %d: %d\n",
 					i, ret);
 			mmu->funcs->detach(mmu, (const char **)iommu_ports,
 					ARRAY_SIZE(iommu_ports));
+			msm_gem_address_space_destroy(aspace);
 			goto fail;
 		}
-
-		sde_kms->mmu[i] = mmu;
 	}
 
 	return 0;
@@ -1410,43 +1519,6 @@
 	return ret;
 }
 
-static void __iomem *_sde_kms_ioremap(struct platform_device *pdev,
-		const char *name, unsigned long *out_size)
-{
-	struct resource *res;
-	unsigned long size;
-	void __iomem *ptr;
-
-	if (out_size)
-		*out_size = 0;
-
-	if (name)
-		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
-	else
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-	if (!res) {
-		/* availability depends on platform */
-		SDE_DEBUG("failed to get memory resource: %s\n", name);
-		return ERR_PTR(-EINVAL);
-	}
-
-	size = resource_size(res);
-
-	ptr = devm_ioremap_nocache(&pdev->dev, res->start, size);
-	if (!ptr) {
-		SDE_ERROR("failed to ioremap: %s\n", name);
-		return ERR_PTR(-ENOMEM);
-	}
-
-	SDE_DEBUG("IO:region %s %p %08lx\n", name, ptr, size);
-
-	if (out_size)
-		*out_size = size;
-
-	return ptr;
-}
-
 static void sde_kms_handle_power_event(u32 event_type, void *usr)
 {
 	struct sde_kms *sde_kms = usr;
@@ -1483,8 +1555,7 @@
 		goto end;
 	}
 
-	sde_kms->mmio = _sde_kms_ioremap(dev->platformdev, "mdp_phys",
-			&sde_kms->mmio_len);
+	sde_kms->mmio = msm_ioremap(dev->platformdev, "mdp_phys", "mdp_phys");
 	if (IS_ERR(sde_kms->mmio)) {
 		rc = PTR_ERR(sde_kms->mmio);
 		SDE_ERROR("mdp register memory map failed: %d\n", rc);
@@ -1492,32 +1563,36 @@
 		goto error;
 	}
 	DRM_INFO("mapped mdp address space @%p\n", sde_kms->mmio);
+	sde_kms->mmio_len = msm_iomap_size(dev->platformdev, "mdp_phys");
 
 	rc = sde_dbg_reg_register_base(SDE_DBG_NAME, sde_kms->mmio,
 			sde_kms->mmio_len);
 	if (rc)
 		SDE_ERROR("dbg base register kms failed: %d\n", rc);
 
-	sde_kms->vbif[VBIF_RT] = _sde_kms_ioremap(dev->platformdev, "vbif_phys",
-			&sde_kms->vbif_len[VBIF_RT]);
+	sde_kms->vbif[VBIF_RT] = msm_ioremap(dev->platformdev, "vbif_phys",
+								"vbif_phys");
 	if (IS_ERR(sde_kms->vbif[VBIF_RT])) {
 		rc = PTR_ERR(sde_kms->vbif[VBIF_RT]);
 		SDE_ERROR("vbif register memory map failed: %d\n", rc);
 		sde_kms->vbif[VBIF_RT] = NULL;
 		goto error;
 	}
-
+	sde_kms->vbif_len[VBIF_RT] = msm_iomap_size(dev->platformdev,
+								"vbif_phys");
 	rc = sde_dbg_reg_register_base("vbif_rt", sde_kms->vbif[VBIF_RT],
 				sde_kms->vbif_len[VBIF_RT]);
 	if (rc)
 		SDE_ERROR("dbg base register vbif_rt failed: %d\n", rc);
 
-	sde_kms->vbif[VBIF_NRT] = _sde_kms_ioremap(dev->platformdev,
-			"vbif_nrt_phys", &sde_kms->vbif_len[VBIF_NRT]);
+	sde_kms->vbif[VBIF_NRT] = msm_ioremap(dev->platformdev, "vbif_nrt_phys",
+								"vbif_nrt_phys");
 	if (IS_ERR(sde_kms->vbif[VBIF_NRT])) {
 		sde_kms->vbif[VBIF_NRT] = NULL;
 		SDE_DEBUG("VBIF NRT is not defined");
 	} else {
+		sde_kms->vbif_len[VBIF_NRT] = msm_iomap_size(dev->platformdev,
+							"vbif_nrt_phys");
 		rc = sde_dbg_reg_register_base("vbif_nrt",
 				sde_kms->vbif[VBIF_NRT],
 				sde_kms->vbif_len[VBIF_NRT]);
@@ -1526,19 +1601,20 @@
 					rc);
 	}
 
-	sde_kms->reg_dma = _sde_kms_ioremap(dev->platformdev, "regdma_phys",
-		&sde_kms->reg_dma_len);
+	sde_kms->reg_dma = msm_ioremap(dev->platformdev, "regdma_phys",
+								"regdma_phys");
 	if (IS_ERR(sde_kms->reg_dma)) {
 		sde_kms->reg_dma = NULL;
 		SDE_DEBUG("REG_DMA is not defined");
 	} else {
+		sde_kms->reg_dma_len = msm_iomap_size(dev->platformdev,
+								"regdma_phys");
 		rc =  sde_dbg_reg_register_base("vbif_nrt",
 				sde_kms->reg_dma,
 				sde_kms->reg_dma_len);
 		if (rc)
 			SDE_ERROR("dbg base register reg_dma failed: %d\n",
 					rc);
-
 	}
 
 	sde_kms->core_client = sde_power_client_create(&priv->phandle, "core");
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index f73cb21..0c5c286 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -24,6 +24,7 @@
 #include "msm_drv.h"
 #include "msm_kms.h"
 #include "msm_mmu.h"
+#include "msm_gem.h"
 #include "sde_dbg.h"
 #include "sde_hw_catalog.h"
 #include "sde_hw_ctl.h"
@@ -88,6 +89,10 @@
 
 #define SDE_NAME_SIZE  12
 
+
+/* timeout in frames waiting for frame done */
+#define SDE_FRAME_DONE_TIMEOUT	60
+
 /*
  * struct sde_irq_callback - IRQ callback handlers
  * @list: list to callback
@@ -154,7 +159,7 @@
 	int core_rev;
 	struct sde_mdss_cfg *catalog;
 
-	struct msm_mmu *mmu[MSM_SMMU_DOMAIN_MAX];
+	struct msm_gem_address_space *aspace[MSM_SMMU_DOMAIN_MAX];
 	int mmu_id[MSM_SMMU_DOMAIN_MAX];
 	struct sde_power_client *core_client;
 
@@ -313,10 +318,12 @@
 
 /**
  * SDE_KMS_INFO_DATALEN - Macro for accessing sde_kms_info data length
+ *			it adds an extra character length to count null.
  * @S: Pointer to sde_kms_info structure
  * Returns: Size of available byte data
  */
-#define SDE_KMS_INFO_DATALEN(S) ((S) ? ((struct sde_kms_info *)(S))->len : 0)
+#define SDE_KMS_INFO_DATALEN(S) ((S) ? ((struct sde_kms_info *)(S))->len + 1 \
+							: 0)
 
 /**
  * sde_kms_info_reset - reset sde_kms_info structure
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index d63fec1..2a98af4 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -94,6 +94,25 @@
 	SDE_PLANE_QOS_PANIC_CTRL = BIT(2),
 };
 
+/**
+ * enum sde_plane_sclcheck_state - User scaler data status
+ *
+ * @SDE_PLANE_SCLCHECK_NONE: No user data provided
+ * @SDE_PLANE_SCLCHECK_INVALID: Invalid user data provided
+ * @SDE_PLANE_SCLCHECK_SCALER_V1: Valid scaler v1 data
+ * @SDE_PLANE_SCLCHECK_SCALER_V1_CHECK: Unchecked scaler v1 data
+ * @SDE_PLANE_SCLCHECK_SCALER_V2: Valid scaler v2 data
+ * @SDE_PLANE_SCLCHECK_SCALER_V2_CHECK: Unchecked scaler v2 data
+ */
+enum sde_plane_sclcheck_state {
+	SDE_PLANE_SCLCHECK_NONE,
+	SDE_PLANE_SCLCHECK_INVALID,
+	SDE_PLANE_SCLCHECK_SCALER_V1,
+	SDE_PLANE_SCLCHECK_SCALER_V1_CHECK,
+	SDE_PLANE_SCLCHECK_SCALER_V2,
+	SDE_PLANE_SCLCHECK_SCALER_V2_CHECK,
+};
+
 /*
  * struct sde_plane - local sde plane structure
  * @csc_cfg: Decoded user configuration for csc
@@ -104,6 +123,7 @@
  * @sbuf_mode: force stream buffer mode if set
  * @sbuf_writeback: force stream buffer writeback if set
  * @revalidate: force revalidation of all the plane properties
+ * @scaler_check_state: Indicates status of user provided pixle extension data
  * @blob_rot_caps: Pointer to rotator capability blob
  */
 struct sde_plane {
@@ -134,7 +154,7 @@
 	bool revalidate;
 
 	struct sde_hw_pixel_ext pixel_ext;
-	bool pixel_ext_usr;
+	enum sde_plane_sclcheck_state scaler_check_state;
 
 	struct sde_csc_cfg csc_cfg;
 	struct sde_csc_cfg *csc_usr_ptr;
@@ -627,10 +647,11 @@
 	qos_params.num = psde->pipe_hw->idx - SSPP_VIG0;
 	qos_params.is_rt = psde->is_rt_pipe;
 
-	SDE_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d\n",
+	SDE_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n",
 			plane->base.id, qos_params.num,
 			qos_params.vbif_idx,
-			qos_params.xin_id, qos_params.is_rt);
+			qos_params.xin_id, qos_params.is_rt,
+			qos_params.clk_ctrl);
 
 	sde_vbif_set_qos_remap(sde_kms, &qos_params);
 }
@@ -704,6 +725,90 @@
 	SDE_DEBUG_PLANE(psde, "0x%llX\n", fd);
 }
 
+/**
+ * _sde_plane_inline_rot_set_ot_limit - set OT limit for the given inline
+ * rotation xin client
+ * @plane: pointer to drm plane
+ * @crtc: pointer to drm crtc
+ * @cfg: pointer to rotator vbif config
+ * @rect_w: rotator frame width
+ * @rect_h: rotator frame height
+ */
+static void _sde_plane_inline_rot_set_ot_limit(struct drm_plane *plane,
+		struct drm_crtc *crtc, const struct sde_rot_vbif_cfg *cfg,
+		u32 rect_w, u32 rect_h)
+{
+	struct sde_vbif_set_ot_params ot_params;
+	struct msm_drm_private *priv;
+	struct sde_kms *sde_kms;
+
+	if (!plane || !plane->dev) {
+		SDE_ERROR("invalid arguments\n");
+		return;
+	}
+
+	priv = plane->dev->dev_private;
+	if (!priv || !priv->kms) {
+		SDE_ERROR("invalid KMS reference\n");
+		return;
+	}
+
+	sde_kms = to_sde_kms(priv->kms);
+
+	memset(&ot_params, 0, sizeof(ot_params));
+	ot_params.xin_id = cfg->xin_id;
+	ot_params.num = cfg->num;
+	ot_params.width = rect_w;
+	ot_params.height = rect_h;
+	ot_params.is_wfd = false;
+	ot_params.frame_rate = crtc->mode.vrefresh;
+	ot_params.vbif_idx = VBIF_RT;
+	ot_params.clk_ctrl = cfg->clk_ctrl;
+	ot_params.rd = cfg->is_read;
+
+	sde_vbif_set_ot_limit(sde_kms, &ot_params);
+}
+
+/**
+ * _sde_plane_inline_rot_set_qos_remap - set vbif QoS for the given inline
+ * rotation xin client
+ * @plane: Pointer to drm plane
+ * @cfg: Pointer to rotator vbif cfg
+ */
+static void _sde_plane_inline_rot_set_qos_remap(struct drm_plane *plane,
+		const struct sde_rot_vbif_cfg *cfg)
+{
+	struct sde_vbif_set_qos_params qos_params;
+	struct msm_drm_private *priv;
+	struct sde_kms *sde_kms;
+
+	if (!plane || !plane->dev) {
+		SDE_ERROR("invalid arguments\n");
+		return;
+	}
+
+	priv = plane->dev->dev_private;
+	if (!priv || !priv->kms) {
+		SDE_ERROR("invalid KMS reference\n");
+		return;
+	}
+
+	sde_kms = to_sde_kms(priv->kms);
+
+	memset(&qos_params, 0, sizeof(qos_params));
+	qos_params.vbif_idx = VBIF_RT;
+	qos_params.xin_id = cfg->xin_id;
+	qos_params.clk_ctrl = cfg->clk_ctrl;
+	qos_params.num = cfg->num;
+	qos_params.is_rt = true;
+
+	SDE_DEBUG("vbif:%d xin:%d num:%d rt:%d clk_ctrl:%d\n",
+			qos_params.vbif_idx, qos_params.xin_id,
+			qos_params.num, qos_params.is_rt, qos_params.clk_ctrl);
+
+	sde_vbif_set_qos_remap(sde_kms, &qos_params);
+}
+
 int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
 {
 	struct sde_plane *psde;
@@ -788,9 +893,22 @@
 		SDE_DEBUG_PLANE(psde, "not updating same src addrs\n");
 	else if (ret)
 		SDE_ERROR_PLANE(psde, "failed to get format layout, %d\n", ret);
-	else if (psde->pipe_hw->ops.setup_sourceaddress)
+	else if (psde->pipe_hw->ops.setup_sourceaddress) {
+		SDE_EVT32(psde->pipe_hw->idx,
+				pipe_cfg->layout.width,
+				pipe_cfg->layout.height,
+				pipe_cfg->layout.plane_addr[0],
+				pipe_cfg->layout.plane_size[0],
+				pipe_cfg->layout.plane_addr[1],
+				pipe_cfg->layout.plane_size[1],
+				pipe_cfg->layout.plane_addr[2],
+				pipe_cfg->layout.plane_size[2],
+				pipe_cfg->layout.plane_addr[3],
+				pipe_cfg->layout.plane_size[3],
+				pstate->multirect_index);
 		psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg,
 						pstate->multirect_index);
+	}
 }
 
 static int _sde_plane_setup_scaler3_lut(struct sde_plane *psde,
@@ -1184,8 +1302,9 @@
 		int error;
 
 		error = _sde_plane_setup_scaler3_lut(psde, pstate);
-		if (error || !psde->pixel_ext_usr ||
-				psde->debugfs_default_scale) {
+		if (error || psde->debugfs_default_scale ||
+			psde->scaler_check_state !=
+				SDE_PLANE_SCLCHECK_SCALER_V2) {
 			/* calculate default config for QSEED3 */
 			_sde_plane_setup_scaler3(psde,
 					psde->pipe_cfg.src_rect.w,
@@ -1195,8 +1314,8 @@
 					psde->scaler3_cfg, fmt,
 					chroma_subsmpl_h, chroma_subsmpl_v);
 		}
-	} else if (!psde->pixel_ext_usr || !pstate ||
-			psde->debugfs_default_scale) {
+	} else if (psde->scaler_check_state != SDE_PLANE_SCLCHECK_SCALER_V1 ||
+			!pstate || psde->debugfs_default_scale) {
 		uint32_t deci_dim, i;
 
 		/* calculate default configuration for QSEED2 */
@@ -1504,7 +1623,12 @@
 		attached_pstate = to_sde_plane_state(attached_state);
 		attached_rstate = &attached_pstate->rot;
 
-		if (attached_rstate->rot_hw != rstate->rot_hw)
+		if (attached_state->fb != state->fb)
+			continue;
+
+		if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) !=
+			sde_plane_get_property(attached_pstate,
+				PLANE_PROP_ROTATION))
 			continue;
 
 		found++;
@@ -1693,6 +1817,24 @@
 			rot_cmd->dst_len[i] = layout.plane_size[i];
 		}
 		rot_cmd->dst_planes = layout.num_planes;
+
+		/* VBIF remapper settings */
+		for (i = 0; rstate->rot_hw->caps->xin_count; i++) {
+			const struct sde_rot_vbif_cfg *cfg =
+					&rstate->rot_hw->caps->vbif_cfg[i];
+
+			_sde_plane_inline_rot_set_qos_remap(plane, cfg);
+
+			if (cfg->is_read) {
+				_sde_plane_inline_rot_set_ot_limit(plane,
+					state->crtc, cfg, rot_cmd->src_rect_w,
+					rot_cmd->src_rect_h);
+			} else {
+				_sde_plane_inline_rot_set_ot_limit(plane,
+					state->crtc, cfg, rot_cmd->dst_rect_w,
+					rot_cmd->dst_rect_h);
+			}
+		}
 	}
 
 	ret = rstate->rot_hw->ops.commit(rstate->rot_hw, rot_cmd, hw_cmd);
@@ -1755,6 +1897,46 @@
 }
 
 /**
+ * _sde_plane_rot_get_fb - attempt to get previously allocated fb/fbo
+ *	If an fb/fbo was already created, either from a previous frame or
+ *	from another plane in the current commit cycle, attempt to reuse
+ *	it for this commit cycle as well.
+ * @plane: Pointer to drm plane
+ * @cstate: Pointer to crtc state
+ * @rstate: Pointer to rotator plane state
+ */
+static void _sde_plane_rot_get_fb(struct drm_plane *plane,
+		struct drm_crtc_state *cstate,
+		struct sde_plane_rot_state *rstate)
+{
+	struct sde_kms_fbo *fbo;
+	struct drm_framebuffer *fb;
+
+	if (!plane || !cstate || !rstate)
+		return;
+
+	fbo = sde_crtc_res_get(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
+			(u64) &rstate->rot_hw->base);
+	fb = sde_crtc_res_get(cstate, SDE_CRTC_RES_ROT_OUT_FB,
+			(u64) &rstate->rot_hw->base);
+	if (fb && fbo) {
+		SDE_DEBUG("plane%d.%d get fb/fbo\n", plane->base.id,
+				rstate->sequence_id);
+	} else if (fbo) {
+		sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
+				(u64) &rstate->rot_hw->base);
+		fbo = NULL;
+	} else if (fb) {
+		sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
+				(u64) &rstate->rot_hw->base);
+		fb = NULL;
+	}
+
+	rstate->out_fbo = fbo;
+	rstate->out_fb = fb;
+}
+
+/**
  * sde_plane_rot_prepare_fb - prepare framebuffer of the new state
  *	for rotator (pre-sspp) stage
  * @plane: Pointer to drm plane
@@ -1790,30 +1972,8 @@
 	sde_plane_rot_calc_cfg(plane, new_state);
 
 	/* check if stream buffer is already attached to rotator */
-	if (sde_plane_enabled(new_state)) {
-		struct sde_kms_fbo *fbo;
-		struct drm_framebuffer *fb;
-
-		fbo = sde_crtc_res_get(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
-				(u64) &new_rstate->rot_hw->base);
-		fb = sde_crtc_res_get(cstate, SDE_CRTC_RES_ROT_OUT_FB,
-				(u64) &new_rstate->rot_hw->base);
-		if (fb && fbo) {
-			SDE_DEBUG("plane%d.%d get fb/fbo\n", plane->base.id,
-					new_rstate->sequence_id);
-		} else if (fbo) {
-			sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
-					(u64) &new_rstate->rot_hw->base);
-			fbo = NULL;
-		} else if (fb) {
-			sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
-					(u64) &new_rstate->rot_hw->base);
-			fb = NULL;
-		}
-
-		new_rstate->out_fbo = fbo;
-		new_rstate->out_fb = fb;
-	}
+	if (sde_plane_enabled(new_state) && !new_rstate->out_fb)
+		_sde_plane_rot_get_fb(plane, cstate, new_rstate);
 
 	/* release buffer if output format configuration changes */
 	if (new_rstate->out_fb &&
@@ -2062,6 +2222,10 @@
 
 		sde_plane_rot_calc_cfg(plane, state);
 
+		/* attempt to reuse stream buffer if already available */
+		if (sde_plane_enabled(state))
+			_sde_plane_rot_get_fb(plane, cstate, rstate);
+
 		ret = sde_plane_rot_submit_command(plane, state,
 				SDE_HW_ROT_CMD_VALIDATE);
 
@@ -2272,7 +2436,8 @@
 				rot_hw->ops.get_maxlinewidth(rot_hw));
 
 	msm_property_set_blob(&psde->property_info, &psde->blob_rot_caps,
-			info->data, info->len, PLANE_PROP_ROT_CAPS_V1);
+			info->data, SDE_KMS_INFO_DATALEN(info),
+			PLANE_PROP_ROT_CAPS_V1);
 
 	sde_hw_rot_put(rot_hw);
 error_rot:
@@ -2400,16 +2565,9 @@
 
 	/* Prefer PARALLEL FETCH Mode over TIME_MX Mode */
 	if (parallel_fetch_qualified) {
-		if (dst[R0].x <= dst[R1].x) {
-			pstate[R0]->multirect_index = SDE_SSPP_RECT_0;
-			pstate[R1]->multirect_index = SDE_SSPP_RECT_1;
-		} else {
-			pstate[R0]->multirect_index = SDE_SSPP_RECT_1;
-			pstate[R1]->multirect_index = SDE_SSPP_RECT_0;
-		}
-
 		pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL;
 		pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL;
+
 		goto done;
 	}
 
@@ -2417,12 +2575,10 @@
 	if (SDE_FORMAT_IS_UBWC(fmt[R0]))
 		buffer_lines = 2 * fmt[R0]->tile_height;
 
-	if (dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) {
-		pstate[R0]->multirect_index = SDE_SSPP_RECT_0;
-		pstate[R1]->multirect_index = SDE_SSPP_RECT_1;
-	} else if (dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines) {
-		pstate[R0]->multirect_index = SDE_SSPP_RECT_1;
-		pstate[R1]->multirect_index = SDE_SSPP_RECT_0;
+	if ((dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) ||
+		(dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines)) {
+		pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
+		pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
 	} else {
 		SDE_ERROR(
 			"No multirect mode possible for the planes (%d - %d)\n",
@@ -2431,9 +2587,15 @@
 		return -EINVAL;
 	}
 
-	pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
-	pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
 done:
+	if (sde_plane[R0]->is_virtual) {
+		pstate[R0]->multirect_index = SDE_SSPP_RECT_1;
+		pstate[R1]->multirect_index = SDE_SSPP_RECT_0;
+	} else {
+		pstate[R0]->multirect_index = SDE_SSPP_RECT_0;
+		pstate[R1]->multirect_index = SDE_SSPP_RECT_1;
+	};
+
 	SDE_DEBUG_PLANE(sde_plane[R0], "R0: %d - %d\n",
 		pstate[R0]->multirect_mode, pstate[R0]->multirect_index);
 	SDE_DEBUG_PLANE(sde_plane[R1], "R1: %d - %d\n",
@@ -2479,6 +2641,7 @@
 	struct drm_framebuffer *fb = new_state->fb;
 	struct sde_plane *psde = to_sde_plane(plane);
 	struct sde_plane_rot_state *new_rstate;
+	struct sde_hw_fmt_layout layout;
 	int ret;
 
 	if (!new_state->fb)
@@ -2500,6 +2663,14 @@
 		return ret;
 	}
 
+	/* validate framebuffer layout before commit */
+	ret = sde_format_populate_layout(new_rstate->mmu_id,
+			new_rstate->out_fb, &layout);
+	if (ret) {
+		SDE_ERROR_PLANE(psde, "failed to get format layout, %d\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -2619,6 +2790,101 @@
 	}
 }
 
+static int _sde_plane_validate_scaler_v2(struct sde_plane *psde,
+		const struct sde_format *fmt,
+		uint32_t img_w, uint32_t img_h,
+		uint32_t src_w, uint32_t src_h,
+		uint32_t deci_w, uint32_t deci_h)
+{
+	int i;
+
+	if (!psde || !fmt) {
+		SDE_ERROR_PLANE(psde, "invalid arguments\n");
+		return -EINVAL;
+	}
+
+	/* don't run checks unless scaler data was changed */
+	if (psde->scaler_check_state != SDE_PLANE_SCLCHECK_SCALER_V2_CHECK ||
+			!psde->scaler3_cfg)
+		return 0;
+
+	psde->scaler_check_state = SDE_PLANE_SCLCHECK_INVALID;
+
+	for (i = 0; i < SDE_MAX_PLANES; i++) {
+		uint32_t hor_req_pixels, hor_fetch_pixels;
+		uint32_t vert_req_pixels, vert_fetch_pixels;
+		uint32_t src_w_tmp, src_h_tmp;
+
+		/* re-use color plane 1's config for plane 2 */
+		if (i == 2)
+			continue;
+
+		src_w_tmp = src_w;
+		src_h_tmp = src_h;
+
+		/*
+		 * For chroma plane, width is half for the following sub sampled
+		 * formats. Except in case of decimation, where hardware avoids
+		 * 1 line of decimation instead of downsampling.
+		 */
+		if (i == 1) {
+			if (!deci_w &&
+					(fmt->chroma_sample == SDE_CHROMA_420 ||
+					 fmt->chroma_sample == SDE_CHROMA_H2V1))
+				src_w_tmp >>= 1;
+			if (!deci_h &&
+					(fmt->chroma_sample == SDE_CHROMA_420 ||
+					 fmt->chroma_sample == SDE_CHROMA_H1V2))
+				src_h_tmp >>= 1;
+		}
+
+		hor_req_pixels = psde->pixel_ext.roi_w[i];
+		vert_req_pixels = psde->pixel_ext.roi_h[i];
+
+		hor_fetch_pixels = DECIMATED_DIMENSION(src_w_tmp +
+				(int8_t)(psde->pixel_ext.left_ftch[i] & 0xFF) +
+				(int8_t)(psde->pixel_ext.right_ftch[i] & 0xFF),
+				deci_w);
+		vert_fetch_pixels = DECIMATED_DIMENSION(src_h_tmp +
+				(int8_t)(psde->pixel_ext.top_ftch[i] & 0xFF) +
+				(int8_t)(psde->pixel_ext.btm_ftch[i] & 0xFF),
+				deci_h);
+
+		if ((hor_req_pixels != hor_fetch_pixels) ||
+			(hor_fetch_pixels > img_w) ||
+			(vert_req_pixels != vert_fetch_pixels) ||
+			(vert_fetch_pixels > img_h)) {
+			SDE_ERROR_PLANE(psde,
+					"req %d/%d, fetch %d/%d, src %dx%d\n",
+					hor_req_pixels, vert_req_pixels,
+					hor_fetch_pixels, vert_fetch_pixels,
+					img_w, img_h);
+			return -EINVAL;
+		}
+
+		/*
+		 * Alpha plane can only be scaled using bilinear or pixel
+		 * repeat/drop, src_width and src_height are only specified
+		 * for Y and UV plane
+		 */
+		if (i != 3 &&
+			(hor_req_pixels != psde->scaler3_cfg->src_width[i] ||
+			vert_req_pixels != psde->scaler3_cfg->src_height[i])) {
+			SDE_ERROR_PLANE(psde,
+				"roi[%d] %d/%d, scaler src %dx%d, src %dx%d\n",
+				i, psde->pixel_ext.roi_w[i],
+				psde->pixel_ext.roi_h[i],
+				psde->scaler3_cfg->src_width[i],
+				psde->scaler3_cfg->src_height[i],
+				src_w, src_h);
+			return -EINVAL;
+		}
+	}
+
+	psde->scaler_check_state = SDE_PLANE_SCLCHECK_SCALER_V2;
+	return 0;
+}
+
 static int sde_plane_sspp_atomic_check(struct drm_plane *plane,
 		struct drm_plane_state *state)
 {
@@ -2754,10 +3020,15 @@
 			"too much scaling requested %ux%u->%ux%u\n",
 			src_deci_w, src_deci_h, dst.w, dst.h);
 		ret = -E2BIG;
+	} else if (_sde_plane_validate_scaler_v2(psde, fmt,
+				rstate->out_fb_width,
+				rstate->out_fb_height,
+				src.w, src.h, deci_w, deci_h)) {
+		ret = -EINVAL;
 	}
 
 	/* check excl rect configs */
-	if (pstate->excl_rect.w && pstate->excl_rect.h) {
+	if (!ret && pstate->excl_rect.w && pstate->excl_rect.h) {
 		struct sde_rect intersect;
 
 		/*
@@ -2931,6 +3202,9 @@
 		switch (idx) {
 		case PLANE_PROP_SCALER_V1:
 		case PLANE_PROP_SCALER_V2:
+		case PLANE_PROP_SCALER_LUT_ED:
+		case PLANE_PROP_SCALER_LUT_CIR:
+		case PLANE_PROP_SCALER_LUT_SEP:
 		case PLANE_PROP_H_DECIMATE:
 		case PLANE_PROP_V_DECIMATE:
 		case PLANE_PROP_SRC_CONFIG:
@@ -3049,7 +3323,8 @@
 					pstate->multirect_index);
 		}
 
-		if (psde->pipe_hw->ops.setup_pe)
+		if (psde->pipe_hw->ops.setup_pe &&
+				(pstate->multirect_index != SDE_SSPP_RECT_1))
 			psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
 					&psde->pixel_ext);
 
@@ -3289,7 +3564,7 @@
 		}
 
 		if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
-			msm_property_install_volatile_range(
+			msm_property_install_range(
 					&psde->property_info, "scaler_v2",
 					0x0, 0, ~0, 0, PLANE_PROP_SCALER_V2);
 			msm_property_install_blob(&psde->property_info,
@@ -3301,7 +3576,7 @@
 					"lut_sep", 0,
 					PLANE_PROP_SCALER_LUT_SEP);
 		} else if (psde->features & SDE_SSPP_SCALER) {
-			msm_property_install_volatile_range(
+			msm_property_install_range(
 					&psde->property_info, "scaler_v1", 0x0,
 					0, ~0, 0, PLANE_PROP_SCALER_V1);
 		}
@@ -3424,7 +3699,8 @@
 	sde_kms_info_add_keyint(info, "max_per_pipe_bw",
 			psde->pipe_sblk->max_per_pipe_bw * 1000LL);
 	msm_property_set_blob(&psde->property_info, &psde->blob_info,
-			info->data, info->len, PLANE_PROP_INFO);
+			info->data, SDE_KMS_INFO_DATALEN(info),
+			PLANE_PROP_INFO);
 
 	kfree(info);
 	kfree(virt_format_list);
@@ -3494,7 +3770,7 @@
 		return;
 	}
 
-	psde->pixel_ext_usr = false;
+	psde->scaler_check_state = SDE_PLANE_SCLCHECK_NONE;
 	if (!usr) {
 		SDE_DEBUG_PLANE(psde, "scale data removed\n");
 		return;
@@ -3505,6 +3781,9 @@
 		return;
 	}
 
+	/* force property to be dirty, even if the pointer didn't change */
+	msm_property_set_dirty(&psde->property_info, PLANE_PROP_SCALER_V1);
+
 	/* populate from user space */
 	pe = &(psde->pixel_ext);
 	memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
@@ -3531,8 +3810,9 @@
 		pe->roi_h[i] = scale_v1.pe.num_ext_pxls_tb[i];
 	}
 
-	psde->pixel_ext_usr = true;
+	psde->scaler_check_state = SDE_PLANE_SCLCHECK_SCALER_V1;
 
+	SDE_EVT32_VERBOSE(DRMID(&psde->base));
 	SDE_DEBUG_PLANE(psde, "user property data copied\n");
 }
 
@@ -3544,13 +3824,13 @@
 	int i;
 	struct sde_hw_scaler3_cfg *cfg;
 
-	if (!psde) {
+	if (!psde || !psde->scaler3_cfg) {
 		SDE_ERROR("invalid plane\n");
 		return;
 	}
 
 	cfg = psde->scaler3_cfg;
-	psde->pixel_ext_usr = false;
+	psde->scaler_check_state = SDE_PLANE_SCLCHECK_NONE;
 	if (!usr) {
 		SDE_DEBUG_PLANE(psde, "scale data removed\n");
 		return;
@@ -3561,6 +3841,15 @@
 		return;
 	}
 
+	/* detach/ignore user data if 'disabled' */
+	if (!scale_v2.enable) {
+		SDE_DEBUG_PLANE(psde, "scale data removed\n");
+		return;
+	}
+
+	/* force property to be dirty, even if the pointer didn't change */
+	msm_property_set_dirty(&psde->property_info, PLANE_PROP_SCALER_V2);
+
 	/* populate from user space */
 	pe = &(psde->pixel_ext);
 	memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
@@ -3620,8 +3909,11 @@
 		pe->btm_rpt[i] = scale_v2.pe.btm_rpt[i];
 		pe->roi_h[i] = scale_v2.pe.num_ext_pxls_tb[i];
 	}
-	psde->pixel_ext_usr = true;
+	psde->scaler_check_state = SDE_PLANE_SCLCHECK_SCALER_V2_CHECK;
 
+	SDE_EVT32_VERBOSE(DRMID(&psde->base), cfg->enable, cfg->de.enable,
+			cfg->src_width[0], cfg->src_height[0],
+			cfg->dst_width, cfg->dst_height);
 	SDE_DEBUG_PLANE(psde, "user property data copied\n");
 }
 
@@ -4013,7 +4305,7 @@
 		return -ENOMEM;
 
 	/* don't error check these */
-	debugfs_create_x32("features", 0644,
+	debugfs_create_x32("features", 0600,
 			psde->debugfs_root, &psde->features);
 
 	/* add register dump support */
@@ -4021,7 +4313,7 @@
 			sblk->src_blk.base + cfg->base,
 			sblk->src_blk.len,
 			kms);
-	sde_debugfs_create_regset32("src_blk", 0444,
+	sde_debugfs_create_regset32("src_blk", 0400,
 			psde->debugfs_root, &psde->debugfs_src);
 
 	if (cfg->features & BIT(SDE_SSPP_SCALER_QSEED3) ||
@@ -4030,11 +4322,11 @@
 				sblk->scaler_blk.base + cfg->base,
 				sblk->scaler_blk.len,
 				kms);
-		sde_debugfs_create_regset32("scaler_blk", 0444,
+		sde_debugfs_create_regset32("scaler_blk", 0400,
 				psde->debugfs_root,
 				&psde->debugfs_scaler);
 		debugfs_create_bool("default_scaling",
-				0644,
+				0600,
 				psde->debugfs_root,
 				&psde->debugfs_default_scale);
 	}
@@ -4045,36 +4337,36 @@
 				sblk->csc_blk.base + cfg->base,
 				sblk->csc_blk.len,
 				kms);
-		sde_debugfs_create_regset32("csc_blk", 0444,
+		sde_debugfs_create_regset32("csc_blk", 0400,
 				psde->debugfs_root, &psde->debugfs_csc);
 	}
 
 	debugfs_create_u32("xin_id",
-			0444,
+			0400,
 			psde->debugfs_root,
 			(u32 *) &cfg->xin_id);
 	debugfs_create_u32("clk_ctrl",
-			0444,
+			0400,
 			psde->debugfs_root,
 			(u32 *) &cfg->clk_ctrl);
 	debugfs_create_x32("creq_vblank",
-			0644,
+			0600,
 			psde->debugfs_root,
 			(u32 *) &sblk->creq_vblank);
 	debugfs_create_x32("danger_vblank",
-			0644,
+			0600,
 			psde->debugfs_root,
 			(u32 *) &sblk->danger_vblank);
 
 	debugfs_create_file("disable_danger",
-			0644,
+			0600,
 			psde->debugfs_root,
 			kms, &sde_plane_danger_enable);
 	debugfs_create_u32("sbuf_mode",
-			0644,
+			0600,
 			psde->debugfs_root, &psde->sbuf_mode);
 	debugfs_create_u32("sbuf_writeback",
-			0644,
+			0600,
 			psde->debugfs_root,
 			&psde->sbuf_writeback);
 
@@ -4191,6 +4483,7 @@
 	psde->pipe = pipe;
 	psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
 	psde->is_virtual = (master_plane_id != 0);
+	psde->scaler_check_state = SDE_PLANE_SCLCHECK_NONE;
 	INIT_LIST_HEAD(&psde->mplane_list);
 	master_plane = drm_plane_find(dev, master_plane_id);
 	if (master_plane) {
@@ -4200,7 +4493,8 @@
 	}
 
 	/* initialize underlying h/w driver */
-	psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
+	psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog,
+							master_plane_id != 0);
 	if (IS_ERR(psde->pipe_hw)) {
 		SDE_ERROR("[%u]SSPP init failed\n", pipe);
 		ret = PTR_ERR(psde->pipe_hw);
@@ -4291,7 +4585,8 @@
 
 	mutex_init(&psde->lock);
 
-	SDE_DEBUG("%s created for pipe %u\n", psde->pipe_name, pipe);
+	SDE_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", psde->pipe_name,
+					pipe, plane->base.id, master_plane_id);
 	return plane;
 
 clean_sspp:
diff --git a/drivers/gpu/drm/msm/sde/sde_reg_dma.c b/drivers/gpu/drm/msm/sde/sde_reg_dma.c
index cc115c5..cc87aeb 100644
--- a/drivers/gpu/drm/msm/sde/sde_reg_dma.c
+++ b/drivers/gpu/drm/msm/sde/sde_reg_dma.c
@@ -62,10 +62,17 @@
 	return -EINVAL;
 }
 
+static int default_last_command(struct sde_hw_ctl *ctl,
+		enum sde_reg_dma_queue q)
+{
+	return 0;
+}
+
 static struct sde_hw_reg_dma reg_dma = {
 	.ops = {default_check_support, default_setup_payload,
 		default_kick_off, default_reset, default_alloc_reg_dma_buf,
-		default_dealloc_reg_dma, default_buf_reset_reg_dma},
+		default_dealloc_reg_dma, default_buf_reset_reg_dma,
+		default_last_command},
 };
 
 int sde_reg_dma_init(void __iomem *addr, struct sde_mdss_cfg *m,
@@ -103,3 +110,26 @@
 {
 	return &reg_dma.ops;
 }
+
+void sde_reg_dma_deinit(void)
+{
+	struct sde_hw_reg_dma op = {
+	.ops = {default_check_support, default_setup_payload,
+		default_kick_off, default_reset, default_alloc_reg_dma_buf,
+		default_dealloc_reg_dma, default_buf_reset_reg_dma,
+		default_last_command},
+	};
+
+	if (!reg_dma.drm_dev || !reg_dma.caps)
+		return;
+
+	switch (reg_dma.caps->version) {
+	case 1:
+		deinit_v1();
+		break;
+	default:
+		break;
+	}
+	memset(&reg_dma, 0, sizeof(reg_dma));
+	memcpy(&reg_dma.ops, &op.ops, sizeof(op.ops));
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_reg_dma.h b/drivers/gpu/drm/msm/sde/sde_reg_dma.h
index c8e464d..70d995a 100644
--- a/drivers/gpu/drm/msm/sde/sde_reg_dma.h
+++ b/drivers/gpu/drm/msm/sde/sde_reg_dma.h
@@ -251,6 +251,7 @@
  * @alloc_reg_dma_buf: allocate reg dma buffer
  * @dealloc_reg_dma: de-allocate reg dma buffer
  * @reset_reg_dma_buf: reset the buffer to init state
+ * @last_command: notify control that last command is queued
  */
 struct sde_hw_reg_dma_ops {
 	int (*check_support)(enum sde_reg_dma_features feature,
@@ -262,6 +263,7 @@
 	struct sde_reg_dma_buffer* (*alloc_reg_dma_buf)(u32 size);
 	int (*dealloc_reg_dma)(struct sde_reg_dma_buffer *lut_buf);
 	int (*reset_reg_dma_buf)(struct sde_reg_dma_buffer *buf);
+	int (*last_command)(struct sde_hw_ctl *ctl, enum sde_reg_dma_queue q);
 };
 
 /**
@@ -298,4 +300,9 @@
  *                            who call this api.
  */
 struct sde_hw_reg_dma_ops *sde_reg_dma_get_ops(void);
+
+/**
+ * sde_reg_dma_deinit() - de-initialize the reg dma
+ */
+void sde_reg_dma_deinit(void);
 #endif /* _SDE_REG_DMA_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index 6ad2c43..0382ed0 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -106,10 +106,8 @@
 	struct sde_rm_rsvp *rsvp;
 	struct sde_rm_rsvp *rsvp_nxt;
 	enum sde_hw_blk_type type;
-	const char *type_name;
 	uint32_t id;
-	void *catalog;
-	void *hw;
+	struct sde_hw_blk *hw;
 };
 
 /**
@@ -143,12 +141,12 @@
 			if (!blk->rsvp && !blk->rsvp_nxt)
 				continue;
 
-			SDE_DEBUG("%d rsvp[s%ue%u->s%ue%u] %s %d\n", stage,
+			SDE_DEBUG("%d rsvp[s%ue%u->s%ue%u] %d %d\n", stage,
 				(blk->rsvp) ? blk->rsvp->seq : 0,
 				(blk->rsvp) ? blk->rsvp->enc_id : 0,
 				(blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0,
 				(blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0,
-				blk->type_name, blk->id);
+				blk->type, blk->id);
 
 			SDE_EVT32(stage,
 				(blk->rsvp) ? blk->rsvp->seq : 0,
@@ -205,9 +203,8 @@
 
 		if ((i->enc_id == 0) || (rsvp && rsvp->enc_id == i->enc_id)) {
 			i->hw = i->blk->hw;
-			SDE_DEBUG("found type %d %s id %d for enc %d\n",
-					i->type, i->blk->type_name, i->blk->id,
-					i->enc_id);
+			SDE_DEBUG("found type %d id %d for enc %d\n",
+					i->type, i->blk->id, i->enc_id);
 			return true;
 		}
 	}
@@ -314,7 +311,6 @@
 {
 	struct sde_rm_hw_blk *blk;
 	struct sde_hw_mdp *hw_mdp;
-	const char *name;
 	void *hw;
 
 	hw_mdp = rm->hw_mdp;
@@ -322,39 +318,30 @@
 	switch (type) {
 	case SDE_HW_BLK_LM:
 		hw = sde_hw_lm_init(id, mmio, cat);
-		name = "lm";
 		break;
 	case SDE_HW_BLK_DSPP:
 		hw = sde_hw_dspp_init(id, mmio, cat);
-		name = "dspp";
 		break;
 	case SDE_HW_BLK_CTL:
 		hw = sde_hw_ctl_init(id, mmio, cat);
-		name = "ctl";
 		break;
 	case SDE_HW_BLK_CDM:
 		hw = sde_hw_cdm_init(id, mmio, cat, hw_mdp);
-		name = "cdm";
 		break;
 	case SDE_HW_BLK_PINGPONG:
 		hw = sde_hw_pingpong_init(id, mmio, cat);
-		name = "pp";
 		break;
 	case SDE_HW_BLK_INTF:
 		hw = sde_hw_intf_init(id, mmio, cat);
-		name = "intf";
 		break;
 	case SDE_HW_BLK_WB:
 		hw = sde_hw_wb_init(id, mmio, cat, hw_mdp);
-		name = "wb";
 		break;
 	case SDE_HW_BLK_DSC:
 		hw = sde_hw_dsc_init(id, mmio, cat);
-		name = "dsc";
 		break;
 	case SDE_HW_BLK_ROT:
 		hw = sde_hw_rot_init(id, mmio, cat);
-		name = "rot";
 		break;
 	case SDE_HW_BLK_SSPP:
 		/* SSPPs are not managed by the resource manager */
@@ -378,10 +365,8 @@
 		return -ENOMEM;
 	}
 
-	blk->type_name = name;
 	blk->type = type;
 	blk->id = id;
-	blk->catalog = hw_catalog_info;
 	blk->hw = hw;
 	list_add_tail(&blk->list, &rm->hw_blks[type]);
 
@@ -561,8 +546,8 @@
 		struct sde_rm_hw_blk **pp,
 		struct sde_rm_hw_blk *primary_lm)
 {
-	struct sde_lm_cfg *lm_cfg = (struct sde_lm_cfg *)lm->catalog;
-	struct sde_pingpong_cfg *pp_cfg;
+	const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap;
+	const struct sde_pingpong_cfg *pp_cfg;
 	struct sde_rm_hw_iter iter;
 
 	*dspp = NULL;
@@ -573,8 +558,8 @@
 
 	/* Check if this layer mixer is a peer of the proposed primary LM */
 	if (primary_lm) {
-		struct sde_lm_cfg *prim_lm_cfg =
-				(struct sde_lm_cfg *)primary_lm->catalog;
+		const struct sde_lm_cfg *prim_lm_cfg =
+				to_sde_hw_mixer(primary_lm->hw)->cap;
 
 		if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) {
 			SDE_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id,
@@ -640,7 +625,7 @@
 		return false;
 	}
 
-	pp_cfg = (struct sde_pingpong_cfg *)((*pp)->catalog);
+	pp_cfg = to_sde_hw_pingpong((*pp)->hw)->caps;
 	if ((reqs->topology->top_name == SDE_RM_TOPOLOGY_PPSPLIT) &&
 			!(test_bit(SDE_PINGPONG_SPLIT, &pp_cfg->features))) {
 		SDE_DEBUG("pp %d doesn't support ppsplit\n", pp_cfg->id);
@@ -728,9 +713,9 @@
 		rc = -ENAVAIL;
 		sde_rm_init_hw_iter(&iter_i, 0, SDE_HW_BLK_PINGPONG);
 		while (_sde_rm_get_hw_locked(rm, &iter_i)) {
-			struct sde_pingpong_cfg *pp_cfg =
-				(struct sde_pingpong_cfg *)
-				(iter_i.blk->catalog);
+			const struct sde_hw_pingpong *pp =
+					to_sde_hw_pingpong(iter_i.blk->hw);
+			const struct sde_pingpong_cfg *pp_cfg = pp->caps;
 
 			if (!(test_bit(SDE_PINGPONG_SLAVE, &pp_cfg->features)))
 				continue;
@@ -759,17 +744,17 @@
 
 	sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_CTL);
 	while (_sde_rm_get_hw_locked(rm, &iter)) {
-		unsigned long caps;
+		const struct sde_hw_ctl *ctl = to_sde_hw_ctl(iter.blk->hw);
+		unsigned long features = ctl->caps->features;
 		bool has_split_display, has_ppsplit;
 
 		if (RESERVED_BY_OTHER(iter.blk, rsvp))
 			continue;
 
-		caps = ((struct sde_ctl_cfg *)iter.blk->catalog)->features;
-		has_split_display = BIT(SDE_CTL_SPLIT_DISPLAY) & caps;
-		has_ppsplit = BIT(SDE_CTL_PINGPONG_SPLIT) & caps;
+		has_split_display = BIT(SDE_CTL_SPLIT_DISPLAY) & features;
+		has_ppsplit = BIT(SDE_CTL_PINGPONG_SPLIT) & features;
 
-		SDE_DEBUG("ctl %d caps 0x%lX\n", iter.blk->id, caps);
+		SDE_DEBUG("ctl %d caps 0x%lX\n", iter.blk->id, features);
 
 		if (top->needs_split_display != has_split_display)
 			continue;
@@ -833,24 +818,23 @@
 		enum sde_hw_blk_type type)
 {
 	struct sde_rm_hw_iter iter;
-	struct sde_cdm_cfg *cdm;
 
 	sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_CDM);
 	while (_sde_rm_get_hw_locked(rm, &iter)) {
+		const struct sde_hw_cdm *cdm = to_sde_hw_cdm(iter.blk->hw);
+		const struct sde_cdm_cfg *caps = cdm->caps;
 		bool match = false;
 
 		if (RESERVED_BY_OTHER(iter.blk, rsvp))
 			continue;
 
-		cdm = (struct sde_cdm_cfg *)(iter.blk->catalog);
-
 		if (type == SDE_HW_BLK_INTF && id != INTF_MAX)
-			match = test_bit(id, &cdm->intf_connect);
+			match = test_bit(id, &caps->intf_connect);
 		else if (type == SDE_HW_BLK_WB && id != WB_MAX)
-			match = test_bit(id, &cdm->wb_connect);
+			match = test_bit(id, &caps->wb_connect);
 
 		SDE_DEBUG("type %d id %d, cdm intfs %lu wbs %lu match %d\n",
-				type, id, cdm->intf_connect, cdm->wb_connect,
+				type, id, caps->intf_connect, caps->wb_connect,
 				match);
 
 		if (!match)
@@ -1112,15 +1096,15 @@
 		list_for_each_entry(blk, &rm->hw_blks[type], list) {
 			if (blk->rsvp == rsvp) {
 				blk->rsvp = NULL;
-				SDE_DEBUG("rel rsvp %d enc %d %s %d\n",
+				SDE_DEBUG("rel rsvp %d enc %d %d %d\n",
 						rsvp->seq, rsvp->enc_id,
-						blk->type_name, blk->id);
+						blk->type, blk->id);
 			}
 			if (blk->rsvp_nxt == rsvp) {
 				blk->rsvp_nxt = NULL;
-				SDE_DEBUG("rel rsvp_nxt %d enc %d %s %d\n",
+				SDE_DEBUG("rel rsvp_nxt %d enc %d %d %d\n",
 						rsvp->seq, rsvp->enc_id,
-						blk->type_name, blk->id);
+						blk->type, blk->id);
 			}
 		}
 	}
diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h
index f731a30..e233fc7 100644
--- a/drivers/gpu/drm/msm/sde/sde_trace.h
+++ b/drivers/gpu/drm/msm/sde/sde_trace.h
@@ -159,35 +159,50 @@
 			__get_str(counter_name), __entry->value)
 )
 
+#define SDE_TRACE_EVTLOG_SIZE	15
 TRACE_EVENT(sde_evtlog,
-	TP_PROTO(const char *tag, u32 tag_id, u64 value1, u64 value2),
-	TP_ARGS(tag, tag_id, value1, value2),
+	TP_PROTO(const char *tag, u32 tag_id, u32 cnt, u32 data[]),
+	TP_ARGS(tag, tag_id, cnt, data),
 	TP_STRUCT__entry(
 			__field(int, pid)
 			__string(evtlog_tag, tag)
 			__field(u32, tag_id)
-			__field(u64, value1)
-			__field(u64, value2)
+			__array(u32, data, SDE_TRACE_EVTLOG_SIZE)
 	),
 	TP_fast_assign(
 			__entry->pid = current->tgid;
 			__assign_str(evtlog_tag, tag);
 			__entry->tag_id = tag_id;
-			__entry->value1 = value1;
-			__entry->value2 = value2;
+			if (cnt > SDE_TRACE_EVTLOG_SIZE)
+				cnt = SDE_TRACE_EVTLOG_SIZE;
+			memcpy(__entry->data, data, cnt * sizeof(u32));
+			memset(&__entry->data[cnt], 0,
+				(SDE_TRACE_EVTLOG_SIZE - cnt) * sizeof(u32));
 	),
-	TP_printk("%d|%s:%d|%llu|%llu", __entry->pid, __get_str(evtlog_tag),
-			__entry->tag_id, __entry->value1, __entry->value2)
+	TP_printk("%d|%s:%d|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
+			__entry->pid, __get_str(evtlog_tag),
+			__entry->tag_id,
+			__entry->data[0], __entry->data[1],
+			__entry->data[2], __entry->data[3],
+			__entry->data[4], __entry->data[5],
+			__entry->data[6], __entry->data[7],
+			__entry->data[8], __entry->data[9],
+			__entry->data[10], __entry->data[11],
+			__entry->data[12], __entry->data[13],
+			__entry->data[14])
 )
 
 TRACE_EVENT(sde_perf_crtc_update,
-	TP_PROTO(u32 crtc, u64 bw_ctl, u32 core_clk_rate,
-		bool stop_req, u32 update_bus, u32 update_clk),
-	TP_ARGS(crtc, bw_ctl, core_clk_rate,
+	TP_PROTO(u32 crtc, u64 bw_ctl_mnoc, u64 bw_ctl_llcc,
+			u64 bw_ctl_ebi, u32 core_clk_rate,
+			bool stop_req, u32 update_bus, u32 update_clk),
+	TP_ARGS(crtc, bw_ctl_mnoc, bw_ctl_llcc, bw_ctl_ebi, core_clk_rate,
 		stop_req, update_bus, update_clk),
 	TP_STRUCT__entry(
 			__field(u32, crtc)
-			__field(u64, bw_ctl)
+			__field(u64, bw_ctl_mnoc)
+			__field(u64, bw_ctl_llcc)
+			__field(u64, bw_ctl_ebi)
 			__field(u32, core_clk_rate)
 			__field(bool, stop_req)
 			__field(u32, update_bus)
@@ -195,19 +210,24 @@
 	),
 	TP_fast_assign(
 			__entry->crtc = crtc;
-			__entry->bw_ctl = bw_ctl;
+			__entry->bw_ctl_mnoc = bw_ctl_mnoc;
+			__entry->bw_ctl_llcc = bw_ctl_llcc;
+			__entry->bw_ctl_ebi = bw_ctl_ebi;
 			__entry->core_clk_rate = core_clk_rate;
 			__entry->stop_req = stop_req;
 			__entry->update_bus = update_bus;
 			__entry->update_clk = update_clk;
 	),
-	 TP_printk("crtc=%d bw=%llu clk_rate=%u stop_req=%d u_bus=%d u_clk=%d",
-			 __entry->crtc,
-			 __entry->bw_ctl,
-			 __entry->core_clk_rate,
-			 __entry->stop_req,
-			 __entry->update_bus,
-			 __entry->update_clk)
+	 TP_printk(
+		"crtc=%d bw_mnoc=%llu bw_llcc=%llu bw_ebi=%llu clk_rate=%u stop_req=%d u_bus=%d u_clk=%d",
+			__entry->crtc,
+			__entry->bw_ctl_mnoc,
+			__entry->bw_ctl_llcc,
+			__entry->bw_ctl_ebi,
+			__entry->core_clk_rate,
+			__entry->stop_req,
+			__entry->update_bus,
+			__entry->update_clk)
 );
 
 #define SDE_ATRACE_END(name) trace_sde_mark_write(current->tgid, name, 0)
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.c b/drivers/gpu/drm/msm/sde/sde_vbif.c
index e63fe8c..847572b 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.c
@@ -312,16 +312,16 @@
 		debugfs_vbif = debugfs_create_dir(vbif_name,
 				sde_kms->debugfs_vbif);
 
-		debugfs_create_u32("features", 0644, debugfs_vbif,
+		debugfs_create_u32("features", 0600, debugfs_vbif,
 			(u32 *)&vbif->features);
 
-		debugfs_create_u32("xin_halt_timeout", 0444, debugfs_vbif,
+		debugfs_create_u32("xin_halt_timeout", 0400, debugfs_vbif,
 			(u32 *)&vbif->xin_halt_timeout);
 
-		debugfs_create_u32("default_rd_ot_limit", 0444, debugfs_vbif,
+		debugfs_create_u32("default_rd_ot_limit", 0400, debugfs_vbif,
 			(u32 *)&vbif->default_ot_rd_limit);
 
-		debugfs_create_u32("default_wr_ot_limit", 0444, debugfs_vbif,
+		debugfs_create_u32("default_wr_ot_limit", 0400, debugfs_vbif,
 			(u32 *)&vbif->default_ot_wr_limit);
 
 		for (j = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) {
@@ -330,11 +330,11 @@
 
 			snprintf(vbif_name, sizeof(vbif_name),
 					"dynamic_ot_rd_%d_pps", j);
-			debugfs_create_u64(vbif_name, 0444, debugfs_vbif,
+			debugfs_create_u64(vbif_name, 0400, debugfs_vbif,
 					(u64 *)&cfg->pps);
 			snprintf(vbif_name, sizeof(vbif_name),
 					"dynamic_ot_rd_%d_ot_limit", j);
-			debugfs_create_u32(vbif_name, 0444, debugfs_vbif,
+			debugfs_create_u32(vbif_name, 0400, debugfs_vbif,
 					(u32 *)&cfg->ot_limit);
 		}
 
@@ -344,11 +344,11 @@
 
 			snprintf(vbif_name, sizeof(vbif_name),
 					"dynamic_ot_wr_%d_pps", j);
-			debugfs_create_u64(vbif_name, 0444, debugfs_vbif,
+			debugfs_create_u64(vbif_name, 0400, debugfs_vbif,
 					(u64 *)&cfg->pps);
 			snprintf(vbif_name, sizeof(vbif_name),
 					"dynamic_ot_wr_%d_ot_limit", j);
-			debugfs_create_u32(vbif_name, 0444, debugfs_vbif,
+			debugfs_create_u32(vbif_name, 0400, debugfs_vbif,
 					(u32 *)&cfg->ot_limit);
 		}
 	}
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index a4b918e..bcd3eaa 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -160,6 +160,7 @@
  * @enable_reg_dump: whether to dump registers into memory, kernel log, or both
  * @dbgbus_sde: debug bus structure for the sde
  * @dbgbus_vbif_rt: debug bus structure for the realtime vbif
+ * @dump_all: dump all entries in register dump
  */
 static struct sde_dbg_base {
 	struct sde_dbg_evtlog *evtlog;
@@ -176,6 +177,7 @@
 
 	struct sde_dbg_sde_debug_bus dbgbus_sde;
 	struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt;
+	bool dump_all;
 } sde_dbg_base;
 
 /* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */
@@ -2427,18 +2429,22 @@
  */
 static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[],
 	u32 len, bool do_panic, const char *name, bool dump_dbgbus_sde,
-	bool dump_dbgbus_vbif_rt)
+	bool dump_dbgbus_vbif_rt, bool dump_all)
 {
 	int i;
 
-	for (i = 0; i < len; i++) {
-		if (blk_arr[i] != NULL)
-			_sde_dump_reg_by_ranges(blk_arr[i],
-				sde_dbg_base.enable_reg_dump);
-	}
-
 	sde_evtlog_dump_all(sde_dbg_base.evtlog);
 
+	if (dump_all || !blk_arr || !len) {
+		_sde_dump_reg_all();
+	} else {
+		for (i = 0; i < len; i++) {
+			if (blk_arr[i] != NULL)
+				_sde_dump_reg_by_ranges(blk_arr[i],
+					sde_dbg_base.enable_reg_dump);
+		}
+	}
+
 	if (dump_dbgbus_sde)
 		_sde_dbg_dump_sde_dbg_bus(&sde_dbg_base.dbgbus_sde);
 
@@ -2459,7 +2465,8 @@
 		ARRAY_SIZE(sde_dbg_base.req_dump_blks),
 		sde_dbg_base.work_panic, "evtlog_workitem",
 		sde_dbg_base.dbgbus_sde.cmn.include_in_deferred_work,
-		sde_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work);
+		sde_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work,
+		sde_dbg_base.dump_all);
 }
 
 void sde_dbg_dump(bool queue_work, const char *name, ...)
@@ -2468,6 +2475,7 @@
 	bool do_panic = false;
 	bool dump_dbgbus_sde = false;
 	bool dump_dbgbus_vbif_rt = false;
+	bool dump_all = false;
 	va_list args;
 	char *blk_name = NULL;
 	struct sde_dbg_reg_base *blk_base = NULL;
@@ -2485,6 +2493,7 @@
 
 	memset(sde_dbg_base.req_dump_blks, 0,
 			sizeof(sde_dbg_base.req_dump_blks));
+	sde_dbg_base.dump_all = false;
 
 	va_start(args, name);
 	i = 0;
@@ -2507,6 +2516,9 @@
 			}
 		}
 
+		if (!strcmp(blk_name, "all"))
+			dump_all = true;
+
 		if (!strcmp(blk_name, "dbg_bus"))
 			dump_dbgbus_sde = true;
 
@@ -2528,7 +2540,7 @@
 		schedule_work(&sde_dbg_base.dump_work);
 	} else {
 		_sde_dump_array(blk_arr, blk_len, do_panic, name,
-				dump_dbgbus_sde, dump_dbgbus_vbif_rt);
+				dump_dbgbus_sde, dump_dbgbus_vbif_rt, dump_all);
 	}
 }
 
@@ -2577,15 +2589,8 @@
 static ssize_t sde_evtlog_dump_write(struct file *file,
 	const char __user *user_buf, size_t count, loff_t *ppos)
 {
-	_sde_dump_reg_all();
-
-	sde_evtlog_dump_all(sde_dbg_base.evtlog);
-
-	_sde_dbg_dump_sde_dbg_bus(&sde_dbg_base.dbgbus_sde);
-	_sde_dbg_dump_vbif_dbg_bus(&sde_dbg_base.dbgbus_vbif_rt);
-
-	if (sde_dbg_base.panic_on_err)
-		panic("sde");
+	_sde_dump_array(NULL, 0, sde_dbg_base.panic_on_err, "dump_debugfs",
+		true, true, true);
 
 	return count;
 }
@@ -2723,6 +2728,9 @@
 	if (off > dbg->max_offset)
 		return -EINVAL;
 
+	if (off % sizeof(u32))
+		return -EINVAL;
+
 	if (cnt > (dbg->max_offset - off))
 		cnt = dbg->max_offset - off;
 
@@ -2754,6 +2762,9 @@
 	if (*ppos)
 		return 0;	/* the end */
 
+	if (dbg->off % sizeof(u32))
+		return -EFAULT;
+
 	len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt);
 	if (len < 0 || len >= sizeof(buf))
 		return 0;
@@ -2797,6 +2808,9 @@
 	if (cnt < 2)
 		return -EFAULT;
 
+	if (off % sizeof(u32))
+		return -EFAULT;
+
 	if (off >= dbg->max_offset)
 		return -EFAULT;
 
@@ -2841,6 +2855,9 @@
 		if (!dbg->buf)
 			return -ENOMEM;
 
+		if (dbg->off % sizeof(u32))
+			return -EFAULT;
+
 		ptr = dbg->base + dbg->off;
 		tot = 0;
 
@@ -2904,16 +2921,16 @@
 	if (!debugfs_root)
 		return -EINVAL;
 
-	debugfs_create_file("dump", 0644, debugfs_root, NULL,
+	debugfs_create_file("dump", 0600, debugfs_root, NULL,
 			&sde_evtlog_fops);
-	debugfs_create_u32("enable", 0644, debugfs_root,
+	debugfs_create_u32("enable", 0600, debugfs_root,
 			&(sde_dbg_base.evtlog->enable));
-	debugfs_create_file("filter", 0644, debugfs_root,
+	debugfs_create_file("filter", 0600, debugfs_root,
 			sde_dbg_base.evtlog,
 			&sde_evtlog_filter_fops);
-	debugfs_create_u32("panic", 0644, debugfs_root,
+	debugfs_create_u32("panic", 0600, debugfs_root,
 			&sde_dbg_base.panic_on_err);
-	debugfs_create_u32("reg_dump", 0644, debugfs_root,
+	debugfs_create_u32("reg_dump", 0600, debugfs_root,
 			&sde_dbg_base.enable_reg_dump);
 
 	if (dbg->dbgbus_sde.entries) {
@@ -2921,7 +2938,7 @@
 		snprintf(debug_name, sizeof(debug_name), "%s_dbgbus",
 				dbg->dbgbus_sde.cmn.name);
 		dbg->dbgbus_sde.cmn.enable_mask = DEFAULT_DBGBUS_SDE;
-		debugfs_create_u32(debug_name, 0644, debugfs_root,
+		debugfs_create_u32(debug_name, 0600, debugfs_root,
 				&dbg->dbgbus_sde.cmn.enable_mask);
 	}
 
@@ -2930,19 +2947,19 @@
 		snprintf(debug_name, sizeof(debug_name), "%s_dbgbus",
 				dbg->dbgbus_vbif_rt.cmn.name);
 		dbg->dbgbus_vbif_rt.cmn.enable_mask = DEFAULT_DBGBUS_VBIFRT;
-		debugfs_create_u32(debug_name, 0644, debugfs_root,
+		debugfs_create_u32(debug_name, 0600, debugfs_root,
 				&dbg->dbgbus_vbif_rt.cmn.enable_mask);
 	}
 
 	list_for_each_entry(blk_base, &dbg->reg_base_list, reg_base_head) {
 		snprintf(debug_name, sizeof(debug_name), "%s_off",
 				blk_base->name);
-		debugfs_create_file(debug_name, 0644, debugfs_root, blk_base,
+		debugfs_create_file(debug_name, 0600, debugfs_root, blk_base,
 				&sde_off_fops);
 
 		snprintf(debug_name, sizeof(debug_name), "%s_reg",
 				blk_base->name);
-		debugfs_create_file(debug_name, 0644, debugfs_root, blk_base,
+		debugfs_create_file(debug_name, 0600, debugfs_root, blk_base,
 				&sde_reg_fops);
 	}
 
@@ -3018,6 +3035,26 @@
 	return 0;
 }
 
+static void sde_dbg_reg_base_destroy(void)
+{
+	struct sde_dbg_reg_range *range_node, *range_tmp;
+	struct sde_dbg_reg_base *blk_base, *blk_tmp;
+	struct sde_dbg_base *dbg_base = &sde_dbg_base;
+
+	if (!dbg_base)
+		return;
+
+	list_for_each_entry_safe(blk_base, blk_tmp, &dbg_base->reg_base_list,
+							reg_base_head) {
+		list_for_each_entry_safe(range_node, range_tmp,
+				&blk_base->sub_range_list, head) {
+			list_del(&range_node->head);
+			kfree(range_node);
+		}
+		list_del(&blk_base->reg_base_head);
+		kfree(blk_base);
+	}
+}
 /**
  * sde_dbg_destroy - destroy sde debug facilities
  */
@@ -3027,6 +3064,7 @@
 	sde_dbg_base_evtlog = NULL;
 	sde_evtlog_destroy(sde_dbg_base.evtlog);
 	sde_dbg_base.evtlog = NULL;
+	sde_dbg_reg_base_destroy();
 }
 
 int sde_dbg_reg_register_base(const char *name, void __iomem *base,
diff --git a/drivers/gpu/drm/msm/sde_dbg_evtlog.c b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
index 699396f..67c664f 100644
--- a/drivers/gpu/drm/msm/sde_dbg_evtlog.c
+++ b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
@@ -99,8 +99,7 @@
 	evtlog->curr = (evtlog->curr + 1) % SDE_EVTLOG_ENTRY;
 	evtlog->last++;
 
-	trace_sde_evtlog(name, line, i > 0 ? log->data[0] : 0,
-			i > 1 ? log->data[1] : 0);
+	trace_sde_evtlog(name, line, log->data_cnt, log->data);
 exit:
 	spin_unlock_irqrestore(&evtlog->spin_lock, flags);
 }
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 452a3be..242cd64 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -30,6 +30,20 @@
 #include "sde_power_handle.h"
 #include "sde_trace.h"
 
+static const char *data_bus_name[SDE_POWER_HANDLE_DBUS_ID_MAX] = {
+	[SDE_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,sde-data-bus",
+	[SDE_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,sde-llcc-bus",
+	[SDE_POWER_HANDLE_DBUS_ID_EBI] = "qcom,sde-ebi-bus",
+};
+
+const char *sde_power_handle_get_dbus_name(u32 bus_id)
+{
+	if (bus_id < SDE_POWER_HANDLE_DBUS_ID_MAX)
+		return data_bus_name[bus_id];
+
+	return NULL;
+}
+
 static void sde_power_event_trigger_locked(struct sde_power_handle *phandle,
 		u32 event_type)
 {
@@ -415,7 +429,9 @@
 			vect->ab = ab_quota[i];
 			vect->ib = ib_quota[i];
 
-			pr_debug("uc_idx=%d %s path idx=%d ab=%llu ib=%llu\n",
+			pr_debug(
+				"%s uc_idx=%d %s path idx=%d ab=%llu ib=%llu\n",
+				bw_table->name,
 				new_uc_idx, (i < rt_axi_port_cnt) ? "rt" : "nrt"
 				, i, vect->ab, vect->ib);
 		}
@@ -433,7 +449,8 @@
 
 int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,
 		struct sde_power_client *pclient,
-		int bus_client, u64 ab_quota, u64 ib_quota)
+		int bus_client, u32 bus_id,
+		u64 ab_quota, u64 ib_quota)
 {
 	int rc = 0;
 	int i;
@@ -442,7 +459,8 @@
 	struct sde_power_client *client;
 
 	if (!phandle || !pclient ||
-			bus_client >= SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX) {
+			bus_client >= SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX ||
+			bus_id >= SDE_POWER_HANDLE_DBUS_ID_MAX) {
 		pr_err("invalid parameters\n");
 		return -EINVAL;
 	}
@@ -465,7 +483,9 @@
 		}
 	}
 
-	rc = _sde_power_data_bus_set_quota(&phandle->data_bus_handle,
+	if (phandle->data_bus_handle[bus_id].data_bus_hdl)
+		rc = _sde_power_data_bus_set_quota(
+			&phandle->data_bus_handle[bus_id],
 			total_ab_rt, total_ab_nrt,
 			total_ib_rt, total_ib_nrt);
 
@@ -484,7 +504,7 @@
 }
 
 static int sde_power_data_bus_parse(struct platform_device *pdev,
-	struct sde_power_data_bus_handle *pdbus)
+	struct sde_power_data_bus_handle *pdbus, const char *name)
 {
 	struct device_node *node;
 	int rc = 0;
@@ -507,7 +527,7 @@
 		rc = 0;
 	}
 
-	node = of_get_child_by_name(pdev->dev.of_node, "qcom,sde-data-bus");
+	node = of_get_child_by_name(pdev->dev.of_node, name);
 	if (node) {
 		rc = of_property_read_u32(node,
 				"qcom,msm-bus,num-paths", &paths);
@@ -533,7 +553,8 @@
 			rc = -EINVAL;
 			goto end;
 		}
-		pr_debug("register data_bus_hdl=%x\n", pdbus->data_bus_hdl);
+		pr_debug("register %s data_bus_hdl=%x\n", name,
+				pdbus->data_bus_hdl);
 	}
 
 end:
@@ -621,7 +642,8 @@
 
 int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,
 		struct sde_power_client *pclient,
-		int bus_client, u64 ab_quota, u64 ib_quota)
+		int bus_client, u32 bus_id,
+		u64 ab_quota, u64 ib_quota)
 {
 	return 0;
 }
@@ -651,7 +673,7 @@
 int sde_power_resource_init(struct platform_device *pdev,
 	struct sde_power_handle *phandle)
 {
-	int rc = 0;
+	int rc = 0, i;
 	struct dss_module_power *mp;
 
 	if (!phandle || !pdev) {
@@ -699,10 +721,16 @@
 		goto bus_err;
 	}
 
-	rc = sde_power_data_bus_parse(pdev, &phandle->data_bus_handle);
-	if (rc) {
-		pr_err("register data bus parse failed rc=%d\n", rc);
-		goto data_bus_err;
+	for (i = SDE_POWER_HANDLE_DBUS_ID_MNOC;
+			i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+		rc = sde_power_data_bus_parse(pdev,
+				&phandle->data_bus_handle[i],
+				data_bus_name[i]);
+		if (rc) {
+			pr_err("register data bus parse failed id=%d rc=%d\n",
+					i, rc);
+			goto data_bus_err;
+		}
 	}
 
 	INIT_LIST_HEAD(&phandle->power_client_clist);
@@ -716,6 +744,8 @@
 	return rc;
 
 data_bus_err:
+	for (i--; i >= 0; i--)
+		sde_power_data_bus_unregister(&phandle->data_bus_handle[i]);
 	sde_power_reg_bus_unregister(phandle->reg_bus_hdl);
 bus_err:
 	msm_dss_put_clk(mp->clk_config, mp->num_clk);
@@ -739,6 +769,7 @@
 	struct dss_module_power *mp;
 	struct sde_power_client *curr_client, *next_client;
 	struct sde_power_event *curr_event, *next_event;
+	int i;
 
 	if (!phandle || !pdev) {
 		pr_err("invalid input param\n");
@@ -766,7 +797,8 @@
 	}
 	mutex_unlock(&phandle->phandle_lock);
 
-	sde_power_data_bus_unregister(&phandle->data_bus_handle);
+	for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
+		sde_power_data_bus_unregister(&phandle->data_bus_handle[i]);
 
 	sde_power_reg_bus_unregister(phandle->reg_bus_hdl);
 
@@ -790,7 +822,7 @@
 int sde_power_resource_enable(struct sde_power_handle *phandle,
 	struct sde_power_client *pclient, bool enable)
 {
-	int rc = 0;
+	int rc = 0, i;
 	bool changed = false;
 	u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx;
 	struct sde_power_client *client;
@@ -837,13 +869,15 @@
 		sde_power_event_trigger_locked(phandle,
 				SDE_POWER_EVENT_PRE_ENABLE);
 
-		rc = sde_power_data_bus_update(&phandle->data_bus_handle,
-									enable);
-		if (rc) {
-			pr_err("failed to set data bus vote rc=%d\n", rc);
-			goto data_bus_hdl_err;
+		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
+			rc = sde_power_data_bus_update(
+					&phandle->data_bus_handle[i], enable);
+			if (rc) {
+				pr_err("failed to set data bus vote id=%d rc=%d\n",
+						i, rc);
+				goto data_bus_hdl_err;
+			}
 		}
-
 		/*
 		 * - When the target is RSCC enabled, regulator should
 		 *   be enabled by the s/w only for the first time during
@@ -897,7 +931,9 @@
 		if (!phandle->rsc_client)
 			msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
 									enable);
-		sde_power_data_bus_update(&phandle->data_bus_handle, enable);
+		for (i = 0 ; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
+			sde_power_data_bus_update(&phandle->data_bus_handle[i],
+					enable);
 
 		sde_power_event_trigger_locked(phandle,
 				SDE_POWER_EVENT_POST_DISABLE);
@@ -915,7 +951,8 @@
 	if (!phandle->rsc_client)
 		msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
 vreg_err:
-	sde_power_data_bus_update(&phandle->data_bus_handle, 0);
+	for (i = 0 ; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
+		sde_power_data_bus_update(&phandle->data_bus_handle[i], 0);
 data_bus_hdl_err:
 	phandle->current_usecase_ndx = prev_usecase_ndx;
 	mutex_unlock(&phandle->phandle_lock);
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index c526b71..78c325d 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -16,9 +16,9 @@
 
 #define MAX_CLIENT_NAME_LEN 128
 
-#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA	2000000
+#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA	1600000000
 #define SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA	0
-#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA	2000000
+#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA	1600000000
 #define SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA	0
 
 #include <linux/sde_io_util.h>
@@ -60,6 +60,19 @@
 };
 
 /**
+ * enum SDE_POWER_HANDLE_DBUS_ID - data bus identifier
+ * @SDE_POWER_HANDLE_DBUS_ID_MNOC: DPU/MNOC data bus
+ * @SDE_POWER_HANDLE_DBUS_ID_LLCC: MNOC/LLCC data bus
+ * @SDE_POWER_HANDLE_DBUS_ID_EBI: LLCC/EBI data bus
+ */
+enum SDE_POWER_HANDLE_DBUS_ID {
+	SDE_POWER_HANDLE_DBUS_ID_MNOC,
+	SDE_POWER_HANDLE_DBUS_ID_LLCC,
+	SDE_POWER_HANDLE_DBUS_ID_EBI,
+	SDE_POWER_HANDLE_DBUS_ID_MAX,
+};
+
+/**
  * struct sde_power_client: stores the power client for sde driver
  * @name:	name of the client
  * @usecase_ndx: current regs bus vote type
@@ -152,7 +165,8 @@
 	struct device *dev;
 	u32 current_usecase_ndx;
 	u32 reg_bus_hdl;
-	struct sde_power_data_bus_handle data_bus_handle;
+	struct sde_power_data_bus_handle data_bus_handle
+		[SDE_POWER_HANDLE_DBUS_ID_MAX];
 	struct list_head event_list;
 	struct sde_rsc_client *rsc_client;
 	bool rsc_client_init;
@@ -254,6 +268,7 @@
  * @phandle:  power handle containing the resources
  * @client: client information to set quota
  * @bus_client: real-time or non-real-time bus client
+ * @bus_id: identifier of data bus, see SDE_POWER_HANDLE_DBUS_ID
  * @ab_quota: arbitrated bus bandwidth
  * @ib_quota: instantaneous bus bandwidth
  *
@@ -261,7 +276,8 @@
  */
 int sde_power_data_bus_set_quota(struct sde_power_handle *phandle,
 		struct sde_power_client *pclient,
-		int bus_client, u64 ab_quota, u64 ib_quota);
+		int bus_client, u32 bus_id,
+		u64 ab_quota, u64 ib_quota);
 
 /**
  * sde_power_data_bus_bandwidth_ctrl() - control data bus bandwidth enable
@@ -298,4 +314,11 @@
 void sde_power_handle_unregister_event(struct sde_power_handle *phandle,
 		struct sde_power_event *event);
 
+/**
+ * sde_power_handle_get_dbus_name - get name of given data bus identifier
+ * @bus_id:	data bus identifier
+ * Return:	Pointer to name string if success; NULL otherwise
+ */
+const char *sde_power_handle_get_dbus_name(u32 bus_id);
+
 #endif /* _SDE_POWER_HANDLE_H_ */
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index ac79968..9730f0b 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -30,6 +30,9 @@
 #include "sde_rsc_priv.h"
 #include "sde_dbg.h"
 
+#define SDE_RSC_DRV_DBG_NAME		"sde_rsc_drv"
+#define SDE_RSC_WRAPPER_DBG_NAME	"sde_rsc_wrapper"
+
 /* worst case time to execute the one tcs vote(sleep/wake) - ~1ms */
 #define SINGLE_TCS_EXECUTION_TIME				1064000
 
@@ -657,18 +660,17 @@
  * sde_rsc_client_vote() - ab/ib vote from rsc client
  *
  * @client:	 Client pointer provided by sde_rsc_client_create().
+ * @bus_id: data bus for which to be voted
  * @ab:		 aggregated bandwidth vote from client.
  * @ib:		 instant bandwidth vote from client.
  *
  * Return: error code.
  */
 int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
-	u64 ab_vote, u64 ib_vote)
+		u32 bus_id, u64 ab_vote, u64 ib_vote)
 {
 	int rc = 0;
 	struct sde_rsc_priv *rsc;
-	bool amc_mode = false;
-	enum rpmh_state state;
 
 	if (!caller_client) {
 		pr_err("invalid client for ab/ib vote\n");
@@ -682,11 +684,6 @@
 	if (!rsc)
 		return -EINVAL;
 
-	if (caller_client != rsc->primary_client) {
-		pr_err("only primary client can use sde rsc:: curr client name:%s\n",
-							caller_client->name);
-		return -EINVAL;
-	}
 	pr_debug("client:%s ab:%llu ib:%llu\n",
 			caller_client->name, ab_vote, ib_vote);
 
@@ -695,16 +692,6 @@
 	if (rc)
 		goto clk_enable_fail;
 
-	if (rsc->hw_ops.is_amc_mode)
-		amc_mode = rsc->hw_ops.is_amc_mode(rsc);
-
-	if (rsc->current_state == SDE_RSC_CMD_STATE)
-		state = RPMH_WAKE_ONLY_STATE;
-	else if (amc_mode)
-		state = RPMH_ACTIVE_ONLY_STATE;
-	else
-		state = RPMH_AWAKE_STATE;
-
 	if (rsc->hw_ops.tcs_wait) {
 		rc = rsc->hw_ops.tcs_wait(rsc);
 		if (rc) {
@@ -717,7 +704,8 @@
 
 	rpmh_invalidate(rsc->disp_rsc);
 	sde_power_data_bus_set_quota(&rsc->phandle, rsc->pclient,
-		SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, ab_vote, ib_vote);
+		SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT,
+		bus_id, ab_vote, ib_vote);
 	rpmh_flush(rsc->disp_rsc);
 
 	if (rsc->hw_ops.tcs_use_ok)
@@ -996,13 +984,13 @@
 		return;
 
 	/* don't error check these */
-	debugfs_create_file("status", 0444, rsc->debugfs_root, rsc,
+	debugfs_create_file("status", 0400, rsc->debugfs_root, rsc,
 							&debugfs_status_fops);
-	debugfs_create_file("mode_control", 0644, rsc->debugfs_root, rsc,
+	debugfs_create_file("mode_control", 0600, rsc->debugfs_root, rsc,
 							&mode_control_fops);
-	debugfs_create_file("vsync_mode", 0644, rsc->debugfs_root, rsc,
+	debugfs_create_file("vsync_mode", 0600, rsc->debugfs_root, rsc,
 							&vsync_status_fops);
-	debugfs_create_x32("debug_mode", 0644, rsc->debugfs_root,
+	debugfs_create_x32("debug_mode", 0600, rsc->debugfs_root,
 							&rsc->debug_mode);
 }
 
@@ -1063,6 +1051,10 @@
 	rsc->master_drm = drm;
 	mutex_unlock(&rsc->client_lock);
 
+	sde_dbg_reg_register_base(SDE_RSC_DRV_DBG_NAME, rsc->drv_io.base,
+							rsc->drv_io.len);
+	sde_dbg_reg_register_base(SDE_RSC_WRAPPER_DBG_NAME,
+				rsc->wrapper_io.base, rsc->wrapper_io.len);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
index 82d3e28..7e4f24a 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
@@ -4,6 +4,7 @@
 
 struct nvkm_alarm {
 	struct list_head head;
+	struct list_head exec;
 	u64 timestamp;
 	void (*func)(struct nvkm_alarm *);
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
index f2a86ea..2437f7d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
@@ -50,7 +50,8 @@
 		/* Move to completed list.  We'll drop the lock before
 		 * executing the callback so it can reschedule itself.
 		 */
-		list_move_tail(&alarm->head, &exec);
+		list_del_init(&alarm->head);
+		list_add(&alarm->exec, &exec);
 	}
 
 	/* Shut down interrupt if no more pending alarms. */
@@ -59,8 +60,8 @@
 	spin_unlock_irqrestore(&tmr->lock, flags);
 
 	/* Execute completed callbacks. */
-	list_for_each_entry_safe(alarm, atemp, &exec, head) {
-		list_del_init(&alarm->head);
+	list_for_each_entry_safe(alarm, atemp, &exec, exec) {
+		list_del(&alarm->exec);
 		alarm->func(alarm);
 	}
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index b6a0806..a1c68e6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -368,6 +368,8 @@
 				return fifo_state->static_buffer;
 			else {
 				fifo_state->dynamic_buffer = vmalloc(bytes);
+				if (!fifo_state->dynamic_buffer)
+					goto out_err;
 				return fifo_state->dynamic_buffer;
 			}
 		}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index 05fa092..56b8033 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -1275,11 +1275,14 @@
 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
 	int ret;
 	uint32_t size;
-	uint32_t backup_handle;
+	uint32_t backup_handle = 0;
 
 	if (req->multisample_count != 0)
 		return -EINVAL;
 
+	if (req->mip_levels > DRM_VMW_MAX_MIP_LEVELS)
+		return -EINVAL;
+
 	if (unlikely(vmw_user_surface_size == 0))
 		vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
 			128;
@@ -1315,12 +1318,16 @@
 		ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,
 					     &res->backup,
 					     &user_srf->backup_base);
-		if (ret == 0 && res->backup->base.num_pages * PAGE_SIZE <
-		    res->backup_size) {
-			DRM_ERROR("Surface backup buffer is too small.\n");
-			vmw_dmabuf_unreference(&res->backup);
-			ret = -EINVAL;
-			goto out_unlock;
+		if (ret == 0) {
+			if (res->backup->base.num_pages * PAGE_SIZE <
+			    res->backup_size) {
+				DRM_ERROR("Surface backup buffer is too small.\n");
+				vmw_dmabuf_unreference(&res->backup);
+				ret = -EINVAL;
+				goto out_unlock;
+			} else {
+				backup_handle = req->buffer_handle;
+			}
 		}
 	} else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer)
 		ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index f513207..0058226 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -38,6 +38,7 @@
 	adreno_a6xx_snapshot.o \
 	adreno_a4xx_preempt.o \
 	adreno_a5xx_preempt.o \
+	adreno_a6xx_preempt.o \
 	adreno_sysfs.o \
 	adreno.o \
 	adreno_cp_parser.o \
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index dbacb20..f4552b6 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -70,6 +70,15 @@
 #define A6XX_CP_ADDR_MODE_CNTL           0x842
 #define A6XX_CP_PROTECT_CNTL             0x84F
 #define A6XX_CP_PROTECT_REG              0x850
+#define A6XX_CP_CONTEXT_SWITCH_CNTL      0x8A0
+#define A6XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO   0x8A1
+#define A6XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI   0x8A2
+#define A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO   0x8A3
+#define A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI   0x8A4
+#define A6XX_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_LO   0x8A5
+#define A6XX_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_HI   0x8A6
+#define A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO   0x8A7
+#define A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI   0x8A8
 #define A6XX_CP_PERFCTR_CP_SEL_0         0x8D0
 #define A6XX_CP_PERFCTR_CP_SEL_1         0x8D1
 #define A6XX_CP_PERFCTR_CP_SEL_2         0x8D2
@@ -590,6 +599,7 @@
 #define A6XX_RB_PERFCTR_CMP_SEL_1           0x8E2D
 #define A6XX_RB_PERFCTR_CMP_SEL_2           0x8E2E
 #define A6XX_RB_PERFCTR_CMP_SEL_3           0x8E2F
+#define A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE 0x8E50
 
 /* PC registers */
 #define A6XX_PC_DBG_ECO_CNTL                0x9E00
@@ -798,8 +808,19 @@
 #define A6XX_GMU_CM3_CFG			0x1F82D
 #define A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE	0x1F840
 #define A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0	0x1F841
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1	0x1F842
 #define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L	0x1F844
 #define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H	0x1F845
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_L	0x1F846
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_H	0x1F847
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_L	0x1F848
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_H	0x1F849
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_L	0x1F84A
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_H	0x1F84B
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L	0x1F84C
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H	0x1F84D
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L	0x1F84E
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H	0x1F84F
 #define A6XX_GMU_PWR_COL_INTER_FRAME_CTRL	0x1F8C0
 #define A6XX_GMU_PWR_COL_INTER_FRAME_HYST	0x1F8C1
 #define A6XX_GMU_PWR_COL_SPTPRAC_HYST		0x1F8C2
@@ -852,6 +873,7 @@
 #define A6XX_GPU_GMU_AO_GMU_CGC_DELAY_CNTL      0x23B0A
 #define A6XX_GPU_GMU_AO_GMU_CGC_HYST_CNTL       0x23B0B
 #define A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS	0x23B0C
+#define A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2	0x23B0D
 #define A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK	0x23B0E
 #define A6XX_GMU_AHB_FENCE_STATUS		0x23B13
 #define A6XX_GMU_RBBM_INT_UNMASKED_STATUS	0x23B15
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index 9a44f34..f8bf780 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -326,7 +326,8 @@
 		.major = 3,
 		.minor = 0,
 		.patchid = ANY_ID,
-		.features = ADRENO_64BIT | ADRENO_RPMH,
+		.features = ADRENO_64BIT | ADRENO_RPMH |
+			ADRENO_GPMU | ADRENO_CONTENT_PROTECTION,
 		.sqefw_name = "a630_sqe.fw",
 		.zap_name = "a630_zap",
 		.gpudev = &adreno_a6xx_gpudev,
@@ -339,4 +340,21 @@
 		.gpmu_tsens = 0x000C000D,
 		.max_power = 5448,
 	},
+	{
+		.gpurev = ADRENO_REV_A615,
+		.core = 6,
+		.major = 1,
+		.minor = 5,
+		.patchid = ANY_ID,
+		.features = ADRENO_64BIT | ADRENO_RPMH,
+		.sqefw_name = "a630_sqe.fw",
+		.zap_name = "a615_zap",
+		.gpudev = &adreno_a6xx_gpudev,
+		.gmem_size = SZ_512K,
+		.num_protected_regs = 0x20,
+		.busy_mask = 0xFFFFFFFE,
+		.gpmufw_name = "a630_gmu.bin",
+		.gpmu_major = 0x0,
+		.gpmu_minor = 0x005,
+	},
 };
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index f581cff..6f465aa 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2645,10 +2645,9 @@
 	void __iomem *reg;
 	struct gmu_device *gmu = &device->gmu;
 
-	offsetwords -= gmu->gmu2gpu_offset;
-
 	trace_kgsl_regwrite(device, offsetwords, value);
 
+	offsetwords -= gmu->gmu2gpu_offset;
 	reg = gmu->reg_virt + (offsetwords << 2);
 
 	/*
@@ -2855,8 +2854,14 @@
 			gpu_busy += adj;
 		}
 
-		stats->busy_time = adreno_ticks_to_us(gpu_busy,
-			kgsl_pwrctrl_active_freq(pwr));
+		if (kgsl_gmu_isenabled(device)) {
+			/* clock sourced from XO */
+			stats->busy_time = gpu_busy * 10 / 192;
+		} else {
+			/* clock sourced from GFX3D */
+			stats->busy_time = adreno_ticks_to_us(gpu_busy,
+				kgsl_pwrctrl_active_freq(pwr));
+		}
 	}
 
 	if (device->pwrctrl.bus_control) {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 26c5505..da8951b 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -195,6 +195,7 @@
 	ADRENO_REV_A512 = 512,
 	ADRENO_REV_A530 = 530,
 	ADRENO_REV_A540 = 540,
+	ADRENO_REV_A615 = 615,
 	ADRENO_REV_A630 = 630,
 };
 
@@ -641,6 +642,7 @@
 	ADRENO_REG_GMU_HOST2GMU_INTR_SET,
 	ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
 	ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
+	ADRENO_REG_GPMU_POWER_COUNTER_ENABLE,
 	ADRENO_REG_REGISTER_MAX,
 };
 
@@ -844,11 +846,14 @@
 				unsigned int *cmds,
 				struct kgsl_context *context);
 	int (*preemption_yield_enable)(unsigned int *);
+	unsigned int (*preemption_set_marker)(unsigned int *cmds, int start);
 	unsigned int (*preemption_post_ibsubmit)(
 				struct adreno_device *adreno_dev,
 				unsigned int *cmds);
 	int (*preemption_init)(struct adreno_device *);
 	void (*preemption_schedule)(struct adreno_device *);
+	int (*preemption_context_init)(struct kgsl_context *);
+	void (*preemption_context_destroy)(struct kgsl_context *);
 	void (*enable_64bit)(struct adreno_device *);
 	void (*clk_set_options)(struct adreno_device *,
 				const char *, struct clk *, bool on);
@@ -1140,6 +1145,7 @@
 			ADRENO_GPUREV(adreno_dev) < 700;
 }
 
+ADRENO_TARGET(a615, ADRENO_REV_A615)
 ADRENO_TARGET(a630, ADRENO_REV_A630)
 
 static inline int adreno_is_a630v1(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 314ac85a..13c36e6 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -3017,6 +3017,8 @@
 				A5XX_VBIF_XIN_HALT_CTRL1),
 	ADRENO_REG_DEFINE(ADRENO_REG_VBIF_VERSION,
 				A5XX_VBIF_VERSION),
+	ADRENO_REG_DEFINE(ADRENO_REG_GPMU_POWER_COUNTER_ENABLE,
+				A5XX_GPMU_POWER_COUNTER_ENABLE),
 };
 
 static const struct adreno_reg_offsets a5xx_reg_offsets = {
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 314b2d8..30ada8f 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -29,9 +29,6 @@
 #include "kgsl_gmu.h"
 #include "kgsl_trace.h"
 
-#define A6XX_CP_RB_CNTL_DEFAULT (((ilog2(4) << 8) & 0x1F00) | \
-		(ilog2(KGSL_RB_DWORDS >> 1) & 0x3F))
-
 #define MIN_HBB		13
 
 #define A6XX_LLC_NUM_GPU_SCIDS		5
@@ -67,10 +64,10 @@
 	{A6XX_RBBM_CLOCK_CNTL_SP1, 0x22222222},
 	{A6XX_RBBM_CLOCK_CNTL_SP2, 0x22222222},
 	{A6XX_RBBM_CLOCK_CNTL_SP3, 0x22222222},
-	{A6XX_RBBM_CLOCK_CNTL2_SP0, 0x02222220},
-	{A6XX_RBBM_CLOCK_CNTL2_SP1, 0x02222220},
-	{A6XX_RBBM_CLOCK_CNTL2_SP2, 0x02222220},
-	{A6XX_RBBM_CLOCK_CNTL2_SP3, 0x02222220},
+	{A6XX_RBBM_CLOCK_CNTL2_SP0, 0x02022220},
+	{A6XX_RBBM_CLOCK_CNTL2_SP1, 0x02022220},
+	{A6XX_RBBM_CLOCK_CNTL2_SP2, 0x02022220},
+	{A6XX_RBBM_CLOCK_CNTL2_SP3, 0x02022220},
 	{A6XX_RBBM_CLOCK_DELAY_SP0, 0x0000F3CF},
 	{A6XX_RBBM_CLOCK_DELAY_SP1, 0x0000F3CF},
 	{A6XX_RBBM_CLOCK_DELAY_SP2, 0x0000F3CF},
@@ -79,10 +76,10 @@
 	{A6XX_RBBM_CLOCK_HYST_SP1, 0x00000080},
 	{A6XX_RBBM_CLOCK_HYST_SP2, 0x00000080},
 	{A6XX_RBBM_CLOCK_HYST_SP3, 0x00000080},
-	{A6XX_RBBM_CLOCK_CNTL_TP0, 0x22222222},
-	{A6XX_RBBM_CLOCK_CNTL_TP1, 0x22222222},
-	{A6XX_RBBM_CLOCK_CNTL_TP2, 0x22222222},
-	{A6XX_RBBM_CLOCK_CNTL_TP3, 0x22222222},
+	{A6XX_RBBM_CLOCK_CNTL_TP0, 0x02222222},
+	{A6XX_RBBM_CLOCK_CNTL_TP1, 0x02222222},
+	{A6XX_RBBM_CLOCK_CNTL_TP2, 0x02222222},
+	{A6XX_RBBM_CLOCK_CNTL_TP3, 0x02222222},
 	{A6XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222},
 	{A6XX_RBBM_CLOCK_CNTL2_TP1, 0x22222222},
 	{A6XX_RBBM_CLOCK_CNTL2_TP2, 0x22222222},
@@ -175,7 +172,8 @@
 	const struct kgsl_hwcg_reg *regs;
 	unsigned int count;
 } a6xx_hwcg_registers[] = {
-	{adreno_is_a630, a630_hwcg_regs, ARRAY_SIZE(a630_hwcg_regs)}
+	{adreno_is_a630, a630_hwcg_regs, ARRAY_SIZE(a630_hwcg_regs)},
+	{adreno_is_a615, a630_hwcg_regs, ARRAY_SIZE(a630_hwcg_regs)},
 };
 
 static struct a6xx_protected_regs {
@@ -482,6 +480,12 @@
 	if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_TWO_PASS_USE_WFI))
 		kgsl_regrmw(device, A6XX_PC_DBG_ECO_CNTL, 0, (1 << 8));
 
+	/* Enable the GMEM save/restore feature for preemption */
+	if (adreno_is_preemption_enabled(adreno_dev))
+		kgsl_regwrite(device, A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE,
+			0x1);
+
+	a6xx_preemption_start(adreno_dev);
 	a6xx_protect_init(adreno_dev);
 }
 
@@ -612,6 +616,70 @@
 }
 
 /*
+ * Follow the ME_INIT sequence with a preemption yield to allow the GPU to move
+ * to a different ringbuffer, if desired
+ */
+static int _preemption_init(struct adreno_device *adreno_dev,
+		struct adreno_ringbuffer *rb, unsigned int *cmds,
+		struct kgsl_context *context)
+{
+	unsigned int *cmds_orig = cmds;
+
+	/* Turn CP protection OFF */
+	*cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1);
+	*cmds++ = 0;
+
+	*cmds++ = cp_type7_packet(CP_SET_PSEUDO_REGISTER, 6);
+	*cmds++ = 1;
+	cmds += cp_gpuaddr(adreno_dev, cmds,
+			rb->preemption_desc.gpuaddr);
+
+	*cmds++ = 2;
+	cmds += cp_gpuaddr(adreno_dev, cmds, 0);
+
+	/* Turn CP protection ON */
+	*cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1);
+	*cmds++ = 1;
+
+	*cmds++ = cp_type7_packet(CP_CONTEXT_SWITCH_YIELD, 4);
+	cmds += cp_gpuaddr(adreno_dev, cmds, 0x0);
+	*cmds++ = 0;
+	/* generate interrupt on preemption completion */
+	*cmds++ = 0;
+
+	return cmds - cmds_orig;
+}
+
+static int a6xx_post_start(struct adreno_device *adreno_dev)
+{
+	int ret;
+	unsigned int *cmds, *start;
+	struct adreno_ringbuffer *rb = adreno_dev->cur_rb;
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+	if (!adreno_is_preemption_enabled(adreno_dev))
+		return 0;
+
+	cmds = adreno_ringbuffer_allocspace(rb, 42);
+	if (IS_ERR(cmds)) {
+		KGSL_DRV_ERR(device, "error allocating preemption init cmds");
+		return PTR_ERR(cmds);
+	}
+	start = cmds;
+
+	cmds += _preemption_init(adreno_dev, rb, cmds, NULL);
+
+	rb->_wptr = rb->_wptr - (42 - (cmds - start));
+
+	ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000);
+	if (ret)
+		adreno_spin_idle_debug(adreno_dev,
+			"hw preemption initialization failed to idle\n");
+
+	return ret;
+}
+
+/*
  * a6xx_rb_start() - Start the ringbuffer
  * @adreno_dev: Pointer to adreno device
  * @start_type: Warm or cold start
@@ -651,7 +719,11 @@
 		return ret;
 
 	/* GPU comes up in secured mode, make it unsecured by default */
-	return adreno_set_unsecured_mode(adreno_dev, rb);
+	ret = adreno_set_unsecured_mode(adreno_dev, rb);
+	if (ret)
+		return ret;
+
+	return a6xx_post_start(adreno_dev);
 }
 
 static int _load_firmware(struct kgsl_device *device, const char *fwfile,
@@ -678,9 +750,6 @@
 	}
 
 	release_firmware(fw);
-
-	ret = _load_gmu_firmware(device);
-
 	return ret;
 }
 
@@ -1202,7 +1271,7 @@
 			OOB_BOOT_SLUMBER_CLEAR_MASK);
 
 	if (ret)
-		dev_err(&gmu->pdev->dev, "OOB set after GMU booted timed out\n");
+		dev_err(&gmu->pdev->dev, "Boot OOB timed out\n");
 
 	return ret;
 }
@@ -1222,6 +1291,9 @@
 	int perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1;
 	int ret, state;
 
+	/* Disable the power counter so that the GMU is not busy */
+	kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0);
+
 	if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
 		ret = hfi_notify_slumber(gmu, perf_idx, bus_level);
 		return ret;
@@ -1238,7 +1310,7 @@
 	a6xx_oob_clear(adreno_dev, OOB_BOOT_SLUMBER_CLEAR_MASK);
 
 	if (ret)
-		dev_err(&gmu->pdev->dev, "OOB set for slumber timed out\n");
+		dev_err(&gmu->pdev->dev, "Notify slumber OOB timed out\n");
 	else {
 		kgsl_gmu_regread(device,
 			A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, &state);
@@ -1286,6 +1358,9 @@
 	/* Turn on the HM and SPTP head switches */
 	ret = a6xx_hm_sptprac_enable(device);
 
+	/* Enable the power counter because it was disabled before slumber */
+	kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1);
+
 	return ret;
 error_rsc:
 	dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n");
@@ -1342,6 +1417,8 @@
 	int ret, i;
 
 	switch (boot_state) {
+	case GMU_RESET:
+		/* fall through */
 	case GMU_COLD_BOOT:
 		/* Turn on the HM and SPTP head switches */
 		ret = a6xx_hm_sptprac_enable(device);
@@ -1357,6 +1434,10 @@
 			ret = a6xx_hm_sptprac_enable(device);
 			if (ret)
 				return ret;
+		} else if (boot_state == GMU_RESET) {
+			ret = a6xx_hm_sptprac_enable(device);
+			if (ret)
+				return ret;
 		} else {
 			ret = a6xx_rpmh_power_on_gpu(device);
 			if (ret)
@@ -1384,11 +1465,6 @@
 		if (ret)
 			return ret;
 		break;
-	case GMU_RESET:
-		/* Turn on the HM and SPTP head switches */
-		ret = a6xx_hm_sptprac_enable(device);
-		if (ret)
-			return ret;
 	default:
 		break;
 	}
@@ -1466,7 +1542,7 @@
 		OOB_DCVS_CLEAR_MASK);
 
 	if (ret) {
-		dev_err(&gmu->pdev->dev, "OOB set after GMU booted timed out\n");
+		dev_err(&gmu->pdev->dev, "DCVS OOB timed out\n");
 		goto done;
 	}
 
@@ -1495,10 +1571,17 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct gmu_device *gmu = &device->gmu;
+	unsigned int status, status2;
 
 	if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS,
 			0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) {
-		dev_err(&gmu->pdev->dev, "GMU is not idling\n");
+		kgsl_gmu_regread(device,
+				A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, &status);
+		kgsl_gmu_regread(device,
+				A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2, &status2);
+		dev_err(&gmu->pdev->dev,
+				"GMU not idling: status=0x%x, status2=0x%x\n",
+				status, status2);
 		return -ETIMEDOUT;
 	}
 
@@ -1554,9 +1637,18 @@
  */
 static int a6xx_microcode_read(struct adreno_device *adreno_dev)
 {
-	return _load_firmware(KGSL_DEVICE(adreno_dev),
-			adreno_dev->gpucore->sqefw_name,
-			ADRENO_FW(adreno_dev, ADRENO_FW_SQE));
+	int ret;
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	struct adreno_firmware *sqe_fw = ADRENO_FW(adreno_dev, ADRENO_FW_SQE);
+
+	if (sqe_fw->memdesc.hostptr == NULL) {
+		ret = _load_firmware(device, adreno_dev->gpucore->sqefw_name,
+				sqe_fw);
+		if (ret)
+			return ret;
+	}
+
+	return _load_gmu_firmware(device);
 }
 
 #define VBIF_RESET_ACK_TIMEOUT	100
@@ -1566,6 +1658,8 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	unsigned int reg;
+	unsigned long time;
+	bool vbif_acked = false;
 
 	/*
 	 * For the soft reset case with GMU enabled this part is done
@@ -1584,12 +1678,19 @@
 	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_SW_RESET_CMD, &reg);
 	adreno_writereg(adreno_dev, ADRENO_REG_RBBM_SW_RESET_CMD, 0);
 
-	/* Check VBIF status after reset */
-	if (timed_poll_check(device,
-			A6XX_RBBM_VBIF_GX_RESET_STATUS,
-			VBIF_RESET_ACK_MASK,
-			VBIF_RESET_ACK_TIMEOUT,
-			VBIF_RESET_ACK_MASK))
+	/* Wait for the VBIF reset ack to complete */
+	time = jiffies + msecs_to_jiffies(VBIF_RESET_ACK_TIMEOUT);
+
+	do {
+		kgsl_regread(device, A6XX_RBBM_VBIF_GX_RESET_STATUS, &reg);
+		if ((reg & VBIF_RESET_ACK_MASK) == VBIF_RESET_ACK_MASK) {
+			vbif_acked = true;
+			break;
+		}
+		cpu_relax();
+	} while (!time_after(jiffies, time));
+
+	if (!vbif_acked)
 		return -ETIMEDOUT;
 
 	a6xx_sptprac_enable(adreno_dev);
@@ -2058,7 +2159,7 @@
 	/* 6 - RBBM_ATB_ASYNC_OVERFLOW */
 	ADRENO_IRQ_CALLBACK(a6xx_err_callback),
 	ADRENO_IRQ_CALLBACK(NULL), /* 7 - GPC_ERR */
-	ADRENO_IRQ_CALLBACK(NULL),/* 8 - CP_SW */
+	ADRENO_IRQ_CALLBACK(a6xx_preemption_callback),/* 8 - CP_SW */
 	ADRENO_IRQ_CALLBACK(a6xx_cp_hw_err_callback), /* 9 - CP_HW_ERROR */
 	ADRENO_IRQ_CALLBACK(NULL),  /* 10 - CP_CCU_FLUSH_DEPTH_TS */
 	ADRENO_IRQ_CALLBACK(NULL), /* 11 - CP_CCU_FLUSH_COLOR_TS */
@@ -2431,12 +2532,47 @@
 		A6XX_CP_ALWAYS_ON_COUNTER_HI, -1 },
 };
 
+static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = {
+	/*
+	 * A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0 is used for the GPU
+	 * busy count (see the PWR group above). Mark it as broken
+	 * so it's not re-used.
+	 */
+	{ KGSL_PERFCOUNTER_BROKEN, 0, 0,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H, -1,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_L,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_H, -1,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_L,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_H, -1,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_L,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_H, -1,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H, -1,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, },
+	{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H, -1,
+		A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, },
+};
+
 #define A6XX_PERFCOUNTER_GROUP(offset, name) \
 	ADRENO_PERFCOUNTER_GROUP(a6xx, offset, name)
 
 #define A6XX_PERFCOUNTER_GROUP_FLAGS(offset, name, flags) \
 	ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, flags)
 
+#define A6XX_POWER_COUNTER_GROUP(offset, name) \
+	ADRENO_POWER_COUNTER_GROUP(a6xx, offset, name)
+
 static struct adreno_perfcount_group a6xx_perfcounter_groups
 				[KGSL_PERFCOUNTER_GROUP_MAX] = {
 	A6XX_PERFCOUNTER_GROUP(CP, cp),
@@ -2462,6 +2598,7 @@
 		ADRENO_PERFCOUNTER_GROUP_FIXED),
 	A6XX_PERFCOUNTER_GROUP_FLAGS(ALWAYSON, alwayson,
 		ADRENO_PERFCOUNTER_GROUP_FIXED),
+	A6XX_POWER_COUNTER_GROUP(GPMU, gpmu),
 };
 
 static struct adreno_perfcounters a6xx_perfcounters = {
@@ -2516,6 +2653,11 @@
 	ADRENO_REG_DEFINE(ADRENO_REG_CP_IB2_BUFSZ, A6XX_CP_IB2_REM_SIZE),
 	ADRENO_REG_DEFINE(ADRENO_REG_CP_ROQ_ADDR, A6XX_CP_ROQ_DBG_ADDR),
 	ADRENO_REG_DEFINE(ADRENO_REG_CP_ROQ_DATA, A6XX_CP_ROQ_DBG_DATA),
+	ADRENO_REG_DEFINE(ADRENO_REG_CP_PREEMPT, A6XX_CP_CONTEXT_SWITCH_CNTL),
+	ADRENO_REG_DEFINE(ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_LO,
+			A6XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO),
+	ADRENO_REG_DEFINE(ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI,
+			A6XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI),
 	ADRENO_REG_DEFINE(ADRENO_REG_RBBM_STATUS, A6XX_RBBM_STATUS),
 	ADRENO_REG_DEFINE(ADRENO_REG_RBBM_STATUS3, A6XX_RBBM_STATUS3),
 	ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_CTL, A6XX_RBBM_PERFCTR_CNTL),
@@ -2629,4 +2771,11 @@
 	.iommu_fault_block = a6xx_iommu_fault_block,
 	.reset = a6xx_reset,
 	.soft_reset = a6xx_soft_reset,
+	.preemption_pre_ibsubmit = a6xx_preemption_pre_ibsubmit,
+	.preemption_post_ibsubmit = a6xx_preemption_post_ibsubmit,
+	.preemption_init = a6xx_preemption_init,
+	.preemption_schedule = a6xx_preemption_schedule,
+	.preemption_set_marker = a6xx_preemption_set_marker,
+	.preemption_context_init = a6xx_preemption_context_init,
+	.preemption_context_destroy = a6xx_preemption_context_destroy,
 };
diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h
index 4b96f56..ddf89d6 100644
--- a/drivers/gpu/msm/adreno_a6xx.h
+++ b/drivers/gpu/msm/adreno_a6xx.h
@@ -23,10 +23,93 @@
 #define CP_CLUSTER_SP_PS	0x4
 #define CP_CLUSTER_PS		0x5
 
+/**
+ * struct a6xx_cp_preemption_record - CP context record for
+ * preemption.
+ * @magic: (00) Value at this offset must be equal to
+ * A6XX_CP_CTXRECORD_MAGIC_REF.
+ * @info: (04) Type of record. Written non-zero (usually) by CP.
+ * we must set to zero for all ringbuffers.
+ * @errno: (08) Error code. Initialize this to A6XX_CP_CTXRECORD_ERROR_NONE.
+ * CP will update to another value if a preemption error occurs.
+ * @data: (12) DATA field in YIELD and SET_MARKER packets.
+ * Written by CP when switching out. Not used on switch-in. Initialized to 0.
+ * @cntl: (16) RB_CNTL, saved and restored by CP. We must initialize this.
+ * @rptr: (20) RB_RPTR, saved and restored by CP. We must initialize this.
+ * @wptr: (24) RB_WPTR, saved and restored by CP. We must initialize this.
+ * @_pad28: (28) Reserved/padding.
+ * @rptr_addr: (32) RB_RPTR_ADDR_LO|HI saved and restored. We must initialize.
+ * rbase: (40) RB_BASE_LO|HI saved and restored.
+ * counter: (48) Pointer to preemption counter.
+ */
+struct a6xx_cp_preemption_record {
+	uint32_t  magic;
+	uint32_t  info;
+	uint32_t  errno;
+	uint32_t  data;
+	uint32_t  cntl;
+	uint32_t  rptr;
+	uint32_t  wptr;
+	uint32_t  _pad28;
+	uint64_t  rptr_addr;
+	uint64_t  rbase;
+	uint64_t  counter;
+};
+
+/**
+ * struct a6xx_cp_smmu_info - CP preemption SMMU info.
+ * @magic: (00) The value at this offset must be equal to
+ * A6XX_CP_SMMU_INFO_MAGIC_REF.
+ * @_pad4: (04) Reserved/padding
+ * @ttbr0: (08) Base address of the page table for the
+ * incoming context.
+ * @context_idr: (16) Context Identification Register value.
+ */
+struct a6xx_cp_smmu_info {
+	uint32_t  magic;
+	uint32_t  _pad4;
+	uint64_t  ttbr0;
+	uint32_t  asid;
+	uint32_t  context_idr;
+};
+
+#define A6XX_CP_SMMU_INFO_MAGIC_REF     0x3618CDA3UL
+
+#define A6XX_CP_CTXRECORD_MAGIC_REF     0xAE399D6EUL
+/* Size of each CP preemption record */
+#define A6XX_CP_CTXRECORD_SIZE_IN_BYTES     (2112 * 1024)
+/* Size of the preemption counter block (in bytes) */
+#define A6XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE   (16 * 4)
+/* Size of the user context record block (in bytes) */
+#define A6XX_CP_CTXRECORD_USER_RESTORE_SIZE (192 * 1024)
+/* Size of the performance counter save/restore block (in bytes) */
+#define A6XX_CP_PERFCOUNTER_SAVE_RESTORE_SIZE   (4 * 1024)
+
+#define A6XX_CP_RB_CNTL_DEFAULT (((ilog2(4) << 8) & 0x1F00) | \
+		(ilog2(KGSL_RB_DWORDS >> 1) & 0x3F))
+
+/* Preemption functions */
+void a6xx_preemption_trigger(struct adreno_device *adreno_dev);
+void a6xx_preemption_schedule(struct adreno_device *adreno_dev);
+void a6xx_preemption_start(struct adreno_device *adreno_dev);
+int a6xx_preemption_init(struct adreno_device *adreno_dev);
+
+unsigned int a6xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev,
+		unsigned int *cmds);
+unsigned int a6xx_preemption_pre_ibsubmit(struct adreno_device *adreno_dev,
+		struct adreno_ringbuffer *rb,
+		unsigned int *cmds, struct kgsl_context *context);
+
+unsigned int a6xx_preemption_set_marker(unsigned int *cmds, int start);
+
+void a6xx_preemption_callback(struct adreno_device *adreno_dev, int bit);
+
+int a6xx_preemption_context_init(struct kgsl_context *context);
+
+void a6xx_preemption_context_destroy(struct kgsl_context *context);
 
 void a6xx_snapshot(struct adreno_device *adreno_dev,
 		struct kgsl_snapshot *snapshot);
 
 void a6xx_crashdump_init(struct adreno_device *adreno_dev);
-
 #endif
diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c
new file mode 100644
index 0000000..00325e5
--- /dev/null
+++ b/drivers/gpu/msm/adreno_a6xx_preempt.c
@@ -0,0 +1,654 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "adreno.h"
+#include "adreno_a6xx.h"
+#include "a6xx_reg.h"
+#include "adreno_trace.h"
+#include "adreno_pm4types.h"
+
+#define PREEMPT_RECORD(_field) \
+		offsetof(struct a6xx_cp_preemption_record, _field)
+
+#define PREEMPT_SMMU_RECORD(_field) \
+		offsetof(struct a6xx_cp_smmu_info, _field)
+
+enum {
+	SET_PSEUDO_REGISTER_SAVE_REGISTER_SMMU_INFO = 0,
+	SET_PSEUDO_REGISTER_SAVE_REGISTER_PRIV_NON_SECURE_SAVE_ADDR,
+	SET_PSEUDO_REGISTER_SAVE_REGISTER_PRIV_SECURE_SAVE_ADDR,
+	SET_PSEUDO_REGISTER_SAVE_REGISTER_NON_PRIV_SAVE_ADDR,
+	SET_PSEUDO_REGISTER_SAVE_REGISTER_COUNTER,
+};
+
+static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer)
+{
+	struct adreno_ringbuffer *rb = adreno_dev->cur_rb;
+	unsigned int wptr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rb->preempt_lock, flags);
+
+	adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_WPTR, &wptr);
+
+	if (wptr != rb->wptr) {
+		adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR,
+			rb->wptr);
+		/*
+		 * In case something got submitted while preemption was on
+		 * going, reset the timer.
+		 */
+		reset_timer = true;
+	}
+
+	if (reset_timer)
+		rb->dispatch_q.expires = jiffies +
+			msecs_to_jiffies(adreno_drawobj_timeout);
+
+	spin_unlock_irqrestore(&rb->preempt_lock, flags);
+}
+
+static inline bool adreno_move_preempt_state(struct adreno_device *adreno_dev,
+	enum adreno_preempt_states old, enum adreno_preempt_states new)
+{
+	return (atomic_cmpxchg(&adreno_dev->preempt.state, old, new) == old);
+}
+
+static void _a6xx_preemption_done(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	unsigned int status;
+
+	/*
+	 * In the very unlikely case that the power is off, do nothing - the
+	 * state will be reset on power up and everybody will be happy
+	 */
+
+	if (!kgsl_state_is_awake(device))
+		return;
+
+	adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &status);
+
+	if (status & 0x1) {
+		KGSL_DRV_ERR(device,
+			"Preemption not complete: status=%X cur=%d R/W=%X/%X next=%d R/W=%X/%X\n",
+			status, adreno_dev->cur_rb->id,
+			adreno_get_rptr(adreno_dev->cur_rb),
+			adreno_dev->cur_rb->wptr, adreno_dev->next_rb->id,
+			adreno_get_rptr(adreno_dev->next_rb),
+			adreno_dev->next_rb->wptr);
+
+		/* Set a fault and restart */
+		adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
+		adreno_dispatcher_schedule(device);
+
+		return;
+	}
+
+	del_timer_sync(&adreno_dev->preempt.timer);
+
+	trace_adreno_preempt_done(adreno_dev->cur_rb, adreno_dev->next_rb);
+
+	/* Clean up all the bits */
+	adreno_dev->prev_rb = adreno_dev->cur_rb;
+	adreno_dev->cur_rb = adreno_dev->next_rb;
+	adreno_dev->next_rb = NULL;
+
+	/* Update the wptr for the new command queue */
+	_update_wptr(adreno_dev, true);
+
+	/* Update the dispatcher timer for the new command queue */
+	mod_timer(&adreno_dev->dispatcher.timer,
+		adreno_dev->cur_rb->dispatch_q.expires);
+
+	/* Clear the preempt state */
+	adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+}
+
+static void _a6xx_preemption_fault(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	unsigned int status;
+
+	/*
+	 * If the power is on check the preemption status one more time - if it
+	 * was successful then just transition to the complete state
+	 */
+	if (kgsl_state_is_awake(device)) {
+		adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &status);
+
+		if (status == 0) {
+			adreno_set_preempt_state(adreno_dev,
+				ADRENO_PREEMPT_COMPLETE);
+
+			adreno_dispatcher_schedule(device);
+			return;
+		}
+	}
+
+	KGSL_DRV_ERR(device,
+		"Preemption timed out: cur=%d R/W=%X/%X, next=%d R/W=%X/%X\n",
+		adreno_dev->cur_rb->id,
+		adreno_get_rptr(adreno_dev->cur_rb), adreno_dev->cur_rb->wptr,
+		adreno_dev->next_rb->id,
+		adreno_get_rptr(adreno_dev->next_rb),
+		adreno_dev->next_rb->wptr);
+
+	adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
+	adreno_dispatcher_schedule(device);
+}
+
+static void _a6xx_preemption_worker(struct work_struct *work)
+{
+	struct adreno_preemption *preempt = container_of(work,
+		struct adreno_preemption, work);
+	struct adreno_device *adreno_dev = container_of(preempt,
+		struct adreno_device, preempt);
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+	/* Need to take the mutex to make sure that the power stays on */
+	mutex_lock(&device->mutex);
+
+	if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_FAULTED))
+		_a6xx_preemption_fault(adreno_dev);
+
+	mutex_unlock(&device->mutex);
+}
+
+static void _a6xx_preemption_timer(unsigned long data)
+{
+	struct adreno_device *adreno_dev = (struct adreno_device *) data;
+
+	/* We should only be here from a triggered state */
+	if (!adreno_move_preempt_state(adreno_dev,
+		ADRENO_PREEMPT_TRIGGERED, ADRENO_PREEMPT_FAULTED))
+		return;
+
+	/* Schedule the worker to take care of the details */
+	queue_work(system_unbound_wq, &adreno_dev->preempt.work);
+}
+
+/* Find the highest priority active ringbuffer */
+static struct adreno_ringbuffer *a6xx_next_ringbuffer(
+		struct adreno_device *adreno_dev)
+{
+	struct adreno_ringbuffer *rb;
+	unsigned long flags;
+	unsigned int i;
+
+	FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+		bool empty;
+
+		spin_lock_irqsave(&rb->preempt_lock, flags);
+		empty = adreno_rb_empty(rb);
+		spin_unlock_irqrestore(&rb->preempt_lock, flags);
+
+		if (empty == false)
+			return rb;
+	}
+
+	return NULL;
+}
+
+void a6xx_preemption_trigger(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+	struct adreno_ringbuffer *next;
+	uint64_t ttbr0;
+	unsigned int contextidr;
+	unsigned long flags;
+	uint32_t preempt_level = 0, usesgmem = 1, skipsaverestore = 0;
+
+	/* Put ourselves into a possible trigger state */
+	if (!adreno_move_preempt_state(adreno_dev,
+		ADRENO_PREEMPT_NONE, ADRENO_PREEMPT_START))
+		return;
+
+	/* Get the next ringbuffer to preempt in */
+	next = a6xx_next_ringbuffer(adreno_dev);
+
+	/*
+	 * Nothing to do if every ringbuffer is empty or if the current
+	 * ringbuffer is the only active one
+	 */
+	if (next == NULL || next == adreno_dev->cur_rb) {
+		/*
+		 * Update any critical things that might have been skipped while
+		 * we were looking for a new ringbuffer
+		 */
+
+		if (next != NULL) {
+			_update_wptr(adreno_dev, false);
+
+			mod_timer(&adreno_dev->dispatcher.timer,
+				adreno_dev->cur_rb->dispatch_q.expires);
+		}
+
+		adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+		return;
+	}
+
+	/* Turn off the dispatcher timer */
+	del_timer(&adreno_dev->dispatcher.timer);
+
+	/*
+	 * This is the most critical section - we need to take care not to race
+	 * until we have programmed the CP for the switch
+	 */
+
+	spin_lock_irqsave(&next->preempt_lock, flags);
+
+	/*
+	 * Get the pagetable from the pagetable info.
+	 * The pagetable_desc is allocated and mapped at probe time, and
+	 * preemption_desc at init time, so no need to check if
+	 * sharedmem accesses to these memdescs succeed.
+	 */
+	kgsl_sharedmem_readq(&next->pagetable_desc, &ttbr0,
+		PT_INFO_OFFSET(ttbr0));
+	kgsl_sharedmem_readl(&next->pagetable_desc, &contextidr,
+		PT_INFO_OFFSET(contextidr));
+
+	kgsl_sharedmem_writel(device, &next->preemption_desc,
+		PREEMPT_RECORD(wptr), next->wptr);
+
+	spin_unlock_irqrestore(&next->preempt_lock, flags);
+
+	/* And write it to the smmu info */
+	kgsl_sharedmem_writeq(device, &iommu->smmu_info,
+		PREEMPT_SMMU_RECORD(ttbr0), ttbr0);
+	kgsl_sharedmem_writel(device, &iommu->smmu_info,
+		PREEMPT_SMMU_RECORD(context_idr), contextidr);
+
+	kgsl_regwrite(device,
+		A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO,
+		lower_32_bits(next->preemption_desc.gpuaddr));
+	kgsl_regwrite(device,
+		A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI,
+		upper_32_bits(next->preemption_desc.gpuaddr));
+
+	if (next->drawctxt_active) {
+		struct kgsl_context *context = &next->drawctxt_active->base;
+		uint64_t gpuaddr = context->user_ctxt_record->memdesc.gpuaddr;
+
+		kgsl_regwrite(device,
+			A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO,
+			lower_32_bits(gpuaddr));
+		kgsl_regwrite(device,
+			A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI,
+			upper_32_bits(gpuaddr));
+	}
+
+	adreno_dev->next_rb = next;
+
+	/* Start the timer to detect a stuck preemption */
+	mod_timer(&adreno_dev->preempt.timer,
+		jiffies + msecs_to_jiffies(ADRENO_PREEMPT_TIMEOUT));
+
+	trace_adreno_preempt_trigger(adreno_dev->cur_rb, adreno_dev->next_rb);
+
+	adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_TRIGGERED);
+
+	/* Trigger the preemption */
+	adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT,
+			((preempt_level << 6) & 0xC0) |
+			((skipsaverestore << 9) & 0x200) |
+			((usesgmem << 8) & 0x100) | 0x1);
+}
+
+void a6xx_preemption_callback(struct adreno_device *adreno_dev, int bit)
+{
+	unsigned int status;
+
+	if (!adreno_move_preempt_state(adreno_dev,
+		ADRENO_PREEMPT_TRIGGERED, ADRENO_PREEMPT_PENDING))
+		return;
+
+	adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &status);
+
+	if (status & 0x1) {
+		KGSL_DRV_ERR(KGSL_DEVICE(adreno_dev),
+			"preempt interrupt with non-zero status: %X\n", status);
+
+		/*
+		 * Under the assumption that this is a race between the
+		 * interrupt and the register, schedule the worker to clean up.
+		 * If the status still hasn't resolved itself by the time we get
+		 * there then we have to assume something bad happened
+		 */
+		adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_COMPLETE);
+		adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev));
+		return;
+	}
+
+	del_timer(&adreno_dev->preempt.timer);
+
+	trace_adreno_preempt_done(adreno_dev->cur_rb,
+		adreno_dev->next_rb);
+
+	adreno_dev->prev_rb = adreno_dev->cur_rb;
+	adreno_dev->cur_rb = adreno_dev->next_rb;
+	adreno_dev->next_rb = NULL;
+
+	/* Update the wptr if it changed while preemption was ongoing */
+	_update_wptr(adreno_dev, true);
+
+	/* Update the dispatcher timer for the new command queue */
+	mod_timer(&adreno_dev->dispatcher.timer,
+		adreno_dev->cur_rb->dispatch_q.expires);
+
+	adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+
+	a6xx_preemption_trigger(adreno_dev);
+}
+
+void a6xx_preemption_schedule(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+	if (!adreno_is_preemption_enabled(adreno_dev))
+		return;
+
+	mutex_lock(&device->mutex);
+
+	if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_COMPLETE))
+		_a6xx_preemption_done(adreno_dev);
+
+	a6xx_preemption_trigger(adreno_dev);
+
+	mutex_unlock(&device->mutex);
+}
+
+unsigned int a6xx_preemption_set_marker(unsigned int *cmds, int start)
+{
+	*cmds++ = cp_type7_packet(CP_SET_MARKER, 1);
+
+	/*
+	 * Indicate the beginning  and end of the IB1 list with a SET_MARKER.
+	 * Among other things, this will implicitly enable and disable
+	 * preemption respectively.
+	 */
+	if (start)
+		*cmds++ = 0xD;
+	else
+		*cmds++ = 0xE;
+
+	return 2;
+}
+
+unsigned int a6xx_preemption_pre_ibsubmit(
+		struct adreno_device *adreno_dev,
+		struct adreno_ringbuffer *rb,
+		unsigned int *cmds, struct kgsl_context *context)
+{
+	unsigned int *cmds_orig = cmds;
+
+	if (context)
+		*cmds++ = cp_type7_packet(CP_SET_PSEUDO_REGISTER, 15);
+	else
+		*cmds++ = cp_type7_packet(CP_SET_PSEUDO_REGISTER, 12);
+
+	/* NULL SMMU_INFO buffer - we track in KMD */
+	*cmds++ = SET_PSEUDO_REGISTER_SAVE_REGISTER_SMMU_INFO;
+	cmds += cp_gpuaddr(adreno_dev, cmds, 0x0);
+
+	*cmds++ = SET_PSEUDO_REGISTER_SAVE_REGISTER_PRIV_NON_SECURE_SAVE_ADDR;
+	cmds += cp_gpuaddr(adreno_dev, cmds, rb->preemption_desc.gpuaddr);
+
+	*cmds++ = SET_PSEUDO_REGISTER_SAVE_REGISTER_PRIV_SECURE_SAVE_ADDR;
+	cmds += cp_gpuaddr(adreno_dev, cmds, 0);
+
+	if (context) {
+		uint64_t gpuaddr = context->user_ctxt_record->memdesc.gpuaddr;
+
+		*cmds++ = SET_PSEUDO_REGISTER_SAVE_REGISTER_NON_PRIV_SAVE_ADDR;
+		cmds += cp_gpuaddr(adreno_dev, cmds, gpuaddr);
+	}
+
+	/*
+	 * There is no need to specify this address when we are about to
+	 * trigger preemption. This is because CP internally stores this
+	 * address specified here in the CP_SET_PSEUDO_REGISTER payload to
+	 * the context record and thus knows from where to restore
+	 * the saved perfcounters for the new ringbuffer.
+	 */
+	*cmds++ = SET_PSEUDO_REGISTER_SAVE_REGISTER_COUNTER;
+	cmds += cp_gpuaddr(adreno_dev, cmds,
+			rb->perfcounter_save_restore_desc.gpuaddr);
+
+	return (unsigned int) (cmds - cmds_orig);
+}
+
+unsigned int a6xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev,
+	unsigned int *cmds)
+{
+	unsigned int *cmds_orig = cmds;
+
+	*cmds++ = cp_type7_packet(CP_CONTEXT_SWITCH_YIELD, 4);
+	cmds += cp_gpuaddr(adreno_dev, cmds, 0x0);
+	*cmds++ = 1;
+	*cmds++ = 0;
+
+	return (unsigned int) (cmds - cmds_orig);
+}
+
+void a6xx_preemption_start(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+	struct adreno_ringbuffer *rb;
+	unsigned int i;
+
+	if (!adreno_is_preemption_enabled(adreno_dev))
+		return;
+
+	/* Force the state to be clear */
+	adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+
+	/* smmu_info is allocated and mapped in a6xx_preemption_iommu_init */
+	kgsl_sharedmem_writel(device, &iommu->smmu_info,
+		PREEMPT_SMMU_RECORD(magic), A6XX_CP_SMMU_INFO_MAGIC_REF);
+	kgsl_sharedmem_writeq(device, &iommu->smmu_info,
+		PREEMPT_SMMU_RECORD(ttbr0), MMU_DEFAULT_TTBR0(device));
+
+	/* The CP doesn't use the asid record, so poison it */
+	kgsl_sharedmem_writel(device, &iommu->smmu_info,
+		PREEMPT_SMMU_RECORD(asid), 0xDECAFBAD);
+	kgsl_sharedmem_writel(device, &iommu->smmu_info,
+		PREEMPT_SMMU_RECORD(context_idr),
+		MMU_DEFAULT_CONTEXTIDR(device));
+
+	adreno_writereg64(adreno_dev,
+		ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_LO,
+		ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI,
+		iommu->smmu_info.gpuaddr);
+
+	FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+		/*
+		 * preemption_desc is allocated and mapped at init time,
+		 * so no need to check sharedmem_writel return value
+		 */
+		kgsl_sharedmem_writel(device, &rb->preemption_desc,
+			PREEMPT_RECORD(rptr), 0);
+		kgsl_sharedmem_writel(device, &rb->preemption_desc,
+			PREEMPT_RECORD(wptr), 0);
+
+		adreno_ringbuffer_set_pagetable(rb,
+			device->mmu.defaultpagetable);
+	}
+}
+
+static int a6xx_preemption_ringbuffer_init(struct adreno_device *adreno_dev,
+	struct adreno_ringbuffer *rb, uint64_t counteraddr)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	int ret;
+
+	ret = kgsl_allocate_global(device, &rb->preemption_desc,
+		A6XX_CP_CTXRECORD_SIZE_IN_BYTES, 0, KGSL_MEMDESC_PRIVILEGED,
+		"preemption_desc");
+	if (ret)
+		return ret;
+
+	ret = kgsl_allocate_global(device, &rb->perfcounter_save_restore_desc,
+		A6XX_CP_PERFCOUNTER_SAVE_RESTORE_SIZE, 0,
+		KGSL_MEMDESC_PRIVILEGED, "perfcounter_save_restore_desc");
+	if (ret)
+		return ret;
+
+	kgsl_sharedmem_writel(device, &rb->preemption_desc,
+		PREEMPT_RECORD(magic), A6XX_CP_CTXRECORD_MAGIC_REF);
+	kgsl_sharedmem_writel(device, &rb->preemption_desc,
+		PREEMPT_RECORD(info), 0);
+	kgsl_sharedmem_writel(device, &rb->preemption_desc,
+		PREEMPT_RECORD(data), 0);
+	kgsl_sharedmem_writel(device, &rb->preemption_desc,
+		PREEMPT_RECORD(cntl), A6XX_CP_RB_CNTL_DEFAULT);
+	kgsl_sharedmem_writel(device, &rb->preemption_desc,
+		PREEMPT_RECORD(rptr), 0);
+	kgsl_sharedmem_writel(device, &rb->preemption_desc,
+		PREEMPT_RECORD(wptr), 0);
+	kgsl_sharedmem_writeq(device, &rb->preemption_desc,
+		PREEMPT_RECORD(rptr_addr), SCRATCH_RPTR_GPU_ADDR(device,
+		rb->id));
+	kgsl_sharedmem_writeq(device, &rb->preemption_desc,
+		PREEMPT_RECORD(rbase), rb->buffer_desc.gpuaddr);
+	kgsl_sharedmem_writeq(device, &rb->preemption_desc,
+		PREEMPT_RECORD(counter), counteraddr);
+
+	return 0;
+}
+
+#ifdef CONFIG_QCOM_KGSL_IOMMU
+static int a6xx_preemption_iommu_init(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+
+	/* Allocate mem for storing preemption smmu record */
+	return kgsl_allocate_global(device, &iommu->smmu_info, PAGE_SIZE,
+		KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED,
+		"smmu_info");
+}
+
+static void a6xx_preemption_iommu_close(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+
+	kgsl_free_global(device, &iommu->smmu_info);
+}
+#else
+static int a6xx_preemption_iommu_init(struct adreno_device *adreno_dev)
+{
+	return -ENODEV;
+}
+
+static void a6xx_preemption_iommu_close(struct adreno_device *adreno_dev)
+{
+}
+#endif
+
+static void a6xx_preemption_close(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_preemption *preempt = &adreno_dev->preempt;
+	struct adreno_ringbuffer *rb;
+	unsigned int i;
+
+	del_timer(&preempt->timer);
+	kgsl_free_global(device, &preempt->counters);
+	a6xx_preemption_iommu_close(adreno_dev);
+
+	FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+		kgsl_free_global(device, &rb->preemption_desc);
+		kgsl_free_global(device, &rb->perfcounter_save_restore_desc);
+	}
+}
+
+int a6xx_preemption_init(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	struct adreno_preemption *preempt = &adreno_dev->preempt;
+	struct adreno_ringbuffer *rb;
+	int ret;
+	unsigned int i;
+	uint64_t addr;
+
+	/* We are dependent on IOMMU to make preemption go on the CP side */
+	if (kgsl_mmu_get_mmutype(device) != KGSL_MMU_TYPE_IOMMU)
+		return -ENODEV;
+
+	INIT_WORK(&preempt->work, _a6xx_preemption_worker);
+
+	setup_timer(&preempt->timer, _a6xx_preemption_timer,
+		(unsigned long) adreno_dev);
+
+	/* Allocate mem for storing preemption counters */
+	ret = kgsl_allocate_global(device, &preempt->counters,
+		adreno_dev->num_ringbuffers *
+		A6XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0,
+		"preemption_counters");
+	if (ret)
+		goto err;
+
+	addr = preempt->counters.gpuaddr;
+
+	/* Allocate mem for storing preemption switch record */
+	FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+		ret = a6xx_preemption_ringbuffer_init(adreno_dev, rb, addr);
+		if (ret)
+			goto err;
+
+		addr += A6XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE;
+	}
+
+	ret = a6xx_preemption_iommu_init(adreno_dev);
+
+err:
+	if (ret)
+		a6xx_preemption_close(device);
+
+	return ret;
+}
+
+void a6xx_preemption_context_destroy(struct kgsl_context *context)
+{
+	struct kgsl_device *device = context->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	if (!adreno_is_preemption_enabled(adreno_dev))
+		return;
+
+	gpumem_free_entry(context->user_ctxt_record);
+}
+
+int a6xx_preemption_context_init(struct kgsl_context *context)
+{
+	struct kgsl_device *device = context->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	if (!adreno_is_preemption_enabled(adreno_dev))
+		return 0;
+
+	context->user_ctxt_record = gpumem_alloc_entry(context->dev_priv,
+			A6XX_CP_CTXRECORD_USER_RESTORE_SIZE, 0);
+	if (IS_ERR(context->user_ctxt_record)) {
+		int ret = PTR_ERR(context->user_ctxt_record);
+
+		context->user_ctxt_record = NULL;
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index bca3dd0..2161083 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -206,8 +206,38 @@
 };
 
 static const unsigned int a6xx_gmu_registers[] = {
-	/* GMU */
+	/* GMU GX */
+	0x1A800, 0x1A800, 0x1A810, 0x1A813, 0x1A816, 0x1A816, 0x1A818, 0x1A81B,
+	0x1A81E, 0x1A81E, 0x1A820, 0x1A823, 0x1A826, 0x1A826, 0x1A828, 0x1A82B,
+	0x1A82E, 0x1A82E, 0x1A830, 0x1A833, 0x1A836, 0x1A836, 0x1A838, 0x1A83B,
+	0x1A83E, 0x1A83E, 0x1A840, 0x1A843, 0x1A846, 0x1A846, 0x1A880, 0x1A884,
+	0x1A900, 0x1A92B, 0x1A940, 0x1A940,
+	/* GMU TCM */
 	0x1B400, 0x1C3FF, 0x1C400, 0x1D3FF,
+	/* GMU CX */
+	0x1F400, 0x1F407, 0x1F410, 0x1F412, 0x1F500, 0x1F500, 0x1F507, 0x1F50A,
+	0x1F800, 0x1F804, 0x1F807, 0x1F808, 0x1F80B, 0x1F80C, 0x1F80F, 0x1F81C,
+	0x1F824, 0x1F82A, 0x1F82D, 0x1F830, 0x1F840, 0x1F853, 0x1F887, 0x1F889,
+	0x1F8A0, 0x1F8A2, 0x1F8A4, 0x1F8AF, 0x1F8C0, 0x1F8C3, 0x1F8D0, 0x1F8D0,
+	0x1F8E4, 0x1F8E4, 0x1F8E8, 0x1F8EC, 0x1F900, 0x1F903, 0x1F940, 0x1F940,
+	0x1F942, 0x1F944, 0x1F94C, 0x1F94D, 0x1F94F, 0x1F951, 0x1F954, 0x1F954,
+	0x1F957, 0x1F958, 0x1F95D, 0x1F95D, 0x1F962, 0x1F962, 0x1F964, 0x1F965,
+	0x1F980, 0x1F986, 0x1F990, 0x1F99E, 0x1F9C0, 0x1F9C0, 0x1F9C5, 0x1F9CC,
+	0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA03,
+	/* GPU RSCC */
+	0x23740, 0x23742, 0x23744, 0x23747, 0x2374C, 0x23787, 0x237EC, 0x237EF,
+	0x237F4, 0x2382F, 0x23894, 0x23897, 0x2389C, 0x238D7, 0x2393C, 0x2393F,
+	0x23944, 0x2397F,
+	/* GMU AO */
+	0x23B00, 0x23B16, 0x23C00, 0x23C00,
+	/* GPU CC */
+	0x24000, 0x24012, 0x24040, 0x24052, 0x24400, 0x24404, 0x24407, 0x2440B,
+	0x24415, 0x2441C, 0x2441E, 0x2442D, 0x2443C, 0x2443D, 0x2443F, 0x24440,
+	0x24442, 0x24449, 0x24458, 0x2445A, 0x24540, 0x2455E, 0x24800, 0x24802,
+	0x24C00, 0x24C02, 0x25400, 0x25402, 0x25800, 0x25802, 0x25C00, 0x25C02,
+	0x26000, 0x26002,
+	/* GPU CC ACD */
+	0x26400, 0x26416, 0x26420, 0x26427,
 };
 
 static const struct adreno_vbif_snapshot_registers
@@ -227,16 +257,17 @@
 	0x0000, 0x0002, 0x0010, 0x0010, 0x0012, 0x0012, 0x0018, 0x001B,
 	0x001e, 0x0032, 0x0038, 0x003C, 0x0042, 0x0042, 0x0044, 0x0044,
 	0x0047, 0x0047, 0x0056, 0x0056, 0x00AD, 0x00AE, 0x00B0, 0x00FB,
-	0x0100, 0x011D, 0x0200, 0x020D, 0x0210, 0x0213, 0x0218, 0x023D,
-	0x0400, 0x04F9, 0x0500, 0x0500, 0x0505, 0x050B, 0x050E, 0x0511,
-	0x0533, 0x0533, 0x0540, 0x0555,
+	0x0100, 0x011D, 0x0200, 0x020D, 0x0218, 0x023D, 0x0400, 0x04F9,
+	0x0500, 0x0500, 0x0505, 0x050B, 0x050E, 0x0511, 0x0533, 0x0533,
+	0x0540, 0x0555,
 	/* CP */
-	0x0800, 0x0808, 0x0810, 0x0813, 0x0820, 0x0821, 0x0823, 0x0827,
-	0x0830, 0x0833, 0x0840, 0x0843, 0x084F, 0x086F, 0x0880, 0x088A,
-	0x08A0, 0x08AB, 0x08C0, 0x08C4, 0x08D0, 0x08DD, 0x08F0, 0x08F3,
-	0x0900, 0x0903, 0x0908, 0x0911, 0x0928, 0x093E, 0x0942, 0x094D,
-	0x0980, 0x0984, 0x098D, 0x0996, 0x0998, 0x099E, 0x09A0, 0x09A6,
-	0x09A8, 0x09AE, 0x09B0, 0x09B1, 0x09C2, 0x09C8, 0x0A00, 0x0A03,
+	0x0800, 0x0808, 0x0810, 0x0813, 0x0820, 0x0821, 0x0823, 0x0824,
+	0x0826, 0x0827, 0x0830, 0x0833, 0x0840, 0x0843, 0x084F, 0x086F,
+	0x0880, 0x088A, 0x08A0, 0x08AB, 0x08C0, 0x08C4, 0x08D0, 0x08DD,
+	0x08F0, 0x08F3, 0x0900, 0x0903, 0x0908, 0x0911, 0x0928, 0x093E,
+	0x0942, 0x094D, 0x0980, 0x0984, 0x098D, 0x0996, 0x0998, 0x099E,
+	0x09A0, 0x09A6, 0x09A8, 0x09AE, 0x09B0, 0x09B1, 0x09C2, 0x09C8,
+	0x0A00, 0x0A03,
 	/* VSC */
 	0x0C00, 0x0C04, 0x0C06, 0x0C06, 0x0C10, 0x0CD9, 0x0E00, 0x0E0E,
 	/* UCHE */
@@ -260,6 +291,18 @@
 	0xA630, 0xA630,
 };
 
+/*
+ * Set of registers to dump for A6XX before actually triggering crash dumper.
+ * Registers in pairs - first value is the start offset, second
+ * is the stop offset (inclusive)
+ */
+static const unsigned int a6xx_pre_crashdumper_registers[] = {
+	/* RBBM: RBBM_STATUS - RBBM_STATUS3 */
+	0x210, 0x213,
+	/* CP: CP_STATUS_1 */
+	0x825, 0x825,
+};
+
 enum a6xx_debugbus_id {
 	A6XX_DBGBUS_CP           = 0x1,
 	A6XX_DBGBUS_RBBM         = 0x2,
@@ -532,6 +575,17 @@
 	return (count * 8) + sizeof(*header);
 }
 
+static size_t a6xx_snapshot_pre_crashdump_regs(struct kgsl_device *device,
+		u8 *buf, size_t remain, void *priv)
+{
+	struct kgsl_snapshot_registers pre_cdregs = {
+			.regs = a6xx_pre_crashdumper_registers,
+			.count = ARRAY_SIZE(a6xx_pre_crashdumper_registers)/2,
+	};
+
+	return kgsl_snapshot_dump_registers(device, buf, remain, &pre_cdregs);
+}
+
 static size_t a6xx_snapshot_shader_memory(struct kgsl_device *device,
 		u8 *buf, size_t remain, void *priv)
 {
@@ -1355,16 +1409,21 @@
 	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
 	struct adreno_snapshot_data *snap_data = gpudev->snapshot_data;
 
+	/* Dump the registers which get affected by crash dumper trigger */
+	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
+		snapshot, a6xx_snapshot_pre_crashdump_regs, NULL);
+
+	/* Dump vbif registers as well which get affected by crash dumper */
+	adreno_snapshot_vbif_registers(device, snapshot,
+		a6xx_vbif_snapshot_registers,
+		ARRAY_SIZE(a6xx_vbif_snapshot_registers));
+
 	/* Try to run the crash dumper */
 	_a6xx_do_crashdump(device);
 
 	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
 		snapshot, a6xx_snapshot_registers, NULL);
 
-	adreno_snapshot_vbif_registers(device, snapshot,
-		a6xx_vbif_snapshot_registers,
-		ARRAY_SIZE(a6xx_vbif_snapshot_registers));
-
 	/* CP_SQE indexed registers */
 	kgsl_snapshot_indexed_registers(device, snapshot,
 		A6XX_CP_SQE_STAT_ADDR, A6XX_CP_SQE_STAT_DATA,
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index f217822..c6df7bb 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -341,6 +341,7 @@
 	struct adreno_context *drawctxt;
 	struct kgsl_device *device = dev_priv->device;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
 	int ret;
 	unsigned int local;
 
@@ -421,6 +422,16 @@
 		return ERR_PTR(ret);
 	}
 
+	if (gpudev->preemption_context_init) {
+		ret = gpudev->preemption_context_init(&drawctxt->base);
+		if (ret != 0) {
+			kgsl_context_detach(&drawctxt->base);
+			kgsl_context_put(&drawctxt->base);
+			kfree(drawctxt);
+			return ERR_PTR(ret);
+		}
+	}
+
 	kgsl_sharedmem_writel(device, &device->memstore,
 			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
 			0);
@@ -545,10 +556,18 @@
 void adreno_drawctxt_destroy(struct kgsl_context *context)
 {
 	struct adreno_context *drawctxt;
+	struct adreno_device *adreno_dev;
+	struct adreno_gpudev *gpudev;
 
 	if (context == NULL)
 		return;
 
+	adreno_dev = ADRENO_DEVICE(context->device);
+	gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+
+	if (gpudev->preemption_context_destroy)
+		gpudev->preemption_context_destroy(context);
+
 	drawctxt = ADRENO_CONTEXT(context);
 	debugfs_remove_recursive(drawctxt->debug_root);
 	kfree(drawctxt);
diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c
index 80a04bc..1a2f8ff 100644
--- a/drivers/gpu/msm/adreno_iommu.c
+++ b/drivers/gpu/msm/adreno_iommu.c
@@ -574,6 +574,40 @@
 	return cmds - cmds_orig;
 }
 
+static unsigned int _adreno_iommu_set_pt_v2_a6xx(struct kgsl_device *device,
+					unsigned int *cmds_orig,
+					u64 ttbr0, u32 contextidr,
+					struct adreno_ringbuffer *rb,
+					unsigned int cb_num)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	unsigned int *cmds = cmds_orig;
+
+	cmds += _adreno_iommu_add_idle_cmds(adreno_dev, cmds);
+	cmds += cp_wait_for_me(adreno_dev, cmds);
+
+	/* CP switches the pagetable and flushes the Caches */
+	*cmds++ = cp_packet(adreno_dev, CP_SMMU_TABLE_UPDATE, 4);
+	*cmds++ = lower_32_bits(ttbr0);
+	*cmds++ = upper_32_bits(ttbr0);
+	*cmds++ = contextidr;
+	*cmds++ = cb_num;
+
+	*cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 4, 1);
+	cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr +
+		PT_INFO_OFFSET(ttbr0)));
+	*cmds++ = lower_32_bits(ttbr0);
+	*cmds++ = upper_32_bits(ttbr0);
+	*cmds++ = contextidr;
+
+	/* release all commands with wait_for_me */
+	cmds += cp_wait_for_me(adreno_dev, cmds);
+
+	cmds += _adreno_iommu_add_idle_cmds(adreno_dev, cmds);
+
+	return cmds - cmds_orig;
+}
+
 /**
  * adreno_iommu_set_pt_generate_cmds() - Generate commands to change pagetable
  * @rb: The RB pointer in which these commaands are to be submitted
@@ -588,6 +622,7 @@
 	struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+	struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER];
 	u64 ttbr0;
 	u32 contextidr;
 	unsigned int *cmds_orig = cmds;
@@ -601,7 +636,11 @@
 		iommu->setstate.gpuaddr + KGSL_IOMMU_SETSTATE_NOP_OFFSET);
 
 	if (iommu->version >= 2) {
-		if (adreno_is_a5xx(adreno_dev) || adreno_is_a6xx(adreno_dev))
+		if (adreno_is_a6xx(adreno_dev))
+			cmds += _adreno_iommu_set_pt_v2_a6xx(device, cmds,
+						ttbr0, contextidr, rb,
+						ctx->cb_num);
+		else if (adreno_is_a5xx(adreno_dev))
 			cmds += _adreno_iommu_set_pt_v2_a5xx(device, cmds,
 						ttbr0, contextidr, rb);
 		else if (adreno_is_a4xx(adreno_dev))
diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c
index cd95003..0da4da9 100644
--- a/drivers/gpu/msm/adreno_perfcounter.c
+++ b/drivers/gpu/msm/adreno_perfcounter.c
@@ -654,7 +654,7 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct adreno_perfcount_register *reg;
-	unsigned int shift = counter << 3;
+	unsigned int shift = (counter << 3) % (sizeof(unsigned int) * 8);
 
 	if (adreno_is_a530(adreno_dev)) {
 		if (countable > 43)
@@ -662,13 +662,16 @@
 	} else if (adreno_is_a540(adreno_dev)) {
 		if (countable > 47)
 			return;
+	} else if (adreno_is_a6xx(adreno_dev)) {
+		if (countable > 34)
+			return;
 	} else
 		/* return on platforms that have no GPMU */
 		return;
 
 	reg = &counters->groups[group].regs[counter];
 	kgsl_regrmw(device, reg->select, 0xff << shift, countable << shift);
-	kgsl_regwrite(device, A5XX_GPMU_POWER_COUNTER_ENABLE, 1);
+	adreno_writereg(adreno_dev, ADRENO_REG_GPMU_POWER_COUNTER_ENABLE, 1);
 	reg->value = 0;
 }
 
@@ -684,7 +687,7 @@
 
 	reg = &counters->groups[group].regs[counter];
 	kgsl_regwrite(device, reg->select, countable);
-	kgsl_regwrite(device, A5XX_GPMU_POWER_COUNTER_ENABLE, 1);
+	adreno_writereg(adreno_dev, ADRENO_REG_GPMU_POWER_COUNTER_ENABLE, 1);
 	reg->value = 0;
 }
 
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index fceceda..2a330b4 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -55,6 +55,12 @@
 /* switches SMMU pagetable, used on a5xx only */
 #define CP_SMMU_TABLE_UPDATE 0x53
 
+/*  Set internal CP registers, used to indicate context save data addresses */
+#define CP_SET_PSEUDO_REGISTER      0x56
+
+/* Tell CP the current operation mode, indicates save and restore procedure */
+#define CP_SET_MARKER  0x65
+
 /* register read/modify/write */
 #define CP_REG_RMW		0x21
 
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index bff1fda..15c68fb 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -864,9 +864,12 @@
 			dwords += 2;
 	}
 
-	if (gpudev->preemption_yield_enable &&
-				adreno_is_preemption_enabled(adreno_dev))
-		dwords += 8;
+	if (adreno_is_preemption_enabled(adreno_dev)) {
+		if (gpudev->preemption_set_marker)
+			dwords += 4;
+		else if (gpudev->preemption_yield_enable)
+			dwords += 8;
+	}
 
 	link = kcalloc(dwords, sizeof(unsigned int), GFP_KERNEL);
 	if (!link) {
@@ -897,6 +900,10 @@
 			gpu_ticks_submitted));
 	}
 
+	if (gpudev->preemption_set_marker &&
+			adreno_is_preemption_enabled(adreno_dev))
+		cmds += gpudev->preemption_set_marker(cmds, 1);
+
 	if (numibs) {
 		list_for_each_entry(ib, &cmdobj->cmdlist, node) {
 			/*
@@ -918,9 +925,12 @@
 		}
 	}
 
-	if (gpudev->preemption_yield_enable &&
-				adreno_is_preemption_enabled(adreno_dev))
-		cmds += gpudev->preemption_yield_enable(cmds);
+	if (adreno_is_preemption_enabled(adreno_dev)) {
+		if (gpudev->preemption_set_marker)
+			cmds += gpudev->preemption_set_marker(cmds, 0);
+		else if (gpudev->preemption_yield_enable)
+			cmds += gpudev->preemption_yield_enable(cmds);
+	}
 
 	if (kernel_profiling) {
 		cmds += _get_alwayson_counter(adreno_dev, cmds,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 63374af..72fc5bf3 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2017, 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
@@ -92,6 +92,8 @@
  * @drawctxt_active: The last pagetable that this ringbuffer is set to
  * @preemption_desc: The memory descriptor containing
  * preemption info written/read by CP
+ * @perfcounter_save_restore_desc: Used by CP to save/restore the perfcounter
+ * values across preemption
  * @pagetable_desc: Memory to hold information about the pagetables being used
  * and the commands to switch pagetable on the RB
  * @dispatch_q: The dispatcher side queue for this ringbuffer
@@ -118,6 +120,7 @@
 	struct kgsl_event_group events;
 	struct adreno_context *drawctxt_active;
 	struct kgsl_memdesc preemption_desc;
+	struct kgsl_memdesc perfcounter_save_restore_desc;
 	struct kgsl_memdesc pagetable_desc;
 	struct adreno_dispatcher_drawqueue dispatch_q;
 	wait_queue_head_t ts_expire_waitq;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 6a39792..4e67efb 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -43,7 +43,6 @@
 #include "kgsl_sync.h"
 #include "kgsl_compat.h"
 #include "kgsl_pool.h"
-#include "adreno.h"
 
 #undef MODULE_PARAM_PREFIX
 #define MODULE_PARAM_PREFIX "kgsl."
@@ -246,8 +245,6 @@
 }
 EXPORT_SYMBOL(kgsl_readtimestamp);
 
-static long gpumem_free_entry(struct kgsl_mem_entry *entry);
-
 /* Scheduled by kgsl_mem_entry_put_deferred() */
 static void _deferred_put(struct work_struct *work)
 {
@@ -257,13 +254,6 @@
 	kgsl_mem_entry_put(entry);
 }
 
-static inline void
-kgsl_mem_entry_put_deferred(struct kgsl_mem_entry *entry)
-{
-	if (entry)
-		queue_work(kgsl_driver.mem_workqueue, &entry->work);
-}
-
 static inline struct kgsl_mem_entry *
 kgsl_mem_entry_create(void)
 {
@@ -273,7 +263,6 @@
 		kref_init(&entry->refcount);
 		/* put this ref in userspace memory alloc and map ioctls */
 		kref_get(&entry->refcount);
-		INIT_WORK(&entry->work, _deferred_put);
 	}
 
 	return entry;
@@ -580,8 +569,10 @@
 	context->tid = task_pid_nr(current);
 
 	ret = kgsl_sync_timeline_create(context);
-	if (ret)
+	if (ret) {
+		kgsl_process_private_put(dev_priv->process_priv);
 		goto out;
+	}
 
 	snprintf(name, sizeof(name), "context-%d", id);
 	kgsl_add_event_group(&context->events, context, name,
@@ -609,7 +600,7 @@
  * detached by checking the KGSL_CONTEXT_PRIV_DETACHED bit in
  * context->priv.
  */
-static void kgsl_context_detach(struct kgsl_context *context)
+void kgsl_context_detach(struct kgsl_context *context)
 {
 	struct kgsl_device *device;
 
@@ -1054,10 +1045,7 @@
 	int result = 0;
 
 	mutex_lock(&device->mutex);
-
-	if (!adreno_is_a6xx(ADRENO_DEVICE(device)))
-		device->open_count--;
-
+	device->open_count--;
 	if (device->open_count == 0) {
 
 		/* Wait for the active count to go to 0 */
@@ -1816,7 +1804,7 @@
 	return 0;
 }
 
-static long gpumem_free_entry(struct kgsl_mem_entry *entry)
+long gpumem_free_entry(struct kgsl_mem_entry *entry)
 {
 	pid_t ptname = 0;
 
@@ -1886,7 +1874,7 @@
 		return -EINVAL;
 
 	ret = gpumem_free_entry(entry);
-	kgsl_mem_entry_put_deferred(entry);
+	kgsl_mem_entry_put(entry);
 
 	return ret;
 }
@@ -1904,7 +1892,7 @@
 		return -EINVAL;
 
 	ret = gpumem_free_entry(entry);
-	kgsl_mem_entry_put_deferred(entry);
+	kgsl_mem_entry_put(entry);
 
 	return ret;
 }
@@ -1941,7 +1929,8 @@
 {
 	struct kgsl_mem_entry *entry = priv;
 
-	kgsl_mem_entry_put_deferred(entry);
+	INIT_WORK(&entry->work, _deferred_put);
+	queue_work(kgsl_driver.mem_workqueue, &entry->work);
 }
 
 static long gpuobj_free_on_fence(struct kgsl_device_private *dev_priv,
@@ -2005,7 +1994,7 @@
 	else
 		ret = -EINVAL;
 
-	kgsl_mem_entry_put_deferred(entry);
+	kgsl_mem_entry_put(entry);
 	return ret;
 }
 
@@ -3058,7 +3047,7 @@
 /* The largest allowable alignment for a GPU object is 32MB */
 #define KGSL_MAX_ALIGN (32 * SZ_1M)
 
-static struct kgsl_mem_entry *gpumem_alloc_entry(
+struct kgsl_mem_entry *gpumem_alloc_entry(
 		struct kgsl_device_private *dev_priv,
 		uint64_t size, uint64_t flags)
 {
@@ -3385,13 +3374,7 @@
 	if (entry == NULL)
 		return -EINVAL;
 
-	if (!kgsl_mem_entry_set_pend(entry)) {
-		kgsl_mem_entry_put(entry);
-		return -EBUSY;
-	}
-
 	if (entry->memdesc.cur_bindings != 0) {
-		kgsl_mem_entry_unset_pend(entry);
 		kgsl_mem_entry_put(entry);
 		return -EINVAL;
 	}
@@ -3400,7 +3383,7 @@
 
 	/* One put for find_id(), one put for the kgsl_mem_entry_create() */
 	kgsl_mem_entry_put(entry);
-	kgsl_mem_entry_put_deferred(entry);
+	kgsl_mem_entry_put(entry);
 
 	return 0;
 }
@@ -3460,13 +3443,7 @@
 	if (entry == NULL)
 		return -EINVAL;
 
-	if (!kgsl_mem_entry_set_pend(entry)) {
-		kgsl_mem_entry_put(entry);
-		return -EBUSY;
-	}
-
 	if (entry->bind_tree.rb_node != NULL) {
-		kgsl_mem_entry_unset_pend(entry);
 		kgsl_mem_entry_put(entry);
 		return -EINVAL;
 	}
@@ -3475,7 +3452,7 @@
 
 	/* One put for find_id(), one put for the kgsl_mem_entry_create() */
 	kgsl_mem_entry_put(entry);
-	kgsl_mem_entry_put_deferred(entry);
+	kgsl_mem_entry_put(entry);
 
 	return 0;
 }
@@ -4873,7 +4850,7 @@
 		WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0);
 
 	kgsl_driver.mem_workqueue = alloc_workqueue("kgsl-mementry",
-		WQ_MEM_RECLAIM, 0);
+		WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
 
 	kgsl_events_init();
 
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 3f1c86e..c54e51e 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -445,6 +445,10 @@
 int kgsl_suspend_driver(struct platform_device *pdev, pm_message_t state);
 int kgsl_resume_driver(struct platform_device *pdev);
 
+struct kgsl_mem_entry *gpumem_alloc_entry(struct kgsl_device_private *dev_priv,
+				uint64_t size, uint64_t flags);
+long gpumem_free_entry(struct kgsl_mem_entry *entry);
+
 static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
 				uint64_t gpuaddr, uint64_t size)
 {
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index ca1f181..b621ada 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -378,6 +378,8 @@
  * @pwr_constraint: power constraint from userspace for this context
  * @fault_count: number of times gpu hanged in last _context_throttle_time ms
  * @fault_time: time of the first gpu hang in last _context_throttle_time ms
+ * @user_ctxt_record: memory descriptor used by CP to save/restore VPC data
+ * across preemption
  */
 struct kgsl_context {
 	struct kref refcount;
@@ -395,6 +397,7 @@
 	struct kgsl_pwr_constraint pwr_constraint;
 	unsigned int fault_count;
 	unsigned long fault_time;
+	struct kgsl_mem_entry *user_ctxt_record;
 };
 
 #define _context_comm(_c) \
@@ -689,6 +692,8 @@
 void kgsl_events_init(void);
 void kgsl_events_exit(void);
 
+void kgsl_context_detach(struct kgsl_context *context);
+
 void kgsl_del_event_group(struct kgsl_event_group *group);
 
 void kgsl_add_event_group(struct kgsl_event_group *group,
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index f87e4da..c9f1483 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1202,14 +1202,16 @@
 static int gmu_disable_clks(struct gmu_device *gmu)
 {
 	int ret, j = 0;
+	unsigned int gmu_freq;
 
 	if (IS_ERR_OR_NULL(gmu->clks[0]))
 		return 0;
 
-	ret = clk_set_rate(gmu->clks[0], gmu->gmu_freqs[0]);
+	gmu_freq = gmu->gmu_freqs[gmu->num_gmupwrlevels - 1];
+	ret = clk_set_rate(gmu->clks[0], gmu_freq);
 	if (ret) {
 		dev_err(&gmu->pdev->dev, "fail to reset GMU clk freq %d\n",
-				gmu->gmu_freqs[0]);
+				gmu_freq);
 		return ret;
 	}
 
@@ -1238,19 +1240,38 @@
 	return ret;
 }
 
+#define CX_GDSC_TIMEOUT	500	/* ms */
 static int gmu_disable_gdsc(struct gmu_device *gmu)
 {
 	int ret;
+	unsigned long t;
 
 	if (IS_ERR_OR_NULL(gmu->cx_gdsc))
 		return 0;
 
 	ret = regulator_disable(gmu->cx_gdsc);
-	if (ret)
+	if (ret) {
 		dev_err(&gmu->pdev->dev,
 			"Failed to disable GMU CX gdsc, error %d\n", ret);
+		return ret;
+	}
 
-	return ret;
+	/*
+	 * After GX GDSC is off, CX GDSC must be off
+	 * Voting off alone from GPU driver cannot
+	 * Guarantee CX GDSC off. Polling with 10ms
+	 * timeout to ensure
+	 */
+	t = jiffies + msecs_to_jiffies(CX_GDSC_TIMEOUT);
+	do {
+		if (!regulator_is_enabled(gmu->cx_gdsc))
+			return 0;
+		cond_resched();
+
+	} while (!(time_after(jiffies, t)));
+
+	dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout");
+	return -ETIMEDOUT;
 }
 
 static int gmu_fast_boot(struct kgsl_device *device)
@@ -1399,7 +1420,7 @@
 
 			gmu_irq_enable(device);
 
-			ret = hfi_start(gmu, GMU_WARM_BOOT);
+			ret = hfi_start(gmu, GMU_COLD_BOOT);
 			if (ret)
 				goto error_gpu;
 
diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c
index b05e18d..cc878aa 100644
--- a/drivers/gpu/msm/kgsl_hfi.c
+++ b/drivers/gpu/msm/kgsl_hfi.c
@@ -177,6 +177,7 @@
 {
 	struct kgsl_hfi *hfi = &gmu->hfi;
 	struct pending_msg *msg = NULL, *next;
+	bool in_queue = false;
 
 	trace_kgsl_hfi_receive(rsp->ret_hdr.id,
 		rsp->ret_hdr.size,
@@ -186,13 +187,13 @@
 	list_for_each_entry_safe(msg, next, &hfi->msglist, node) {
 		if (msg->msg_id == rsp->ret_hdr.id &&
 				msg->seqnum == rsp->ret_hdr.seqnum) {
-			list_del(&msg->node);
+			in_queue = true;
 			break;
 		}
 	}
-	spin_unlock(&hfi->msglock);
 
-	if (msg == NULL) {
+	if (in_queue == false) {
+		spin_unlock(&hfi->msglock);
 		dev_err(&gmu->pdev->dev,
 				"Cannot find receiver of ack msg with id=%d\n",
 				rsp->ret_hdr.id);
@@ -201,6 +202,7 @@
 
 	memcpy(&msg->results, (void *) rsp, rsp->hdr.size << 2);
 	complete(&msg->msg_complete);
+	spin_unlock(&hfi->msglock);
 }
 
 static void receive_err_msg(struct gmu_device *gmu, struct hfi_msg_rsp *rsp)
@@ -235,7 +237,7 @@
 
 	if (hfi_cmdq_write(gmu, HFI_CMD_QUEUE, msg) != size) {
 		rc = -EINVAL;
-		goto error;
+		goto done;
 	}
 
 	rc = wait_for_completion_timeout(
@@ -245,11 +247,12 @@
 		dev_err(&gmu->pdev->dev,
 				"Receiving GMU ack %d timed out\n", msg->id);
 		rc = -ETIMEDOUT;
-		goto error;
+		goto done;
 	}
 
-	return 0;
-error:
+	/* If we got here we succeeded */
+	rc = 0;
+done:
 	spin_lock(&hfi->msglock);
 	list_del(&ret_msg->node);
 	spin_unlock(&hfi->msglock);
diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/kgsl_hfi.h
index 83abec4..47d07d9 100644
--- a/drivers/gpu/msm/kgsl_hfi.h
+++ b/drivers/gpu/msm/kgsl_hfi.h
@@ -115,7 +115,7 @@
 	HFI_F2H_QPRI_DEBUG = 40,
 };
 
-#define HFI_RSP_TIMEOUT 50 /* msec */
+#define HFI_RSP_TIMEOUT 500 /* msec */
 #define HFI_H2F_CMD_IRQ_MASK BIT(0)
 
 enum hfi_msg_type {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 938c96d..73c0d71 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -22,7 +22,6 @@
 #include <linux/of_platform.h>
 #include <soc/qcom/scm.h>
 #include <soc/qcom/secure_buffer.h>
-#include <stddef.h>
 #include <linux/compat.h>
 
 #include "kgsl.h"
@@ -1256,7 +1255,7 @@
 	ret = iommu_domain_get_attr(iommu_pt->domain,
 				DOMAIN_ATTR_CONTEXT_BANK, &cb_num);
 	if (ret) {
-		KGSL_CORE_ERR("get DOMAIN_ATTR_PROCID failed: %d\n",
+		KGSL_CORE_ERR("get DOMAIN_ATTR_CONTEXT_BANK failed: %d\n",
 				ret);
 		goto done;
 	}
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index 6337a48..acf8ae4 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -23,7 +23,7 @@
  * These defines control the address range for allocations that
  * are mapped into all pagetables.
  */
-#define KGSL_IOMMU_GLOBAL_MEM_SIZE	SZ_8M
+#define KGSL_IOMMU_GLOBAL_MEM_SIZE	(20 * SZ_1M)
 #define KGSL_IOMMU_GLOBAL_MEM_BASE	0xf8000000
 
 #define KGSL_IOMMU_SECURE_SIZE SZ_256M
diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c
index bb92b8b..c31a85b 100644
--- a/drivers/gpu/msm/kgsl_pool.c
+++ b/drivers/gpu/msm/kgsl_pool.c
@@ -280,6 +280,17 @@
 	return -ENOMEM;
 }
 
+static int kgsl_pool_get_retry_order(unsigned int order)
+{
+	int i;
+
+	for (i = kgsl_num_pools-1; i > 0; i--)
+		if (order >= kgsl_pools[i].pool_order)
+			return kgsl_pools[i].pool_order;
+
+	return 0;
+}
+
 /**
  * kgsl_pool_alloc_page() - Allocate a page of requested size
  * @page_size: Size of the page to be allocated
@@ -326,7 +337,7 @@
 	if (pool == NULL) {
 		/* Retry with lower order pages */
 		if (order > 0) {
-			size = PAGE_SIZE << --order;
+			size = PAGE_SIZE << kgsl_pool_get_retry_order(order);
 			goto eagain;
 		} else {
 			/*
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 4dd7b8e..5c53a05c 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2740,7 +2740,8 @@
 	int ret = 0;
 
 	if ((device->state == KGSL_STATE_NONE) ||
-			(device->state == KGSL_STATE_INIT))
+			(device->state == KGSL_STATE_INIT) ||
+			(device->state == KGSL_STATE_SUSPEND))
 		return ret;
 
 	/* drain to prevent from more commands being submitted */
@@ -2807,6 +2808,7 @@
 		break;
 	case KGSL_STATE_SUSPEND:
 		status = _suspend(device);
+		break;
 	case KGSL_STATE_RESET:
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_RESET);
 		break;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 73e6c53..f0f202b 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -20,6 +20,7 @@
 #include <linux/scatterlist.h>
 #include <soc/qcom/scm.h>
 #include <soc/qcom/secure_buffer.h>
+#include <linux/ratelimit.h>
 
 #include "kgsl.h"
 #include "kgsl_sharedmem.h"
@@ -560,16 +561,74 @@
 }
 #endif
 
+static inline void _cache_op(unsigned int op,
+			const void *start, const void *end)
+{
+	/*
+	 * The dmac_xxx_range functions handle addresses and sizes that
+	 * are not aligned to the cacheline size correctly.
+	 */
+	switch (_fixup_cache_range_op(op)) {
+	case KGSL_CACHE_OP_FLUSH:
+		dmac_flush_range(start, end);
+		break;
+	case KGSL_CACHE_OP_CLEAN:
+		dmac_clean_range(start, end);
+		break;
+	case KGSL_CACHE_OP_INV:
+		dmac_inv_range(start, end);
+		break;
+	}
+}
+
+static int kgsl_do_cache_op(struct page *page, void *addr,
+		uint64_t offset, uint64_t size, unsigned int op)
+{
+	if (page != NULL) {
+		unsigned long pfn = page_to_pfn(page) + offset / PAGE_SIZE;
+		/*
+		 *  page_address() returns the kernel virtual address of page.
+		 *  For high memory kernel virtual address exists only if page
+		 *  has been mapped. So use a version of kmap rather than
+		 *  page_address() for high memory.
+		 */
+		if (PageHighMem(page)) {
+			offset &= ~PAGE_MASK;
+
+			do {
+				unsigned int len = size;
+
+				if (len + offset > PAGE_SIZE)
+					len = PAGE_SIZE - offset;
+
+				page = pfn_to_page(pfn++);
+				addr = kmap_atomic(page);
+				_cache_op(op, addr + offset,
+						addr + offset + len);
+				kunmap_atomic(addr);
+
+				size -= len;
+				offset = 0;
+			} while (size);
+
+			return 0;
+		}
+
+		addr = page_address(page);
+	}
+
+	_cache_op(op, addr + offset, addr + offset + (size_t) size);
+	return 0;
+}
+
 int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
 		uint64_t size, unsigned int op)
 {
-	/*
-	 * If the buffer is mapped in the kernel operate on that address
-	 * otherwise use the user address
-	 */
-
-	void *addr = (memdesc->hostptr) ?
-		memdesc->hostptr : (void *) memdesc->useraddr;
+	void *addr = NULL;
+	struct sg_table *sgt = NULL;
+	struct scatterlist *sg;
+	unsigned int i, pos = 0;
+	int ret = 0;
 
 	if (size == 0 || size > UINT_MAX)
 		return -EINVAL;
@@ -578,38 +637,57 @@
 	if ((offset + size < offset) || (offset + size < size))
 		return -ERANGE;
 
-	/* Make sure the offset + size do not overflow the address */
-	if (addr + ((size_t) offset + (size_t) size) < addr)
-		return -ERANGE;
-
 	/* Check that offset+length does not exceed memdesc->size */
 	if (offset + size > memdesc->size)
 		return -ERANGE;
 
-	/* Return quietly if the buffer isn't mapped on the CPU */
-	if (addr == NULL)
-		return 0;
+	if (memdesc->hostptr) {
+		addr = memdesc->hostptr;
+		/* Make sure the offset + size do not overflow the address */
+		if (addr + ((size_t) offset + (size_t) size) < addr)
+			return -ERANGE;
 
-	addr = addr + offset;
-
-	/*
-	 * The dmac_xxx_range functions handle addresses and sizes that
-	 * are not aligned to the cacheline size correctly.
-	 */
-
-	switch (_fixup_cache_range_op(op)) {
-	case KGSL_CACHE_OP_FLUSH:
-		dmac_flush_range(addr, addr + (size_t) size);
-		break;
-	case KGSL_CACHE_OP_CLEAN:
-		dmac_clean_range(addr, addr + (size_t) size);
-		break;
-	case KGSL_CACHE_OP_INV:
-		dmac_inv_range(addr, addr + (size_t) size);
-		break;
+		ret = kgsl_do_cache_op(NULL, addr, offset, size, op);
+		return ret;
 	}
 
-	return 0;
+	/*
+	 * If the buffer is not to mapped to kernel, perform cache
+	 * operations after mapping to kernel.
+	 */
+	if (memdesc->sgt != NULL)
+		sgt = memdesc->sgt;
+	else {
+		if (memdesc->pages == NULL)
+			return ret;
+
+		sgt = kgsl_alloc_sgt_from_pages(memdesc);
+		if (IS_ERR(sgt))
+			return PTR_ERR(sgt);
+	}
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		uint64_t sg_offset, sg_left;
+
+		if (offset >= (pos + sg->length)) {
+			pos += sg->length;
+			continue;
+		}
+		sg_offset = offset > pos ? offset - pos : 0;
+		sg_left = (sg->length - sg_offset > size) ? size :
+					sg->length - sg_offset;
+		ret = kgsl_do_cache_op(sg_page(sg), NULL, sg_offset,
+							sg_left, op);
+		size -= sg_left;
+		if (size == 0)
+			break;
+		pos += sg->length;
+	}
+
+	if (memdesc->sgt == NULL)
+		kgsl_free_sgt(sgt);
+
+	return ret;
 }
 EXPORT_SYMBOL(kgsl_cache_range_op);
 
@@ -623,6 +701,10 @@
 	size_t len;
 	unsigned int align;
 
+	static DEFINE_RATELIMIT_STATE(_rs,
+					DEFAULT_RATELIMIT_INTERVAL,
+					DEFAULT_RATELIMIT_BURST);
+
 	size = PAGE_ALIGN(size);
 	if (size == 0 || size > UINT_MAX)
 		return -EINVAL;
@@ -685,7 +767,8 @@
 			 */
 			memdesc->size = (size - len);
 
-			if (sharedmem_noretry_flag != true)
+			if (sharedmem_noretry_flag != true &&
+					__ratelimit(&_rs))
 				KGSL_CORE_ERR(
 					"Out of memory: only allocated %lldKB of %lldKB requested\n",
 					(size - len) >> 10, size >> 10);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index dd41e4e..5466a49 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -292,8 +292,10 @@
 	else {
 		ret = kgsl_sharedmem_page_alloc_user(memdesc, (size_t) size);
 		if (ret == 0) {
-			if (kgsl_memdesc_map(memdesc) == NULL)
+			if (kgsl_memdesc_map(memdesc) == NULL) {
+				kgsl_sharedmem_free(memdesc);
 				ret = -ENOMEM;
+			}
 		}
 	}
 
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 96873c4..817a6b1 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -52,6 +52,10 @@
 	fence_init(&kfence->fence, &kgsl_sync_fence_ops, &ktimeline->lock,
 		ktimeline->fence_context, timestamp);
 
+	/*
+	 * sync_file_create() takes a refcount to the fence. This refcount is
+	 * put when the fence is signaled.
+	 */
 	kfence->sync_file = sync_file_create(&kfence->fence);
 
 	if (kfence->sync_file == NULL) {
@@ -61,9 +65,6 @@
 		return NULL;
 	}
 
-	/* Get a refcount to the fence. Put when signaled */
-	fence_get(&kfence->fence);
-
 	spin_lock_irqsave(&ktimeline->lock, flags);
 	list_add_tail(&kfence->child_list, &ktimeline->child_list_head);
 	spin_unlock_irqrestore(&ktimeline->lock, flags);
@@ -707,6 +708,14 @@
 	list_add_tail(&sfence->child_list, &syncsource->child_list_head);
 	spin_unlock(&syncsource->lock);
 out:
+	/*
+	 * We're transferring ownership of the fence to the sync file.
+	 * The sync file takes an extra refcount when it is created, so put
+	 * our refcount.
+	 */
+	if (sync_file)
+		fence_put(&sfence->fence);
+
 	if (ret) {
 		if (sync_file)
 			fput(sync_file->file);
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 2e04608..cb2e85c 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -440,6 +440,9 @@
 		.driver_data = APPLE_HAS_FN },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI),
 		.driver_data = APPLE_HAS_FN },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+		USB_DEVICE_ID_APPLE_ALU_ANSI),
+		.driver_data = APPLE_HAS_FN },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO),
 		.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS),
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index a5dd7e6..d7f6cf0 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1791,6 +1791,8 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ISO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_JIS) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+		USB_DEVICE_ID_APPLE_ALU_ANSI) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
@@ -2056,7 +2058,6 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
-	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER) },
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c
index 8a57ed2..621e08f 100644
--- a/drivers/hwtracing/coresight/coresight-cti.c
+++ b/drivers/hwtracing/coresight/coresight-cti.c
@@ -64,7 +64,7 @@
 #define ITCHIN			(0xEF4)
 #define ITTRIGIN		(0xEF8)
 
-#define CTI_MAX_TRIGGERS	(8)
+#define CTI_MAX_TRIGGERS	(32)
 #define CTI_MAX_CHANNELS	(4)
 #define AFFINITY_LEVEL_L2	1
 
@@ -670,6 +670,7 @@
 	struct cti_drvdata *drvdata;
 	unsigned long flag;
 	int trig;
+	int refcnt;
 
 	if (IS_ERR_OR_NULL(cti))
 		return;
@@ -678,6 +679,7 @@
 
 	mutex_lock(&drvdata->mutex);
 
+	refcnt = drvdata->refcnt;
 	spin_lock_irqsave(&drvdata->spinlock, flag);
 	if (cti_cpu_verify_access(drvdata))
 		goto err;
@@ -692,6 +694,8 @@
 			cti_trigout_gpio_disable(drvdata);
 	}
 
+	if (refcnt)
+		pm_runtime_put(drvdata->dev);
 	mutex_unlock(&drvdata->mutex);
 	return;
 err:
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 860fe6e..a3da8ffd 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, 2017, The Linux Foundation. All rights reserved.
  *
  * Description: CoreSight Funnel driver
  *
@@ -23,6 +23,7 @@
 #include <linux/coresight.h>
 #include <linux/amba/bus.h>
 #include <linux/clk.h>
+#include <linux/of_address.h>
 
 #include "coresight-priv.h"
 
@@ -168,6 +169,29 @@
 };
 ATTRIBUTE_GROUPS(coresight_funnel);
 
+static int funnel_get_resource_byname(struct device_node *np,
+				   char *ch_base, struct resource *res)
+{
+	const char *name = NULL;
+	int index = 0, found = 0;
+
+	while (!of_property_read_string_index(np, "reg-names", index, &name)) {
+		if (strcmp(ch_base, name)) {
+			index++;
+			continue;
+		}
+
+		/* We have a match and @index is where it's at */
+		found = 1;
+		break;
+	}
+
+	if (!found)
+		return -EINVAL;
+
+	return of_address_to_resource(np, index, res);
+}
+
 static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
 {
 	int ret;
@@ -175,7 +199,8 @@
 	struct device *dev = &adev->dev;
 	struct coresight_platform_data *pdata = NULL;
 	struct funnel_drvdata *drvdata;
-	struct resource *res = &adev->res;
+	struct resource *res;
+	struct resource res_real;
 	struct coresight_desc desc = { 0 };
 	struct device_node *np = adev->dev.of_node;
 
@@ -199,8 +224,19 @@
 	}
 	dev_set_drvdata(dev, drvdata);
 
-	/* Validity for the resource is already checked by the AMBA core */
-	base = devm_ioremap_resource(dev, res);
+	if (of_property_read_bool(np, "qcom,duplicate-funnel")) {
+		ret = funnel_get_resource_byname(np, "funnel-base-real",
+						 &res_real);
+		if (ret)
+			return ret;
+
+		res = &res_real;
+		base = devm_ioremap(dev, res->start, resource_size(res));
+	} else {
+		/* Validity of resource is already checked by the AMBA core */
+		res = &adev->res;
+		base = devm_ioremap_resource(dev, res);
+	}
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
diff --git a/drivers/hwtracing/coresight/coresight-ost.c b/drivers/hwtracing/coresight/coresight-ost.c
index e40751a..63fea00 100644
--- a/drivers/hwtracing/coresight/coresight-ost.c
+++ b/drivers/hwtracing/coresight/coresight-ost.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -30,19 +30,26 @@
 
 static struct stm_drvdata *stmdrvdata;
 
-static uint32_t stm_channel_alloc(uint32_t off)
+static uint32_t stm_channel_alloc(void)
 {
 	struct stm_drvdata *drvdata = stmdrvdata;
-	uint32_t ch;
-	unsigned long flags;
+	uint32_t ch, off, num_ch_per_cpu;
+	int cpu;
 
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	do {
-		ch = find_next_zero_bit(drvdata->chs.bitmap,
-					drvdata->numsp, off);
-	} while ((ch < drvdata->numsp) &&
-		 test_and_set_bit(ch, drvdata->chs.bitmap));
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	num_ch_per_cpu = drvdata->numsp/num_present_cpus();
+
+	cpu = get_cpu();
+
+	off = num_ch_per_cpu * cpu;
+	ch = find_next_zero_bit(drvdata->chs.bitmap,
+				drvdata->numsp, off);
+	if (unlikely(ch >= (off + num_ch_per_cpu))) {
+		put_cpu();
+		return drvdata->numsp;
+	}
+
+	set_bit(ch, drvdata->chs.bitmap);
+	put_cpu();
 
 	return ch;
 }
@@ -65,11 +72,8 @@
 static void stm_channel_free(uint32_t ch)
 {
 	struct stm_drvdata *drvdata = stmdrvdata;
-	unsigned long flags;
 
-	spin_lock_irqsave(&drvdata->spinlock, flags);
 	clear_bit(ch, drvdata->chs.bitmap);
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 }
 
 static int stm_trace_ost_header(unsigned long ch_addr, uint32_t flags,
@@ -146,7 +150,14 @@
 	unsigned long ch_addr;
 
 	/* allocate channel and get the channel address */
-	ch = stm_channel_alloc(0);
+	ch = stm_channel_alloc();
+	if (unlikely(ch >= drvdata->numsp)) {
+		drvdata->ch_alloc_fail_count++;
+		dev_err_ratelimited(drvdata->dev,
+				    "Channel allocation failed %d",
+				    drvdata->ch_alloc_fail_count);
+		return 0;
+	}
 
 	ch_addr = (unsigned long)stm_channel_addr(drvdata, ch);
 
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index eb5dd84..c8f2702e 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * Description: CoreSight System Trace Macrocell driver
  *
@@ -729,7 +729,7 @@
 	numsp &= 0x1ffff;
 	if (!numsp)
 		numsp = STM_32_CHANNEL;
-	return numsp;
+	return STM_32_CHANNEL;
 }
 
 static void stm_init_default_data(struct stm_drvdata *drvdata)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 9bdde0b..d0ae889 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -771,33 +771,47 @@
 
 	mutex_lock(&drvdata->mem_lock);
 
-	/*
-	 * ETR DDR memory is not allocated until user enables
-	 * tmc at least once. If user specifies different ETR
-	 * DDR size than the default size or switches between
-	 * contiguous or scatter-gather memory type after
-	 * enabling tmc; the new selection will be honored from
-	 * next tmc enable session.
-	 */
-	if (drvdata->size != drvdata->mem_size ||
-	    drvdata->memtype != drvdata->mem_type) {
-		tmc_etr_free_mem(drvdata);
-		drvdata->size = drvdata->mem_size;
-		drvdata->memtype = drvdata->mem_type;
-	}
-	ret = tmc_etr_alloc_mem(drvdata);
-	if (ret) {
-		pm_runtime_put(drvdata->dev);
-		mutex_unlock(&drvdata->mem_lock);
-		return ret;
-	}
-	mutex_unlock(&drvdata->mem_lock);
-
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 	if (drvdata->reading) {
 		ret = -EBUSY;
-		goto out;
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		mutex_unlock(&drvdata->mem_lock);
+		return ret;
 	}
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+		/*
+		 * ETR DDR memory is not allocated until user enables
+		 * tmc at least once. If user specifies different ETR
+		 * DDR size than the default size or switches between
+		 * contiguous or scatter-gather memory type after
+		 * enabling tmc; the new selection will be honored from
+		 * next tmc enable session.
+		 */
+		if (drvdata->size != drvdata->mem_size ||
+		    drvdata->memtype != drvdata->mem_type) {
+			tmc_etr_free_mem(drvdata);
+			drvdata->size = drvdata->mem_size;
+			drvdata->memtype = drvdata->mem_type;
+		}
+		ret = tmc_etr_alloc_mem(drvdata);
+		if (ret) {
+			mutex_unlock(&drvdata->mem_lock);
+			return ret;
+		}
+	} else {
+		drvdata->usbch = usb_qdss_open("qdss", drvdata,
+					       usb_notifier);
+		if (IS_ERR_OR_NULL(drvdata->usbch)) {
+			dev_err(drvdata->dev, "usb_qdss_open failed\n");
+			ret = PTR_ERR(drvdata->usbch);
+			mutex_unlock(&drvdata->mem_lock);
+			return ret;
+		}
+	}
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
 
 	val = local_xchg(&drvdata->mode, mode);
 	/*
@@ -808,9 +822,14 @@
 	if (val == CS_MODE_SYSFS)
 		goto out;
 
-	tmc_etr_enable_hw(drvdata);
+	if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+		tmc_etr_enable_hw(drvdata);
+
+	drvdata->enable = true;
+	drvdata->sticky_enable = true;
 out:
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	mutex_unlock(&drvdata->mem_lock);
 
 	if (!ret)
 		dev_info(drvdata->dev, "TMC-ETR enabled\n");
@@ -880,8 +899,15 @@
 
 	val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
 	/* Disable the TMC only if it needs to */
-	if (val != CS_MODE_DISABLED)
-		tmc_etr_disable_hw(drvdata);
+	if (val != CS_MODE_DISABLED) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
+			__tmc_etr_disable_to_bam(drvdata);
+			tmc_etr_bam_disable(drvdata);
+			usb_qdss_close(drvdata->usbch);
+		} else {
+			tmc_etr_disable_hw(drvdata);
+		}
+	}
 
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
@@ -913,6 +939,11 @@
 		goto out;
 	}
 
+	if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	val = local_read(&drvdata->mode);
 	/* Don't interfere if operated from Perf */
 	if (val == CS_MODE_PERF) {
@@ -940,11 +971,12 @@
 int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
 {
 	unsigned long flags;
+	void *vaddr = NULL;
 
 	/* config types are set a boot time and never change */
 	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
 		return -EINVAL;
-
+	mutex_lock(&drvdata->mem_lock);
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
 	/* RE-enable the TMC if need be */
@@ -957,12 +989,16 @@
 		 */
 		tmc_etr_enable_hw(drvdata);
 	} else {
-		tmc_etr_free_mem(drvdata);
+		vaddr = drvdata->vaddr;
 		drvdata->buf = NULL;
 	}
 
 	drvdata->reading = false;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	if (vaddr)
+		tmc_etr_free_mem(drvdata);
+
+	mutex_unlock(&drvdata->mem_lock);
 	return 0;
 }
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index f9449fe..012c56e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -497,14 +497,12 @@
 	struct coresight_desc desc = { 0 };
 	struct device_node *np = adev->dev.of_node;
 
-	if (np) {
-		pdata = of_get_coresight_platform_data(dev, np);
-		if (IS_ERR(pdata)) {
-			ret = PTR_ERR(pdata);
-			goto out;
-		}
-		adev->dev.platform_data = pdata;
+	pdata = of_get_coresight_platform_data(dev, np);
+	if (IS_ERR(pdata)) {
+		ret = PTR_ERR(pdata);
+		goto out;
 	}
+	adev->dev.platform_data = pdata;
 
 	ret = -ENOMEM;
 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
@@ -531,10 +529,8 @@
 	drvdata->memwidth = tmc_get_memwidth(devid);
 
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		if (np)
-			ret = of_property_read_u32(np,
-						   "arm,buffer-size",
-						   &drvdata->size);
+		ret = of_property_read_u32(np, "arm,buffer-size",
+					   &drvdata->size);
 		if (ret)
 			drvdata->size = SZ_1M;
 
@@ -544,6 +540,7 @@
 			drvdata->memtype  = TMC_ETR_MEM_TYPE_CONTIG;
 		drvdata->mem_size = drvdata->size;
 		drvdata->mem_type = drvdata->memtype;
+		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
 	} else {
 		drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
 	}
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 989af91..051ab8e 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -25,10 +25,12 @@
 #include <linux/pm_runtime.h>
 #include <linux/dma-mapping.h>
 #include <linux/qcom-geni-se.h>
+#include <linux/ipc_logging.h>
 
 #define SE_I2C_TX_TRANS_LEN		(0x26C)
 #define SE_I2C_RX_TRANS_LEN		(0x270)
 #define SE_I2C_SCL_COUNTERS		(0x278)
+#define SE_GENI_IOS			(0x908)
 
 #define SE_I2C_ERR  (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |\
 			M_GP_IRQ_1_EN | M_GP_IRQ_3_EN | M_GP_IRQ_4_EN)
@@ -53,6 +55,21 @@
 #define SLV_ADDR_SHFT		(9)
 
 #define I2C_CORE2X_VOTE		(10000)
+#define GP_IRQ0			0
+#define GP_IRQ1			1
+#define GP_IRQ2			2
+#define GP_IRQ3			3
+#define GP_IRQ4			4
+#define GP_IRQ5			5
+#define GENI_OVERRUN		6
+#define GENI_ILLEGAL_CMD	7
+#define GENI_ABORT_DONE		8
+#define GENI_TIMEOUT		9
+
+#define I2C_NACK		GP_IRQ1
+#define I2C_BUS_PROTO		GP_IRQ3
+#define I2C_ARB_LOST		GP_IRQ4
+#define DM_I2C_RX_ERR		((GP_IRQ1 | GP_IRQ3 | GP_IRQ4) >> 4)
 
 struct geni_i2c_dev {
 	struct device *dev;
@@ -67,6 +84,29 @@
 	int cur_wr;
 	int cur_rd;
 	struct device *wrapper_dev;
+	void *ipcl;
+};
+
+struct geni_i2c_err_log {
+	int err;
+	const char *msg;
+};
+
+static struct geni_i2c_err_log gi2c_log[] = {
+	[GP_IRQ0] = {-EINVAL, "Unknown I2C err GP_IRQ0"},
+	[I2C_NACK] = {-ENOTCONN,
+			"NACK: slv unresponsive, check its power/reset-ln"},
+	[GP_IRQ2] = {-EINVAL, "Unknown I2C err GP IRQ2"},
+	[I2C_BUS_PROTO] = {-EPROTO,
+				"Bus proto err, noisy/unepxected start/stop"},
+	[I2C_ARB_LOST] = {-EBUSY,
+				"Bus arbitration lost, clock line undriveable"},
+	[GP_IRQ5] = {-EINVAL, "Unknown I2C err GP IRQ5"},
+	[GENI_OVERRUN] = {-EIO, "Cmd overrun, check GENI cmd-state machine"},
+	[GENI_ILLEGAL_CMD] = {-EILSEQ,
+				"Illegal cmd, check GENI cmd-state machine"},
+	[GENI_ABORT_DONE] = {-ETIMEDOUT, "Abort after timeout successful"},
+	[GENI_TIMEOUT] = {-ETIMEDOUT, "I2C TXN timed out"},
 };
 
 static inline void qcom_geni_i2c_conf(void __iomem *base, int dfs, int div)
@@ -81,25 +121,67 @@
 	mb();
 }
 
+static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
+{
+	u32 m_stat = readl_relaxed(gi2c->base + SE_GENI_M_IRQ_STATUS);
+	u32 rx_st = readl_relaxed(gi2c->base + SE_GENI_RX_FIFO_STATUS);
+	u32 tx_st = readl_relaxed(gi2c->base + SE_GENI_TX_FIFO_STATUS);
+	u32 m_cmd = readl_relaxed(gi2c->base + SE_GENI_M_CMD0);
+	u32 geni_s = readl_relaxed(gi2c->base + SE_GENI_STATUS);
+	u32 geni_ios = readl_relaxed(gi2c->base + SE_GENI_IOS);
+
+	if (err == I2C_NACK || err == GENI_ABORT_DONE) {
+		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n",
+			    gi2c_log[err].msg);
+		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+			     "m_stat:0x%x, tx_stat:0x%x, rx_stat:0x%x, ",
+			     m_stat, tx_st, rx_st);
+		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+			     "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
+			     m_cmd, geni_s, geni_ios);
+	} else {
+		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n",
+			     gi2c_log[err].msg);
+		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+			     "m_stat:0x%x, tx_stat:0x%x, rx_stat:0x%x, ",
+			     m_stat, tx_st, rx_st);
+		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+			     "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
+			     m_cmd, geni_s, geni_ios);
+	}
+	gi2c->err = gi2c_log[err].err;
+}
+
 static irqreturn_t geni_i2c_irq(int irq, void *dev)
 {
 	struct geni_i2c_dev *gi2c = dev;
 	int i, j;
 	u32 m_stat = readl_relaxed(gi2c->base + SE_GENI_M_IRQ_STATUS);
-	u32 tx_stat = readl_relaxed(gi2c->base + SE_GENI_TX_FIFO_STATUS);
-	u32 rx_stat = readl_relaxed(gi2c->base + SE_GENI_RX_FIFO_STATUS);
+	u32 rx_st = readl_relaxed(gi2c->base + SE_GENI_RX_FIFO_STATUS);
 	u32 dm_tx_st = readl_relaxed(gi2c->base + SE_DMA_TX_IRQ_STAT);
 	u32 dm_rx_st = readl_relaxed(gi2c->base + SE_DMA_RX_IRQ_STAT);
 	u32 dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN);
 	struct i2c_msg *cur = gi2c->cur;
 
-	dev_dbg(gi2c->dev,
-		"got i2c irq:%d, stat:0x%x, tx stat:0x%x, rx stat:0x%x\n",
-		irq, m_stat, tx_stat, rx_stat);
-	if (!cur || (m_stat & SE_I2C_ERR) || (dm_tx_st & TX_SBE) ||
-		    (dm_rx_st & RX_SBE)) {
-		dev_err(gi2c->dev, "i2c err:st:0x%x, dm_t: 0x%x, dm_r: 0x%x\n",
-				   m_stat, dm_tx_st, dm_tx_st);
+	if (!cur || (m_stat & M_CMD_FAILURE_EN) ||
+		    (dm_rx_st & (DM_I2C_RX_ERR)) ||
+		    (m_stat & M_CMD_ABORT_EN)) {
+
+		if (m_stat & M_GP_IRQ_1_EN)
+			geni_i2c_err(gi2c, I2C_NACK);
+		if (m_stat & M_GP_IRQ_3_EN)
+			geni_i2c_err(gi2c, I2C_BUS_PROTO);
+		if (m_stat & M_GP_IRQ_4_EN)
+			geni_i2c_err(gi2c, I2C_ARB_LOST);
+		if (m_stat & M_CMD_OVERRUN_EN)
+			geni_i2c_err(gi2c, GENI_OVERRUN);
+		if (m_stat & M_ILLEGAL_CMD_EN)
+			geni_i2c_err(gi2c, GENI_ILLEGAL_CMD);
+		if (m_stat & M_CMD_ABORT_EN)
+			geni_i2c_err(gi2c, GENI_ABORT_DONE);
+		if (m_stat & M_GP_IRQ_0_EN)
+			geni_i2c_err(gi2c, GP_IRQ0);
+
 		if (!dma)
 			writel_relaxed(0, (gi2c->base +
 					   SE_GENI_TX_WATERMARK_REG));
@@ -115,7 +197,7 @@
 
 	if (((m_stat & M_RX_FIFO_WATERMARK_EN) ||
 		(m_stat & M_RX_FIFO_LAST_EN)) && (cur->flags & I2C_M_RD)) {
-		u32 rxcnt = rx_stat & RX_FIFO_WC_MSK;
+		u32 rxcnt = rx_st & RX_FIFO_WC_MSK;
 
 		for (j = 0; j < rxcnt; j++) {
 			u32 temp;
@@ -131,7 +213,6 @@
 					i, temp);
 				break;
 			}
-			dev_dbg(gi2c->dev, "FIFO i: %d, read 0x%x\n", i, temp);
 		}
 	} else if ((m_stat & M_TX_FIFO_WATERMARK_EN) &&
 					!(cur->flags & I2C_M_RD)) {
@@ -188,7 +269,8 @@
 	reinit_completion(&gi2c->xfer);
 	ret = pm_runtime_get_sync(gi2c->dev);
 	if (ret < 0) {
-		dev_err(gi2c->dev, "error turning SE resources:%d\n", ret);
+		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+			    "error turning SE resources:%d\n", ret);
 		pm_runtime_put_noidle(gi2c->dev);
 		/* Set device in suspended since resume failed */
 		pm_runtime_set_suspended(gi2c->dev);
@@ -259,7 +341,7 @@
 		mb();
 		timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
 		if (!timeout) {
-			gi2c->err = -ETIMEDOUT;
+			geni_i2c_err(gi2c, GENI_TIMEOUT);
 			gi2c->cur = NULL;
 			geni_abort_m_cmd(gi2c->base);
 			timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
@@ -432,6 +514,8 @@
 
 	pm_runtime_disable(gi2c->dev);
 	i2c_del_adapter(&gi2c->adap);
+	if (gi2c->ipcl)
+		ipc_log_context_destroy(gi2c->ipcl);
 	return 0;
 }
 
@@ -455,6 +539,12 @@
 	int ret;
 	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
 
+	if (!gi2c->ipcl) {
+		char ipc_name[I2C_NAME_SIZE];
+
+		snprintf(ipc_name, I2C_NAME_SIZE, "i2c-%d", gi2c->adap.nr);
+		gi2c->ipcl = ipc_log_context_create(2, ipc_name, 0);
+	}
 	ret = se_geni_resources_on(&gi2c->i2c_rsc);
 	if (ret)
 		return ret;
@@ -465,6 +555,8 @@
 		gi2c->tx_wm = gi2c_tx_depth - 1;
 		geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth);
 		se_config_packing(gi2c->base, 8, 4, true);
+		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+			    "i2c fifo depth:%d\n", gi2c_tx_depth);
 	}
 	enable_irq(gi2c->irq);
 	return 0;
diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c
index 21d38c8..7f4f9c4 100644
--- a/drivers/iio/adc/bcm_iproc_adc.c
+++ b/drivers/iio/adc/bcm_iproc_adc.c
@@ -143,7 +143,7 @@
 	iproc_adc_dbg_reg(dev, adc_priv, IPROC_SOFT_BYPASS_DATA);
 }
 
-static irqreturn_t iproc_adc_interrupt_handler(int irq, void *data)
+static irqreturn_t iproc_adc_interrupt_thread(int irq, void *data)
 {
 	u32 channel_intr_status;
 	u32 intr_status;
@@ -167,7 +167,7 @@
 	return IRQ_NONE;
 }
 
-static irqreturn_t iproc_adc_interrupt_thread(int irq, void *data)
+static irqreturn_t iproc_adc_interrupt_handler(int irq, void *data)
 {
 	irqreturn_t retval = IRQ_NONE;
 	struct iproc_adc_priv *adc_priv;
@@ -181,7 +181,7 @@
 	adc_priv = iio_priv(indio_dev);
 
 	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_STATUS, &intr_status);
-	dev_dbg(&indio_dev->dev, "iproc_adc_interrupt_thread(),INTRPT_STS:%x\n",
+	dev_dbg(&indio_dev->dev, "iproc_adc_interrupt_handler(),INTRPT_STS:%x\n",
 			intr_status);
 
 	intr_channels = (intr_status & IPROC_ADC_INTR_MASK) >> IPROC_ADC_INTR;
@@ -566,8 +566,8 @@
 	}
 
 	ret = devm_request_threaded_irq(&pdev->dev, adc_priv->irqno,
-				iproc_adc_interrupt_thread,
 				iproc_adc_interrupt_handler,
+				iproc_adc_interrupt_thread,
 				IRQF_SHARED, "iproc-adc", indio_dev);
 	if (ret) {
 		dev_err(&pdev->dev, "request_irq error %d\n", ret);
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
index 3afc53a..c298fd8 100644
--- a/drivers/iio/light/ltr501.c
+++ b/drivers/iio/light/ltr501.c
@@ -74,9 +74,9 @@
 static const struct reg_field reg_field_it =
 				REG_FIELD(LTR501_ALS_MEAS_RATE, 3, 4);
 static const struct reg_field reg_field_als_intr =
-				REG_FIELD(LTR501_INTR, 0, 0);
-static const struct reg_field reg_field_ps_intr =
 				REG_FIELD(LTR501_INTR, 1, 1);
+static const struct reg_field reg_field_ps_intr =
+				REG_FIELD(LTR501_INTR, 0, 0);
 static const struct reg_field reg_field_als_rate =
 				REG_FIELD(LTR501_ALS_MEAS_RATE, 0, 2);
 static const struct reg_field reg_field_ps_rate =
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index 0204595..268210e 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -40,9 +40,9 @@
 #define AS3935_AFE_PWR_BIT	BIT(0)
 
 #define AS3935_INT		0x03
-#define AS3935_INT_MASK		0x07
+#define AS3935_INT_MASK		0x0f
 #define AS3935_EVENT_INT	BIT(3)
-#define AS3935_NOISE_INT	BIT(1)
+#define AS3935_NOISE_INT	BIT(0)
 
 #define AS3935_DATA		0x07
 #define AS3935_DATA_MASK	0x3F
@@ -215,7 +215,7 @@
 
 	st->buffer[0] = val & AS3935_DATA_MASK;
 	iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer,
-					   pf->timestamp);
+					   iio_get_time_ns(indio_dev));
 err_read:
 	iio_trigger_notify_done(indio_dev->trig);
 
@@ -244,7 +244,7 @@
 
 	switch (val) {
 	case AS3935_EVENT_INT:
-		iio_trigger_poll(st->trig);
+		iio_trigger_poll_chained(st->trig);
 		break;
 	case AS3935_NOISE_INT:
 		dev_warn(&st->spi->dev, "noise level is too high\n");
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index fe7cc70..c9ea89d 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -87,6 +87,7 @@
 	u32 power_on_delay;
 	u32 power_off_delay;
 	bool manage_pin_ctrl;
+	struct kobject *sysfs_kobject;
 };
 
 static struct hbtp_data *hbtp;
@@ -1350,6 +1351,39 @@
 	},
 };
 
+static ssize_t hbtp_display_pwr_store(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	u32 status;
+	ssize_t ret;
+	char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL};
+
+	mutex_lock(&hbtp->mutex);
+	ret = kstrtou32(buf, 10, &status);
+	if (ret) {
+		pr_err("hbtp: ret error: %zd\n", ret);
+		return ret;
+	}
+	if (!hbtp || !hbtp->input_dev) {
+		pr_err("hbtp: hbtp or hbtp->input_dev not ready!\n");
+		return ret;
+	}
+	if (status) {
+		pr_debug("hbtp: display power on!\n");
+		kobject_uevent_env(&hbtp->input_dev->dev.kobj,
+			KOBJ_ONLINE, envp);
+	} else {
+		pr_debug("hbtp: display power off!\n");
+		kobject_uevent_env(&hbtp->input_dev->dev.kobj,
+			KOBJ_OFFLINE, envp);
+	}
+	mutex_unlock(&hbtp->mutex);
+	return count;
+}
+
+static struct kobj_attribute hbtp_display_attribute =
+		__ATTR(display_pwr, 0660, NULL, hbtp_display_pwr_store);
+
 static int __init hbtp_init(void)
 {
 	int error;
@@ -1382,6 +1416,16 @@
 		goto err_platform_drv_reg;
 	}
 
+	hbtp->sysfs_kobject = kobject_create_and_add("hbtp", kernel_kobj);
+	if (!hbtp->sysfs_kobject)
+		pr_err("%s: Could not create sysfs kobject\n", __func__);
+	else {
+		error = sysfs_create_file(hbtp->sysfs_kobject,
+			&hbtp_display_attribute.attr);
+		if (error)
+			pr_err("failed to create the display_pwr sysfs\n");
+	}
+
 	return 0;
 
 err_platform_drv_reg:
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 7826994..cd834da 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1118,8 +1118,10 @@
  * Asus UX32VD             0x361f02        00, 15, 0e      clickpad
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
  * Fujitsu LIFEBOOK E544   0x470f00        d0, 12, 09      2 hw buttons
+ * Fujitsu LIFEBOOK E546   0x470f00        50, 12, 09      2 hw buttons
  * Fujitsu LIFEBOOK E547   0x470f00        50, 12, 09      2 hw buttons
  * Fujitsu LIFEBOOK E554   0x570f01        40, 14, 0c      2 hw buttons
+ * Fujitsu LIFEBOOK E557   0x570f01        40, 14, 0c      2 hw buttons
  * Fujitsu T725            0x470f01        05, 12, 09      2 hw buttons
  * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
  * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
@@ -1525,6 +1527,13 @@
 		},
 	},
 	{
+		/* Fujitsu LIFEBOOK E546  does not work with crc_enabled == 0 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E546"),
+		},
+	},
+	{
 		/* Fujitsu LIFEBOOK E547 does not work with crc_enabled == 0 */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
@@ -1546,6 +1555,13 @@
 		},
 	},
 	{
+		/* Fujitsu LIFEBOOK E557 does not work with crc_enabled == 0 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E557"),
+		},
+	},
+	{
 		/* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index cb9726e..1d5c514 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -412,6 +412,7 @@
 
 #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
 #define ARM_SMMU_OPT_FATAL_ASF		(1 << 1)
+#define ARM_SMMU_OPT_SKIP_INIT		(1 << 2)
 #define ARM_SMMU_OPT_DYNAMIC		(1 << 3)
 #define ARM_SMMU_OPT_3LVL_TABLES	(1 << 4)
 	u32				options;
@@ -530,6 +531,7 @@
 static struct arm_smmu_option_prop arm_smmu_options[] = {
 	{ ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" },
 	{ ARM_SMMU_OPT_FATAL_ASF, "qcom,fatal-asf" },
+	{ ARM_SMMU_OPT_SKIP_INIT, "qcom,skip-init" },
 	{ ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" },
 	{ ARM_SMMU_OPT_3LVL_TABLES, "qcom,use-3-lvl-tables" },
 	{ 0, NULL},
@@ -3221,10 +3223,12 @@
 	 * Reset stream mapping groups: Initial values mark all SMRn as
 	 * invalid and all S2CRn as bypass unless overridden.
 	 */
-	for (i = 0; i < smmu->num_mapping_groups; ++i)
-		arm_smmu_write_sme(smmu, i);
+	if (!(smmu->options & ARM_SMMU_OPT_SKIP_INIT)) {
+		for (i = 0; i < smmu->num_mapping_groups; ++i)
+			arm_smmu_write_sme(smmu, i);
 
-	arm_smmu_context_bank_reset(smmu);
+		arm_smmu_context_bank_reset(smmu);
+	}
 
 	/* Invalidate the TLB, just in case */
 	writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
@@ -3317,8 +3321,7 @@
 	}
 
 	for (i = 0; i < smmu->num_mapping_groups; i++) {
-		if (smmu->s2crs[i].cbndx == cb) {
-			smmu->s2crs[i].cbndx = 0;
+		if (smmu->s2crs[i].cb_handoff && smmu->s2crs[i].cbndx == cb) {
 			smmu->s2crs[i].cb_handoff = false;
 			smmu->s2crs[i].count -= 1;
 		}
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index 560bb43..b5e817b 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -25,6 +25,13 @@
 #define FAST_PAGE_SIZE (1UL << FAST_PAGE_SHIFT)
 #define FAST_PAGE_MASK (~(PAGE_SIZE - 1))
 #define FAST_PTE_ADDR_MASK		((av8l_fast_iopte)0xfffffffff000)
+#define FAST_MAIR_ATTR_IDX_CACHE	1
+#define FAST_PTE_ATTRINDX_SHIFT		2
+#define FAST_PTE_ATTRINDX_MASK		0x7
+#define FAST_PTE_SH_SHIFT		8
+#define FAST_PTE_SH_MASK	   (((av8l_fast_iopte)0x3) << FAST_PTE_SH_SHIFT)
+#define FAST_PTE_SH_OS             (((av8l_fast_iopte)2) << FAST_PTE_SH_SHIFT)
+#define FAST_PTE_SH_IS             (((av8l_fast_iopte)3) << FAST_PTE_SH_SHIFT)
 
 static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot,
 				 bool coherent)
@@ -56,6 +63,36 @@
 		dmac_clean_range(start, end);
 }
 
+static bool __fast_is_pte_coherent(av8l_fast_iopte *ptep)
+{
+	int attr_idx = (*ptep & (FAST_PTE_ATTRINDX_MASK <<
+			FAST_PTE_ATTRINDX_SHIFT)) >>
+			FAST_PTE_ATTRINDX_SHIFT;
+
+	if ((attr_idx == FAST_MAIR_ATTR_IDX_CACHE) &&
+		(((*ptep & FAST_PTE_SH_MASK) == FAST_PTE_SH_IS) ||
+		  (*ptep & FAST_PTE_SH_MASK) == FAST_PTE_SH_OS))
+		return true;
+
+	return false;
+}
+
+static bool is_dma_coherent(struct device *dev, unsigned long attrs)
+{
+	bool is_coherent;
+
+	if (attrs & DMA_ATTR_FORCE_COHERENT)
+		is_coherent = true;
+	else if (attrs & DMA_ATTR_FORCE_NON_COHERENT)
+		is_coherent = false;
+	else if (is_device_dma_coherent(dev))
+		is_coherent = true;
+	else
+		is_coherent = false;
+
+	return is_coherent;
+}
+
 /*
  * Checks if the allocated range (ending at @end) covered the upcoming
  * stale bit.  We don't need to know exactly where the range starts since
@@ -313,7 +350,7 @@
 	int nptes = len >> FAST_PAGE_SHIFT;
 	bool skip_sync = (attrs & DMA_ATTR_SKIP_CPU_SYNC);
 	int prot = __fast_dma_direction_to_prot(dir);
-	bool is_coherent = is_device_dma_coherent(dev);
+	bool is_coherent = is_dma_coherent(dev, attrs);
 
 	prot = __get_iommu_pgprot(attrs, prot, is_coherent);
 
@@ -357,7 +394,7 @@
 	int nptes = len >> FAST_PAGE_SHIFT;
 	struct page *page = phys_to_page((*pmd & FAST_PTE_ADDR_MASK));
 	bool skip_sync = (attrs & DMA_ATTR_SKIP_CPU_SYNC);
-	bool is_coherent = is_device_dma_coherent(dev);
+	bool is_coherent = is_dma_coherent(dev, attrs);
 
 	if (!skip_sync && !is_coherent)
 		__fast_dma_page_dev_to_cpu(page, offset, size, dir);
@@ -377,7 +414,7 @@
 	unsigned long offset = iova & ~FAST_PAGE_MASK;
 	struct page *page = phys_to_page((*pmd & FAST_PTE_ADDR_MASK));
 
-	if (!is_device_dma_coherent(dev))
+	if (!__fast_is_pte_coherent(pmd))
 		__fast_dma_page_dev_to_cpu(page, offset, size, dir);
 }
 
@@ -389,7 +426,7 @@
 	unsigned long offset = iova & ~FAST_PAGE_MASK;
 	struct page *page = phys_to_page((*pmd & FAST_PTE_ADDR_MASK));
 
-	if (!is_device_dma_coherent(dev))
+	if (!__fast_is_pte_coherent(pmd))
 		__fast_dma_page_cpu_to_dev(page, offset, size, dir);
 }
 
@@ -469,7 +506,7 @@
 	struct sg_mapping_iter miter;
 	unsigned int count = ALIGN(size, SZ_4K) >> PAGE_SHIFT;
 	int prot = IOMMU_READ | IOMMU_WRITE; /* TODO: extract from attrs */
-	bool is_coherent = is_device_dma_coherent(dev);
+	bool is_coherent = is_dma_coherent(dev, attrs);
 	pgprot_t remap_prot = __get_dma_pgprot(attrs, PAGE_KERNEL, is_coherent);
 	struct page **pages;
 
@@ -591,7 +628,7 @@
 	unsigned long uaddr = vma->vm_start;
 	struct page **pages;
 	int i, nr_pages, ret = 0;
-	bool coherent = is_device_dma_coherent(dev);
+	bool coherent = is_dma_coherent(dev, attrs);
 
 	vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
 					     coherent);
@@ -611,6 +648,21 @@
 	return ret;
 }
 
+static int fast_smmu_get_sgtable(struct device *dev, struct sg_table *sgt,
+				void *cpu_addr, dma_addr_t dma_addr,
+				size_t size, unsigned long attrs)
+{
+	unsigned int n_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+	struct vm_struct *area;
+
+	area = find_vm_area(cpu_addr);
+	if (!area || !area->pages)
+		return -EINVAL;
+
+	return sg_alloc_table_from_pages(sgt, area->pages, n_pages, 0, size,
+					GFP_KERNEL);
+}
+
 static dma_addr_t fast_smmu_dma_map_resource(
 			struct device *dev, phys_addr_t phys_addr,
 			size_t size, enum dma_data_direction dir,
@@ -659,12 +711,6 @@
 	spin_unlock_irqrestore(&mapping->lock, flags);
 }
 
-
-static int fast_smmu_dma_supported(struct device *dev, u64 mask)
-{
-	return mask <= 0xffffffff;
-}
-
 static int fast_smmu_mapping_error(struct device *dev,
 				   dma_addr_t dma_addr)
 {
@@ -708,6 +754,7 @@
 	.alloc = fast_smmu_alloc,
 	.free = fast_smmu_free,
 	.mmap = fast_smmu_mmap_attrs,
+	.get_sgtable = fast_smmu_get_sgtable,
 	.map_page = fast_smmu_map_page,
 	.unmap_page = fast_smmu_unmap_page,
 	.sync_single_for_cpu = fast_smmu_sync_single_for_cpu,
@@ -718,7 +765,6 @@
 	.sync_sg_for_device = fast_smmu_sync_sg_for_device,
 	.map_resource = fast_smmu_dma_map_resource,
 	.unmap_resource = fast_smmu_dma_unmap_resource,
-	.dma_supported = fast_smmu_dma_supported,
 	.mapping_error = fast_smmu_mapping_error,
 };
 
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index ea72b9c..2ef496d 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -89,6 +89,7 @@
 #define ARM_LPAE_PTE_TYPE_TABLE		3
 #define ARM_LPAE_PTE_TYPE_PAGE		3
 
+#define ARM_LPAE_PTE_SH_MASK		(((arm_lpae_iopte)0x3) << 8)
 #define ARM_LPAE_PTE_NSTABLE		(((arm_lpae_iopte)1) << 63)
 #define ARM_LPAE_PTE_XN			(((arm_lpae_iopte)3) << 53)
 #define ARM_LPAE_PTE_AF			(((arm_lpae_iopte)1) << 10)
@@ -894,8 +895,9 @@
 					ARM_LPAE_PTE_ATTRINDX_SHIFT)) >>
 					ARM_LPAE_PTE_ATTRINDX_SHIFT;
 		if ((attr_idx == ARM_LPAE_MAIR_ATTR_IDX_CACHE) &&
-		    ((*ptep & ARM_LPAE_PTE_SH_IS) ||
-		     (*ptep & ARM_LPAE_PTE_SH_OS)))
+		   (((*ptep & ARM_LPAE_PTE_SH_MASK) == ARM_LPAE_PTE_SH_IS)
+		     ||
+		     (*ptep & ARM_LPAE_PTE_SH_MASK) == ARM_LPAE_PTE_SH_OS))
 			return true;
 	} else {
 		if (*ptep & ARM_LPAE_PTE_MEMATTR_OIWB)
diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c
index 9b13fce..2db06b0 100644
--- a/drivers/iommu/io-pgtable-fast.c
+++ b/drivers/iommu/io-pgtable-fast.c
@@ -395,11 +395,16 @@
 	for (i = 0; i < 4; ++i) {
 		for (j = 0; j < 512; ++j) {
 			av8l_fast_iopte pte, *pudp;
+			void *addr;
 
 			page = alloc_page(GFP_KERNEL | __GFP_ZERO);
 			if (!page)
 				goto err_free_pages;
 			pages[pg++] = page;
+
+			addr = page_address(page);
+			dmac_clean_range(addr, addr + SZ_4K);
+
 			pte = page_to_phys(page) | AV8L_FAST_PTE_TYPE_TABLE;
 			pudp = data->puds[i] + j;
 			*pudp = pte;
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index 6bb435b..c98d8c2 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -1554,10 +1554,14 @@
 	memset(buf, 0, 100);
 
 	phys = iommu_iova_to_phys_hard(ddev->domain, ddev->iova);
-	if (!phys)
+	if (!phys) {
 		strlcpy(buf, "FAIL\n", 100);
-	else
+		phys = iommu_iova_to_phys(ddev->domain, ddev->iova);
+		dev_err(ddev->dev, "ATOS for %pa failed. Software walk returned: %pa\n",
+			&ddev->iova, &phys);
+	} else {
 		snprintf(buf, 100, "%pa\n", &phys);
+	}
 
 	buflen = strlen(buf);
 	if (copy_to_user(ubuf, buf, buflen)) {
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 5f144a6..400839d 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -696,6 +696,16 @@
 	  variable brightness.  It also supports outputting the Avdd supply for
 	  AMOLED displays.
 
+config LEDS_QPNP_HAPTICS
+	tristate "Haptics support for QPNP PMIC"
+	depends on LEDS_CLASS && MFD_SPMI_PMIC
+	help
+	  This option enables device driver support for the haptics peripheral
+	  found on Qualcomm Technologies, Inc. QPNP PMICs.  The haptic
+	  peripheral is capable of driving both LRA and ERM vibrators.  This
+	  module provides haptic feedback for user actions such as a long press
+	  on the touch screen.
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index e0ca2e8..ba9bb8d 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -75,6 +75,7 @@
 obj-$(CONFIG_LEDS_QPNP_FLASH)		+= leds-qpnp-flash.o
 obj-$(CONFIG_LEDS_QPNP_FLASH_V2)	+= leds-qpnp-flash-v2.o
 obj-$(CONFIG_LEDS_QPNP_WLED)		+= leds-qpnp-wled.o
+obj-$(CONFIG_LEDS_QPNP_HAPTICS)	+= leds-qpnp-haptics.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c
new file mode 100644
index 0000000..1eaa652
--- /dev/null
+++ b/drivers/leds/leds-qpnp-haptics.c
@@ -0,0 +1,2497 @@
+/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"haptics: %s: " fmt, __func__
+
+#include <linux/atomic.h>
+#include <linux/delay.h>
+#include <linux/hrtimer.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/qpnp/qpnp-misc.h>
+#include <linux/qpnp/qpnp-revid.h>
+
+/* Register definitions */
+#define HAP_STATUS_1_REG(chip)		(chip->base + 0x0A)
+#define HAP_BUSY_BIT			BIT(1)
+#define SC_FLAG_BIT			BIT(3)
+#define AUTO_RES_ERROR_BIT		BIT(4)
+
+#define HAP_LRA_AUTO_RES_LO_REG(chip)	(chip->base + 0x0B)
+#define HAP_LRA_AUTO_RES_HI_REG(chip)	(chip->base + 0x0C)
+
+#define HAP_INT_RT_STS_REG(chip)	(chip->base + 0x10)
+#define SC_INT_RT_STS_BIT		BIT(0)
+#define PLAY_INT_RT_STS_BIT		BIT(1)
+
+#define HAP_EN_CTL_REG(chip)		(chip->base + 0x46)
+#define HAP_EN_BIT			BIT(7)
+
+#define HAP_EN_CTL2_REG(chip)		(chip->base + 0x48)
+#define BRAKE_EN_BIT			BIT(0)
+
+#define HAP_AUTO_RES_CTRL_REG(chip)	(chip->base + 0x4B)
+#define AUTO_RES_EN_BIT			BIT(7)
+#define AUTO_RES_ERR_RECOVERY_BIT	BIT(3)
+
+#define HAP_CFG1_REG(chip)		(chip->base + 0x4C)
+#define HAP_ACT_TYPE_MASK		BIT(0)
+#define HAP_LRA				0
+#define HAP_ERM				1
+
+#define HAP_CFG2_REG(chip)		(chip->base + 0x4D)
+#define HAP_WAVE_SINE			0
+#define HAP_WAVE_SQUARE			1
+#define HAP_LRA_RES_TYPE_MASK		BIT(0)
+
+#define HAP_SEL_REG(chip)		(chip->base + 0x4E)
+#define HAP_WF_SOURCE_MASK		GENMASK(5, 4)
+#define HAP_WF_SOURCE_SHIFT		4
+
+#define HAP_LRA_AUTO_RES_REG(chip)	(chip->base + 0x4F)
+/* For pmi8998 */
+#define LRA_AUTO_RES_MODE_MASK		GENMASK(6, 4)
+#define LRA_AUTO_RES_MODE_SHIFT		4
+#define LRA_HIGH_Z_MASK			GENMASK(3, 2)
+#define LRA_HIGH_Z_SHIFT		2
+#define LRA_RES_CAL_MASK		GENMASK(1, 0)
+#define HAP_RES_CAL_PERIOD_MIN		4
+#define HAP_RES_CAL_PERIOD_MAX		32
+/* For pm660 */
+#define PM660_AUTO_RES_MODE_BIT		BIT(7)
+#define PM660_AUTO_RES_MODE_SHIFT	7
+#define PM660_CAL_DURATION_MASK		GENMASK(6, 5)
+#define PM660_CAL_DURATION_SHIFT	5
+#define PM660_QWD_DRIVE_DURATION_BIT	BIT(4)
+#define PM660_QWD_DRIVE_DURATION_SHIFT	4
+#define PM660_CAL_EOP_BIT		BIT(3)
+#define PM660_CAL_EOP_SHIFT		3
+#define PM660_LRA_RES_CAL_MASK		GENMASK(2, 0)
+#define HAP_PM660_RES_CAL_PERIOD_MAX	256
+
+#define HAP_VMAX_CFG_REG(chip)		(chip->base + 0x51)
+#define HAP_VMAX_OVD_BIT		BIT(6)
+#define HAP_VMAX_MASK			GENMASK(5, 1)
+#define HAP_VMAX_SHIFT			1
+#define HAP_VMAX_MIN_MV			116
+#define HAP_VMAX_MAX_MV			3596
+
+#define HAP_ILIM_CFG_REG(chip)		(chip->base + 0x52)
+#define HAP_ILIM_SEL_MASK		BIT(0)
+#define HAP_ILIM_400_MA			0
+#define HAP_ILIM_800_MA			1
+
+#define HAP_SC_DEB_REG(chip)		(chip->base + 0x53)
+#define HAP_SC_DEB_MASK			GENMASK(2, 0)
+#define HAP_SC_DEB_CYCLES_MIN		0
+#define HAP_DEF_SC_DEB_CYCLES		8
+#define HAP_SC_DEB_CYCLES_MAX		32
+
+#define HAP_RATE_CFG1_REG(chip)		(chip->base + 0x54)
+#define HAP_RATE_CFG1_MASK		GENMASK(7, 0)
+
+#define HAP_RATE_CFG2_REG(chip)		(chip->base + 0x55)
+#define HAP_RATE_CFG2_MASK		GENMASK(3, 0)
+/* Shift needed to convert drive period upper bits [11:8] */
+#define HAP_RATE_CFG2_SHIFT		8
+
+#define HAP_INT_PWM_REG(chip)		(chip->base + 0x56)
+#define INT_PWM_FREQ_SEL_MASK		GENMASK(1, 0)
+#define INT_PWM_FREQ_253_KHZ		0
+#define INT_PWM_FREQ_505_KHZ		1
+#define INT_PWM_FREQ_739_KHZ		2
+#define INT_PWM_FREQ_1076_KHZ		3
+
+#define HAP_EXT_PWM_REG(chip)		(chip->base + 0x57)
+#define EXT_PWM_FREQ_SEL_MASK		GENMASK(1, 0)
+#define EXT_PWM_FREQ_25_KHZ		0
+#define EXT_PWM_FREQ_50_KHZ		1
+#define EXT_PWM_FREQ_75_KHZ		2
+#define EXT_PWM_FREQ_100_KHZ		3
+
+#define HAP_PWM_CAP_REG(chip)		(chip->base + 0x58)
+
+#define HAP_SC_CLR_REG(chip)		(chip->base + 0x59)
+#define SC_CLR_BIT			BIT(0)
+
+#define HAP_BRAKE_REG(chip)		(chip->base + 0x5C)
+#define HAP_BRAKE_PAT_MASK		0x3
+
+#define HAP_WF_REPEAT_REG(chip)		(chip->base + 0x5E)
+#define WF_REPEAT_MASK			GENMASK(6, 4)
+#define WF_REPEAT_SHIFT			4
+#define WF_REPEAT_MIN			1
+#define WF_REPEAT_MAX			128
+#define WF_S_REPEAT_MASK		GENMASK(1, 0)
+#define WF_S_REPEAT_MIN			1
+#define WF_S_REPEAT_MAX			8
+
+#define HAP_WF_S1_REG(chip)		(chip->base + 0x60)
+#define HAP_WF_SIGN_BIT			BIT(7)
+#define HAP_WF_OVD_BIT			BIT(6)
+#define HAP_WF_SAMP_MAX			GENMASK(5, 1)
+#define HAP_WF_SAMPLE_LEN		8
+
+#define HAP_PLAY_REG(chip)		(chip->base + 0x70)
+#define PLAY_BIT			BIT(7)
+#define PAUSE_BIT			BIT(0)
+
+#define HAP_SEC_ACCESS_REG(chip)	(chip->base + 0xD0)
+
+#define HAP_TEST2_REG(chip)		(chip->base + 0xE3)
+#define HAP_EXT_PWM_DTEST_MASK		GENMASK(6, 4)
+#define HAP_EXT_PWM_DTEST_SHIFT		4
+#define PWM_MAX_DTEST_LINES		4
+#define HAP_EXT_PWM_PEAK_DATA		0x7F
+#define HAP_EXT_PWM_HALF_DUTY		50
+#define HAP_EXT_PWM_FULL_DUTY		100
+#define HAP_EXT_PWM_DATA_FACTOR		39
+
+/* Other definitions */
+#define HAP_BRAKE_PAT_LEN		4
+#define HAP_WAVE_SAMP_LEN		8
+#define NUM_WF_SET			4
+#define HAP_WAVE_SAMP_SET_LEN		(HAP_WAVE_SAMP_LEN * NUM_WF_SET)
+#define HAP_RATE_CFG_STEP_US		5
+#define HAP_WAVE_PLAY_RATE_US_MIN	0
+#define HAP_DEF_WAVE_PLAY_RATE_US	5715
+#define HAP_WAVE_PLAY_RATE_US_MAX	20475
+#define HAP_MAX_PLAY_TIME_MS		15000
+
+enum hap_brake_pat {
+	NO_BRAKE = 0,
+	BRAKE_VMAX_4,
+	BRAKE_VMAX_2,
+	BRAKE_VMAX,
+};
+
+enum hap_auto_res_mode {
+	HAP_AUTO_RES_NONE,
+	HAP_AUTO_RES_ZXD,
+	HAP_AUTO_RES_QWD,
+	HAP_AUTO_RES_MAX_QWD,
+	HAP_AUTO_RES_ZXD_EOP,
+};
+
+enum hap_pm660_auto_res_mode {
+	HAP_PM660_AUTO_RES_ZXD,
+	HAP_PM660_AUTO_RES_QWD,
+};
+
+/* high Z option lines */
+enum hap_high_z {
+	HAP_LRA_HIGH_Z_NONE, /* opt0 for PM660 */
+	HAP_LRA_HIGH_Z_OPT1,
+	HAP_LRA_HIGH_Z_OPT2,
+	HAP_LRA_HIGH_Z_OPT3,
+};
+
+/* play modes */
+enum hap_mode {
+	HAP_DIRECT,
+	HAP_BUFFER,
+	HAP_AUDIO,
+	HAP_PWM,
+};
+
+/* wave/sample repeat */
+enum hap_rep_type {
+	HAP_WAVE_REPEAT = 1,
+	HAP_WAVE_SAMP_REPEAT,
+};
+
+/* status flags */
+enum hap_status {
+	AUTO_RESONANCE_ENABLED = BIT(0),
+};
+
+enum hap_play_control {
+	HAP_STOP,
+	HAP_PAUSE,
+	HAP_PLAY,
+};
+
+/* pwm channel parameters */
+struct pwm_param {
+	struct pwm_device	*pwm_dev;
+	u32			duty_us;
+	u32			period_us;
+};
+
+/*
+ *  hap_lra_ares_param - Haptic auto_resonance parameters
+ *  @ lra_qwd_drive_duration - LRA QWD drive duration
+ *  @ calibrate_at_eop - Calibrate at EOP
+ *  @ lra_res_cal_period - LRA resonance calibration period
+ *  @ auto_res_mode - auto resonace mode
+ *  @ lra_high_z - high z option line
+ */
+struct hap_lra_ares_param {
+	int				lra_qwd_drive_duration;
+	int				calibrate_at_eop;
+	enum hap_high_z			lra_high_z;
+	u16				lra_res_cal_period;
+	u8				auto_res_mode;
+};
+
+/*
+ *  hap_chip - Haptics data structure
+ *  @ pdev - platform device pointer
+ *  @ regmap - regmap pointer
+ *  @ bus_lock - spin lock for bus read/write
+ *  @ play_lock - mutex lock for haptics play/enable control
+ *  @ haptics_work - haptics worker
+ *  @ stop_timer - hrtimer for stopping haptics
+ *  @ auto_res_err_poll_timer - hrtimer for auto-resonance error
+ *  @ base - base address
+ *  @ play_irq - irq for play
+ *  @ sc_irq - irq for short circuit
+ *  @ pwm_data - pwm configuration
+ *  @ ares_cfg - auto resonance configuration
+ *  @ play_time_ms - play time set by the user in ms
+ *  @ max_play_time_ms - max play time in ms
+ *  @ vmax_mv - max voltage in mv
+ *  @ ilim_ma - limiting current in ma
+ *  @ sc_deb_cycles - short circuit debounce cycles
+ *  @ wave_play_rate_us - play rate for waveform
+ *  @ last_rate_cfg - Last rate config updated
+ *  @ wave_rep_cnt - waveform repeat count
+ *  @ wave_s_rep_cnt - waveform sample repeat count
+ *  @ ext_pwm_freq_khz - external pwm frequency in KHz
+ *  @ ext_pwm_dtest_line - DTEST line for external pwm
+ *  @ status_flags - status
+ *  @ play_mode - play mode
+ *  @ act_type - actuator type
+ *  @ wave_shape - waveform shape
+ *  @ wave_samp_idx - wave sample id used to refer start of a sample set
+ *  @ wave_samp - array of wave samples
+ *  @ brake_pat - pattern for active breaking
+ *  @ en_brake - brake state
+ *  @ misc_clk_trim_error_reg - MISC clock trim error register if present
+ *  @ clk_trim_error_code - MISC clock trim error code
+ *  @ drive_period_code_max_limit - calculated drive period code with
+      percentage variation on the higher side.
+ *  @ drive_period_code_min_limit - calculated drive period code with
+      percentage variation on the lower side
+ *  @ drive_period_code_max_var_pct - maximum limit of percentage variation of
+      drive period code
+ *  @ drive_period_code_min_var_pct - minimum limit of percentage variation of
+      drive period code
+ *  @ last_sc_time - Last time short circuit was detected
+ *  @ sc_count - counter to determine the duration of short circuit
+      condition
+ *  @ perm_disable - Flag to disable module permanently
+ *  @ state - current state of haptics
+ *  @ module_en - module enable status of haptics
+ *  @ lra_auto_mode - Auto mode selection
+ *  @ play_irq_en - Play interrupt enable status
+ *  @ auto_res_err_recovery_hw - Enable auto resonance error recovery by HW
+ */
+struct hap_chip {
+	struct platform_device		*pdev;
+	struct regmap			*regmap;
+	struct pmic_revid_data		*revid;
+	struct led_classdev		cdev;
+	spinlock_t			bus_lock;
+	struct mutex			play_lock;
+	struct mutex			param_lock;
+	struct work_struct		haptics_work;
+	struct hrtimer			stop_timer;
+	struct hrtimer			auto_res_err_poll_timer;
+	u16				base;
+	int				play_irq;
+	int				sc_irq;
+	struct pwm_param		pwm_data;
+	struct hap_lra_ares_param	ares_cfg;
+	u32				play_time_ms;
+	u32				max_play_time_ms;
+	u32				vmax_mv;
+	u8				ilim_ma;
+	u32				sc_deb_cycles;
+	u32				wave_play_rate_us;
+	u16				last_rate_cfg;
+	u32				wave_rep_cnt;
+	u32				wave_s_rep_cnt;
+	u32				ext_pwm_freq_khz;
+	u8				ext_pwm_dtest_line;
+	u32				status_flags;
+	enum hap_mode			play_mode;
+	u8				act_type;
+	u8				wave_shape;
+	u8				wave_samp_idx;
+	u32				wave_samp[HAP_WAVE_SAMP_SET_LEN];
+	u32				brake_pat[HAP_BRAKE_PAT_LEN];
+	bool				en_brake;
+	u32				misc_clk_trim_error_reg;
+	u8				clk_trim_error_code;
+	u16				drive_period_code_max_limit;
+	u16				drive_period_code_min_limit;
+	u8				drive_period_code_max_var_pct;
+	u8				drive_period_code_min_var_pct;
+	ktime_t				last_sc_time;
+	u8				sc_count;
+	bool				perm_disable;
+	atomic_t			state;
+	bool				module_en;
+	bool				lra_auto_mode;
+	bool				play_irq_en;
+	bool				auto_res_err_recovery_hw;
+};
+
+static int qpnp_haptics_parse_buffer_dt(struct hap_chip *chip);
+static int qpnp_haptics_parse_pwm_dt(struct hap_chip *chip);
+
+static int qpnp_haptics_read_reg(struct hap_chip *chip, u16 addr, u8 *val,
+				int len)
+{
+	int rc;
+
+	rc = regmap_bulk_read(chip->regmap, addr, val, len);
+	if (rc < 0)
+		pr_err("Error reading address: 0x%x - rc %d\n", addr, rc);
+
+	return rc;
+}
+
+static inline bool is_secure(u16 addr)
+{
+	return ((addr & 0xFF) > 0xD0);
+}
+
+static int qpnp_haptics_write_reg(struct hap_chip *chip, u16 addr, u8 *val,
+				int len)
+{
+	unsigned long flags;
+	unsigned int unlock = 0xA5;
+	int rc = 0, i;
+
+	spin_lock_irqsave(&chip->bus_lock, flags);
+
+	if (is_secure(addr)) {
+		for (i = 0; i < len; i++) {
+			rc = regmap_write(chip->regmap,
+					HAP_SEC_ACCESS_REG(chip), unlock);
+			if (rc < 0) {
+				pr_err("Error writing unlock code - rc %d\n",
+					rc);
+				goto out;
+			}
+
+			rc = regmap_write(chip->regmap, addr + i, val[i]);
+			if (rc < 0) {
+				pr_err("Error writing address 0x%x - rc %d\n",
+					addr + i, rc);
+				goto out;
+			}
+		}
+	} else {
+		if (len > 1)
+			rc = regmap_bulk_write(chip->regmap, addr, val, len);
+		else
+			rc = regmap_write(chip->regmap, addr, *val);
+	}
+
+	if (rc < 0)
+		pr_err("Error writing address: 0x%x - rc %d\n", addr, rc);
+
+out:
+	spin_unlock_irqrestore(&chip->bus_lock, flags);
+	return rc;
+}
+
+static int qpnp_haptics_masked_write_reg(struct hap_chip *chip, u16 addr,
+					u8 mask, u8 val)
+{
+	unsigned long flags;
+	unsigned int unlock = 0xA5;
+	int rc;
+
+	spin_lock_irqsave(&chip->bus_lock, flags);
+	if (is_secure(addr)) {
+		rc = regmap_write(chip->regmap, HAP_SEC_ACCESS_REG(chip),
+				unlock);
+		if (rc < 0) {
+			pr_err("Error writing unlock code - rc %d\n", rc);
+			goto out;
+		}
+	}
+
+	rc = regmap_update_bits(chip->regmap, addr, mask, val);
+	if (rc < 0)
+		pr_err("Error writing address: 0x%x - rc %d\n", addr, rc);
+
+	if (!rc)
+		pr_debug("wrote to address 0x%x = 0x%x\n", addr, val);
+out:
+	spin_unlock_irqrestore(&chip->bus_lock, flags);
+	return rc;
+}
+
+static bool is_sw_lra_auto_resonance_control(struct hap_chip *chip)
+{
+	if (chip->act_type != HAP_LRA)
+		return false;
+
+	if (chip->auto_res_err_recovery_hw)
+		return false;
+
+	/*
+	 * For short pattern in auto mode, we use buffer mode and auto
+	 * resonance is not needed.
+	 */
+	if (chip->lra_auto_mode && chip->play_mode == HAP_BUFFER)
+		return false;
+
+	return true;
+}
+
+#define HAPTICS_BACK_EMF_DELAY_US	20000
+static int qpnp_haptics_auto_res_enable(struct hap_chip *chip, bool enable)
+{
+	int rc = 0;
+	u32 delay_us = HAPTICS_BACK_EMF_DELAY_US;
+	u8 val, auto_res_mode_qwd;
+
+	if (chip->act_type != HAP_LRA)
+		return 0;
+
+	if (chip->revid->pmic_subtype == PM660_SUBTYPE)
+		auto_res_mode_qwd = (chip->ares_cfg.auto_res_mode ==
+						HAP_PM660_AUTO_RES_QWD);
+	else
+		auto_res_mode_qwd = (chip->ares_cfg.auto_res_mode ==
+							HAP_AUTO_RES_QWD);
+
+	/*
+	 * Do not enable auto resonance if auto mode is enabled and auto
+	 * resonance mode is QWD, meaning short pattern.
+	 */
+	if (chip->lra_auto_mode && auto_res_mode_qwd && enable) {
+		pr_debug("auto_mode enabled, not enabling auto_res\n");
+		return 0;
+	}
+
+	/*
+	 * For auto resonance detection to work properly, sufficient back-emf
+	 * has to be generated. In general, back-emf takes some time to build
+	 * up. When the auto resonance mode is chosen as QWD, high-z will be
+	 * applied for every LRA cycle and hence there won't be enough back-emf
+	 * at the start-up. Hence, the motor needs to vibrate for few LRA cycles
+	 * after the PLAY bit is asserted. Enable the auto resonance after
+	 * 'time_required_to_generate_back_emf_us' is completed.
+	 */
+
+	if (auto_res_mode_qwd && enable)
+		usleep_range(delay_us, delay_us + 1);
+
+	val = enable ? AUTO_RES_EN_BIT : 0;
+
+	if (chip->revid->pmic_subtype == PM660_SUBTYPE)
+		rc = qpnp_haptics_masked_write_reg(chip,
+				HAP_AUTO_RES_CTRL_REG(chip),
+				AUTO_RES_EN_BIT, val);
+	else
+		rc = qpnp_haptics_masked_write_reg(chip, HAP_TEST2_REG(chip),
+				AUTO_RES_EN_BIT, val);
+	if (rc < 0)
+		return rc;
+
+	if (enable)
+		chip->status_flags |= AUTO_RESONANCE_ENABLED;
+	else
+		chip->status_flags &= ~AUTO_RESONANCE_ENABLED;
+
+	pr_debug("auto_res %sabled\n", enable ? "en" : "dis");
+	return rc;
+}
+
+static int qpnp_haptics_update_rate_cfg(struct hap_chip *chip, u16 play_rate)
+{
+	int rc;
+	u8 val[2];
+
+	if (chip->last_rate_cfg == play_rate) {
+		pr_debug("Same rate_cfg %x\n", play_rate);
+		return 0;
+	}
+
+	val[0] = play_rate & HAP_RATE_CFG1_MASK;
+	val[1] = (play_rate >> HAP_RATE_CFG2_SHIFT) & HAP_RATE_CFG2_MASK;
+	rc = qpnp_haptics_write_reg(chip, HAP_RATE_CFG1_REG(chip), val, 2);
+	if (rc < 0)
+		return rc;
+
+	pr_debug("Play rate code 0x%x\n", play_rate);
+	chip->last_rate_cfg = play_rate;
+	return 0;
+}
+
+static void qpnp_haptics_update_lra_frequency(struct hap_chip *chip)
+{
+	u8 lra_auto_res[2], val;
+	u32 play_rate_code;
+	u16 rate_cfg;
+	int rc;
+
+	rc = qpnp_haptics_read_reg(chip, HAP_LRA_AUTO_RES_LO_REG(chip),
+				lra_auto_res, 2);
+	if (rc < 0) {
+		pr_err("Error in reading LRA_AUTO_RES_LO/HI, rc=%d\n", rc);
+		return;
+	}
+
+	play_rate_code =
+		 (lra_auto_res[1] & 0xF0) << 4 | (lra_auto_res[0] & 0xFF);
+
+	pr_debug("lra_auto_res_lo = 0x%x lra_auto_res_hi = 0x%x play_rate_code = 0x%x\n",
+		lra_auto_res[0], lra_auto_res[1], play_rate_code);
+
+	rc = qpnp_haptics_read_reg(chip, HAP_STATUS_1_REG(chip), &val, 1);
+	if (rc < 0)
+		return;
+
+	/*
+	 * If the drive period code read from AUTO_RES_LO and AUTO_RES_HI
+	 * registers is more than the max limit percent variation or less
+	 * than the min limit percent variation specified through DT, then
+	 * auto-resonance is disabled.
+	 */
+
+	if ((val & AUTO_RES_ERROR_BIT) ||
+		((play_rate_code <= chip->drive_period_code_min_limit) ||
+		(play_rate_code >= chip->drive_period_code_max_limit))) {
+		if (val & AUTO_RES_ERROR_BIT)
+			pr_debug("Auto-resonance error %x\n", val);
+		else
+			pr_debug("play rate %x out of bounds [min: 0x%x, max: 0x%x]\n",
+				play_rate_code,
+				chip->drive_period_code_min_limit,
+				chip->drive_period_code_max_limit);
+		rc = qpnp_haptics_auto_res_enable(chip, false);
+		if (rc < 0)
+			pr_debug("Auto-resonance disable failed\n");
+		return;
+	}
+
+	/*
+	 * bits[7:4] of AUTO_RES_HI should be written to bits[3:0] of RATE_CFG2
+	 */
+	lra_auto_res[1] >>= 4;
+	rate_cfg = lra_auto_res[1] << 8 | lra_auto_res[0];
+	rc = qpnp_haptics_update_rate_cfg(chip, rate_cfg);
+	if (rc < 0)
+		pr_debug("Error in updating rate_cfg\n");
+}
+
+#define MAX_RETRIES	5
+#define HAP_CYCLES	4
+static bool is_haptics_idle(struct hap_chip *chip)
+{
+	unsigned long wait_time_us;
+	int rc, i;
+	u8 val;
+
+	rc = qpnp_haptics_read_reg(chip, HAP_STATUS_1_REG(chip), &val, 1);
+	if (rc < 0)
+		return false;
+
+	if (!(val & HAP_BUSY_BIT))
+		return true;
+
+	if (chip->play_time_ms <= 20)
+		wait_time_us = chip->play_time_ms * 1000;
+	else
+		wait_time_us = chip->wave_play_rate_us * HAP_CYCLES;
+
+	for (i = 0; i < MAX_RETRIES; i++) {
+		/* wait for play_rate cycles */
+		usleep_range(wait_time_us, wait_time_us + 1);
+
+		if (chip->play_mode == HAP_DIRECT ||
+				chip->play_mode == HAP_PWM)
+			return true;
+
+		rc = qpnp_haptics_read_reg(chip, HAP_STATUS_1_REG(chip), &val,
+					1);
+		if (rc < 0)
+			return false;
+
+		if (!(val & HAP_BUSY_BIT))
+			return true;
+	}
+
+	if (i >= MAX_RETRIES && (val & HAP_BUSY_BIT)) {
+		pr_debug("Haptics Busy after %d retries\n", i);
+		return false;
+	}
+
+	return true;
+}
+
+static int qpnp_haptics_mod_enable(struct hap_chip *chip, bool enable)
+{
+	u8 val;
+	int rc;
+
+	if (chip->module_en == enable)
+		return 0;
+
+	if (!enable) {
+		if (!is_haptics_idle(chip))
+			pr_debug("Disabling module forcibly\n");
+	}
+
+	val = enable ? HAP_EN_BIT : 0;
+	rc = qpnp_haptics_write_reg(chip, HAP_EN_CTL_REG(chip), &val, 1);
+	if (rc < 0)
+		return rc;
+
+	chip->module_en = enable;
+	return 0;
+}
+
+static int qpnp_haptics_play_control(struct hap_chip *chip,
+					enum hap_play_control ctrl)
+{
+	u8 val;
+	int rc;
+
+	switch (ctrl) {
+	case HAP_STOP:
+		val = 0;
+		break;
+	case HAP_PAUSE:
+		val = PAUSE_BIT;
+		break;
+	case HAP_PLAY:
+		val = PLAY_BIT;
+		break;
+	default:
+		return 0;
+	}
+
+	rc = qpnp_haptics_write_reg(chip, HAP_PLAY_REG(chip), &val, 1);
+	if (rc < 0) {
+		pr_err("Error in writing to PLAY_REG, rc=%d\n", rc);
+		return rc;
+	}
+
+	pr_debug("haptics play ctrl: %d\n", ctrl);
+	return rc;
+}
+
+#define AUTO_RES_ERR_POLL_TIME_NS	(20 * NSEC_PER_MSEC)
+static int qpnp_haptics_play(struct hap_chip *chip, bool enable)
+{
+	int rc = 0, time_ms = chip->play_time_ms;
+
+	if (chip->perm_disable && enable)
+		return 0;
+
+	mutex_lock(&chip->play_lock);
+
+	if (enable) {
+		if (chip->play_mode == HAP_PWM) {
+			rc = pwm_enable(chip->pwm_data.pwm_dev);
+			if (rc < 0) {
+				pr_err("Error in enabling PWM, rc=%d\n", rc);
+				goto out;
+			}
+		}
+
+		rc = qpnp_haptics_auto_res_enable(chip, false);
+		if (rc < 0) {
+			pr_err("Error in disabling auto_res, rc=%d\n", rc);
+			goto out;
+		}
+
+		rc = qpnp_haptics_mod_enable(chip, true);
+		if (rc < 0) {
+			pr_err("Error in enabling module, rc=%d\n", rc);
+			goto out;
+		}
+
+		rc = qpnp_haptics_play_control(chip, HAP_PLAY);
+		if (rc < 0) {
+			pr_err("Error in enabling play, rc=%d\n", rc);
+			goto out;
+		}
+
+		if (chip->play_mode != HAP_BUFFER)
+			hrtimer_start(&chip->stop_timer,
+				ktime_set(time_ms / MSEC_PER_SEC,
+				(time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC),
+				HRTIMER_MODE_REL);
+
+		rc = qpnp_haptics_auto_res_enable(chip, true);
+		if (rc < 0) {
+			pr_err("Error in enabling auto_res, rc=%d\n", rc);
+			goto out;
+		}
+
+		if (is_sw_lra_auto_resonance_control(chip))
+			hrtimer_start(&chip->auto_res_err_poll_timer,
+				ktime_set(0, AUTO_RES_ERR_POLL_TIME_NS),
+				HRTIMER_MODE_REL);
+	} else {
+		rc = qpnp_haptics_play_control(chip, HAP_STOP);
+		if (rc < 0) {
+			pr_err("Error in disabling play, rc=%d\n", rc);
+			goto out;
+		}
+
+		if (is_sw_lra_auto_resonance_control(chip)) {
+			if (chip->status_flags & AUTO_RESONANCE_ENABLED)
+				qpnp_haptics_update_lra_frequency(chip);
+			hrtimer_cancel(&chip->auto_res_err_poll_timer);
+		}
+
+		if (chip->play_mode == HAP_PWM)
+			pwm_disable(chip->pwm_data.pwm_dev);
+	}
+
+out:
+	mutex_unlock(&chip->play_lock);
+	return rc;
+}
+
+static void qpnp_haptics_work(struct work_struct *work)
+{
+	struct hap_chip *chip = container_of(work, struct hap_chip,
+						haptics_work);
+	int rc;
+	bool enable;
+
+	enable = atomic_read(&chip->state);
+	pr_debug("state: %d\n", enable);
+	rc = qpnp_haptics_play(chip, enable);
+	if (rc < 0)
+		pr_err("Error in %sing haptics, rc=%d\n",
+			enable ? "play" : "stopp", rc);
+}
+
+static enum hrtimer_restart hap_stop_timer(struct hrtimer *timer)
+{
+	struct hap_chip *chip = container_of(timer, struct hap_chip,
+					stop_timer);
+
+	atomic_set(&chip->state, 0);
+	schedule_work(&chip->haptics_work);
+
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart hap_auto_res_err_poll_timer(struct hrtimer *timer)
+{
+	struct hap_chip *chip = container_of(timer, struct hap_chip,
+					auto_res_err_poll_timer);
+
+	if (!(chip->status_flags & AUTO_RESONANCE_ENABLED))
+		return HRTIMER_NORESTART;
+
+	qpnp_haptics_update_lra_frequency(chip);
+	hrtimer_forward(&chip->auto_res_err_poll_timer, ktime_get(),
+			ktime_set(0, AUTO_RES_ERR_POLL_TIME_NS));
+
+	return HRTIMER_NORESTART;
+}
+
+static int qpnp_haptics_suspend(struct device *dev)
+{
+	struct hap_chip *chip = dev_get_drvdata(dev);
+	int rc;
+
+	rc = qpnp_haptics_play(chip, false);
+	if (rc < 0)
+		pr_err("Error in stopping haptics, rc=%d\n", rc);
+
+	rc = qpnp_haptics_mod_enable(chip, false);
+	if (rc < 0)
+		pr_err("Error in disabling module, rc=%d\n", rc);
+
+	return 0;
+}
+
+static int qpnp_haptics_wave_rep_config(struct hap_chip *chip,
+					enum hap_rep_type type)
+{
+	int rc;
+	u8 val = 0, mask = 0;
+
+	if (type & HAP_WAVE_REPEAT) {
+		if (chip->wave_rep_cnt < WF_REPEAT_MIN)
+			chip->wave_rep_cnt = WF_REPEAT_MIN;
+		else if (chip->wave_rep_cnt > WF_REPEAT_MAX)
+			chip->wave_rep_cnt = WF_REPEAT_MAX;
+		mask = WF_REPEAT_MASK;
+		val = ilog2(chip->wave_rep_cnt) << WF_REPEAT_SHIFT;
+	}
+
+	if (type & HAP_WAVE_SAMP_REPEAT) {
+		if (chip->wave_s_rep_cnt < WF_S_REPEAT_MIN)
+			chip->wave_s_rep_cnt = WF_S_REPEAT_MIN;
+		else if (chip->wave_s_rep_cnt > WF_S_REPEAT_MAX)
+			chip->wave_s_rep_cnt = WF_S_REPEAT_MAX;
+		mask |= WF_S_REPEAT_MASK;
+		val |= ilog2(chip->wave_s_rep_cnt);
+	}
+
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_WF_REPEAT_REG(chip),
+			mask, val);
+	return rc;
+}
+
+/* configuration api for buffer mode */
+static int qpnp_haptics_buffer_config(struct hap_chip *chip, u32 *wave_samp,
+				bool overdrive)
+{
+	u8 buf[HAP_WAVE_SAMP_LEN];
+	u32 *ptr;
+	int rc, i;
+
+	if (wave_samp) {
+		ptr = wave_samp;
+	} else {
+		if (chip->wave_samp_idx >= ARRAY_SIZE(chip->wave_samp)) {
+			pr_err("Incorrect wave_samp_idx %d\n",
+				chip->wave_samp_idx);
+			return -EINVAL;
+		}
+
+		ptr = &chip->wave_samp[chip->wave_samp_idx];
+	}
+
+	/* Don't set override bit in waveform sample for PM660 */
+	if (chip->revid->pmic_subtype == PM660_SUBTYPE)
+		overdrive = false;
+
+	/* Configure WAVE_SAMPLE1 to WAVE_SAMPLE8 register */
+	for (i = 0; i < HAP_WAVE_SAMP_LEN; i++) {
+		buf[i] = ptr[i];
+		if (buf[i])
+			buf[i] |= (overdrive ? HAP_WF_OVD_BIT : 0);
+	}
+
+	rc = qpnp_haptics_write_reg(chip, HAP_WF_S1_REG(chip), buf,
+			HAP_WAVE_SAMP_LEN);
+	return rc;
+}
+
+/* configuration api for pwm */
+static int qpnp_haptics_pwm_config(struct hap_chip *chip)
+{
+	u8 val = 0;
+	int rc;
+
+	if (chip->ext_pwm_freq_khz == 0)
+		return 0;
+
+	/* Configure the EXTERNAL_PWM register */
+	if (chip->ext_pwm_freq_khz <= EXT_PWM_FREQ_25_KHZ) {
+		chip->ext_pwm_freq_khz = EXT_PWM_FREQ_25_KHZ;
+		val = 0;
+	} else if (chip->ext_pwm_freq_khz <= EXT_PWM_FREQ_50_KHZ) {
+		chip->ext_pwm_freq_khz = EXT_PWM_FREQ_50_KHZ;
+		val = 1;
+	} else if (chip->ext_pwm_freq_khz <= EXT_PWM_FREQ_75_KHZ) {
+		chip->ext_pwm_freq_khz = EXT_PWM_FREQ_75_KHZ;
+		val = 2;
+	} else {
+		chip->ext_pwm_freq_khz = EXT_PWM_FREQ_100_KHZ;
+		val = 3;
+	}
+
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_EXT_PWM_REG(chip),
+			EXT_PWM_FREQ_SEL_MASK, val);
+	if (rc < 0)
+		return rc;
+
+	if (chip->ext_pwm_dtest_line < 0 ||
+			chip->ext_pwm_dtest_line > PWM_MAX_DTEST_LINES) {
+		pr_err("invalid dtest line\n");
+		return -EINVAL;
+	}
+
+	if (chip->ext_pwm_dtest_line > 0) {
+		/* disable auto res for PWM mode */
+		val = chip->ext_pwm_dtest_line << HAP_EXT_PWM_DTEST_SHIFT;
+		rc = qpnp_haptics_masked_write_reg(chip, HAP_TEST2_REG(chip),
+			HAP_EXT_PWM_DTEST_MASK | AUTO_RES_EN_BIT, val);
+		if (rc < 0)
+			return rc;
+	}
+
+	rc = pwm_config(chip->pwm_data.pwm_dev,
+			chip->pwm_data.duty_us * NSEC_PER_USEC,
+			chip->pwm_data.period_us * NSEC_PER_USEC);
+	if (rc < 0) {
+		pr_err("pwm_config failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int qpnp_haptics_lra_auto_res_config(struct hap_chip *chip,
+					struct hap_lra_ares_param *tmp_cfg)
+{
+	struct hap_lra_ares_param *ares_cfg;
+	int rc;
+	u8 val = 0, mask = 0;
+
+	/* disable auto resonance for ERM */
+	if (chip->act_type == HAP_ERM) {
+		val = 0x00;
+		rc = qpnp_haptics_write_reg(chip, HAP_LRA_AUTO_RES_REG(chip),
+					&val, 1);
+		return rc;
+	}
+
+	if (chip->auto_res_err_recovery_hw) {
+		rc = qpnp_haptics_masked_write_reg(chip,
+			HAP_AUTO_RES_CTRL_REG(chip),
+			AUTO_RES_ERR_RECOVERY_BIT, AUTO_RES_ERR_RECOVERY_BIT);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (tmp_cfg)
+		ares_cfg = tmp_cfg;
+	else
+		ares_cfg = &chip->ares_cfg;
+
+	if (ares_cfg->lra_res_cal_period < HAP_RES_CAL_PERIOD_MIN)
+		ares_cfg->lra_res_cal_period = HAP_RES_CAL_PERIOD_MIN;
+
+	if (chip->revid->pmic_subtype == PM660_SUBTYPE) {
+		if (ares_cfg->lra_res_cal_period >
+				HAP_PM660_RES_CAL_PERIOD_MAX)
+			ares_cfg->lra_res_cal_period =
+				HAP_PM660_RES_CAL_PERIOD_MAX;
+
+		if (ares_cfg->auto_res_mode == HAP_PM660_AUTO_RES_QWD)
+			ares_cfg->lra_res_cal_period = 0;
+
+		if (ares_cfg->lra_res_cal_period)
+			val = ilog2(ares_cfg->lra_res_cal_period /
+					HAP_RES_CAL_PERIOD_MIN) + 1;
+	} else {
+		if (ares_cfg->lra_res_cal_period > HAP_RES_CAL_PERIOD_MAX)
+			ares_cfg->lra_res_cal_period =
+				HAP_RES_CAL_PERIOD_MAX;
+
+		if (ares_cfg->lra_res_cal_period)
+			val = ilog2(ares_cfg->lra_res_cal_period /
+					HAP_RES_CAL_PERIOD_MIN);
+	}
+
+	if (chip->revid->pmic_subtype == PM660_SUBTYPE) {
+		val |= ares_cfg->auto_res_mode << PM660_AUTO_RES_MODE_SHIFT;
+		mask = PM660_AUTO_RES_MODE_BIT;
+		val |= ares_cfg->lra_high_z << PM660_CAL_DURATION_SHIFT;
+		mask |= PM660_CAL_DURATION_MASK;
+		if (ares_cfg->lra_qwd_drive_duration != -EINVAL) {
+			val |= ares_cfg->lra_qwd_drive_duration <<
+				PM660_QWD_DRIVE_DURATION_SHIFT;
+			mask |= PM660_QWD_DRIVE_DURATION_BIT;
+		}
+		if (ares_cfg->calibrate_at_eop != -EINVAL) {
+			val |= ares_cfg->calibrate_at_eop <<
+				PM660_CAL_EOP_SHIFT;
+			mask |= PM660_CAL_EOP_BIT;
+		}
+		mask |= PM660_LRA_RES_CAL_MASK;
+	} else {
+		val |= (ares_cfg->auto_res_mode << LRA_AUTO_RES_MODE_SHIFT);
+		val |= (ares_cfg->lra_high_z << LRA_HIGH_Z_SHIFT);
+		mask = LRA_AUTO_RES_MODE_MASK | LRA_HIGH_Z_MASK |
+			LRA_RES_CAL_MASK;
+	}
+
+	pr_debug("mode: %d hi_z period: %d cal_period: %d\n",
+		ares_cfg->auto_res_mode, ares_cfg->lra_high_z,
+		ares_cfg->lra_res_cal_period);
+
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_LRA_AUTO_RES_REG(chip),
+			mask, val);
+	return rc;
+}
+
+/* configuration api for play mode */
+static int qpnp_haptics_play_mode_config(struct hap_chip *chip)
+{
+	u8 val = 0;
+	int rc;
+
+	if (!is_haptics_idle(chip))
+		return -EBUSY;
+
+	val = chip->play_mode << HAP_WF_SOURCE_SHIFT;
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_SEL_REG(chip),
+			HAP_WF_SOURCE_MASK, val);
+	if (!rc) {
+		if (chip->play_mode == HAP_BUFFER && !chip->play_irq_en) {
+			enable_irq(chip->play_irq);
+			chip->play_irq_en = true;
+		} else if (chip->play_mode != HAP_BUFFER && chip->play_irq_en) {
+			disable_irq(chip->play_irq);
+			chip->play_irq_en = false;
+		}
+	}
+	return rc;
+}
+
+/* configuration api for max voltage */
+static int qpnp_haptics_vmax_config(struct hap_chip *chip, int vmax_mv,
+				bool overdrive)
+{
+	u8 val = 0;
+	int rc;
+
+	if (vmax_mv < 0)
+		return -EINVAL;
+
+	/* Allow setting override bit in VMAX_CFG only for PM660 */
+	if (chip->revid->pmic_subtype != PM660_SUBTYPE)
+		overdrive = false;
+
+	if (vmax_mv < HAP_VMAX_MIN_MV)
+		vmax_mv = HAP_VMAX_MIN_MV;
+	else if (vmax_mv > HAP_VMAX_MAX_MV)
+		vmax_mv = HAP_VMAX_MAX_MV;
+
+	val = DIV_ROUND_CLOSEST(vmax_mv, HAP_VMAX_MIN_MV);
+	val <<= HAP_VMAX_SHIFT;
+	if (overdrive)
+		val |= HAP_VMAX_OVD_BIT;
+
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_VMAX_CFG_REG(chip),
+			HAP_VMAX_MASK | HAP_VMAX_OVD_BIT, val);
+	return rc;
+}
+
+/* configuration api for ilim */
+static int qpnp_haptics_ilim_config(struct hap_chip *chip)
+{
+	int rc;
+
+	if (chip->ilim_ma < HAP_ILIM_400_MA)
+		chip->ilim_ma = HAP_ILIM_400_MA;
+	else if (chip->ilim_ma > HAP_ILIM_800_MA)
+		chip->ilim_ma = HAP_ILIM_800_MA;
+
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_ILIM_CFG_REG(chip),
+			HAP_ILIM_SEL_MASK, chip->ilim_ma);
+	return rc;
+}
+
+/* configuration api for short circuit debounce */
+static int qpnp_haptics_sc_deb_config(struct hap_chip *chip)
+{
+	u8 val = 0;
+	int rc;
+
+	if (chip->sc_deb_cycles < HAP_SC_DEB_CYCLES_MIN)
+		chip->sc_deb_cycles = HAP_SC_DEB_CYCLES_MIN;
+	else if (chip->sc_deb_cycles > HAP_SC_DEB_CYCLES_MAX)
+		chip->sc_deb_cycles = HAP_SC_DEB_CYCLES_MAX;
+
+	if (chip->sc_deb_cycles != HAP_SC_DEB_CYCLES_MIN)
+		val = ilog2(chip->sc_deb_cycles /
+			HAP_DEF_SC_DEB_CYCLES) + 1;
+	else
+		val = HAP_SC_DEB_CYCLES_MIN;
+
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_SC_DEB_REG(chip),
+			HAP_SC_DEB_MASK, val);
+
+	return rc;
+}
+
+static int qpnp_haptics_brake_config(struct hap_chip *chip, u32 *brake_pat)
+{
+	int rc, i;
+	u32 temp, *ptr;
+	u8 val;
+
+	/* Configure BRAKE register */
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_EN_CTL2_REG(chip),
+			BRAKE_EN_BIT, (u8)chip->en_brake);
+	if (rc < 0)
+		return rc;
+
+	/* If braking is not enabled, skip configuring brake pattern */
+	if (!chip->en_brake)
+		return 0;
+
+	if (!brake_pat)
+		ptr = chip->brake_pat;
+	else
+		ptr = brake_pat;
+
+	for (i = HAP_BRAKE_PAT_LEN - 1, val = 0; i >= 0; i--) {
+		ptr[i] &= HAP_BRAKE_PAT_MASK;
+		temp = i << 1;
+		val |= ptr[i] << temp;
+	}
+
+	rc = qpnp_haptics_write_reg(chip, HAP_BRAKE_REG(chip), &val, 1);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static int qpnp_haptics_auto_mode_config(struct hap_chip *chip, int time_ms)
+{
+	struct hap_lra_ares_param ares_cfg;
+	enum hap_mode old_play_mode;
+	u8 old_ares_mode;
+	u32 brake_pat[HAP_BRAKE_PAT_LEN] = {0};
+	u32 wave_samp[HAP_WAVE_SAMP_LEN] = {0};
+	int rc, vmax_mv;
+
+	if (!chip->lra_auto_mode)
+		return false;
+
+	/* For now, this is for LRA only */
+	if (chip->act_type == HAP_ERM)
+		return 0;
+
+	old_ares_mode = chip->ares_cfg.auto_res_mode;
+	old_play_mode = chip->play_mode;
+	pr_debug("auto_mode, time_ms: %d\n", time_ms);
+	if (time_ms <= 20) {
+		wave_samp[0] = HAP_WF_SAMP_MAX;
+		wave_samp[1] = HAP_WF_SAMP_MAX;
+		if (time_ms > 15)
+			wave_samp[2] = HAP_WF_SAMP_MAX;
+
+		/* short pattern */
+		rc = qpnp_haptics_parse_buffer_dt(chip);
+		if (!rc) {
+			rc = qpnp_haptics_wave_rep_config(chip,
+				HAP_WAVE_REPEAT | HAP_WAVE_SAMP_REPEAT);
+			if (rc < 0) {
+				pr_err("Error in configuring wave_rep config %d\n",
+					rc);
+				return rc;
+			}
+
+			rc = qpnp_haptics_buffer_config(chip, wave_samp, true);
+			if (rc < 0) {
+				pr_err("Error in configuring buffer mode %d\n",
+					rc);
+				return rc;
+			}
+		}
+
+		ares_cfg.lra_high_z = HAP_LRA_HIGH_Z_OPT1;
+		ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MIN;
+		if (chip->revid->pmic_subtype == PM660_SUBTYPE) {
+			ares_cfg.auto_res_mode = HAP_PM660_AUTO_RES_QWD;
+			ares_cfg.lra_qwd_drive_duration = 0;
+			ares_cfg.calibrate_at_eop = 0;
+		} else {
+			ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD;
+			ares_cfg.lra_qwd_drive_duration = -EINVAL;
+			ares_cfg.calibrate_at_eop = -EINVAL;
+		}
+
+		vmax_mv = HAP_VMAX_MAX_MV;
+		rc = qpnp_haptics_vmax_config(chip, vmax_mv, true);
+		if (rc < 0)
+			return rc;
+
+		rc = qpnp_haptics_brake_config(chip, brake_pat);
+		if (rc < 0)
+			return rc;
+
+		/* enable play_irq for buffer mode */
+		if (chip->play_irq >= 0 && !chip->play_irq_en) {
+			enable_irq(chip->play_irq);
+			chip->play_irq_en = true;
+		}
+
+		chip->play_mode = HAP_BUFFER;
+		chip->wave_shape = HAP_WAVE_SQUARE;
+	} else {
+		/* long pattern */
+		ares_cfg.lra_high_z = HAP_LRA_HIGH_Z_OPT1;
+		if (chip->revid->pmic_subtype == PM660_SUBTYPE) {
+			ares_cfg.auto_res_mode = HAP_PM660_AUTO_RES_ZXD;
+			ares_cfg.lra_res_cal_period =
+				HAP_PM660_RES_CAL_PERIOD_MAX;
+			ares_cfg.lra_qwd_drive_duration = 0;
+			ares_cfg.calibrate_at_eop = 1;
+		} else {
+			ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP;
+			ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MAX;
+			ares_cfg.lra_qwd_drive_duration = -EINVAL;
+			ares_cfg.calibrate_at_eop = -EINVAL;
+		}
+
+		vmax_mv = chip->vmax_mv;
+		rc = qpnp_haptics_vmax_config(chip, vmax_mv, false);
+		if (rc < 0)
+			return rc;
+
+		brake_pat[0] = 0x3;
+		rc = qpnp_haptics_brake_config(chip, brake_pat);
+		if (rc < 0)
+			return rc;
+
+		/* enable play_irq for direct mode */
+		if (chip->play_irq >= 0 && chip->play_irq_en) {
+			disable_irq(chip->play_irq);
+			chip->play_irq_en = false;
+		}
+
+		chip->play_mode = HAP_DIRECT;
+		chip->wave_shape = HAP_WAVE_SINE;
+	}
+
+	chip->ares_cfg.auto_res_mode = ares_cfg.auto_res_mode;
+	rc = qpnp_haptics_lra_auto_res_config(chip, &ares_cfg);
+	if (rc < 0) {
+		chip->ares_cfg.auto_res_mode = old_ares_mode;
+		return rc;
+	}
+
+	rc = qpnp_haptics_play_mode_config(chip);
+	if (rc < 0) {
+		chip->play_mode = old_play_mode;
+		return rc;
+	}
+
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG2_REG(chip),
+			HAP_LRA_RES_TYPE_MASK, chip->wave_shape);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static irqreturn_t qpnp_haptics_play_irq_handler(int irq, void *data)
+{
+	struct hap_chip *chip = data;
+	int rc;
+
+	if (chip->play_mode != HAP_BUFFER)
+		goto irq_handled;
+
+	if (chip->wave_samp[chip->wave_samp_idx + HAP_WAVE_SAMP_LEN] > 0) {
+		chip->wave_samp_idx += HAP_WAVE_SAMP_LEN;
+		if (chip->wave_samp_idx >= ARRAY_SIZE(chip->wave_samp)) {
+			pr_debug("Samples over\n");
+			/* fall through to stop playing */
+		} else {
+			pr_debug("moving to next sample set %d\n",
+				chip->wave_samp_idx);
+
+			rc = qpnp_haptics_buffer_config(chip, NULL, false);
+			if (rc < 0) {
+				pr_err("Error in configuring buffer, rc=%d\n",
+					rc);
+				goto irq_handled;
+			}
+
+			/*
+			 * Moving to next set of wave sample. No need to stop
+			 * or change the play control. Just return.
+			 */
+			goto irq_handled;
+		}
+	}
+
+	rc = qpnp_haptics_play_control(chip, HAP_STOP);
+	if (rc < 0) {
+		pr_err("Error in disabling play, rc=%d\n", rc);
+		goto irq_handled;
+	}
+	chip->wave_samp_idx = 0;
+
+irq_handled:
+	return IRQ_HANDLED;
+}
+
+#define SC_MAX_COUNT		5
+#define SC_COUNT_RST_DELAY_US	1000000
+static irqreturn_t qpnp_haptics_sc_irq_handler(int irq, void *data)
+{
+	struct hap_chip *chip = data;
+	int rc;
+	u8 val;
+	s64 sc_delta_time_us;
+	ktime_t temp;
+
+	rc = qpnp_haptics_read_reg(chip, HAP_STATUS_1_REG(chip), &val, 1);
+	if (rc < 0)
+		goto irq_handled;
+
+	if (!(val & SC_FLAG_BIT)) {
+		chip->sc_count = 0;
+		goto irq_handled;
+	}
+
+	pr_debug("SC irq fired\n");
+	temp = ktime_get();
+	sc_delta_time_us = ktime_us_delta(temp, chip->last_sc_time);
+	chip->last_sc_time = temp;
+
+	if (sc_delta_time_us > SC_COUNT_RST_DELAY_US)
+		chip->sc_count = 0;
+	else
+		chip->sc_count++;
+
+	val = SC_CLR_BIT;
+	rc = qpnp_haptics_write_reg(chip, HAP_SC_CLR_REG(chip), &val, 1);
+	if (rc < 0) {
+		pr_err("Error in writing to SC_CLR_REG, rc=%d\n", rc);
+		goto irq_handled;
+	}
+
+	/* Permanently disable module if SC condition persists */
+	if (chip->sc_count > SC_MAX_COUNT) {
+		pr_crit("SC persists, permanently disabling haptics\n");
+		rc = qpnp_haptics_mod_enable(chip, false);
+		if (rc < 0) {
+			pr_err("Error in disabling module, rc=%d\n", rc);
+			goto irq_handled;
+		}
+		chip->perm_disable = true;
+	}
+
+irq_handled:
+	return IRQ_HANDLED;
+}
+
+/* All sysfs show/store functions below */
+
+#define HAP_STR_SIZE	128
+static int parse_string(const char *in_buf, char *out_buf)
+{
+	int i;
+
+	if (snprintf(out_buf, HAP_STR_SIZE, "%s", in_buf) > HAP_STR_SIZE)
+		return -EINVAL;
+
+	for (i = 0; i < strlen(out_buf); i++) {
+		if (out_buf[i] == ' ' || out_buf[i] == '\n' ||
+			out_buf[i] == '\t') {
+			out_buf[i] = '\0';
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static ssize_t qpnp_haptics_show_state(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", chip->module_en);
+}
+
+static ssize_t qpnp_haptics_store_state(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+
+	/* At present, nothing to do with setting state */
+	return count;
+}
+
+static ssize_t qpnp_haptics_show_duration(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	ktime_t time_rem;
+	s64 time_us = 0;
+
+	if (hrtimer_active(&chip->stop_timer)) {
+		time_rem = hrtimer_get_remaining(&chip->stop_timer);
+		time_us = ktime_to_us(time_rem);
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%lld\n", time_us / 1000);
+	return 0;
+}
+
+static ssize_t qpnp_haptics_store_duration(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	u32 val;
+	int rc;
+
+	rc = kstrtouint(buf, 0, &val);
+	if (rc < 0)
+		return rc;
+
+	/* setting 0 on duration is NOP for now */
+	if (val <= 0)
+		return count;
+
+	if (val > chip->max_play_time_ms)
+		return -EINVAL;
+
+	mutex_lock(&chip->param_lock);
+	rc = qpnp_haptics_auto_mode_config(chip, val);
+	if (rc < 0) {
+		pr_err("Unable to do auto mode config\n");
+		mutex_unlock(&chip->param_lock);
+		return rc;
+	}
+
+	chip->play_time_ms = val;
+	mutex_unlock(&chip->param_lock);
+
+	return count;
+}
+
+static ssize_t qpnp_haptics_show_activate(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	/* For now nothing to show */
+	return snprintf(buf, PAGE_SIZE, "%d\n", 0);
+}
+
+static ssize_t qpnp_haptics_store_activate(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	u32 val;
+	int rc;
+
+	rc = kstrtouint(buf, 0, &val);
+	if (rc < 0)
+		return rc;
+
+	if (val != 0 && val != 1)
+		return count;
+
+	if (val) {
+		hrtimer_cancel(&chip->stop_timer);
+		if (is_sw_lra_auto_resonance_control(chip))
+			hrtimer_cancel(&chip->auto_res_err_poll_timer);
+		cancel_work_sync(&chip->haptics_work);
+
+		atomic_set(&chip->state, 1);
+		schedule_work(&chip->haptics_work);
+	} else {
+		rc = qpnp_haptics_mod_enable(chip, false);
+		if (rc < 0) {
+			pr_err("Error in disabling module, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return count;
+}
+
+static ssize_t qpnp_haptics_show_play_mode(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	char *str;
+
+	if (chip->play_mode == HAP_BUFFER)
+		str = "buffer";
+	else if (chip->play_mode == HAP_DIRECT)
+		str = "direct";
+	else if (chip->play_mode == HAP_AUDIO)
+		str = "audio";
+	else if (chip->play_mode == HAP_PWM)
+		str = "pwm";
+	else
+		return -EINVAL;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", str);
+}
+
+static ssize_t qpnp_haptics_store_play_mode(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	char str[HAP_STR_SIZE + 1];
+	int rc = 0, temp, old_mode;
+
+	rc = parse_string(buf, str);
+	if (rc < 0)
+		return rc;
+
+	if (strcmp(str, "buffer") == 0)
+		temp = HAP_BUFFER;
+	else if (strcmp(str, "direct") == 0)
+		temp = HAP_DIRECT;
+	else if (strcmp(str, "audio") == 0)
+		temp = HAP_AUDIO;
+	else if (strcmp(str, "pwm") == 0)
+		temp = HAP_PWM;
+	else
+		return -EINVAL;
+
+	if (temp == chip->play_mode)
+		return count;
+
+	if (temp == HAP_BUFFER) {
+		rc = qpnp_haptics_parse_buffer_dt(chip);
+		if (!rc) {
+			rc = qpnp_haptics_wave_rep_config(chip,
+				HAP_WAVE_REPEAT | HAP_WAVE_SAMP_REPEAT);
+			if (rc < 0) {
+				pr_err("Error in configuring wave_rep config %d\n",
+					rc);
+				return rc;
+			}
+		}
+
+		rc = qpnp_haptics_buffer_config(chip, NULL, true);
+	} else if (temp == HAP_PWM) {
+		rc = qpnp_haptics_parse_pwm_dt(chip);
+		if (!rc)
+			rc = qpnp_haptics_pwm_config(chip);
+	}
+
+	if (rc < 0)
+		return rc;
+
+	rc = qpnp_haptics_mod_enable(chip, false);
+	if (rc < 0)
+		return rc;
+
+	old_mode = chip->play_mode;
+	chip->play_mode = temp;
+	rc = qpnp_haptics_play_mode_config(chip);
+	if (rc < 0) {
+		chip->play_mode = old_mode;
+		return rc;
+	}
+
+	if (chip->play_mode == HAP_AUDIO) {
+		rc = qpnp_haptics_mod_enable(chip, true);
+		if (rc < 0) {
+			chip->play_mode = old_mode;
+			return rc;
+		}
+	}
+
+	return count;
+}
+
+static ssize_t qpnp_haptics_show_wf_samp(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	char str[HAP_STR_SIZE + 1];
+	char *ptr = str;
+	int i, len = 0;
+
+	for (i = 0; i < ARRAY_SIZE(chip->wave_samp); i++) {
+		len = scnprintf(ptr, HAP_STR_SIZE, "%x ", chip->wave_samp[i]);
+		ptr += len;
+	}
+	ptr[len] = '\0';
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", str);
+}
+
+static ssize_t qpnp_haptics_store_wf_samp(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	u8 samp[HAP_WAVE_SAMP_SET_LEN] = {0};
+	int bytes_read, rc;
+	unsigned int data, pos = 0, i = 0;
+
+	while (pos < count && i < ARRAY_SIZE(samp) &&
+		sscanf(buf + pos, "%x%n", &data, &bytes_read) == 1) {
+		/* bit 0 is not used in WF_Sx */
+		samp[i++] = data & GENMASK(7, 1);
+		pos += bytes_read;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(chip->wave_samp); i++)
+		chip->wave_samp[i] = samp[i];
+
+	rc = qpnp_haptics_buffer_config(chip, NULL, false);
+	if (rc < 0) {
+		pr_err("Error in configuring buffer mode %d\n", rc);
+		return rc;
+	}
+
+	return count;
+}
+
+static ssize_t qpnp_haptics_show_wf_rep_count(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", chip->wave_rep_cnt);
+}
+
+static ssize_t qpnp_haptics_store_wf_rep_count(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	int data, rc, old_wave_rep_cnt;
+
+	rc = kstrtoint(buf, 10, &data);
+	if (rc < 0)
+		return rc;
+
+	old_wave_rep_cnt = chip->wave_rep_cnt;
+	chip->wave_rep_cnt = data;
+	rc = qpnp_haptics_wave_rep_config(chip, HAP_WAVE_REPEAT);
+	if (rc < 0) {
+		chip->wave_rep_cnt = old_wave_rep_cnt;
+		return rc;
+	}
+
+	return count;
+}
+
+static ssize_t qpnp_haptics_show_wf_s_rep_count(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", chip->wave_s_rep_cnt);
+}
+
+static ssize_t qpnp_haptics_store_wf_s_rep_count(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	int data, rc, old_wave_s_rep_cnt;
+
+	rc = kstrtoint(buf, 10, &data);
+	if (rc < 0)
+		return rc;
+
+	old_wave_s_rep_cnt = chip->wave_s_rep_cnt;
+	chip->wave_s_rep_cnt = data;
+	rc = qpnp_haptics_wave_rep_config(chip, HAP_WAVE_SAMP_REPEAT);
+	if (rc < 0) {
+		chip->wave_s_rep_cnt = old_wave_s_rep_cnt;
+		return rc;
+	}
+
+	return count;
+}
+
+static ssize_t qpnp_haptics_show_vmax(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", chip->vmax_mv);
+}
+
+static ssize_t qpnp_haptics_store_vmax(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	int data, rc, old_vmax_mv;
+
+	rc = kstrtoint(buf, 10, &data);
+	if (rc < 0)
+		return rc;
+
+	old_vmax_mv = chip->vmax_mv;
+	chip->vmax_mv = data;
+	rc = qpnp_haptics_vmax_config(chip, chip->vmax_mv, false);
+	if (rc < 0) {
+		chip->vmax_mv = old_vmax_mv;
+		return rc;
+	}
+
+	return count;
+}
+
+static ssize_t qpnp_haptics_show_lra_auto_mode(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", chip->lra_auto_mode);
+}
+
+static ssize_t qpnp_haptics_store_lra_auto_mode(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev);
+	int rc, data;
+
+	rc = kstrtoint(buf, 10, &data);
+	if (rc < 0)
+		return rc;
+
+	if (data != 0 && data != 1)
+		return count;
+
+	chip->lra_auto_mode = !!data;
+	return count;
+}
+
+static struct device_attribute qpnp_haptics_attrs[] = {
+	__ATTR(state, 0664, qpnp_haptics_show_state, qpnp_haptics_store_state),
+	__ATTR(duration, 0664, qpnp_haptics_show_duration,
+		qpnp_haptics_store_duration),
+	__ATTR(activate, 0664, qpnp_haptics_show_activate,
+		qpnp_haptics_store_activate),
+	__ATTR(play_mode, 0664, qpnp_haptics_show_play_mode,
+		qpnp_haptics_store_play_mode),
+	__ATTR(wf_samp, 0664, qpnp_haptics_show_wf_samp,
+		qpnp_haptics_store_wf_samp),
+	__ATTR(wf_rep_count, 0664, qpnp_haptics_show_wf_rep_count,
+		qpnp_haptics_store_wf_rep_count),
+	__ATTR(wf_s_rep_count, 0664, qpnp_haptics_show_wf_s_rep_count,
+		qpnp_haptics_store_wf_s_rep_count),
+	__ATTR(vmax_mv, 0664, qpnp_haptics_show_vmax, qpnp_haptics_store_vmax),
+	__ATTR(lra_auto_mode, 0664, qpnp_haptics_show_lra_auto_mode,
+		qpnp_haptics_store_lra_auto_mode),
+};
+
+/* Dummy functions for brightness */
+static
+enum led_brightness qpnp_haptics_brightness_get(struct led_classdev *cdev)
+{
+	return 0;
+}
+
+static void qpnp_haptics_brightness_set(struct led_classdev *cdev,
+					enum led_brightness level)
+{
+}
+
+static int qpnp_haptics_config(struct hap_chip *chip)
+{
+	u8 rc_clk_err_deci_pct;
+	u16 play_rate = 0;
+	int rc;
+
+	/* Configure the CFG1 register for actuator type */
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG1_REG(chip),
+			HAP_ACT_TYPE_MASK, chip->act_type);
+	if (rc < 0)
+		return rc;
+
+	/* Configure auto resonance parameters */
+	rc = qpnp_haptics_lra_auto_res_config(chip, NULL);
+	if (rc < 0)
+		return rc;
+
+	/* Configure the PLAY MODE register */
+	rc = qpnp_haptics_play_mode_config(chip);
+	if (rc < 0)
+		return rc;
+
+	/* Configure the VMAX register */
+	rc = qpnp_haptics_vmax_config(chip, chip->vmax_mv, false);
+	if (rc < 0)
+		return rc;
+
+	/* Configure the ILIM register */
+	rc = qpnp_haptics_ilim_config(chip);
+	if (rc < 0)
+		return rc;
+
+	/* Configure the short circuit debounce register */
+	rc = qpnp_haptics_sc_deb_config(chip);
+	if (rc < 0)
+		return rc;
+
+	/* Configure the WAVE SHAPE register */
+	rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG2_REG(chip),
+			HAP_LRA_RES_TYPE_MASK, chip->wave_shape);
+	if (rc < 0)
+		return rc;
+
+	play_rate = chip->wave_play_rate_us / HAP_RATE_CFG_STEP_US;
+
+	/*
+	 * The frequency of 19.2 MHz RC clock is subject to variation. Currently
+	 * some PMI chips have MISC_TRIM_ERROR_RC19P2_CLK register present in
+	 * MISC peripheral. This register holds the trim error of RC clock.
+	 */
+	if (chip->act_type == HAP_LRA && chip->misc_clk_trim_error_reg) {
+		/*
+		 * Error is available in bits[3:0] and each LSB is 0.7%.
+		 * Bit 7 is the sign bit for error code. If it is set, then a
+		 * negative error correction needs to be made. Otherwise, a
+		 * positive error correction needs to be made.
+		 */
+		rc_clk_err_deci_pct = (chip->clk_trim_error_code & 0x0F) * 7;
+		if (chip->clk_trim_error_code & BIT(7))
+			play_rate = (play_rate *
+					(1000 - rc_clk_err_deci_pct)) / 1000;
+		else
+			play_rate = (play_rate *
+					(1000 + rc_clk_err_deci_pct)) / 1000;
+
+		pr_debug("TRIM register = 0x%x, play_rate=%d\n",
+			chip->clk_trim_error_code, play_rate);
+	}
+
+	/*
+	 * Configure RATE_CFG1 and RATE_CFG2 registers.
+	 * Note: For ERM these registers act as play rate and
+	 * for LRA these represent resonance period
+	 */
+	rc = qpnp_haptics_update_rate_cfg(chip, play_rate);
+	if (chip->act_type == HAP_LRA) {
+		chip->drive_period_code_max_limit = (play_rate *
+			(100 + chip->drive_period_code_max_var_pct)) / 100;
+		chip->drive_period_code_min_limit = (play_rate *
+			(100 - chip->drive_period_code_min_var_pct)) / 100;
+		pr_debug("Drive period code max limit %x min limit %x\n",
+			chip->drive_period_code_max_limit,
+			chip->drive_period_code_min_limit);
+	}
+
+	rc = qpnp_haptics_brake_config(chip, NULL);
+	if (rc < 0)
+		return rc;
+
+	if (chip->play_mode == HAP_BUFFER) {
+		rc = qpnp_haptics_wave_rep_config(chip,
+			HAP_WAVE_REPEAT | HAP_WAVE_SAMP_REPEAT);
+		if (rc < 0)
+			return rc;
+
+		rc = qpnp_haptics_buffer_config(chip, NULL, false);
+	} else if (chip->play_mode == HAP_PWM) {
+		rc = qpnp_haptics_pwm_config(chip);
+	} else if (chip->play_mode == HAP_AUDIO) {
+		rc = qpnp_haptics_mod_enable(chip, true);
+	}
+
+	if (rc < 0)
+		return rc;
+
+	/* setup play irq */
+	if (chip->play_irq >= 0) {
+		rc = devm_request_threaded_irq(&chip->pdev->dev, chip->play_irq,
+			NULL, qpnp_haptics_play_irq_handler, IRQF_ONESHOT,
+			"haptics_play_irq", chip);
+		if (rc < 0) {
+			pr_err("Unable to request play(%d) IRQ(err:%d)\n",
+				chip->play_irq, rc);
+			return rc;
+		}
+
+		/* use play_irq only for buffer mode */
+		if (chip->play_mode != HAP_BUFFER) {
+			disable_irq(chip->play_irq);
+			chip->play_irq_en = false;
+		}
+	}
+
+	/* setup short circuit irq */
+	if (chip->sc_irq >= 0) {
+		rc = devm_request_threaded_irq(&chip->pdev->dev, chip->sc_irq,
+			NULL, qpnp_haptics_sc_irq_handler, IRQF_ONESHOT,
+			"haptics_sc_irq", chip);
+		if (rc < 0) {
+			pr_err("Unable to request sc(%d) IRQ(err:%d)\n",
+				chip->sc_irq, rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int qpnp_haptics_parse_buffer_dt(struct hap_chip *chip)
+{
+	struct device_node *node = chip->pdev->dev.of_node;
+	u32 temp;
+	int rc, i, wf_samp_len;
+
+	if (chip->wave_rep_cnt > 0 || chip->wave_s_rep_cnt > 0)
+		return 0;
+
+	chip->wave_rep_cnt = WF_REPEAT_MIN;
+	rc = of_property_read_u32(node, "qcom,wave-rep-cnt", &temp);
+	if (!rc) {
+		chip->wave_rep_cnt = temp;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read rep cnt rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->wave_s_rep_cnt = WF_S_REPEAT_MIN;
+	rc = of_property_read_u32(node,
+			"qcom,wave-samp-rep-cnt", &temp);
+	if (!rc) {
+		chip->wave_s_rep_cnt = temp;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read samp rep cnt rc=%d\n", rc);
+		return rc;
+	}
+
+	wf_samp_len = of_property_count_elems_of_size(node,
+			"qcom,wave-samples", sizeof(u32));
+	if (wf_samp_len > 0) {
+		if (wf_samp_len > HAP_WAVE_SAMP_SET_LEN) {
+			pr_err("Invalid length for wave samples\n");
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32_array(node, "qcom,wave-samples",
+				chip->wave_samp, wf_samp_len);
+		if (rc < 0) {
+			pr_err("Error in reading qcom,wave-samples, rc=%d\n",
+				rc);
+			return rc;
+		}
+	} else {
+		/* Use default values */
+		for (i = 0; i < HAP_WAVE_SAMP_LEN; i++)
+			chip->wave_samp[i] = HAP_WF_SAMP_MAX;
+	}
+
+	return 0;
+}
+
+static int qpnp_haptics_parse_pwm_dt(struct hap_chip *chip)
+{
+	struct device_node *node = chip->pdev->dev.of_node;
+	u32 temp;
+	int rc;
+
+	if (chip->pwm_data.period_us > 0 && chip->pwm_data.duty_us > 0)
+		return 0;
+
+	chip->pwm_data.pwm_dev = of_pwm_get(node, NULL);
+	if (IS_ERR(chip->pwm_data.pwm_dev)) {
+		rc = PTR_ERR(chip->pwm_data.pwm_dev);
+		pr_err("Cannot get PWM device rc=%d\n", rc);
+		chip->pwm_data.pwm_dev = NULL;
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,period-us", &temp);
+	if (!rc) {
+		chip->pwm_data.period_us = temp;
+	} else {
+		pr_err("Cannot read PWM period rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,duty-us", &temp);
+	if (!rc) {
+		chip->pwm_data.duty_us = temp;
+	} else {
+		pr_err("Cannot read PWM duty rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,ext-pwm-dtest-line", &temp);
+	if (!rc)
+		chip->ext_pwm_dtest_line = temp;
+
+	rc = of_property_read_u32(node, "qcom,ext-pwm-freq-khz", &temp);
+	if (!rc) {
+		chip->ext_pwm_freq_khz = temp;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read ext pwm freq rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int qpnp_haptics_parse_dt(struct hap_chip *chip)
+{
+	struct device_node *node = chip->pdev->dev.of_node;
+	struct device_node *revid_node, *misc_node;
+	const char *temp_str;
+	int rc, temp;
+
+	rc = of_property_read_u32(node, "reg", &temp);
+	if (rc < 0) {
+		pr_err("Couldn't find reg in node = %s rc = %d\n",
+			node->full_name, rc);
+		return rc;
+	}
+
+	if (temp <= 0) {
+		pr_err("Invalid base address %x\n", temp);
+		return -EINVAL;
+	}
+	chip->base = (u16)temp;
+
+	revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
+	if (!revid_node) {
+		pr_err("Missing qcom,pmic-revid property\n");
+		return -EINVAL;
+	}
+
+	chip->revid = get_revid_data(revid_node);
+	of_node_put(revid_node);
+	if (IS_ERR_OR_NULL(chip->revid)) {
+		pr_err("Unable to get pmic_revid rc=%ld\n",
+			PTR_ERR(chip->revid));
+		/*
+		 * the revid peripheral must be registered, any failure
+		 * here only indicates that the rev-id module has not
+		 * probed yet.
+		 */
+		return -EPROBE_DEFER;
+	}
+
+	if (of_find_property(node, "qcom,pmic-misc", NULL)) {
+		misc_node = of_parse_phandle(node, "qcom,pmic-misc", 0);
+		if (!misc_node)
+			return -EINVAL;
+
+		rc = of_property_read_u32(node, "qcom,misc-clk-trim-error-reg",
+				&chip->misc_clk_trim_error_reg);
+		if (rc < 0 || !chip->misc_clk_trim_error_reg) {
+			pr_err("Invalid or missing misc-clk-trim-error-reg\n");
+			of_node_put(misc_node);
+			return rc;
+		}
+
+		rc = qpnp_misc_read_reg(misc_node,
+				chip->misc_clk_trim_error_reg,
+				&chip->clk_trim_error_code);
+		if (rc < 0) {
+			pr_err("Couldn't get clk_trim_error_code, rc=%d\n", rc);
+			of_node_put(misc_node);
+			return -EPROBE_DEFER;
+		}
+		of_node_put(misc_node);
+	}
+
+	chip->play_irq = platform_get_irq_byname(chip->pdev, "hap-play-irq");
+	if (chip->play_irq < 0) {
+		pr_err("Unable to get play irq\n");
+		return chip->play_irq;
+	}
+
+	chip->sc_irq = platform_get_irq_byname(chip->pdev, "hap-sc-irq");
+	if (chip->sc_irq < 0) {
+		pr_err("Unable to get sc irq\n");
+		return chip->sc_irq;
+	}
+
+	chip->act_type = HAP_LRA;
+	rc = of_property_read_u32(node, "qcom,actuator-type", &temp);
+	if (!rc) {
+		if (temp != HAP_LRA && temp != HAP_ERM) {
+			pr_err("Incorrect actuator type\n");
+			return -EINVAL;
+		}
+		chip->act_type = temp;
+	}
+
+	chip->lra_auto_mode = of_property_read_bool(node, "qcom,lra-auto-mode");
+
+	rc = of_property_read_string(node, "qcom,play-mode", &temp_str);
+	if (!rc) {
+		if (strcmp(temp_str, "direct") == 0)
+			chip->play_mode = HAP_DIRECT;
+		else if (strcmp(temp_str, "buffer") == 0)
+			chip->play_mode = HAP_BUFFER;
+		else if (strcmp(temp_str, "pwm") == 0)
+			chip->play_mode = HAP_PWM;
+		else if (strcmp(temp_str, "audio") == 0)
+			chip->play_mode = HAP_AUDIO;
+		else {
+			pr_err("Invalid play mode\n");
+			return -EINVAL;
+		}
+	} else {
+		if (rc == -EINVAL && chip->act_type == HAP_LRA) {
+			pr_info("Play mode not specified, using auto mode\n");
+			chip->lra_auto_mode = true;
+		} else {
+			pr_err("Unable to read play mode\n");
+			return rc;
+		}
+	}
+
+	chip->max_play_time_ms = HAP_MAX_PLAY_TIME_MS;
+	rc = of_property_read_u32(node, "qcom,max-play-time-ms", &temp);
+	if (!rc) {
+		chip->max_play_time_ms = temp;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read max-play-time rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->vmax_mv = HAP_VMAX_MAX_MV;
+	rc = of_property_read_u32(node, "qcom,vmax-mv", &temp);
+	if (!rc) {
+		chip->vmax_mv = temp;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read Vmax rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->ilim_ma = HAP_ILIM_400_MA;
+	rc = of_property_read_u32(node, "qcom,ilim-ma", &temp);
+	if (!rc) {
+		chip->ilim_ma = (u8)temp;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read ILIM rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->sc_deb_cycles = HAP_DEF_SC_DEB_CYCLES;
+	rc = of_property_read_u32(node, "qcom,sc-dbc-cycles", &temp);
+	if (!rc) {
+		chip->sc_deb_cycles = temp;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read sc debounce rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->wave_shape = HAP_WAVE_SQUARE;
+	rc = of_property_read_string(node, "qcom,wave-shape", &temp_str);
+	if (!rc) {
+		if (strcmp(temp_str, "sine") == 0)
+			chip->wave_shape = HAP_WAVE_SINE;
+		else if (strcmp(temp_str, "square") == 0)
+			chip->wave_shape = HAP_WAVE_SQUARE;
+		else {
+			pr_err("Unsupported wave shape\n");
+			return -EINVAL;
+		}
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read wave shape rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->wave_play_rate_us = HAP_DEF_WAVE_PLAY_RATE_US;
+	rc = of_property_read_u32(node,
+			"qcom,wave-play-rate-us", &temp);
+	if (!rc) {
+		chip->wave_play_rate_us = temp;
+	} else if (rc != -EINVAL) {
+		pr_err("Unable to read play rate rc=%d\n", rc);
+		return rc;
+	}
+
+	if (chip->wave_play_rate_us < HAP_WAVE_PLAY_RATE_US_MIN)
+		chip->wave_play_rate_us = HAP_WAVE_PLAY_RATE_US_MIN;
+	else if (chip->wave_play_rate_us > HAP_WAVE_PLAY_RATE_US_MAX)
+		chip->wave_play_rate_us = HAP_WAVE_PLAY_RATE_US_MAX;
+
+	chip->en_brake = of_property_read_bool(node, "qcom,en-brake");
+
+	rc = of_property_count_elems_of_size(node,
+			"qcom,brake-pattern", sizeof(u32));
+	if (rc > 0) {
+		if (rc != HAP_BRAKE_PAT_LEN) {
+			pr_err("Invalid length for brake pattern\n");
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32_array(node, "qcom,brake-pattern",
+				chip->brake_pat, HAP_BRAKE_PAT_LEN);
+		if (rc < 0) {
+			pr_err("Error in reading qcom,brake-pattern, rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	/* Read the following properties only for LRA */
+	if (chip->act_type == HAP_LRA) {
+		rc = of_property_read_string(node, "qcom,lra-auto-res-mode",
+					&temp_str);
+		if (!rc) {
+			if (chip->revid->pmic_subtype == PM660_SUBTYPE) {
+				chip->ares_cfg.auto_res_mode =
+						HAP_PM660_AUTO_RES_QWD;
+				if (strcmp(temp_str, "zxd") == 0)
+					chip->ares_cfg.auto_res_mode =
+						HAP_PM660_AUTO_RES_ZXD;
+				else if (strcmp(temp_str, "qwd") == 0)
+					chip->ares_cfg.auto_res_mode =
+						HAP_PM660_AUTO_RES_QWD;
+			} else {
+				chip->ares_cfg.auto_res_mode =
+						HAP_AUTO_RES_ZXD_EOP;
+				if (strcmp(temp_str, "none") == 0)
+					chip->ares_cfg.auto_res_mode =
+						HAP_AUTO_RES_NONE;
+				else if (strcmp(temp_str, "zxd") == 0)
+					chip->ares_cfg.auto_res_mode =
+						HAP_AUTO_RES_ZXD;
+				else if (strcmp(temp_str, "qwd") == 0)
+					chip->ares_cfg.auto_res_mode =
+						HAP_AUTO_RES_QWD;
+				else if (strcmp(temp_str, "max-qwd") == 0)
+					chip->ares_cfg.auto_res_mode =
+						HAP_AUTO_RES_MAX_QWD;
+				else
+					chip->ares_cfg.auto_res_mode =
+						HAP_AUTO_RES_ZXD_EOP;
+			}
+		} else if (rc != -EINVAL) {
+			pr_err("Unable to read auto res mode rc=%d\n", rc);
+			return rc;
+		}
+
+		chip->ares_cfg.lra_high_z = HAP_LRA_HIGH_Z_OPT3;
+		rc = of_property_read_string(node, "qcom,lra-high-z",
+					&temp_str);
+		if (!rc) {
+			if (strcmp(temp_str, "none") == 0)
+				chip->ares_cfg.lra_high_z =
+					HAP_LRA_HIGH_Z_NONE;
+			else if (strcmp(temp_str, "opt1") == 0)
+				chip->ares_cfg.lra_high_z =
+					HAP_LRA_HIGH_Z_OPT1;
+			else if (strcmp(temp_str, "opt2") == 0)
+				chip->ares_cfg.lra_high_z =
+					 HAP_LRA_HIGH_Z_OPT2;
+			else
+				chip->ares_cfg.lra_high_z =
+					 HAP_LRA_HIGH_Z_OPT3;
+			if (chip->revid->pmic_subtype == PM660_SUBTYPE) {
+				if (strcmp(temp_str, "opt0") == 0)
+					chip->ares_cfg.lra_high_z =
+						HAP_LRA_HIGH_Z_NONE;
+			}
+		} else if (rc != -EINVAL) {
+			pr_err("Unable to read LRA high-z rc=%d\n", rc);
+			return rc;
+		}
+
+		chip->ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MAX;
+		rc = of_property_read_u32(node,
+				"qcom,lra-res-cal-period", &temp);
+		if (!rc) {
+			chip->ares_cfg.lra_res_cal_period = temp;
+		} else if (rc != -EINVAL) {
+			pr_err("Unable to read cal period rc=%d\n", rc);
+			return rc;
+		}
+
+		chip->ares_cfg.lra_qwd_drive_duration = -EINVAL;
+		chip->ares_cfg.calibrate_at_eop = -EINVAL;
+		if (chip->revid->pmic_subtype == PM660_SUBTYPE) {
+			rc = of_property_read_u32(node,
+					"qcom,lra-qwd-drive-duration",
+					&chip->ares_cfg.lra_qwd_drive_duration);
+			if (rc && rc != -EINVAL) {
+				pr_err("Unable to read LRA QWD drive duration rc=%d\n",
+					rc);
+				return rc;
+			}
+
+			rc = of_property_read_u32(node,
+					"qcom,lra-calibrate-at-eop",
+					&chip->ares_cfg.calibrate_at_eop);
+			if (rc && rc != -EINVAL) {
+				pr_err("Unable to read Calibrate at EOP rc=%d\n",
+					rc);
+				return rc;
+			}
+		}
+
+		chip->drive_period_code_max_var_pct = 25;
+		rc = of_property_read_u32(node,
+			"qcom,drive-period-code-max-variation-pct", &temp);
+		if (!rc) {
+			if (temp > 0 && temp < 100)
+				chip->drive_period_code_max_var_pct = (u8)temp;
+		} else if (rc != -EINVAL) {
+			pr_err("Unable to read drive period code max var pct rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		chip->drive_period_code_min_var_pct = 25;
+		rc = of_property_read_u32(node,
+			"qcom,drive-period-code-min-variation-pct", &temp);
+		if (!rc) {
+			if (temp > 0 && temp < 100)
+				chip->drive_period_code_min_var_pct = (u8)temp;
+		} else if (rc != -EINVAL) {
+			pr_err("Unable to read drive period code min var pct rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		chip->auto_res_err_recovery_hw =
+			of_property_read_bool(node,
+				"qcom,auto-res-err-recovery-hw");
+
+		if (chip->revid->pmic_subtype != PM660_SUBTYPE)
+			chip->auto_res_err_recovery_hw = false;
+	}
+
+	if (rc == -EINVAL)
+		rc = 0;
+
+	if (chip->play_mode == HAP_BUFFER)
+		rc = qpnp_haptics_parse_buffer_dt(chip);
+	else if (chip->play_mode == HAP_PWM)
+		rc = qpnp_haptics_parse_pwm_dt(chip);
+
+	return rc;
+}
+
+static int qpnp_haptics_probe(struct platform_device *pdev)
+{
+	struct hap_chip *chip;
+	int rc, i;
+
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!chip->regmap) {
+		dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+		return -EINVAL;
+	}
+
+	chip->pdev = pdev;
+	rc = qpnp_haptics_parse_dt(chip);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "Error in parsing DT parameters, rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	spin_lock_init(&chip->bus_lock);
+	mutex_init(&chip->play_lock);
+	mutex_init(&chip->param_lock);
+	INIT_WORK(&chip->haptics_work, qpnp_haptics_work);
+
+	rc = qpnp_haptics_config(chip);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "Error in configuring haptics, rc=%d\n",
+			rc);
+		goto fail;
+	}
+
+	hrtimer_init(&chip->stop_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	chip->stop_timer.function = hap_stop_timer;
+	hrtimer_init(&chip->auto_res_err_poll_timer, CLOCK_MONOTONIC,
+			HRTIMER_MODE_REL);
+	chip->auto_res_err_poll_timer.function = hap_auto_res_err_poll_timer;
+	dev_set_drvdata(&pdev->dev, chip);
+
+	chip->cdev.name = "vibrator";
+	chip->cdev.brightness_get = qpnp_haptics_brightness_get;
+	chip->cdev.brightness_set = qpnp_haptics_brightness_set;
+	chip->cdev.max_brightness = 100;
+	rc = devm_led_classdev_register(&pdev->dev, &chip->cdev);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "Error in registering led class device, rc=%d\n",
+			rc);
+		goto register_fail;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(qpnp_haptics_attrs); i++) {
+		rc = sysfs_create_file(&chip->cdev.dev->kobj,
+				&qpnp_haptics_attrs[i].attr);
+		if (rc < 0) {
+			dev_err(&pdev->dev, "Error in creating sysfs file, rc=%d\n",
+				rc);
+			goto sysfs_fail;
+		}
+	}
+
+	return 0;
+
+sysfs_fail:
+	for (--i; i >= 0; i--)
+		sysfs_remove_file(&chip->cdev.dev->kobj,
+				&qpnp_haptics_attrs[i].attr);
+register_fail:
+	cancel_work_sync(&chip->haptics_work);
+	hrtimer_cancel(&chip->auto_res_err_poll_timer);
+	hrtimer_cancel(&chip->stop_timer);
+fail:
+	mutex_destroy(&chip->play_lock);
+	mutex_destroy(&chip->param_lock);
+	if (chip->pwm_data.pwm_dev)
+		pwm_put(chip->pwm_data.pwm_dev);
+	dev_set_drvdata(&pdev->dev, NULL);
+	return rc;
+}
+
+static int qpnp_haptics_remove(struct platform_device *pdev)
+{
+	struct hap_chip *chip = dev_get_drvdata(&pdev->dev);
+
+	cancel_work_sync(&chip->haptics_work);
+	hrtimer_cancel(&chip->auto_res_err_poll_timer);
+	hrtimer_cancel(&chip->stop_timer);
+	mutex_destroy(&chip->play_lock);
+	mutex_destroy(&chip->param_lock);
+	if (chip->pwm_data.pwm_dev)
+		pwm_put(chip->pwm_data.pwm_dev);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	return 0;
+}
+
+static const struct dev_pm_ops qpnp_haptics_pm_ops = {
+	.suspend	= qpnp_haptics_suspend,
+};
+
+static const struct of_device_id hap_match_table[] = {
+	{ .compatible = "qcom,qpnp-haptics" },
+	{ },
+};
+
+static struct platform_driver qpnp_haptics_driver = {
+	.driver		= {
+		.name		= "qcom,qpnp-haptics",
+		.of_match_table	= hap_match_table,
+		.pm		= &qpnp_haptics_pm_ops,
+	},
+	.probe		= qpnp_haptics_probe,
+	.remove		= qpnp_haptics_remove,
+};
+module_platform_driver(qpnp_haptics_driver);
+
+MODULE_DESCRIPTION("QPNP haptics driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mailbox/msm_qmp.c b/drivers/mailbox/msm_qmp.c
index dd022d3..f0bb0bc 100644
--- a/drivers/mailbox/msm_qmp.c
+++ b/drivers/mailbox/msm_qmp.c
@@ -26,7 +26,6 @@
 #define QMP_MAGIC	0x4d41494c	/* MAIL */
 #define QMP_VERSION	0x1
 #define QMP_FEATURES	0x0
-#define QMP_NUM_CHANS	0x1
 #define QMP_TOUT_MS	5000
 #define QMP_TX_TOUT_MS	2000
 
@@ -107,63 +106,89 @@
 };
 
 /**
- * struct qmp_device - local information for managing a single mailbox
- * @dev:		The device that corresponds to this mailbox
- * @mbox:		The mbox controller for this mailbox
- * @name:		The name of this mailbox
- * @local_state:	Current state of the mailbox protocol
- * @link_complete:	Use to block until link negotiation with remote proc
- *			is complete
- * @ch_complete:	Use to block until the channel is fully opened
+ * struct qmp_mbox - local information for managing a single mailbox
+ * @list:		List head for adding mbox to linked list
+ * @ctrl:		Controller for this mailbox
+ * @priority:		Priority of mailbox in the linked list
+ * @num_assigned:	Number of channels assigned for allocated pool
+ * @num_shutdown:	Number of channels that have shutdown
+ * @desc:		Reference to the mailbox descriptor in SMEM
+ * @rx_disabled:	Disable rx if multiple client are sending from this mbox
  * @tx_sent:		True if tx is sent and remote proc has not sent ack
- * @ch_in_use:		True if this mailbox's channel owned by a client
- * @rx_buf:		buffer to pass to client, holds copied data from mailbox
- * @version:		Version and features received during link negotiation
+ * @idx_in_flight:	current channel idx whos tx is in flight
  * @mcore_mbox_offset:	Offset of mcore mbox from the msgram start
  * @mcore_mbox_size:	Size of the mcore mbox
- * @desc:		Reference to the mailbox descriptor in SMEM
+ * @rx_pkt:		buffer to pass to client, holds copied data from mailbox
+ * @version:		Version and features received during link negotiation
+ * @local_state:	Current state of the mailbox protocol
+ * @state_lock:		Serialize mailbox state changes
+ * @tx_lock:		Serialize access for writes to mailbox
+ * @link_complete:	Use to block until link negotiation with remote proc
+ * @ch_complete:	Use to block until the channel is fully opened
+ * @ch_in_use:		True if this mailbox's channel owned by a client
+ * @dwork:		Delayed work to detect timed out tx
+ */
+struct qmp_mbox {
+	struct list_head list;
+	struct mbox_controller ctrl;
+	int priority;
+	u32 num_assigned;
+	u32 num_shutdown;
+
+	void __iomem *desc;
+	bool rx_disabled;
+	bool tx_sent;
+	u32 idx_in_flight;
+	u32 mcore_mbox_offset;
+	u32 mcore_mbox_size;
+	struct qmp_pkt rx_pkt;
+
+	struct qmp_core_version version;
+	enum qmp_local_state local_state;
+	struct mutex state_lock;
+	spinlock_t tx_lock;
+
+	struct completion link_complete;
+	struct completion ch_complete;
+	struct delayed_work dwork;
+	struct qmp_device *mdev;
+};
+
+/**
+ * struct qmp_device - local information for managing a single qmp edge
+ * @dev:		The device that corresponds to this edge
+ * @name:		The name of this mailbox
+ * @mboxes:		The mbox controller for this mailbox
  * @msgram:		Reference to the start of msgram
- * @irq_mask:		Mask written to @tx_irq_reg to trigger irq
  * @tx_irq_reg:		Reference to the register to send an irq to remote proc
  * @rx_reset_reg:	Reference to the register to reset the rx irq, if
  *			applicable
- * @rx_irq_line:	The incoming interrupt line
- * @tx_irq_count:	Number of tx interrupts triggered
- * @rx_irq_count:	Number of rx interrupts received
- * @kwork:		Work to be executed when an irq is received
+ * @kwork:		kwork for rx handling
  * @kworker:		Handle to entitiy to process incoming data
  * @task:		Handle to task context used to run @kworker
- * @state_lock:		Serialize mailbox state changes
- * @dwork:		Delayed work to detect timed out tx
- * @tx_lock:		Serialize access for writes to mailbox
+ * @irq_mask:		Mask written to @tx_irq_reg to trigger irq
+ * @rx_irq_line:	The incoming interrupt line
+ * @rx_work:		Work to be executed when an irq is received
+ * @tx_irq_count:	Number of tx interrupts triggered
+ * @rx_irq_count:	Number of rx interrupts received
  */
 struct qmp_device {
 	struct device *dev;
-	struct mbox_controller *mbox;
 	const char *name;
-	enum qmp_local_state local_state;
-	struct completion link_complete;
-	struct completion ch_complete;
-	bool tx_sent;
-	bool ch_in_use;
-	struct qmp_pkt rx_pkt;
-	struct qmp_core_version version;
-	u32 mcore_mbox_offset;
-	u32 mcore_mbox_size;
-	void __iomem *desc;
+	struct list_head mboxes;
+
 	void __iomem *msgram;
-	u32 irq_mask;
 	void __iomem *tx_irq_reg;
 	void __iomem *rx_reset_reg;
-	u32 rx_irq_line;
-	u32 tx_irq_count;
-	u32 rx_irq_count;
+
 	struct kthread_work kwork;
 	struct kthread_worker kworker;
 	struct task_struct *task;
-	struct mutex state_lock;
-	struct delayed_work dwork;
-	spinlock_t tx_lock;
+
+	u32 irq_mask;
+	u32 rx_irq_line;
+	u32 tx_irq_count;
+	u32 rx_irq_count;
 };
 
 /**
@@ -181,25 +206,7 @@
 	mdev->tx_irq_count++;
 }
 
-/**
- * qmp_irq_handler() - handle irq from remote entitity.
- * @irq:	irq number for the trggered interrupt.
- * @priv:	private pointer to qmp mbox device.
- */
-irqreturn_t qmp_irq_handler(int irq, void *priv)
-{
-	struct qmp_device *mdev = (struct qmp_device *)priv;
-
-	if (mdev->rx_reset_reg)
-		writel_relaxed(mdev->irq_mask, mdev->rx_reset_reg);
-
-	kthread_queue_work(&mdev->kworker, &mdev->kwork);
-	mdev->rx_irq_count++;
-
-	return IRQ_HANDLED;
-}
-
-static void memcpy32_toio(void *dest, void *src, size_t size)
+static void memcpy32_toio(void __iomem *dest, void *src, size_t size)
 {
 	u32 *dest_local = (u32 *)dest;
 	u32 *src_local = (u32 *)src;
@@ -210,7 +217,7 @@
 		iowrite32(*src_local++, dest_local++);
 }
 
-static void memcpy32_fromio(void *dest, void *src, size_t size)
+static void memcpy32_fromio(void *dest, void __iomem *src, size_t size)
 {
 	u32 *dest_local = (u32 *)dest;
 	u32 *src_local = (u32 *)src;
@@ -222,62 +229,75 @@
 }
 
 /**
- * set_ucore_link_ack() - set the link ack in the ucore channel desc.
- * @mdev:	the mailbox for the field that is being set.
- * @state:	the value to set the ack field to.
- */
-static void set_ucore_link_ack(struct qmp_device *mdev, u32 state)
-{
-	u32 offset;
-
-	offset = offsetof(struct mbox_desc, ucore);
-	offset += offsetof(struct channel_desc, link_state_ack);
-	iowrite32(state, mdev->desc + offset);
-}
-
-/**
- * set_ucore_ch_ack() - set the channel ack in the ucore channel desc.
- * @mdev:	the mailbox for the field that is being set.
- * @state:	the value to set the ack field to.
- */
-static void set_ucore_ch_ack(struct qmp_device *mdev, u32 state)
-{
-	u32 offset;
-
-	offset = offsetof(struct mbox_desc, ucore);
-	offset += offsetof(struct channel_desc, ch_state_ack);
-	iowrite32(state, mdev->desc + offset);
-}
-
-/**
- * set_mcore_ch() - set the channel state in the mcore channel desc.
- * @mdev:	the mailbox for the field that is being set.
- * @state:	the value to set the channel field to.
- */
-static void set_mcore_ch(struct qmp_device *mdev, u32 state)
-{
-	u32 offset;
-
-	offset = offsetof(struct mbox_desc, mcore);
-	offset += offsetof(struct channel_desc, ch_state);
-	iowrite32(state, mdev->desc + offset);
-}
-
-/**
  * qmp_notify_timeout() - Notify client of tx timeout with -EIO
  * @work:	Structure for work that was scheduled.
  */
 static void qmp_notify_timeout(struct work_struct *work)
 {
 	struct delayed_work *dwork = to_delayed_work(work);
-	struct qmp_device *mdev = container_of(dwork, struct qmp_device, dwork);
-	struct mbox_chan *chan = &mdev->mbox->chans[0];
+	struct qmp_mbox *mbox = container_of(dwork, struct qmp_mbox, dwork);
+	struct mbox_chan *chan = &mbox->ctrl.chans[mbox->idx_in_flight];
 	int err = -EIO;
+	unsigned long flags;
 
-	pr_err("%s: qmp tx timeout for %s\n", __func__, mdev->name);
+	spin_lock_irqsave(&mbox->tx_lock, flags);
+	if (!mbox->tx_sent) {
+		spin_unlock_irqrestore(&mbox->tx_lock, flags);
+		return;
+	}
+	pr_err("%s: qmp tx timeout for %d\n", __func__, mbox->idx_in_flight);
+	mbox->tx_sent = false;
+	spin_unlock_irqrestore(&mbox->tx_lock, flags);
 	mbox_chan_txdone(chan, err);
 }
 
+static inline void qmp_schedule_tx_timeout(struct qmp_mbox *mbox)
+{
+	schedule_delayed_work(&mbox->dwork, msecs_to_jiffies(QMP_TX_TOUT_MS));
+}
+
+/**
+ * set_ucore_link_ack() - set the link ack in the ucore channel desc.
+ * @mbox:	the mailbox for the field that is being set.
+ * @state:	the value to set the ack field to.
+ */
+static void set_ucore_link_ack(struct qmp_mbox *mbox, u32 state)
+{
+	u32 offset;
+
+	offset = offsetof(struct mbox_desc, ucore);
+	offset += offsetof(struct channel_desc, link_state_ack);
+	iowrite32(state, mbox->desc + offset);
+}
+
+/**
+ * set_ucore_ch_ack() - set the channel ack in the ucore channel desc.
+ * @mbox:	the mailbox for the field that is being set.
+ * @state:	the value to set the ack field to.
+ */
+static void set_ucore_ch_ack(struct qmp_mbox *mbox, u32 state)
+{
+	u32 offset;
+
+	offset = offsetof(struct mbox_desc, ucore);
+	offset += offsetof(struct channel_desc, ch_state_ack);
+	iowrite32(state, mbox->desc + offset);
+}
+
+/**
+ * set_mcore_ch() - set the channel state in the mcore channel desc.
+ * @mbox:	the mailbox for the field that is being set.
+ * @state:	the value to set the channel field to.
+ */
+static void set_mcore_ch(struct qmp_mbox *mbox, u32 state)
+{
+	u32 offset;
+
+	offset = offsetof(struct mbox_desc, mcore);
+	offset += offsetof(struct channel_desc, ch_state);
+	iowrite32(state, mbox->desc + offset);
+}
+
 /**
  * qmp_startup() - Start qmp mailbox channel for communication. Waits for
  *			remote subsystem to open channel if link is not
@@ -288,35 +308,27 @@
  */
 static int qmp_startup(struct mbox_chan *chan)
 {
-	struct qmp_device *mdev = chan->con_priv;
+	struct qmp_mbox *mbox = chan->con_priv;
 
-	if (!mdev)
+	if (!mbox)
 		return -EINVAL;
 
-	mutex_lock(&mdev->state_lock);
-	if (mdev->local_state == CHANNEL_CONNECTED) {
-		mutex_unlock(&mdev->state_lock);
-		return -EINVAL;
-	}
-	if (!completion_done(&mdev->link_complete)) {
-		mutex_unlock(&mdev->state_lock);
+	mutex_lock(&mbox->state_lock);
+	if (!completion_done(&mbox->link_complete)) {
+		mutex_unlock(&mbox->state_lock);
 		return -EAGAIN;
 	}
 
-	set_mcore_ch(mdev, QMP_MBOX_CH_CONNECTED);
-	mdev->local_state = LOCAL_CONNECTING;
-	mutex_unlock(&mdev->state_lock);
+	set_mcore_ch(mbox, QMP_MBOX_CH_CONNECTED);
+	mbox->local_state = LOCAL_CONNECTING;
+	mutex_unlock(&mbox->state_lock);
 
-	send_irq(mdev);
-	wait_for_completion_interruptible_timeout(&mdev->ch_complete,
+	send_irq(mbox->mdev);
+	wait_for_completion_interruptible_timeout(&mbox->ch_complete,
 					msecs_to_jiffies(QMP_TOUT_MS));
 	return 0;
 }
 
-static inline void qmp_schedule_tx_timeout(struct qmp_device *mdev)
-{
-	schedule_delayed_work(&mdev->dwork, msecs_to_jiffies(QMP_TX_TOUT_MS));
-}
 
 /**
  * qmp_send_data() - Copy the data to the channel's mailbox and notify
@@ -331,31 +343,39 @@
  */
 static int qmp_send_data(struct mbox_chan *chan, void *data)
 {
-	struct qmp_device *mdev = chan->con_priv;
+	struct qmp_mbox *mbox = chan->con_priv;
+	struct qmp_device *mdev;
 	struct qmp_pkt *pkt = (struct qmp_pkt *)data;
 	void __iomem *addr;
 	unsigned long flags;
+	int i;
 
-	if (!mdev || !data || mdev->local_state != CHANNEL_CONNECTED)
+	if (!mbox || !data || mbox->local_state != CHANNEL_CONNECTED)
 		return -EINVAL;
+	mdev = mbox->mdev;
 
-	spin_lock_irqsave(&mdev->tx_lock, flags);
-	addr = mdev->msgram + mdev->mcore_mbox_offset;
-	if (ioread32(addr)) {
-		spin_unlock_irqrestore(&mdev->tx_lock, flags);
+	spin_lock_irqsave(&mbox->tx_lock, flags);
+	addr = mdev->msgram + mbox->mcore_mbox_offset;
+	if (mbox->tx_sent) {
+		spin_unlock_irqrestore(&mbox->tx_lock, flags);
 		return -EBUSY;
 	}
 
-	if (pkt->size + sizeof(pkt->size) > mdev->mcore_mbox_size) {
-		spin_unlock_irqrestore(&mdev->tx_lock, flags);
+	if (pkt->size + sizeof(pkt->size) > mbox->mcore_mbox_size) {
+		spin_unlock_irqrestore(&mbox->tx_lock, flags);
 		return -EINVAL;
 	}
+
 	memcpy32_toio(addr + sizeof(pkt->size), pkt->data, pkt->size);
 	iowrite32(pkt->size, addr);
-	mdev->tx_sent = true;
+	mbox->tx_sent = true;
+	for (i = 0; i < mbox->ctrl.num_chans; i++) {
+		if (chan == &mbox->ctrl.chans[i])
+			mbox->idx_in_flight = i;
+	}
 	send_irq(mdev);
-	qmp_schedule_tx_timeout(mdev);
-	spin_unlock_irqrestore(&mdev->tx_lock, flags);
+	qmp_schedule_tx_timeout(mbox);
+	spin_unlock_irqrestore(&mbox->tx_lock, flags);
 	return 0;
 }
 
@@ -367,16 +387,23 @@
  */
 static void qmp_shutdown(struct mbox_chan *chan)
 {
-	struct qmp_device *mdev = chan->con_priv;
+	struct qmp_mbox *mbox = chan->con_priv;
 
-	mutex_lock(&mdev->state_lock);
-	if (mdev->local_state != LINK_DISCONNECTED) {
-		mdev->local_state = LOCAL_DISCONNECTING;
-		set_mcore_ch(mdev, QMP_MBOX_CH_DISCONNECTED);
-		send_irq(mdev);
+	mutex_lock(&mbox->state_lock);
+	mbox->num_shutdown++;
+	if (mbox->num_shutdown < mbox->num_assigned) {
+		mutex_unlock(&mbox->state_lock);
+		return;
 	}
-	mdev->ch_in_use = false;
-	mutex_unlock(&mdev->state_lock);
+
+	if (mbox->local_state != LINK_DISCONNECTED) {
+		mbox->local_state = LOCAL_DISCONNECTING;
+		set_mcore_ch(mbox, QMP_MBOX_CH_DISCONNECTED);
+		send_irq(mbox->mdev);
+	}
+	mbox->num_shutdown = 0;
+	mbox->num_assigned = 0;
+	mutex_unlock(&mbox->state_lock);
 }
 
 /**
@@ -396,33 +423,34 @@
 /**
  * qmp_recv_data() - received notification that data is available in the
  *			mailbox. Copy data from mailbox and pass to client.
- * @mdev:	mailbox device that received the notification.
+ * @mbox:		mailbox device that received the notification.
  * @mbox_of:	offset of mailbox from msgram start.
  */
-static void qmp_recv_data(struct qmp_device *mdev, u32 mbox_of)
+static void qmp_recv_data(struct qmp_mbox *mbox, u32 mbox_of)
 {
 	void __iomem *addr;
 	struct qmp_pkt *pkt;
 
-	addr = mdev->msgram + mbox_of;
-	pkt = &mdev->rx_pkt;
+	addr = mbox->mdev->msgram + mbox_of;
+	pkt = &mbox->rx_pkt;
 	pkt->size = ioread32(addr);
 
-	if (pkt->size > mdev->mcore_mbox_size)
+	if (pkt->size > mbox->mcore_mbox_size)
 		pr_err("%s: Invalid mailbox packet\n", __func__);
 	else {
 		memcpy32_fromio(pkt->data, addr + sizeof(pkt->size), pkt->size);
-		mbox_chan_received_data(&mdev->mbox->chans[0], &pkt);
+		mbox_chan_received_data(&mbox->ctrl.chans[mbox->idx_in_flight],
+				pkt);
 	}
 	iowrite32(0, addr);
-	send_irq(mdev);
+	send_irq(mbox->mdev);
 }
 
 /**
  * init_mcore_state() - initialize the mcore state of a mailbox.
  * @mdev:	mailbox device to be initialized.
  */
-static void init_mcore_state(struct qmp_device *mdev)
+static void init_mcore_state(struct qmp_mbox *mbox)
 {
 	struct channel_desc mcore;
 	u32 offset = offsetof(struct mbox_desc, mcore);
@@ -431,40 +459,60 @@
 	mcore.link_state_ack = QMP_MBOX_LINK_DOWN;
 	mcore.ch_state = QMP_MBOX_CH_DISCONNECTED;
 	mcore.ch_state_ack = QMP_MBOX_CH_DISCONNECTED;
-	mcore.mailbox_size = mdev->mcore_mbox_size;
-	mcore.mailbox_offset = mdev->mcore_mbox_offset;
-	memcpy32_toio(mdev->desc + offset, &mcore, sizeof(mcore));
+	mcore.mailbox_size = mbox->mcore_mbox_size;
+	mcore.mailbox_offset = mbox->mcore_mbox_offset;
+	memcpy32_toio(mbox->desc + offset, &mcore, sizeof(mcore));
+}
+
+/**
+ * qmp_irq_handler() - handle irq from remote entitity.
+ * @irq:	irq number for the trggered interrupt.
+ * @priv:	private pointer to qmp mbox device.
+ */
+static irqreturn_t qmp_irq_handler(int irq, void *priv)
+{
+	struct qmp_device *mdev = (struct qmp_device *)priv;
+
+	if (mdev->rx_reset_reg)
+		writel_relaxed(mdev->irq_mask, mdev->rx_reset_reg);
+
+	kthread_queue_work(&mdev->kworker, &mdev->kwork);
+	mdev->rx_irq_count++;
+
+	return IRQ_HANDLED;
 }
 
 /**
  * __qmp_rx_worker() - Handle incoming messages from remote processor.
- * @mdev:	mailbox device that received notification.
+ * @mbox:	mailbox device that received notification.
  */
-static void __qmp_rx_worker(struct qmp_device *mdev)
+static void __qmp_rx_worker(struct qmp_mbox *mbox)
 {
-	u32 msg_len;
+	u32 msg_len, idx;
 	struct mbox_desc desc;
+	struct qmp_device *mdev = mbox->mdev;
+	unsigned long flags;
 
-	memcpy_fromio(&desc, mdev->desc, sizeof(desc));
+	memcpy_fromio(&desc, mbox->desc, sizeof(desc));
 	if (desc.magic != QMP_MAGIC)
 		return;
 
-	mutex_lock(&mdev->state_lock);
-	switch (mdev->local_state) {
+	mutex_lock(&mbox->state_lock);
+	switch (mbox->local_state) {
 	case LINK_DISCONNECTED:
-		mdev->version.version = desc.version;
-		mdev->version.features = desc.features;
-		set_ucore_link_ack(mdev, desc.ucore.link_state);
+		mbox->version.version = desc.version;
+		mbox->version.features = desc.features;
+		set_ucore_link_ack(mbox, desc.ucore.link_state);
 		if (desc.mcore.mailbox_size) {
-			mdev->mcore_mbox_size = desc.mcore.mailbox_size;
-			mdev->mcore_mbox_offset = desc.mcore.mailbox_offset;
+			mbox->mcore_mbox_size = desc.mcore.mailbox_size;
+			mbox->mcore_mbox_offset = desc.mcore.mailbox_offset;
 		}
-		init_mcore_state(mdev);
-		mdev->local_state = LINK_NEGOTIATION;
-		mdev->rx_pkt.data = devm_kzalloc(mdev->dev,
+		init_mcore_state(mbox);
+		mbox->local_state = LINK_NEGOTIATION;
+		mbox->rx_pkt.data = devm_kzalloc(mdev->dev,
 						 desc.ucore.mailbox_size,
 						 GFP_KERNEL);
-		if (!mdev->rx_pkt.data) {
+		if (!mbox->rx_pkt.data) {
 			pr_err("In %s: failed to allocate rx pkt\n", __func__);
 			break;
 		}
@@ -477,8 +525,8 @@
 					__func__);
 			break;
 		}
-		mdev->local_state = LINK_CONNECTED;
-		complete_all(&mdev->link_complete);
+		mbox->local_state = LINK_CONNECTED;
+		complete_all(&mbox->link_complete);
 		break;
 	case LINK_CONNECTED:
 		if (desc.ucore.ch_state == desc.ucore.ch_state_ack) {
@@ -486,23 +534,23 @@
 					__func__);
 			break;
 		}
-		set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+		set_ucore_ch_ack(mbox, desc.ucore.ch_state);
 		send_irq(mdev);
 		break;
 	case LOCAL_CONNECTING:
 		if (desc.mcore.ch_state_ack == QMP_MBOX_CH_CONNECTED &&
 				desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED)
-			mdev->local_state = LOCAL_CONNECTED;
+			mbox->local_state = LOCAL_CONNECTED;
 
 		if (desc.ucore.ch_state != desc.ucore.ch_state_ack) {
-			set_ucore_ch_ack(mdev, desc.ucore.ch_state);
+			set_ucore_ch_ack(mbox, desc.ucore.ch_state);
 			send_irq(mdev);
 		}
-		if (mdev->local_state == LOCAL_CONNECTED &&
+		if (mbox->local_state == LOCAL_CONNECTED &&
 				desc.mcore.ch_state == QMP_MBOX_CH_CONNECTED &&
 				desc.ucore.ch_state == QMP_MBOX_CH_CONNECTED) {
-			mdev->local_state = CHANNEL_CONNECTED;
-			complete_all(&mdev->ch_complete);
+			mbox->local_state = CHANNEL_CONNECTED;
+			complete_all(&mbox->ch_complete);
 		}
 		break;
 	case LOCAL_CONNECTED:
@@ -511,50 +559,58 @@
 					__func__);
 			break;
 		}
-		set_ucore_ch_ack(mdev, desc.ucore.ch_state);
-		mdev->local_state = CHANNEL_CONNECTED;
+		set_ucore_ch_ack(mbox, desc.ucore.ch_state);
+		mbox->local_state = CHANNEL_CONNECTED;
 		send_irq(mdev);
-		complete_all(&mdev->ch_complete);
+		complete_all(&mbox->ch_complete);
 		break;
 	case CHANNEL_CONNECTED:
 		if (desc.ucore.ch_state == QMP_MBOX_CH_DISCONNECTED) {
-			set_ucore_ch_ack(mdev, desc.ucore.ch_state);
-			mdev->local_state = LOCAL_CONNECTED;
+			set_ucore_ch_ack(mbox, desc.ucore.ch_state);
+			mbox->local_state = LOCAL_CONNECTED;
 			send_irq(mdev);
 		}
 
 		msg_len = ioread32(mdev->msgram + desc.ucore.mailbox_offset);
-		if (msg_len)
-			qmp_recv_data(mdev, desc.ucore.mailbox_offset);
+		if (msg_len && !mbox->rx_disabled)
+			qmp_recv_data(mbox, desc.ucore.mailbox_offset);
 
-		if (mdev->tx_sent) {
+		spin_lock_irqsave(&mbox->tx_lock, flags);
+		idx = mbox->idx_in_flight;
+		if (mbox->tx_sent) {
 			msg_len = ioread32(mdev->msgram +
-						mdev->mcore_mbox_offset);
+						mbox->mcore_mbox_offset);
 			if (msg_len == 0) {
-				mdev->tx_sent = false;
-				cancel_delayed_work(&mdev->dwork);
-				mbox_chan_txdone(&mdev->mbox->chans[0], 0);
+				mbox->tx_sent = false;
+				cancel_delayed_work(&mbox->dwork);
+				spin_unlock_irqrestore(&mbox->tx_lock, flags);
+				mbox_chan_txdone(&mbox->ctrl.chans[idx], 0);
+				spin_lock_irqsave(&mbox->tx_lock, flags);
 			}
 		}
+		spin_unlock_irqrestore(&mbox->tx_lock, flags);
 		break;
 	case LOCAL_DISCONNECTING:
 		if (desc.mcore.ch_state_ack == QMP_MBOX_CH_DISCONNECTED &&
 				desc.mcore.ch_state == desc.mcore.ch_state_ack)
-			mdev->local_state = LINK_CONNECTED;
-		reinit_completion(&mdev->ch_complete);
+			mbox->local_state = LINK_CONNECTED;
+		reinit_completion(&mbox->ch_complete);
 		break;
 	default:
 		pr_err("In %s: Local Channel State corrupted\n", __func__);
 	}
-	mutex_unlock(&mdev->state_lock);
+	mutex_unlock(&mbox->state_lock);
 }
 
 static void rx_worker(struct kthread_work *work)
 {
 	struct qmp_device *mdev;
+	struct qmp_mbox *mbox;
 
 	mdev = container_of(work, struct qmp_device, kwork);
-	__qmp_rx_worker(mdev);
+	list_for_each_entry(mbox, &mdev->mboxes, list) {
+		__qmp_rx_worker(mbox);
+	}
 }
 
 /**
@@ -566,48 +622,207 @@
 static struct mbox_chan *qmp_mbox_of_xlate(struct mbox_controller *mbox,
 		const struct of_phandle_args *spec)
 {
-	struct qmp_device *mdev = dev_get_drvdata(mbox->dev);
-	unsigned int channel = spec->args[0];
+	struct qmp_mbox *dev = container_of(mbox, struct qmp_mbox, ctrl);
+	struct mbox_chan *chan;
 
-	if (!mdev || channel >= mbox->num_chans)
-		return ERR_PTR(-EINVAL);
-
-	mutex_lock(&mdev->state_lock);
-	if (mdev->ch_in_use) {
-		pr_err("%s, mbox channel already in use %s\n", __func__,
-								mdev->name);
-		mutex_unlock(&mdev->state_lock);
-		return ERR_PTR(-EBUSY);
+	if (dev->num_assigned >= mbox->num_chans || !dev->ctrl.chans) {
+		pr_err("%s: QMP out of channels\n", __func__);
+		return ERR_PTR(-ENOMEM);
 	}
-	mdev->ch_in_use = true;
-	mutex_unlock(&mdev->state_lock);
-	return &mbox->chans[0];
+
+	mutex_lock(&dev->state_lock);
+	chan = &dev->ctrl.chans[dev->num_assigned++];
+	mutex_unlock(&dev->state_lock);
+
+	return chan;
 }
 
 /**
- * parse_devicetree() - Parse the device tree information for QMP, map io
- *			memory and register for needed interrupts
- * @pdev:	platform device for this driver.
- * @mdev:	mailbox device to hold the device tree configuration.
+ * cleanup_workqueue() - Flush all work and stop the thread for this mailbox.
+ * @mdev:	mailbox device to cleanup.
+ */
+static void cleanup_workqueue(struct qmp_device *mdev)
+{
+	kthread_flush_worker(&mdev->kworker);
+	kthread_stop(mdev->task);
+	mdev->task = NULL;
+}
+
+static int qmp_mbox_remove(struct platform_device *pdev)
+{
+	struct qmp_device *mdev = platform_get_drvdata(pdev);
+	struct qmp_mbox *mbox = NULL;
+
+	disable_irq(mdev->rx_irq_line);
+	cleanup_workqueue(mdev);
+
+	list_for_each_entry(mbox, &mdev->mboxes, list) {
+		mbox_controller_unregister(&mbox->ctrl);
+	}
+	return 0;
+}
+
+/**
+ * get_mbox_num_chans() - Find how many mbox channels need to be allocated
+ *
+ * @node:	device node for this mailbox.
+ *
+ * Return: the number of phandles referring to this device node
+ */
+static u32 get_mbox_num_chans(struct device_node *node)
+{
+	int i, j, ret;
+	u32 num_chans = 0;
+	struct device_node *np;
+	struct of_phandle_args p;
+
+	for_each_node_with_property(np, "mboxes") {
+		if (!of_device_is_available(np))
+			continue;
+		i = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
+		for (j = 0; j < i; j++) {
+			ret = of_parse_phandle_with_args(np, "mboxes",
+							"#mbox-cells", j, &p);
+			if (!ret && p.np == node) {
+				num_chans++;
+				break;
+			}
+		}
+	}
+	if (num_chans)
+		return num_chans;
+
+	return 1;
+}
+
+/**
+ * mdev_add_mbox() - Add a mailbox to qmp device based on priority
+ *
+ * @mdev:	qmp device to add mailbox to.
+ * @new:	new mailbox to add to qmp device.
+ */
+static void mdev_add_mbox(struct qmp_device *mdev, struct qmp_mbox *new)
+{
+	struct qmp_mbox *mbox;
+
+	list_for_each_entry(mbox, &mdev->mboxes, list) {
+		if (mbox->priority > new->priority)
+			continue;
+		list_add_tail(&new->list, &mbox->list);
+		return;
+	}
+	list_add_tail(&new->list, &mdev->mboxes);
+}
+
+static struct mbox_chan_ops qmp_mbox_ops = {
+	.startup = qmp_startup,
+	.shutdown = qmp_shutdown,
+	.send_data = qmp_send_data,
+	.last_tx_done = qmp_last_tx_done,
+};
+
+static const struct of_device_id qmp_mbox_match_table[] = {
+	{ .compatible = "qcom,qmp-mbox" },
+	{},
+};
+
+/**
+ * qmp_mbox_init() - Parse the device tree for qmp mailbox and init structure
+ *
+ * @n:		child device node representing a mailbox.
+ * @mbox:	device structure for this edge.
  *
  * Return: 0 on succes or standard Linux error code.
  */
-static int qmp_parse_devicetree(struct platform_device *pdev,
-					struct qmp_device *mdev)
+static int qmp_mbox_init(struct device_node *n, struct qmp_device *mdev)
 {
+	int rc, i;
+	char *key;
+	struct qmp_mbox *mbox;
+	struct mbox_chan *chans;
+	u32 mbox_of, mbox_size, desc_of, priority, num_chans;
+
+	key = "mbox-desc-offset";
+	rc = of_property_read_u32(n, key, &desc_of);
+	if (rc) {
+		pr_err("%s: missing key %s\n", __func__, key);
+		return 0;
+	}
+	key = "priority";
+	rc = of_property_read_u32(n, key, &priority);
+	if (rc) {
+		pr_err("%s: missing key %s\n", __func__, key);
+		return 0;
+	}
+	mbox = devm_kzalloc(mdev->dev, sizeof(*mbox), GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+
+	rc = of_property_read_u32(n, "mbox-offset", &mbox_of);
+	if (!rc)
+		mbox->mcore_mbox_offset = mbox_of;
+	rc = of_property_read_u32(n, "mbox-size", &mbox_size);
+	if (!rc)
+		mbox->mcore_mbox_size = mbox_size;
+
+	mbox->mdev = mdev;
+	mbox->priority = priority;
+	mbox->desc = mdev->msgram + desc_of;
+	num_chans = get_mbox_num_chans(n);
+	mbox->rx_disabled = (num_chans > 1) ? true : false;
+	chans = devm_kzalloc(mdev->dev, sizeof(*chans) * num_chans, GFP_KERNEL);
+	if (!chans)
+		return -ENOMEM;
+
+	for (i = 0; i < num_chans; i++)
+		chans[i].con_priv = mbox;
+
+	mbox->ctrl.dev = mdev->dev;
+	mbox->ctrl.ops = &qmp_mbox_ops;
+	mbox->ctrl.chans = chans;
+	mbox->ctrl.num_chans = num_chans;
+	mbox->ctrl.txdone_irq = true;
+	mbox->ctrl.txdone_poll = false;
+	mbox->ctrl.of_xlate = qmp_mbox_of_xlate;
+
+	rc = mbox_controller_register(&mbox->ctrl);
+	if (rc) {
+		pr_err("%s: failed to register mbox controller %d\n", __func__,
+				rc);
+		return rc;
+	}
+	spin_lock_init(&mbox->tx_lock);
+	mutex_init(&mbox->state_lock);
+	mbox->local_state = LINK_DISCONNECTED;
+	init_completion(&mbox->link_complete);
+	init_completion(&mbox->ch_complete);
+	mbox->tx_sent = false;
+	mbox->num_assigned = 0;
+	INIT_DELAYED_WORK(&mbox->dwork, qmp_notify_timeout);
+
+	mdev_add_mbox(mdev, mbox);
+	return 0;
+}
+
+
+/**
+ * qmp_edge_init() - Parse the device tree information for QMP, map io
+ *			memory and register for needed interrupts
+ * @pdev:	platform device for this driver.
+ *
+ * Return: 0 on succes or standard Linux error code.
+ */
+static int qmp_edge_init(struct platform_device *pdev)
+{
+	struct qmp_device *mdev = platform_get_drvdata(pdev);
 	struct device_node *node = pdev->dev.of_node;
+	struct resource *msgram_r, *tx_irq_reg_r;
 	char *key;
 	int rc;
-	const char *subsys_name;
-	u32 rx_irq_line, tx_irq_mask;
-	u32 desc_of = 0;
-	u32 mbox_of = 0;
-	u32 mbox_size = 0;
-	struct resource *msgram_r, *tx_irq_reg_r;
 
 	key = "label";
-	subsys_name = of_get_property(node, key, NULL);
-	if (!subsys_name) {
+	mdev->name = of_get_property(node, key, NULL);
+	if (!mdev->name) {
 		pr_err("%s: missing key %s\n", __func__, key);
 		return -ENODEV;
 	}
@@ -627,143 +842,60 @@
 	}
 
 	key = "qcom,irq-mask";
-	rc = of_property_read_u32(node, key, &tx_irq_mask);
+	rc = of_property_read_u32(node, key, &mdev->irq_mask);
 	if (rc) {
 		pr_err("%s: missing key %s\n", __func__, key);
 		return -ENODEV;
 	}
 
 	key = "interrupts";
-	rx_irq_line = irq_of_parse_and_map(node, 0);
-	if (!rx_irq_line) {
+	mdev->rx_irq_line = irq_of_parse_and_map(node, 0);
+	if (!mdev->rx_irq_line) {
 		pr_err("%s: missing key %s\n", __func__, key);
 		return -ENODEV;
 	}
 
-	key = "mbox-desc-offset";
-	rc = of_property_read_u32(node, key, &desc_of);
-	if (rc) {
-		pr_err("%s: missing key %s\n", __func__, key);
-		return -ENODEV;
-	}
-
-	key = "mbox-offset";
-	rc = of_property_read_u32(node, key, &mbox_of);
-	if (!rc)
-		mdev->mcore_mbox_offset = mbox_of;
-
-	key = "mbox-size";
-	rc = of_property_read_u32(node, key, &mbox_size);
-	if (!rc)
-		mdev->mcore_mbox_size = mbox_size;
-
-	mdev->name = subsys_name;
-	mdev->msgram = devm_ioremap_nocache(&pdev->dev, msgram_r->start,
-						resource_size(msgram_r));
-	if (!mdev->msgram)
-		return -ENOMEM;
-
-	mdev->desc = mdev->msgram + desc_of;
-	if (!mdev->desc)
-		return -ENOMEM;
-
-	mdev->irq_mask = tx_irq_mask;
+	mdev->dev = &pdev->dev;
 	mdev->tx_irq_reg = devm_ioremap_nocache(&pdev->dev, tx_irq_reg_r->start,
 						resource_size(tx_irq_reg_r));
-	if (!mdev->tx_irq_reg)
-		return -ENOMEM;
+	mdev->msgram = devm_ioremap_nocache(&pdev->dev, msgram_r->start,
+						resource_size(msgram_r));
+	if (!mdev->msgram || !mdev->tx_irq_reg)
+		return -EIO;
 
-	mdev->rx_irq_line = rx_irq_line;
+	INIT_LIST_HEAD(&mdev->mboxes);
 	return 0;
 }
 
-/**
- * cleanup_workqueue() - Flush all work and stop the thread for this mailbox.
- * @mdev:	mailbox device to cleanup.
- */
-static void cleanup_workqueue(struct qmp_device *mdev)
-{
-	kthread_flush_worker(&mdev->kworker);
-	kthread_stop(mdev->task);
-	mdev->task = NULL;
-}
-
-static struct mbox_chan_ops qmp_mbox_ops = {
-	.startup = qmp_startup,
-	.shutdown = qmp_shutdown,
-	.send_data = qmp_send_data,
-	.last_tx_done = qmp_last_tx_done,
-};
-
-static const struct of_device_id qmp_mbox_match_table[] = {
-	{ .compatible = "qcom,qmp-mbox" },
-	{},
-};
-
 static int qmp_mbox_probe(struct platform_device *pdev)
 {
-	struct device_node *node = pdev->dev.of_node;
-	struct mbox_controller *mbox;
+	struct device_node *edge_node = pdev->dev.of_node;
 	struct qmp_device *mdev;
-	struct mbox_chan *chans;
 	int ret = 0;
 
 	mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
 	if (!mdev)
 		return -ENOMEM;
-	platform_set_drvdata(pdev, mdev);
 
-	ret = qmp_parse_devicetree(pdev, mdev);
+	platform_set_drvdata(pdev, mdev);
+	ret = qmp_edge_init(pdev);
 	if (ret)
 		return ret;
 
-	mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
-	if (!mbox)
-		return -ENOMEM;
+	ret = qmp_mbox_init(edge_node, mdev);
+	if (ret)
+		return ret;
 
-	chans = devm_kzalloc(&pdev->dev, sizeof(*chans) * QMP_NUM_CHANS,
-								GFP_KERNEL);
-	if (!chans)
-		return -ENOMEM;
-
-	mbox->dev = &pdev->dev;
-	mbox->ops = &qmp_mbox_ops;
-	mbox->chans = chans;
-	mbox->chans[0].con_priv = mdev;
-	mbox->num_chans = QMP_NUM_CHANS;
-	mbox->txdone_irq = true;
-	mbox->txdone_poll = false;
-	mbox->of_xlate = qmp_mbox_of_xlate;
-
-	mdev->dev = &pdev->dev;
-	mdev->mbox = mbox;
-	spin_lock_init(&mdev->tx_lock);
-	mutex_init(&mdev->state_lock);
-	mdev->local_state = LINK_DISCONNECTED;
 	kthread_init_work(&mdev->kwork, rx_worker);
 	kthread_init_worker(&mdev->kworker);
 	mdev->task = kthread_run(kthread_worker_fn, &mdev->kworker, "qmp_%s",
 								mdev->name);
-	init_completion(&mdev->link_complete);
-	init_completion(&mdev->ch_complete);
-	mdev->tx_sent = false;
-	mdev->ch_in_use = false;
-	INIT_DELAYED_WORK(&mdev->dwork, qmp_notify_timeout);
-
-	ret = mbox_controller_register(mbox);
-	if (ret) {
-		cleanup_workqueue(mdev);
-		pr_err("%s: failed to register mbox controller %d\n", __func__,
-									ret);
-		return ret;
-	}
 
 	ret = devm_request_irq(&pdev->dev, mdev->rx_irq_line, qmp_irq_handler,
 		IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND | IRQF_SHARED,
-		node->name, mdev);
+		edge_node->name, mdev);
 	if (ret < 0) {
-		cleanup_workqueue(mdev);
-		mbox_controller_unregister(mdev->mbox);
+		qmp_mbox_remove(pdev);
 		pr_err("%s: request irq on %d failed: %d\n", __func__,
 							mdev->rx_irq_line, ret);
 		return ret;
@@ -773,19 +905,11 @@
 		pr_err("%s: enable_irq_wake on %d failed: %d\n", __func__,
 							mdev->rx_irq_line, ret);
 
+	/* Trigger RX */
 	qmp_irq_handler(0, mdev);
 	return 0;
 }
 
-static int qmp_mbox_remove(struct platform_device *pdev)
-{
-	struct qmp_device *mdev = platform_get_drvdata(pdev);
-
-	cleanup_workqueue(mdev);
-	mbox_controller_unregister(mdev->mbox);
-	return 0;
-}
-
 static struct platform_driver qmp_mbox_driver = {
 	.probe = qmp_mbox_probe,
 	.remove = qmp_mbox_remove,
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index 1f649d6..bde20b4 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -79,7 +79,7 @@
 #define CMD_STATUS_COMPL		BIT(16)
 
 /* Control/Hidden TCS */
-#define TCS_HIDDEN_MAX_SLOTS		3
+#define TCS_HIDDEN_MAX_SLOTS		2
 #define TCS_HIDDEN_CMD0_DRV_DATA	0x38
 #define TCS_HIDDEN_CMD_SHIFT		0x08
 
@@ -852,7 +852,6 @@
 	struct tcs_mbox_msg *msg = data;
 	const struct device *dev = chan->cl->dev;
 	int ret = 0;
-	int count = 0;
 
 	if (!msg) {
 		dev_err(dev, "Payload error\n");
@@ -894,12 +893,7 @@
 		tcs_mbox_invalidate(chan);
 
 	/* Post the message to the TCS and trigger */
-	do {
-		ret = tcs_mbox_write(chan, msg, true);
-		if (ret != -EBUSY)
-			break;
-		udelay(100);
-	} while (++count < 100);
+	ret = tcs_mbox_write(chan, msg, true);
 
 tx_fail:
 	/* If there was an error in the request, schedule a response */
@@ -915,7 +909,7 @@
 
 	/* If we were just busy waiting for TCS, dump the state and return */
 	if (ret == -EBUSY) {
-		dev_err(dev, "TCS Busy, retrying RPMH message send\n");
+		pr_info("TCS Busy, retrying RPMH message send\n");
 		dump_tcs_stats(drv);
 		ret = -EAGAIN;
 	}
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index e7b8f49..89fc93b 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -277,6 +277,23 @@
 
 	  If unsure, say N.
 
+config DM_REQ_CRYPT
+	tristate "Req Crypt target support"
+	depends on BLK_DEV_DM
+	select XTS
+	select CRYPTO_XTS
+	---help---
+	  This request based device-mapper target allows you to create a device that
+	  transparently encrypts the data on it. You'll need to activate
+	  the ciphers you're going to use in the cryptoapi configuration.
+	  The DM REQ CRYPT operates on requests (bigger payloads) to utilize
+	  crypto hardware better.
+
+	  To compile this code as a module, choose M here: the module will
+	  be called dm-req-crypt.
+
+	  If unsure, say N.
+
 config DM_SNAPSHOT
        tristate "Snapshot target"
        depends on BLK_DEV_DM
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index f26ce41..f14e2fc 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -59,6 +59,7 @@
 obj-$(CONFIG_DM_CACHE_CLEANER)	+= dm-cache-cleaner.o
 obj-$(CONFIG_DM_ERA)		+= dm-era.o
 obj-$(CONFIG_DM_LOG_WRITES)	+= dm-log-writes.o
+obj-$(CONFIG_DM_REQ_CRYPT)	+= dm-req-crypt.o
 obj-$(CONFIG_DM_ANDROID_VERITY) += dm-android-verity.o
 
 ifeq ($(CONFIG_DM_UEVENT),y)
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
new file mode 100644
index 0000000..3ffe7e5
--- /dev/null
+++ b/drivers/md/dm-req-crypt.c
@@ -0,0 +1,1364 @@
+/*
+ * DM request based crypto driver
+ *
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/mempool.h>
+#include <linux/slab.h>
+#include <linux/crypto.h>
+#include <linux/qcrypto.h>
+#include <linux/workqueue.h>
+#include <linux/backing-dev.h>
+#include <linux/atomic.h>
+#include <linux/scatterlist.h>
+#include <linux/device-mapper.h>
+#include <linux/printk.h>
+
+#include <asm/page.h>
+#include <asm/unaligned.h>
+#include <crypto/skcipher.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/hash.h>
+#include <crypto/md5.h>
+#include <crypto/algapi.h>
+#include <crypto/ice.h>
+
+#define DM_MSG_PREFIX "req-crypt"
+
+#define MAX_SG_LIST	1024
+#define REQ_DM_512_KB (512*1024)
+#define MAX_ENCRYPTION_BUFFERS 1
+#define MIN_IOS 256
+#define MIN_POOL_PAGES 32
+#define KEY_SIZE_XTS 32
+#define AES_XTS_IV_LEN 16
+#define MAX_MSM_ICE_KEY_LUT_SIZE 32
+#define SECTOR_SIZE 512
+#define MIN_CRYPTO_TRANSFER_SIZE (4 * 1024)
+
+#define DM_REQ_CRYPT_ERROR -1
+#define DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC -2
+
+/*
+ * ENCRYPTION_MODE_CRYPTO means dm-req-crypt would invoke crypto operations
+ * for all of the requests. Crypto operations are performed by crypto engine
+ * plugged with Linux Kernel Crypto APIs
+ */
+#define DM_REQ_CRYPT_ENCRYPTION_MODE_CRYPTO 0
+/*
+ * ENCRYPTION_MODE_TRANSPARENT means dm-req-crypt would not invoke crypto
+ * operations for any of the requests. Data would be encrypted or decrypted
+ * using Inline Crypto Engine(ICE) embedded in storage hardware
+ */
+#define DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT 1
+
+#define DM_REQ_CRYPT_QUEUE_SIZE 256
+
+struct req_crypt_result {
+	struct completion completion;
+	int err;
+};
+
+#define FDE_KEY_ID	0
+#define PFE_KEY_ID	1
+
+static struct dm_dev *dev;
+static struct kmem_cache *_req_crypt_io_pool;
+static struct kmem_cache *_req_dm_scatterlist_pool;
+static sector_t start_sector_orig;
+static struct workqueue_struct *req_crypt_queue;
+static struct workqueue_struct *req_crypt_split_io_queue;
+static mempool_t *req_io_pool;
+static mempool_t *req_page_pool;
+static mempool_t *req_scatterlist_pool;
+static bool is_fde_enabled;
+static struct crypto_skcipher *tfm;
+static unsigned int encryption_mode;
+static struct ice_crypto_setting *ice_settings;
+
+unsigned int num_engines;
+unsigned int num_engines_fde, fde_cursor;
+unsigned int num_engines_pfe, pfe_cursor;
+struct crypto_engine_entry *fde_eng, *pfe_eng;
+DEFINE_MUTEX(engine_list_mutex);
+
+struct req_dm_crypt_io {
+	struct ice_crypto_setting ice_settings;
+	struct work_struct work;
+	struct request *cloned_request;
+	int error;
+	atomic_t pending;
+	struct timespec start_time;
+	bool should_encrypt;
+	bool should_decrypt;
+	u32 key_id;
+};
+
+struct req_dm_split_req_io {
+	struct work_struct work;
+	struct scatterlist *req_split_sg_read;
+	struct req_crypt_result result;
+	struct crypto_engine_entry *engine;
+	u8 IV[AES_XTS_IV_LEN];
+	int size;
+	struct request *clone;
+};
+
+#ifdef CONFIG_FIPS_ENABLE
+static struct qcrypto_func_set dm_qcrypto_func;
+#else
+static struct qcrypto_func_set dm_qcrypto_func = {
+		qcrypto_cipher_set_device_hw,
+		qcrypto_cipher_set_flag,
+		qcrypto_get_num_engines,
+		qcrypto_get_engine_list
+};
+#endif
+static void req_crypt_cipher_complete
+		(struct crypto_async_request *req, int err);
+static void req_cryptd_split_req_queue_cb
+		(struct work_struct *work);
+static void req_cryptd_split_req_queue
+		(struct req_dm_split_req_io *io);
+static void req_crypt_split_io_complete
+		(struct req_crypt_result *res, int err);
+
+static  bool req_crypt_should_encrypt(struct req_dm_crypt_io *req)
+{
+	int ret = 0;
+	bool should_encrypt = false;
+	struct bio *bio = NULL;
+	bool is_encrypted = false;
+	bool is_inplace = false;
+
+	if (!req || !req->cloned_request || !req->cloned_request->bio)
+		return false;
+
+	if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT)
+		return false;
+	bio = req->cloned_request->bio;
+
+	/* req->key_id = key_id; @todo support more than 1 pfe key */
+	if ((ret == 0) && (is_encrypted || is_inplace)) {
+		should_encrypt = true;
+		req->key_id = PFE_KEY_ID;
+	} else if (is_fde_enabled) {
+		should_encrypt = true;
+		req->key_id = FDE_KEY_ID;
+	}
+
+	return should_encrypt;
+}
+
+static  bool req_crypt_should_deccrypt(struct req_dm_crypt_io *req)
+{
+	int ret = 0;
+	bool should_deccrypt = false;
+	struct bio *bio = NULL;
+	bool is_encrypted = false;
+	bool is_inplace = false;
+
+	if (!req || !req->cloned_request || !req->cloned_request->bio)
+		return false;
+	if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT)
+		return false;
+
+	bio = req->cloned_request->bio;
+
+	/* req->key_id = key_id; @todo support more than 1 pfe key */
+	if ((ret == 0) && (is_encrypted && !is_inplace)) {
+		should_deccrypt = true;
+		req->key_id = PFE_KEY_ID;
+	} else if (is_fde_enabled) {
+		should_deccrypt = true;
+		req->key_id = FDE_KEY_ID;
+	}
+
+	return should_deccrypt;
+}
+
+static void req_crypt_inc_pending(struct req_dm_crypt_io *io)
+{
+	atomic_inc(&io->pending);
+}
+
+static void req_crypt_dec_pending_encrypt(struct req_dm_crypt_io *io)
+{
+	int error = 0;
+	struct request *clone = NULL;
+
+	if (io) {
+		error = io->error;
+		if (io->cloned_request) {
+			clone = io->cloned_request;
+		} else {
+			DMERR("%s io->cloned_request is NULL\n",
+								__func__);
+			/*
+			 * If Clone is NULL we cannot do anything,
+			 * this should never happen
+			 */
+			WARN_ON(1);
+		}
+	} else {
+		DMERR("%s io is NULL\n", __func__);
+		/*
+		 * If Clone is NULL we cannot do anything,
+		 * this should never happen
+		 */
+		WARN_ON(1);
+	}
+
+	atomic_dec(&io->pending);
+
+	if (error < 0) {
+		dm_kill_unmapped_request(clone, error);
+		mempool_free(io, req_io_pool);
+	} else
+		dm_dispatch_request(clone);
+}
+
+static void req_crypt_dec_pending_decrypt(struct req_dm_crypt_io *io)
+{
+	int error = 0;
+	struct request *clone = NULL;
+
+	if (io) {
+		error = io->error;
+		if (io->cloned_request) {
+			clone = io->cloned_request;
+		} else {
+			DMERR("%s io->cloned_request is NULL\n",
+								__func__);
+			/*
+			 * If Clone is NULL we cannot do anything,
+			 * this should never happen
+			 */
+			WARN_ON(1);
+		}
+	} else {
+		DMERR("%s io is NULL\n",
+							__func__);
+		/*
+		 * If Clone is NULL we cannot do anything,
+		 * this should never happen
+		 */
+		WARN_ON(1);
+	}
+
+	/* Should never get here if io or Clone is NULL */
+	dm_end_request(clone, error);
+	atomic_dec(&io->pending);
+	mempool_free(io, req_io_pool);
+}
+
+/*
+ * The callback that will be called by the worker queue to perform Decryption
+ * for reads and use the dm function to complete the bios and requests.
+ */
+static void req_cryptd_crypt_read_convert(struct req_dm_crypt_io *io)
+{
+	struct request *clone = NULL;
+	int error = DM_REQ_CRYPT_ERROR;
+	int total_sg_len = 0, total_bytes_in_req = 0, temp_size = 0, i = 0;
+	struct scatterlist *sg = NULL;
+	struct scatterlist *req_sg_read = NULL;
+
+	unsigned int engine_list_total = 0;
+	struct crypto_engine_entry *curr_engine_list = NULL;
+	bool split_transfers = 0;
+	sector_t tempiv;
+	struct req_dm_split_req_io *split_io = NULL;
+
+	if (io) {
+		error = io->error;
+		if (io->cloned_request) {
+			clone = io->cloned_request;
+		} else {
+			DMERR("%s io->cloned_request is NULL\n",
+								__func__);
+			error = DM_REQ_CRYPT_ERROR;
+			goto submit_request;
+		}
+	} else {
+		DMERR("%s io is NULL\n",
+							__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto submit_request;
+	}
+
+	req_crypt_inc_pending(io);
+
+	mutex_lock(&engine_list_mutex);
+
+	engine_list_total = (io->key_id == FDE_KEY_ID ? num_engines_fde :
+						   (io->key_id == PFE_KEY_ID ?
+							num_engines_pfe : 0));
+
+	curr_engine_list = (io->key_id == FDE_KEY_ID ? fde_eng :
+						   (io->key_id == PFE_KEY_ID ?
+							pfe_eng : NULL));
+
+	mutex_unlock(&engine_list_mutex);
+
+	req_sg_read = (struct scatterlist *)mempool_alloc(req_scatterlist_pool,
+								GFP_KERNEL);
+	if (!req_sg_read) {
+		DMERR("%s req_sg_read allocation failed\n",
+						__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+	memset(req_sg_read, 0, sizeof(struct scatterlist) * MAX_SG_LIST);
+
+	total_sg_len = blk_rq_map_sg_no_cluster(clone->q, clone, req_sg_read);
+	if ((total_sg_len <= 0) || (total_sg_len > MAX_SG_LIST)) {
+		DMERR("%s Request Error%d", __func__, total_sg_len);
+		error = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+
+	total_bytes_in_req = clone->__data_len;
+	if (total_bytes_in_req > REQ_DM_512_KB) {
+		DMERR("%s total_bytes_in_req > 512 MB %d",
+				__func__, total_bytes_in_req);
+		error = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+
+
+	if ((clone->__data_len >= (MIN_CRYPTO_TRANSFER_SIZE *
+		engine_list_total))
+		&& (engine_list_total > 1))
+		split_transfers = 1;
+
+	if (split_transfers) {
+		split_io = kzalloc(sizeof(struct req_dm_split_req_io)
+				* engine_list_total, GFP_KERNEL);
+		if (!split_io) {
+			DMERR("%s split_io allocation failed\n", __func__);
+			error = DM_REQ_CRYPT_ERROR;
+			goto skcipher_req_alloc_failure;
+		}
+
+		split_io[0].req_split_sg_read = sg = req_sg_read;
+		split_io[engine_list_total - 1].size = total_bytes_in_req;
+		for (i = 0; i < (engine_list_total); i++) {
+			while ((sg) && i < (engine_list_total - 1)) {
+				split_io[i].size += sg->length;
+				split_io[engine_list_total - 1].size -=
+						sg->length;
+				if (split_io[i].size >=
+						(total_bytes_in_req /
+							engine_list_total)) {
+					split_io[i + 1].req_split_sg_read =
+							sg_next(sg);
+					sg_mark_end(sg);
+					break;
+				}
+				sg = sg_next(sg);
+			}
+			split_io[i].engine = &curr_engine_list[i];
+			init_completion(&split_io[i].result.completion);
+			memset(&split_io[i].IV, 0, AES_XTS_IV_LEN);
+			tempiv = clone->__sector + (temp_size / SECTOR_SIZE);
+			memcpy(&split_io[i].IV, &tempiv, sizeof(sector_t));
+			temp_size +=  split_io[i].size;
+			split_io[i].clone = clone;
+			req_cryptd_split_req_queue(&split_io[i]);
+		}
+	} else {
+		split_io = kzalloc(sizeof(struct req_dm_split_req_io),
+				GFP_KERNEL);
+		if (!split_io) {
+			DMERR("%s split_io allocation failed\n", __func__);
+			error = DM_REQ_CRYPT_ERROR;
+			goto skcipher_req_alloc_failure;
+		}
+		split_io->engine = &curr_engine_list[0];
+		init_completion(&split_io->result.completion);
+		memcpy(split_io->IV, &clone->__sector, sizeof(sector_t));
+		split_io->req_split_sg_read = req_sg_read;
+		split_io->size = total_bytes_in_req;
+		split_io->clone = clone;
+		req_cryptd_split_req_queue(split_io);
+	}
+
+	if (!split_transfers) {
+		wait_for_completion_interruptible(&split_io->result.completion);
+		if (split_io->result.err) {
+			DMERR("%s error = %d for request\n",
+				 __func__, split_io->result.err);
+			error = DM_REQ_CRYPT_ERROR;
+			goto skcipher_req_alloc_failure;
+		}
+	} else {
+		for (i = 0; i < (engine_list_total); i++) {
+			wait_for_completion_interruptible(
+					&split_io[i].result.completion);
+			if (split_io[i].result.err) {
+				DMERR("%s error = %d for %dst request\n",
+					 __func__, split_io[i].result.err, i);
+				error = DM_REQ_CRYPT_ERROR;
+				goto skcipher_req_alloc_failure;
+			}
+		}
+	}
+	error = 0;
+skcipher_req_alloc_failure:
+
+	mempool_free(req_sg_read, req_scatterlist_pool);
+	kfree(split_io);
+submit_request:
+	if (io)
+		io->error = error;
+	req_crypt_dec_pending_decrypt(io);
+}
+
+/*
+ * This callback is called by the worker queue to perform non-decrypt reads
+ * and use the dm function to complete the bios and requests.
+ */
+static void req_cryptd_crypt_read_plain(struct req_dm_crypt_io *io)
+{
+	struct request *clone = NULL;
+	int error = 0;
+
+	if (!io || !io->cloned_request) {
+		DMERR("%s io is invalid\n", __func__);
+		WARN_ON(1); /* should not happen */
+	}
+
+	clone = io->cloned_request;
+
+	dm_end_request(clone, error);
+	mempool_free(io, req_io_pool);
+}
+
+/*
+ * The callback that will be called by the worker queue to perform Encryption
+ * for writes and submit the request using the elevelator.
+ */
+static void req_cryptd_crypt_write_convert(struct req_dm_crypt_io *io)
+{
+	struct request *clone = NULL;
+	struct bio *bio_src = NULL;
+	unsigned int total_sg_len_req_in = 0, total_sg_len_req_out = 0,
+		total_bytes_in_req = 0, error = DM_MAPIO_REMAPPED, rc = 0;
+	struct req_iterator iter;
+	struct req_iterator iter1;
+	struct skcipher_request *req = NULL;
+	struct req_crypt_result result;
+	struct bio_vec bvec;
+	struct scatterlist *req_sg_in = NULL;
+	struct scatterlist *req_sg_out = NULL;
+	int copy_bio_sector_to_req = 0;
+	gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+	struct page *page = NULL;
+	u8 IV[AES_XTS_IV_LEN];
+	int remaining_size = 0, err = 0;
+	struct crypto_engine_entry engine;
+	unsigned int engine_list_total = 0;
+	struct crypto_engine_entry *curr_engine_list = NULL;
+	unsigned int *engine_cursor = NULL;
+
+
+	if (io) {
+		if (io->cloned_request) {
+			clone = io->cloned_request;
+		} else {
+			DMERR("%s io->cloned_request is NULL\n",
+								__func__);
+			error = DM_REQ_CRYPT_ERROR;
+			goto submit_request;
+		}
+	} else {
+		DMERR("%s io is NULL\n",
+							__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto submit_request;
+	}
+
+	req_crypt_inc_pending(io);
+
+	req = skcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		DMERR("%s skcipher request allocation failed\n",
+					__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+
+	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				req_crypt_cipher_complete, &result);
+
+	mutex_lock(&engine_list_mutex);
+	engine_list_total = (io->key_id == FDE_KEY_ID ? num_engines_fde :
+						   (io->key_id == PFE_KEY_ID ?
+							num_engines_pfe : 0));
+
+	curr_engine_list = (io->key_id == FDE_KEY_ID ? fde_eng :
+						(io->key_id == PFE_KEY_ID ?
+						pfe_eng : NULL));
+
+	engine_cursor = (io->key_id == FDE_KEY_ID ? &fde_cursor :
+					(io->key_id == PFE_KEY_ID ? &pfe_cursor
+					: NULL));
+	if ((engine_list_total < 1) || (curr_engine_list == NULL) ||
+				(engine_cursor == NULL)) {
+		DMERR("%s Unknown Key ID!\n", __func__);
+		error = DM_REQ_CRYPT_ERROR;
+		mutex_unlock(&engine_list_mutex);
+		goto skcipher_req_alloc_failure;
+	}
+
+	engine = curr_engine_list[*engine_cursor];
+	(*engine_cursor)++;
+	(*engine_cursor) %= engine_list_total;
+
+	err = (dm_qcrypto_func.cipher_set)(req, engine.ce_device,
+				   engine.hw_instance);
+	if (err) {
+		DMERR("%s qcrypto_cipher_set_device_hw failed with err %d\n",
+				__func__, err);
+		mutex_unlock(&engine_list_mutex);
+		goto skcipher_req_alloc_failure;
+	}
+	mutex_unlock(&engine_list_mutex);
+
+	init_completion(&result.completion);
+
+	(dm_qcrypto_func.cipher_flag)(req,
+		QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
+	crypto_skcipher_clear_flags(tfm, ~0);
+	crypto_skcipher_setkey(tfm, NULL, KEY_SIZE_XTS);
+
+	req_sg_in = (struct scatterlist *)mempool_alloc(req_scatterlist_pool,
+								GFP_KERNEL);
+	if (!req_sg_in) {
+		DMERR("%s req_sg_in allocation failed\n",
+					__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+	memset(req_sg_in, 0, sizeof(struct scatterlist) * MAX_SG_LIST);
+
+	req_sg_out = (struct scatterlist *)mempool_alloc(req_scatterlist_pool,
+								GFP_KERNEL);
+	if (!req_sg_out) {
+		DMERR("%s req_sg_out allocation failed\n",
+					__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+	memset(req_sg_out, 0, sizeof(struct scatterlist) * MAX_SG_LIST);
+
+	total_sg_len_req_in = blk_rq_map_sg(clone->q, clone, req_sg_in);
+	if ((total_sg_len_req_in <= 0) ||
+			(total_sg_len_req_in > MAX_SG_LIST)) {
+		DMERR("%s Request Error%d", __func__, total_sg_len_req_in);
+		error = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+
+	total_bytes_in_req = clone->__data_len;
+	if (total_bytes_in_req > REQ_DM_512_KB) {
+		DMERR("%s total_bytes_in_req > 512 MB %d",
+				__func__, total_bytes_in_req);
+		error = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+
+	rq_for_each_segment(bvec, clone, iter) {
+		if (bvec.bv_len > remaining_size) {
+			page = NULL;
+			while (page == NULL) {
+				page = mempool_alloc(req_page_pool, gfp_mask);
+				if (!page) {
+					DMERR("%s Crypt page alloc failed",
+							__func__);
+					congestion_wait(BLK_RW_ASYNC, HZ/100);
+				}
+			}
+
+			bvec.bv_page = page;
+			bvec.bv_offset = 0;
+			remaining_size = PAGE_SIZE -  bvec.bv_len;
+			if (remaining_size < 0)
+				WARN_ON(1);
+		} else {
+			bvec.bv_page = page;
+			bvec.bv_offset = PAGE_SIZE - remaining_size;
+			remaining_size = remaining_size -  bvec.bv_len;
+		}
+	}
+
+	total_sg_len_req_out = blk_rq_map_sg(clone->q, clone, req_sg_out);
+	if ((total_sg_len_req_out <= 0) ||
+			(total_sg_len_req_out > MAX_SG_LIST)) {
+		DMERR("%s Request Error %d", __func__, total_sg_len_req_out);
+		error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
+		goto skcipher_req_alloc_failure;
+	}
+
+	memset(IV, 0, AES_XTS_IV_LEN);
+	memcpy(IV, &clone->__sector, sizeof(sector_t));
+
+	skcipher_request_set_crypt(req, req_sg_in, req_sg_out,
+			total_bytes_in_req, (void *) IV);
+
+	rc = crypto_skcipher_encrypt(req);
+
+	switch (rc) {
+	case 0:
+		break;
+
+	case -EBUSY:
+		/*
+		 * Lets make this synchronous request by waiting on
+		 * in progress as well
+		 */
+	case -EINPROGRESS:
+		wait_for_completion_interruptible(&result.completion);
+		if (result.err) {
+			DMERR("%s error = %d encrypting the request\n",
+				 __func__, result.err);
+			error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
+			goto skcipher_req_alloc_failure;
+		}
+		break;
+
+	default:
+		error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
+		goto skcipher_req_alloc_failure;
+	}
+
+	__rq_for_each_bio(bio_src, clone) {
+		if (copy_bio_sector_to_req == 0)
+			copy_bio_sector_to_req++;
+		blk_queue_bounce(clone->q, &bio_src);
+	}
+
+	/*
+	 * Recalculate the phy_segments as we allocate new pages
+	 * This is used by storage driver to fill the sg list.
+	 */
+	blk_recalc_rq_segments(clone);
+
+skcipher_req_alloc_failure:
+	if (req)
+		skcipher_request_free(req);
+
+	if (error == DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC) {
+		rq_for_each_segment(bvec, clone, iter1) {
+			if (bvec.bv_offset == 0) {
+				mempool_free(bvec.bv_page, req_page_pool);
+				bvec.bv_page = NULL;
+			} else
+				bvec.bv_page = NULL;
+		}
+	}
+
+	mempool_free(req_sg_in, req_scatterlist_pool);
+	mempool_free(req_sg_out, req_scatterlist_pool);
+submit_request:
+	if (io)
+		io->error = error;
+	req_crypt_dec_pending_encrypt(io);
+}
+
+/*
+ * This callback is called by the worker queue to perform non-encrypted writes
+ * and submit the request using the elevelator.
+ */
+static void req_cryptd_crypt_write_plain(struct req_dm_crypt_io *io)
+{
+	struct request *clone = NULL;
+
+	if (!io || !io->cloned_request) {
+		DMERR("%s io is invalid\n", __func__);
+		WARN_ON(1); /* should not happen */
+	}
+
+	clone = io->cloned_request;
+	io->error = 0;
+	dm_dispatch_request(clone);
+}
+
+/* Queue callback function that will get triggered */
+static void req_cryptd_crypt(struct work_struct *work)
+{
+	struct req_dm_crypt_io *io =
+			container_of(work, struct req_dm_crypt_io, work);
+
+	if (rq_data_dir(io->cloned_request) == WRITE) {
+		if (io->should_encrypt)
+			req_cryptd_crypt_write_convert(io);
+		else
+			req_cryptd_crypt_write_plain(io);
+	} else if (rq_data_dir(io->cloned_request) == READ) {
+		if (io->should_decrypt)
+			req_cryptd_crypt_read_convert(io);
+		else
+			req_cryptd_crypt_read_plain(io);
+	} else {
+		DMERR("%s received non-write request for Clone 0x%p\n",
+				__func__, io->cloned_request);
+	}
+}
+
+static void req_cryptd_split_req_queue_cb(struct work_struct *work)
+{
+	struct req_dm_split_req_io *io =
+			container_of(work, struct req_dm_split_req_io, work);
+	struct skcipher_request *req = NULL;
+	struct req_crypt_result result;
+	int err = 0;
+	struct crypto_engine_entry *engine = NULL;
+
+	if ((!io) || (!io->req_split_sg_read) || (!io->engine)) {
+		DMERR("%s Input invalid\n",
+			 __func__);
+		err = DM_REQ_CRYPT_ERROR;
+		/* If io is not populated this should not be called */
+		WARN_ON(1);
+	}
+	req = skcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		DMERR("%s skcipher request allocation failed\n", __func__);
+		err = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+
+	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+					req_crypt_cipher_complete, &result);
+
+	engine = io->engine;
+
+	err = (dm_qcrypto_func.cipher_set)(req, engine->ce_device,
+			engine->hw_instance);
+	if (err) {
+		DMERR("%s qcrypto_cipher_set_device_hw failed with err %d\n",
+				__func__, err);
+		goto skcipher_req_alloc_failure;
+	}
+	init_completion(&result.completion);
+	(dm_qcrypto_func.cipher_flag)(req,
+		QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
+
+	crypto_skcipher_clear_flags(tfm, ~0);
+	crypto_skcipher_setkey(tfm, NULL, KEY_SIZE_XTS);
+
+	skcipher_request_set_crypt(req, io->req_split_sg_read,
+			io->req_split_sg_read, io->size, (void *) io->IV);
+
+	err = crypto_skcipher_decrypt(req);
+	switch (err) {
+	case 0:
+		break;
+
+	case -EBUSY:
+		/*
+		 * Lets make this synchronous request by waiting on
+		 * in progress as well
+		 */
+	case -EINPROGRESS:
+		wait_for_completion_io(&result.completion);
+		if (result.err) {
+			DMERR("%s error = %d encrypting the request\n",
+				 __func__, result.err);
+			err = DM_REQ_CRYPT_ERROR;
+			goto skcipher_req_alloc_failure;
+		}
+		break;
+
+	default:
+		err = DM_REQ_CRYPT_ERROR;
+		goto skcipher_req_alloc_failure;
+	}
+	err = 0;
+skcipher_req_alloc_failure:
+	if (req)
+		skcipher_request_free(req);
+
+	req_crypt_split_io_complete(&io->result, err);
+}
+
+static void req_cryptd_split_req_queue(struct req_dm_split_req_io *io)
+{
+	INIT_WORK(&io->work, req_cryptd_split_req_queue_cb);
+	queue_work(req_crypt_split_io_queue, &io->work);
+}
+
+static void req_cryptd_queue_crypt(struct req_dm_crypt_io *io)
+{
+	INIT_WORK(&io->work, req_cryptd_crypt);
+	queue_work(req_crypt_queue, &io->work);
+}
+
+/*
+ * Cipher complete callback, this is triggered by the Linux crypto api once
+ * the operation is done. This signals the waiting thread that the crypto
+ * operation is complete.
+ */
+static void req_crypt_cipher_complete(struct crypto_async_request *req, int err)
+{
+	struct req_crypt_result *res = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	res->err = err;
+	complete(&res->completion);
+}
+
+static void req_crypt_split_io_complete(struct req_crypt_result *res, int err)
+{
+	if (err == -EINPROGRESS)
+		return;
+
+	res->err = err;
+	complete(&res->completion);
+}
+/*
+ * If bio->bi_dev is a partition, remap the location
+ */
+static inline void req_crypt_blk_partition_remap(struct bio *bio)
+{
+	struct block_device *bdev = bio->bi_bdev;
+
+	if (bio_sectors(bio) && bdev != bdev->bd_contains) {
+		struct hd_struct *p = bdev->bd_part;
+		/*
+		 * Check for integer overflow, should never happen.
+		 */
+		if (p->start_sect > (UINT_MAX - bio->bi_iter.bi_sector))
+			WARN_ON(1);
+
+		bio->bi_iter.bi_sector += p->start_sect;
+		bio->bi_bdev = bdev->bd_contains;
+	}
+}
+
+/*
+ * The endio function is called from ksoftirqd context (atomic).
+ * For write operations the new pages created form the mempool
+ * is freed and returned.  * For read operations, decryption is
+ * required, since this is called in a atomic  * context, the
+ * request is sent to a worker queue to complete decryptiona and
+ * free the request once done.
+ */
+static int req_crypt_endio(struct dm_target *ti, struct request *clone,
+			    int error, union map_info *map_context)
+{
+	int err = 0;
+	struct req_iterator iter1;
+	struct bio_vec bvec;
+	struct req_dm_crypt_io *req_io = map_context->ptr;
+
+	/* If it is for ICE, free up req_io and return */
+	if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) {
+		mempool_free(req_io, req_io_pool);
+		err = error;
+		goto submit_request;
+	}
+
+	if (rq_data_dir(clone) == WRITE) {
+		rq_for_each_segment(bvec, clone, iter1) {
+			if (req_io->should_encrypt && bvec.bv_offset == 0) {
+				mempool_free(bvec.bv_page, req_page_pool);
+				bvec.bv_page = NULL;
+			} else
+				bvec.bv_page = NULL;
+		}
+		mempool_free(req_io, req_io_pool);
+		goto submit_request;
+	} else if (rq_data_dir(clone) == READ) {
+		req_io->error = error;
+		req_cryptd_queue_crypt(req_io);
+		err = DM_ENDIO_INCOMPLETE;
+		goto submit_request;
+	}
+
+submit_request:
+	return err;
+}
+
+/*
+ * This function is called with interrupts disabled
+ * The function remaps the clone for the underlying device.
+ * If it is a write request, it calls into the worker queue to
+ * encrypt the data
+ * and submit the request directly using the elevator
+ * For a read request no pre-processing is required the request
+ * is returned to dm once mapping is done
+ */
+static int req_crypt_map(struct dm_target *ti, struct request *clone,
+			 union map_info *map_context)
+{
+	struct req_dm_crypt_io *req_io = NULL;
+	int error = DM_REQ_CRYPT_ERROR, copy_bio_sector_to_req = 0;
+	struct bio *bio_src = NULL;
+	gfp_t gfp_flag = GFP_KERNEL;
+
+	if (in_interrupt() || irqs_disabled())
+		gfp_flag = GFP_NOWAIT;
+
+	req_io = mempool_alloc(req_io_pool, gfp_flag);
+	if (!req_io) {
+		WARN_ON(1);
+		error = DM_REQ_CRYPT_ERROR;
+		goto submit_request;
+	}
+
+	/* Save the clone in the req_io, the callback to the worker
+	 * queue will get the req_io
+	 */
+	req_io->cloned_request = clone;
+	map_context->ptr = req_io;
+	atomic_set(&req_io->pending, 0);
+
+	if (rq_data_dir(clone) == WRITE)
+		req_io->should_encrypt = req_crypt_should_encrypt(req_io);
+	if (rq_data_dir(clone) == READ)
+		req_io->should_decrypt = req_crypt_should_deccrypt(req_io);
+
+	/* Get the queue of the underlying original device */
+	clone->q = bdev_get_queue(dev->bdev);
+	clone->rq_disk = dev->bdev->bd_disk;
+
+	__rq_for_each_bio(bio_src, clone) {
+		bio_src->bi_bdev = dev->bdev;
+		/* Currently the way req-dm works is that once the underlying
+		 * device driver completes the request by calling into the
+		 * block layer. The block layer completes the bios (clones) and
+		 * then the cloned request. This is undesirable for req-dm-crypt
+		 * hence added a flag BIO_DONTFREE, this flag will ensure that
+		 * blk layer does not complete the cloned bios before completing
+		 * the request. When the crypt endio is called, post-processing
+		 * is done and then the dm layer will complete the bios (clones)
+		 * and free them.
+		 */
+		if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT)
+			bio_src->bi_flags |= 1 << BIO_INLINECRYPT;
+		else
+			bio_src->bi_flags |= 1 << BIO_DONTFREE;
+
+		/*
+		 * If this device has partitions, remap block n
+		 * of partition p to block n+start(p) of the disk.
+		 */
+		req_crypt_blk_partition_remap(bio_src);
+		if (copy_bio_sector_to_req == 0) {
+			clone->__sector = bio_src->bi_iter.bi_sector;
+			copy_bio_sector_to_req++;
+		}
+		blk_queue_bounce(clone->q, &bio_src);
+	}
+
+	if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) {
+		/* Set all crypto parameters for inline crypto engine */
+		memcpy(&req_io->ice_settings, ice_settings,
+					sizeof(struct ice_crypto_setting));
+	} else {
+		/* ICE checks for key_index which could be >= 0. If a chip has
+		 * both ICE and GPCE and wanted to use GPCE, there could be
+		 * issue. Storage driver send all requests to ICE driver. If
+		 * it sees key_index as 0, it would assume it is for ICE while
+		 * it is not. Hence set invalid key index by default.
+		 */
+		req_io->ice_settings.key_index = -1;
+
+	}
+
+	if (rq_data_dir(clone) == READ ||
+		encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) {
+		error = DM_MAPIO_REMAPPED;
+		goto submit_request;
+	} else if (rq_data_dir(clone) == WRITE) {
+		req_cryptd_queue_crypt(req_io);
+		error = DM_MAPIO_SUBMITTED;
+		goto submit_request;
+	}
+
+submit_request:
+	return error;
+
+}
+
+static void deconfigure_qcrypto(void)
+{
+	mempool_destroy(req_page_pool);
+	req_page_pool = NULL;
+
+	mempool_destroy(req_scatterlist_pool);
+	req_scatterlist_pool = NULL;
+
+	if (req_crypt_split_io_queue) {
+		destroy_workqueue(req_crypt_split_io_queue);
+		req_crypt_split_io_queue = NULL;
+	}
+	if (req_crypt_queue) {
+		destroy_workqueue(req_crypt_queue);
+		req_crypt_queue = NULL;
+	}
+
+	kmem_cache_destroy(_req_dm_scatterlist_pool);
+
+	mutex_lock(&engine_list_mutex);
+	kfree(pfe_eng);
+	pfe_eng = NULL;
+	kfree(fde_eng);
+	fde_eng = NULL;
+	mutex_unlock(&engine_list_mutex);
+
+	if (tfm) {
+		crypto_free_skcipher(tfm);
+		tfm = NULL;
+	}
+}
+
+static void req_crypt_dtr(struct dm_target *ti)
+{
+	DMDEBUG("dm-req-crypt Destructor.\n");
+
+	mempool_destroy(req_io_pool);
+	req_io_pool = NULL;
+
+	if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) {
+		kfree(ice_settings);
+		ice_settings = NULL;
+	} else {
+		deconfigure_qcrypto();
+	}
+
+	kmem_cache_destroy(_req_crypt_io_pool);
+
+	if (dev) {
+		dm_put_device(ti, dev);
+		dev = NULL;
+	}
+}
+
+static int configure_qcrypto(void)
+{
+	struct crypto_engine_entry *eng_list = NULL;
+	struct block_device *bdev = NULL;
+	int err = DM_REQ_CRYPT_ERROR, i;
+	struct request_queue *q = NULL;
+
+	bdev = dev->bdev;
+	q = bdev_get_queue(bdev);
+	blk_queue_max_hw_sectors(q, DM_REQ_CRYPT_QUEUE_SIZE);
+
+	/* Allocate the crypto alloc blk cipher and keep the handle */
+	tfm = crypto_alloc_skcipher("qcom-xts(aes)", 0, 0);
+	if (IS_ERR(tfm)) {
+		DMERR("%s skcipher tfm allocation failed : error\n",
+						 __func__);
+		tfm = NULL;
+		goto exit_err;
+	}
+
+	num_engines_fde = num_engines_pfe = 0;
+
+	mutex_lock(&engine_list_mutex);
+	num_engines = (dm_qcrypto_func.get_num_engines)();
+	if (!num_engines) {
+		DMERR(KERN_INFO "%s qcrypto_get_num_engines failed\n",
+					__func__);
+		err = DM_REQ_CRYPT_ERROR;
+		mutex_unlock(&engine_list_mutex);
+		goto exit_err;
+	}
+
+	eng_list = kcalloc(num_engines, sizeof(*eng_list), GFP_KERNEL);
+	if (eng_list == NULL) {
+		DMERR("%s engine list allocation failed\n", __func__);
+		err = DM_REQ_CRYPT_ERROR;
+		mutex_unlock(&engine_list_mutex);
+		goto exit_err;
+	}
+
+	(dm_qcrypto_func.get_engine_list)(num_engines, eng_list);
+
+	for (i = 0; i < num_engines; i++) {
+		if (eng_list[i].ce_device == FDE_KEY_ID)
+			num_engines_fde++;
+		if (eng_list[i].ce_device == PFE_KEY_ID)
+			num_engines_pfe++;
+	}
+
+	fde_eng = kcalloc(num_engines_fde, sizeof(*fde_eng), GFP_KERNEL);
+	if (fde_eng == NULL) {
+		DMERR("%s fde engine list allocation failed\n", __func__);
+		mutex_unlock(&engine_list_mutex);
+		goto exit_err;
+	}
+
+	pfe_eng = kcalloc(num_engines_pfe, sizeof(*pfe_eng), GFP_KERNEL);
+	if (pfe_eng == NULL) {
+		DMERR("%s pfe engine list allocation failed\n", __func__);
+		mutex_unlock(&engine_list_mutex);
+		goto exit_err;
+	}
+
+	fde_cursor = 0;
+	pfe_cursor = 0;
+
+	for (i = 0; i < num_engines; i++) {
+		if (eng_list[i].ce_device == FDE_KEY_ID)
+			fde_eng[fde_cursor++] = eng_list[i];
+		if (eng_list[i].ce_device == PFE_KEY_ID)
+			pfe_eng[pfe_cursor++] = eng_list[i];
+	}
+
+	fde_cursor = 0;
+	pfe_cursor = 0;
+	mutex_unlock(&engine_list_mutex);
+
+	_req_dm_scatterlist_pool = kmem_cache_create("req_dm_scatterlist",
+				sizeof(struct scatterlist) * MAX_SG_LIST,
+				 __alignof__(struct scatterlist), 0, NULL);
+	if (!_req_dm_scatterlist_pool)
+		goto exit_err;
+
+	req_crypt_queue = alloc_workqueue("req_cryptd",
+					WQ_UNBOUND |
+					WQ_CPU_INTENSIVE |
+					WQ_MEM_RECLAIM,
+					0);
+	if (!req_crypt_queue) {
+		DMERR("%s req_crypt_queue not allocated\n", __func__);
+		goto exit_err;
+	}
+
+	req_crypt_split_io_queue = alloc_workqueue("req_crypt_split",
+					WQ_UNBOUND |
+					WQ_CPU_INTENSIVE |
+					WQ_MEM_RECLAIM,
+					0);
+	if (!req_crypt_split_io_queue) {
+		DMERR("%s req_crypt_split_io_queue not allocated\n", __func__);
+		goto exit_err;
+	}
+	req_scatterlist_pool = mempool_create_slab_pool(MIN_IOS,
+					_req_dm_scatterlist_pool);
+	if (!req_scatterlist_pool) {
+		DMERR("%s req_scatterlist_pool is not allocated\n", __func__);
+		err = -ENOMEM;
+		goto exit_err;
+	}
+
+	req_page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
+	if (!req_page_pool) {
+		DMERR("%s req_page_pool not allocated\n", __func__);
+		goto exit_err;
+	}
+
+	err = 0;
+
+exit_err:
+	kfree(eng_list);
+	return err;
+}
+
+/*
+ * Construct an encryption mapping:
+ * <cipher> <key> <iv_offset> <dev_path> <start>
+ */
+static int req_crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+	int err = DM_REQ_CRYPT_ERROR;
+	unsigned long long tmpll;
+	char dummy;
+	int ret;
+
+	DMDEBUG("dm-req-crypt Constructor.\n");
+
+	if (argc < 5) {
+		DMERR(" %s Not enough args\n", __func__);
+		err = DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
+	}
+
+	if (argv[3]) {
+		if (dm_get_device(ti, argv[3],
+				dm_table_get_mode(ti->table), &dev)) {
+			DMERR(" %s Device Lookup failed\n", __func__);
+			err =  DM_REQ_CRYPT_ERROR;
+			goto ctr_exit;
+		}
+	} else {
+		DMERR(" %s Arg[3] invalid\n", __func__);
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
+	}
+
+	if (argv[4]) {
+		if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
+			DMERR("%s Invalid device sector\n", __func__);
+			err =  DM_REQ_CRYPT_ERROR;
+			goto ctr_exit;
+		}
+	} else {
+		DMERR(" %s Arg[4] invalid\n", __func__);
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
+	}
+	start_sector_orig = tmpll;
+
+	/* Allow backward compatible */
+	if (argc >= 6) {
+		if (argv[5]) {
+			if (!strcmp(argv[5], "fde_enabled"))
+				is_fde_enabled = true;
+			else
+				is_fde_enabled = false;
+		} else {
+			DMERR(" %s Arg[5] invalid\n", __func__);
+			err =  DM_REQ_CRYPT_ERROR;
+			goto ctr_exit;
+		}
+	} else {
+		DMERR(" %s Arg[5] missing, set FDE enabled.\n", __func__);
+		is_fde_enabled = true; /* backward compatible */
+	}
+
+	_req_crypt_io_pool = KMEM_CACHE(req_dm_crypt_io, 0);
+	if (!_req_crypt_io_pool) {
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
+	}
+
+	encryption_mode = DM_REQ_CRYPT_ENCRYPTION_MODE_CRYPTO;
+	if (argc >= 7 && argv[6]) {
+		if (!strcmp(argv[6], "ice"))
+			encryption_mode =
+				DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT;
+	}
+
+	if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) {
+		/* configure ICE settings */
+		ice_settings =
+			kzalloc(sizeof(struct ice_crypto_setting), GFP_KERNEL);
+		if (!ice_settings) {
+			err = -ENOMEM;
+			goto ctr_exit;
+		}
+		ice_settings->key_size = ICE_CRYPTO_KEY_SIZE_128;
+		ice_settings->algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS;
+		ice_settings->key_mode = ICE_CRYPTO_USE_LUT_SW_KEY;
+		if (kstrtou16(argv[1], 0, &ice_settings->key_index) ||
+			ice_settings->key_index < 0 ||
+			ice_settings->key_index > MAX_MSM_ICE_KEY_LUT_SIZE) {
+			DMERR("%s Err: key index %d received for ICE\n",
+				__func__, ice_settings->key_index);
+			err = DM_REQ_CRYPT_ERROR;
+			goto ctr_exit;
+		}
+	} else {
+		ret = configure_qcrypto();
+		if (ret) {
+			DMERR("%s failed to configure qcrypto\n", __func__);
+			err = ret;
+			goto ctr_exit;
+		}
+	}
+
+	req_io_pool = mempool_create_slab_pool(MIN_IOS, _req_crypt_io_pool);
+	if (!req_io_pool) {
+		DMERR("%s req_io_pool not allocated\n", __func__);
+		err = -ENOMEM;
+		goto ctr_exit;
+	}
+
+	/*
+	 * If underlying device supports flush/discard, mapped target
+	 * should also allow it
+	 */
+	ti->num_flush_bios = 1;
+	ti->num_discard_bios = 1;
+
+	err = 0;
+	DMINFO("%s: Mapping block_device %s to dm-req-crypt ok!\n",
+	       __func__, argv[3]);
+ctr_exit:
+	if (err)
+		req_crypt_dtr(ti);
+
+	return err;
+}
+
+static int req_crypt_iterate_devices(struct dm_target *ti,
+				 iterate_devices_callout_fn fn, void *data)
+{
+	return fn(ti, dev, start_sector_orig, ti->len, data);
+}
+void set_qcrypto_func_dm(void *dev,
+			void *flag,
+			void *engines,
+			void *engine_list)
+{
+	dm_qcrypto_func.cipher_set  = dev;
+	dm_qcrypto_func.cipher_flag = flag;
+	dm_qcrypto_func.get_num_engines = engines;
+	dm_qcrypto_func.get_engine_list = engine_list;
+}
+EXPORT_SYMBOL(set_qcrypto_func_dm);
+
+static struct target_type req_crypt_target = {
+	.name   = "req-crypt",
+	.version = {1, 0, 0},
+	.module = THIS_MODULE,
+	.ctr    = req_crypt_ctr,
+	.dtr    = req_crypt_dtr,
+	.map_rq = req_crypt_map,
+	.rq_end_io = req_crypt_endio,
+	.iterate_devices = req_crypt_iterate_devices,
+};
+
+static int __init req_dm_crypt_init(void)
+{
+	int r;
+
+
+	r = dm_register_target(&req_crypt_target);
+	if (r < 0) {
+		DMERR("register failed %d", r);
+		return r;
+	}
+
+	DMINFO("dm-req-crypt successfully initalized.\n");
+
+	return r;
+}
+
+static void __exit req_dm_crypt_exit(void)
+{
+	dm_unregister_target(&req_crypt_target);
+}
+
+module_init(req_dm_crypt_init);
+module_exit(req_dm_crypt_exit);
+
+MODULE_DESCRIPTION(DM_NAME " target for request based transparent encryption / decryption");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index ba7c4c6..bca4c0e 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -283,7 +283,7 @@
  * Must be called without clone's queue lock held,
  * see end_clone_request() for more details.
  */
-static void dm_end_request(struct request *clone, int error)
+void dm_end_request(struct request *clone, int error)
 {
 	int rw = rq_data_dir(clone);
 	struct dm_rq_target_io *tio = clone->end_io_data;
@@ -464,7 +464,7 @@
  * Target's rq_end_io() function isn't called.
  * This may be used when the target's map_rq() or clone_and_map_rq() functions fail.
  */
-static void dm_kill_unmapped_request(struct request *rq, int error)
+void dm_kill_unmapped_request(struct request *rq, int error)
 {
 	rq->cmd_flags |= REQ_FAILED;
 	dm_complete_request(rq, error);
@@ -512,6 +512,13 @@
 		dm_complete_request(rq, r);
 }
 
+void dm_dispatch_request(struct request *rq)
+{
+	struct dm_rq_target_io *tio = tio_from_request(rq);
+
+	dm_dispatch_clone_request(tio->clone, rq);
+}
+
 static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig,
 				 void *data)
 {
diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h
index aeda2b6..fbe0165 100644
--- a/drivers/media/dvb-core/demux.h
+++ b/drivers/media/dvb-core/demux.h
@@ -40,6 +40,8 @@
  * Common definitions
  */
 
+#define DMX_EVENT_QUEUE_SIZE 500 /* number of events */
+
 /*
  * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
  */
@@ -61,6 +63,104 @@
 #endif
 
 /*
+ * enum dmx_success: Success codes for the Demux Callback API.
+ */
+enum dmx_success {
+	DMX_OK = 0, /* Received Ok */
+	DMX_OK_PES_END, /* Received OK, data reached end of PES packet */
+	DMX_OK_PCR, /* Received OK, data with new PCR/STC pair */
+	DMX_OK_EOS, /* Received OK, reached End-of-Stream (EOS) */
+	DMX_OK_MARKER, /* Received OK, reached a data Marker */
+	DMX_LENGTH_ERROR, /* Incorrect length */
+	DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
+	DMX_CRC_ERROR, /* Incorrect CRC */
+	DMX_FRAME_ERROR, /* Frame alignment error */
+	DMX_FIFO_ERROR, /* Receiver FIFO overrun */
+	DMX_MISSED_ERROR, /* Receiver missed packet */
+	DMX_OK_DECODER_BUF, /* Received OK, new ES data in decoder buffer */
+	DMX_OK_IDX, /* Received OK, new index event */
+	DMX_OK_SCRAMBLING_STATUS, /* Received OK, new scrambling status */
+};
+
+
+/*
+ * struct dmx_data_ready: Parameters for event notification callback.
+ * Event notification notifies demux device that data is written
+ * and available in the device's output buffer or provides
+ * notification on errors and other events. In the latter case
+ * data_length is zero.
+ */
+struct dmx_data_ready {
+	enum dmx_success status;
+
+	/*
+	 * data_length may be 0 in case of DMX_OK_PES_END or DMX_OK_EOS
+	 * and in non-DMX_OK_XXX events. In DMX_OK_PES_END,
+	 * data_length is for data coming after the end of PES.
+	 */
+	int data_length;
+
+	union {
+		struct {
+			int start_gap;
+			int actual_length;
+			int disc_indicator_set;
+			int pes_length_mismatch;
+			u64 stc;
+			u32 tei_counter;
+			u32 cont_err_counter;
+			u32 ts_packets_num;
+		} pes_end;
+
+		struct {
+			u64 pcr;
+			u64 stc;
+			int disc_indicator_set;
+		} pcr;
+
+		struct {
+			int handle;
+			int cookie;
+			u32 offset;
+			u32 len;
+			int pts_exists;
+			u64 pts;
+			int dts_exists;
+			u64 dts;
+			u32 tei_counter;
+			u32 cont_err_counter;
+			u32 ts_packets_num;
+			u32 ts_dropped_bytes;
+			u64 stc;
+		} buf;
+
+		struct {
+			u64 id;
+		} marker;
+
+		struct dmx_index_event_info idx_event;
+		struct dmx_scrambling_status_event_info scrambling_bits;
+	};
+};
+
+/*
+ * struct data_buffer: Parameters of buffer allocated by
+ * demux device for input/output. Can be used to directly map the
+ * demux-device buffer to HW output if HW supports it.
+ */
+struct data_buffer {
+	/* dvb_ringbuffer managed by demux-device */
+	const struct dvb_ringbuffer *ringbuff;
+
+
+	/*
+	 * Private handle returned by kernel demux when
+	 * map_buffer is called in case external buffer
+	 * is used. NULL if buffer is allocated internally.
+	 */
+	void *priv_handle;
+};
+/*
  * TS packet reception
  */
 
@@ -95,10 +195,18 @@
  * Using this API, the client can set the filtering properties to start/stop
  * filtering TS packets on a particular TS feed.
  */
+struct dmx_ts_feed;
+
+typedef int (*dmx_ts_data_ready_cb)(
+		struct dmx_ts_feed *source,
+		struct dmx_data_ready *dmx_data_ready);
+
 struct dmx_ts_feed {
 	int is_filtering;
 	struct dmx_demux *parent;
+	struct data_buffer buffer;
 	void *priv;
+	struct dmx_decoder_buffers *decoder_buffers;
 	int (*set)(struct dmx_ts_feed *feed,
 		   u16 pid,
 		   int type,
@@ -107,6 +215,34 @@
 		   ktime_t timeout);
 	int (*start_filtering)(struct dmx_ts_feed *feed);
 	int (*stop_filtering)(struct dmx_ts_feed *feed);
+	int (*set_video_codec)(struct dmx_ts_feed *feed,
+				enum dmx_video_codec video_codec);
+	int (*set_idx_params)(struct dmx_ts_feed *feed,
+				struct dmx_indexing_params *idx_params);
+	int (*get_decoder_buff_status)(
+			struct dmx_ts_feed *feed,
+			struct dmx_buffer_status *dmx_buffer_status);
+	int (*reuse_decoder_buffer)(
+			struct dmx_ts_feed *feed,
+			int cookie);
+	int (*data_ready_cb)(struct dmx_ts_feed *feed,
+			dmx_ts_data_ready_cb callback);
+	int (*notify_data_read)(struct dmx_ts_feed *feed,
+			u32 bytes_num);
+	int (*set_tsp_out_format)(struct dmx_ts_feed *feed,
+				enum dmx_tsp_format_t tsp_format);
+	int (*set_secure_mode)(struct dmx_ts_feed *feed,
+				struct dmx_secure_mode *sec_mode);
+	int (*set_cipher_ops)(struct dmx_ts_feed *feed,
+				struct dmx_cipher_operations *cipher_ops);
+	int (*oob_command)(struct dmx_ts_feed *feed,
+			struct dmx_oob_command *cmd);
+	int (*ts_insertion_init)(struct dmx_ts_feed *feed);
+	int (*ts_insertion_terminate)(struct dmx_ts_feed *feed);
+	int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
+			char *data, size_t size);
+	int (*get_scrambling_bits)(struct dmx_ts_feed *feed, u8 *value);
+	int (*flush_buffer)(struct dmx_ts_feed *feed, size_t length);
 };
 
 /*
@@ -131,14 +267,21 @@
  * corresponding bits are compared. The filter only accepts sections that are
  * equal to filter_value in all the tested bit positions.
  */
+
+struct dmx_section_feed;
 struct dmx_section_filter {
 	u8 filter_value[DMX_MAX_FILTER_SIZE];
 	u8 filter_mask[DMX_MAX_FILTER_SIZE];
 	u8 filter_mode[DMX_MAX_FILTER_SIZE];
 	struct dmx_section_feed *parent; /* Back-pointer */
+	struct data_buffer buffer;
 	void *priv; /* Pointer to private data of the API client */
 };
 
+typedef int (*dmx_section_data_ready_cb)(
+		struct dmx_section_filter *source,
+		struct dmx_data_ready *dmx_data_ready);
+
 /**
  * struct dmx_section_feed - Structure that contains a section feed filter
  *
@@ -189,8 +332,24 @@
 			      struct dmx_section_filter *filter);
 	int (*start_filtering)(struct dmx_section_feed *feed);
 	int (*stop_filtering)(struct dmx_section_feed *feed);
+	int (*data_ready_cb)(struct dmx_section_feed *feed,
+			dmx_section_data_ready_cb callback);
+	int (*notify_data_read)(struct dmx_section_filter *filter,
+			u32 bytes_num);
+	int (*set_secure_mode)(struct dmx_section_feed *feed,
+				struct dmx_secure_mode *sec_mode);
+	int (*set_cipher_ops)(struct dmx_section_feed *feed,
+				struct dmx_cipher_operations *cipher_ops);
+	int (*oob_command)(struct dmx_section_feed *feed,
+				struct dmx_oob_command *cmd);
+	int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value);
+	int (*flush_buffer)(struct dmx_section_feed *feed, size_t length);
 };
 
+/*
+ * Callback functions
+ */
+
 /**
  * typedef dmx_ts_cb - DVB demux TS filter callback function prototype
  *
@@ -295,9 +454,19 @@
 			      size_t buffer2_len,
 			      struct dmx_section_filter *source);
 
-/*
- * DVB Front-End
- */
+typedef int (*dmx_ts_fullness) (
+				struct dmx_ts_feed *source,
+				int required_space,
+				int wait);
+
+typedef int (*dmx_section_fullness) (
+				struct dmx_section_filter *source,
+				int required_space,
+				int wait);
+
+/*--------------------------------------------------------------------------*/
+/* DVB Front-End */
+/*--------------------------------------------------------------------------*/
 
 /**
  * enum dmx_frontend_source - Used to identify the type of frontend
@@ -312,6 +481,13 @@
 enum dmx_frontend_source {
 	DMX_MEMORY_FE,
 	DMX_FRONTEND_0,
+	DMX_FRONTEND_1,
+	DMX_FRONTEND_2,
+	DMX_FRONTEND_3,
+	DMX_STREAM_0,    /* external stream input, e.g. LVDS */
+	DMX_STREAM_1,
+	DMX_STREAM_2,
+	DMX_STREAM_3
 };
 
 /**
@@ -345,14 +521,24 @@
  */
 enum dmx_demux_caps {
 	DMX_TS_FILTERING = 1,
+	DMX_PES_FILTERING = 2,
 	DMX_SECTION_FILTERING = 4,
 	DMX_MEMORY_BASED_FILTERING = 8,
+	DMX_CRC_CHECKING = 16,
+	DMX_TS_DESCRAMBLING = 32
 };
 
 /*
  * Demux resource type identifier.
  */
 
+/*
+ * DMX_FE_ENTRY(): Casts elements in the list of registered
+ * front-ends from the generic type struct list_head
+ * to the type * struct dmx_frontend.
+ *
+ */
+
 /**
  * DMX_FE_ENTRY - Casts elements in the list of registered
  *		  front-ends from the generic type struct list_head
@@ -557,6 +743,10 @@
 	enum dmx_demux_caps capabilities;
 	struct dmx_frontend *frontend;
 	void *priv;
+	struct data_buffer dvr_input; /* DVR input buffer */
+	int dvr_input_protected;
+	struct dentry *debugfs_demux_dir; /* debugfs dir */
+
 	int (*open)(struct dmx_demux *demux);
 	int (*close)(struct dmx_demux *demux);
 	int (*write)(struct dmx_demux *demux, const char __user *buf,
@@ -582,15 +772,31 @@
 
 	int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids);
 
-	/* private: */
+	int (*get_caps)(struct dmx_demux *demux, struct dmx_caps *caps);
 
-	/*
-	 * Only used at av7110, to read some data from firmware.
-	 * As this was never documented, we have no clue about what's
-	 * there, and its usage on other drivers aren't encouraged.
-	 */
+	int (*set_source)(struct dmx_demux *demux, const dmx_source_t *src);
+
+	int (*set_tsp_format)(struct dmx_demux *demux,
+				enum dmx_tsp_format_t tsp_format);
+
+	int (*set_playback_mode)(struct dmx_demux *demux,
+				 enum dmx_playback_mode_t mode,
+				 dmx_ts_fullness ts_fullness_callback,
+				 dmx_section_fullness sec_fullness_callback);
+
+	int (*write_cancel)(struct dmx_demux *demux);
+
 	int (*get_stc)(struct dmx_demux *demux, unsigned int num,
 		       u64 *stc, unsigned int *base);
+
+	int (*map_buffer)(struct dmx_demux *demux,
+			struct dmx_buffer *dmx_buffer,
+			void **priv_handle, void **mem);
+
+	int (*unmap_buffer)(struct dmx_demux *demux,
+			void *priv_handle);
+
+	int (*get_tsp_size)(struct dmx_demux *demux);
 };
 
 #endif /* #ifndef __DEMUX_H */
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index 7b67e1d..e868f92 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -28,15 +28,74 @@
 #include <linux/poll.h>
 #include <linux/ioctl.h>
 #include <linux/wait.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/compat.h>
+#include <linux/mm.h>
 #include "dmxdev.h"
 
-static int debug;
+static int overflow_auto_flush = 1;
+module_param(overflow_auto_flush, int, 0644);
+MODULE_PARM_DESC(overflow_auto_flush,
+	"Automatically flush buffer on overflow (default: on)");
 
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+#define DMX_DEFAULT_DECODER_BUFFER_SIZE (32768)
 
-#define dprintk	if (debug) printk
+static inline int dvb_dmxdev_verify_buffer_size(u32 size, u32 max_size,
+	u32 size_align)
+{
+	if (size_align)
+		return size <= max_size && !(size % size_align);
+	else
+		return size <= max_size;
+}
+
+static int dvb_filter_verify_buffer_size(struct dmxdev_filter *filter)
+{
+	struct dmx_caps caps;
+	size_t size = filter->buffer.size;
+
+	/*
+	 * For backward compatibility, if no demux capabilities can
+	 * be retrieved assume size is ok.
+	 * Decoder filter buffer size is verified when decoder buffer is set.
+	 */
+	if (filter->dev->demux->get_caps) {
+		filter->dev->demux->get_caps(filter->dev->demux, &caps);
+
+		if (filter->type == DMXDEV_TYPE_SEC)
+			return dvb_dmxdev_verify_buffer_size(
+				size,
+				caps.section.max_size,
+				caps.section.size_alignment);
+
+		if (filter->params.pes.output == DMX_OUT_TAP)
+			return dvb_dmxdev_verify_buffer_size(
+				size,
+				caps.pes.max_size,
+				caps.pes.size_alignment);
+
+		size = (filter->params.pes.output == DMX_OUT_TS_TAP) ?
+			filter->dev->dvr_buffer.size : size;
+
+		if (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP ||
+			filter->params.pes.output == DMX_OUT_TS_TAP) {
+			if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188)
+				return dvb_dmxdev_verify_buffer_size(
+					size,
+					caps.recording_188_tsp.max_size,
+					caps.recording_188_tsp.size_alignment);
+
+			return dvb_dmxdev_verify_buffer_size(
+					size,
+					caps.recording_192_tsp.max_size,
+					caps.recording_192_tsp.size_alignment);
+		}
+	}
+
+	return 1;
+}
 
 static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
 				   const u8 *src, size_t len)
@@ -50,16 +109,400 @@
 
 	free = dvb_ringbuffer_free(buf);
 	if (len > free) {
-		dprintk("dmxdev: buffer overflow\n");
+		pr_debug("dmxdev: buffer overflow\n");
 		return -EOVERFLOW;
 	}
 
 	return dvb_ringbuffer_write(buf, src, len);
 }
 
-static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
-				      int non_blocking, char __user *buf,
-				      size_t count, loff_t *ppos)
+static inline void dvb_dmxdev_notify_data_read(struct dmxdev_filter *filter,
+					int bytes_read)
+{
+	if (!filter)
+		return;
+
+	if (filter->type == DMXDEV_TYPE_SEC) {
+		if (filter->feed.sec.feed->notify_data_read)
+			filter->feed.sec.feed->notify_data_read(
+						filter->filter.sec,
+						bytes_read);
+	} else {
+		struct dmxdev_feed *feed;
+
+		/*
+		 * All feeds of same demux-handle share the same output
+		 * buffer, it is enough to notify on the buffer status
+		 * on one of the feeds
+		 */
+		feed = list_first_entry(&filter->feed.ts,
+					struct dmxdev_feed, next);
+
+		if (feed->ts->notify_data_read)
+			feed->ts->notify_data_read(
+						feed->ts,
+						bytes_read);
+	}
+}
+
+static inline u32 dvb_dmxdev_advance_event_idx(u32 index)
+{
+	index++;
+	if (index >= DMX_EVENT_QUEUE_SIZE)
+		index = 0;
+
+	return index;
+}
+
+static inline int dvb_dmxdev_events_is_full(struct dmxdev_events_queue *events)
+{
+	int new_write_index;
+
+	new_write_index = dvb_dmxdev_advance_event_idx(events->write_index);
+	if (new_write_index == events->read_index)
+		return 1;
+
+	return 0;
+
+}
+
+static inline void dvb_dmxdev_flush_events(struct dmxdev_events_queue *events)
+{
+	events->read_index = 0;
+	events->write_index = 0;
+	events->notified_index = 0;
+	events->bytes_read_no_event = 0;
+	events->current_event_data_size = 0;
+	events->wakeup_events_counter = 0;
+}
+
+static inline void dvb_dmxdev_flush_output(struct dvb_ringbuffer *buffer,
+					struct dmxdev_events_queue *events)
+{
+	dvb_dmxdev_flush_events(events);
+	dvb_ringbuffer_flush(buffer);
+}
+
+static int dvb_dmxdev_update_pes_event(struct dmx_filter_event *event,
+					int bytes_read)
+{
+	int start_delta;
+
+	if (event->params.pes.total_length <= bytes_read)
+		return event->params.pes.total_length;
+
+	/*
+	 * only part of the data relevant to this event was read.
+	 * Update the event's information to reflect the new state.
+	 */
+	event->params.pes.total_length -= bytes_read;
+
+	start_delta = event->params.pes.start_offset -
+		event->params.pes.base_offset;
+
+	if (bytes_read <= start_delta) {
+		event->params.pes.base_offset +=
+			bytes_read;
+	} else {
+		start_delta =
+			bytes_read - start_delta;
+
+		event->params.pes.start_offset += start_delta;
+		event->params.pes.actual_length -= start_delta;
+
+		event->params.pes.base_offset =
+			event->params.pes.start_offset;
+	}
+
+	return 0;
+}
+
+static int dvb_dmxdev_update_section_event(struct dmx_filter_event *event,
+					int bytes_read)
+{
+	int start_delta;
+
+	if (event->params.section.total_length <= bytes_read)
+		return event->params.section.total_length;
+
+	/*
+	 * only part of the data relevant to this event was read.
+	 * Update the event's information to reflect the new state.
+	 */
+
+	event->params.section.total_length -= bytes_read;
+
+	start_delta = event->params.section.start_offset -
+		event->params.section.base_offset;
+
+	if (bytes_read <= start_delta) {
+		event->params.section.base_offset +=
+			bytes_read;
+	} else {
+		start_delta =
+			bytes_read - start_delta;
+
+		event->params.section.start_offset += start_delta;
+		event->params.section.actual_length -= start_delta;
+
+		event->params.section.base_offset =
+			event->params.section.start_offset;
+	}
+
+	return 0;
+}
+
+static int dvb_dmxdev_update_rec_event(struct dmx_filter_event *event,
+					int bytes_read)
+{
+	if (event->params.recording_chunk.size <= bytes_read)
+		return event->params.recording_chunk.size;
+
+	/*
+	 * only part of the data relevant to this event was read.
+	 * Update the event's information to reflect the new state.
+	 */
+	event->params.recording_chunk.size -= bytes_read;
+	event->params.recording_chunk.offset += bytes_read;
+
+	return 0;
+}
+
+static int dvb_dmxdev_add_event(struct dmxdev_events_queue *events,
+					struct dmx_filter_event *event)
+{
+	int res;
+	int new_write_index;
+	int data_event;
+
+	/* Check if the event is disabled */
+	if (events->event_mask.disable_mask & event->type)
+		return 0;
+
+	/* Check if we are adding an event that user already read its data */
+	if (events->bytes_read_no_event) {
+		data_event = 1;
+
+		if (event->type == DMX_EVENT_NEW_PES)
+			res = dvb_dmxdev_update_pes_event(event,
+						events->bytes_read_no_event);
+		else if (event->type == DMX_EVENT_NEW_SECTION)
+			res = dvb_dmxdev_update_section_event(event,
+						events->bytes_read_no_event);
+		else if (event->type == DMX_EVENT_NEW_REC_CHUNK)
+			res = dvb_dmxdev_update_rec_event(event,
+						events->bytes_read_no_event);
+		else
+			data_event = 0;
+
+		if (data_event) {
+			if (res) {
+				/*
+				 * Data relevant to this event was fully
+				 * consumed already, discard event.
+				 */
+				events->bytes_read_no_event -= res;
+				return 0;
+			}
+			events->bytes_read_no_event = 0;
+		} else {
+			/*
+			 * data was read beyond the non-data event,
+			 * making it not relevant anymore
+			 */
+			return 0;
+		}
+	}
+
+	new_write_index = dvb_dmxdev_advance_event_idx(events->write_index);
+	if (new_write_index == events->read_index) {
+		pr_err("dmxdev: events overflow\n");
+		return -EOVERFLOW;
+	}
+
+	events->queue[events->write_index] = *event;
+	events->write_index = new_write_index;
+
+	if (!(events->event_mask.no_wakeup_mask & event->type))
+		events->wakeup_events_counter++;
+
+	return 0;
+}
+
+static int dvb_dmxdev_remove_event(struct dmxdev_events_queue *events,
+					struct dmx_filter_event *event)
+{
+	if (events->notified_index == events->write_index)
+		return -ENODATA;
+
+	*event = events->queue[events->notified_index];
+
+	events->notified_index =
+		dvb_dmxdev_advance_event_idx(events->notified_index);
+
+	if (!(events->event_mask.no_wakeup_mask & event->type))
+		events->wakeup_events_counter--;
+
+	return 0;
+}
+
+static int dvb_dmxdev_update_events(struct dmxdev_events_queue *events,
+					int bytes_read)
+{
+	struct dmx_filter_event *event;
+	int res;
+	int data_event;
+
+	/*
+	 * If data events are not enabled on this filter,
+	 * there's nothing to update.
+	 */
+	if (events->data_read_event_masked)
+		return 0;
+
+	/*
+	 * Go through all events that were notified and
+	 * remove them from the events queue if their respective
+	 * data was read.
+	 */
+	while ((events->read_index != events->notified_index) &&
+		   (bytes_read)) {
+		event = events->queue + events->read_index;
+
+		data_event = 1;
+
+		if (event->type == DMX_EVENT_NEW_PES)
+			res = dvb_dmxdev_update_pes_event(event, bytes_read);
+		else if (event->type == DMX_EVENT_NEW_SECTION)
+			res = dvb_dmxdev_update_section_event(event,
+								bytes_read);
+		else if (event->type == DMX_EVENT_NEW_REC_CHUNK)
+			res = dvb_dmxdev_update_rec_event(event, bytes_read);
+		else
+			data_event = 0;
+
+		if (data_event) {
+			if (res) {
+				/*
+				 * Data relevant to this event was
+				 * fully consumed, remove it from the queue.
+				 */
+				bytes_read -= res;
+				events->read_index =
+					dvb_dmxdev_advance_event_idx(
+						events->read_index);
+			} else {
+				bytes_read = 0;
+			}
+		} else {
+			/*
+			 * non-data event was already notified,
+			 * no need to keep it
+			 */
+			events->read_index = dvb_dmxdev_advance_event_idx(
+						events->read_index);
+		}
+	}
+
+	if (!bytes_read)
+		return 0;
+
+	/*
+	 * If we reached here it means:
+	 * bytes_read != 0
+	 * events->read_index == events->notified_index
+	 * Check if there are pending events in the queue
+	 * which the user didn't read while their relevant data
+	 * was read.
+	 */
+	while ((events->notified_index != events->write_index) &&
+		   (bytes_read)) {
+		event = events->queue + events->notified_index;
+
+		data_event = 1;
+
+		if (event->type == DMX_EVENT_NEW_PES)
+			res = dvb_dmxdev_update_pes_event(event, bytes_read);
+		else if (event->type == DMX_EVENT_NEW_SECTION)
+			res = dvb_dmxdev_update_section_event(event,
+								bytes_read);
+		else if (event->type == DMX_EVENT_NEW_REC_CHUNK)
+			res = dvb_dmxdev_update_rec_event(event, bytes_read);
+		else
+			data_event = 0;
+
+		if (data_event) {
+			if (res) {
+				/*
+				 * Data relevant to this event was
+				 * fully consumed, remove it from the queue.
+				 */
+				bytes_read -= res;
+				events->notified_index =
+					dvb_dmxdev_advance_event_idx(
+						events->notified_index);
+				if (!(events->event_mask.no_wakeup_mask &
+					event->type))
+					events->wakeup_events_counter--;
+			} else {
+				bytes_read = 0;
+			}
+		} else {
+			if (bytes_read)
+				/*
+				 * data was read beyond the non-data event,
+				 * making it not relevant anymore
+				 */
+				events->notified_index =
+					dvb_dmxdev_advance_event_idx(
+						events->notified_index);
+				if (!(events->event_mask.no_wakeup_mask &
+					event->type))
+					events->wakeup_events_counter--;
+		}
+
+		events->read_index = events->notified_index;
+	}
+
+	/*
+	 * Check if data was read without having a respective
+	 * event in the events-queue
+	 */
+	if (bytes_read)
+		events->bytes_read_no_event += bytes_read;
+
+	return 0;
+}
+
+static inline int dvb_dmxdev_check_data(struct dmxdev_filter *filter,
+			struct dvb_ringbuffer *src)
+{
+	int data_status_change;
+
+	if (filter)
+		if (mutex_lock_interruptible(&filter->mutex))
+			return -ERESTARTSYS;
+
+	if (!src->data ||
+		!dvb_ringbuffer_empty(src) ||
+		src->error ||
+		(filter &&
+		 (filter->state != DMXDEV_STATE_GO) &&
+		 (filter->state != DMXDEV_STATE_DONE)))
+		data_status_change = 1;
+	else
+		data_status_change = 0;
+
+	if (filter)
+		mutex_unlock(&filter->mutex);
+
+	return data_status_change;
+}
+
+static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_filter *filter,
+					struct dvb_ringbuffer *src,
+					int non_blocking, char __user *buf,
+					size_t count, loff_t *ppos)
 {
 	size_t todo;
 	ssize_t avail;
@@ -70,7 +513,7 @@
 
 	if (src->error) {
 		ret = src->error;
-		dvb_ringbuffer_flush(src);
+		src->error = 0;
 		return ret;
 	}
 
@@ -80,15 +523,35 @@
 			break;
 		}
 
+		if (filter) {
+			if ((filter->state == DMXDEV_STATE_DONE) &&
+				dvb_ringbuffer_empty(src))
+				break;
+
+			mutex_unlock(&filter->mutex);
+		}
+
 		ret = wait_event_interruptible(src->queue,
-					       !dvb_ringbuffer_empty(src) ||
-					       (src->error != 0));
+				dvb_dmxdev_check_data(filter, src));
+
+		if (filter) {
+			if (mutex_lock_interruptible(&filter->mutex))
+				return -ERESTARTSYS;
+
+			if ((filter->state != DMXDEV_STATE_GO) &&
+				(filter->state != DMXDEV_STATE_DONE))
+				return -ENODEV;
+		}
+
 		if (ret < 0)
 			break;
 
+		if (!src->data)
+			return 0;
+
 		if (src->error) {
 			ret = src->error;
-			dvb_ringbuffer_flush(src);
+			src->error = 0;
 			break;
 		}
 
@@ -103,6 +566,9 @@
 		buf += ret;
 	}
 
+	if (count - todo) /* some data was read? */
+		wake_up_all(&src->queue);
+
 	return (count - todo) ? (count - todo) : ret;
 }
 
@@ -120,13 +586,238 @@
 	return NULL;
 }
 
+static void dvb_dvr_oob_cmd(struct dmxdev *dmxdev, struct dmx_oob_command *cmd)
+{
+	int i;
+	struct dmxdev_filter *filter;
+	struct dmxdev_feed *feed;
+
+	for (i = 0; i < dmxdev->filternum; i++) {
+		filter = &dmxdev->filter[i];
+		if (!filter || filter->state != DMXDEV_STATE_GO)
+			continue;
+
+		switch (filter->type) {
+		case DMXDEV_TYPE_SEC:
+			filter->feed.sec.feed->oob_command(
+				filter->feed.sec.feed, cmd);
+			break;
+		case DMXDEV_TYPE_PES:
+			feed = list_first_entry(&filter->feed.ts,
+						struct dmxdev_feed, next);
+			feed->ts->oob_command(feed->ts, cmd);
+			break;
+		case DMXDEV_TYPE_NONE:
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static int dvb_dvr_feed_cmd(struct dmxdev *dmxdev, struct dvr_command *dvr_cmd)
+{
+	int ret = 0;
+	size_t todo;
+	int bytes_written = 0;
+	size_t split;
+	size_t tsp_size;
+	u8 *data_start;
+	struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
+
+	todo = dvr_cmd->cmd.data_feed_count;
+
+	if (dmxdev->demux->get_tsp_size)
+		tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux);
+	else
+		tsp_size = 188;
+
+	while (todo >= tsp_size) {
+		/* wait for input */
+		ret = wait_event_interruptible(
+			src->queue,
+			(dvb_ringbuffer_avail(src) >= tsp_size) ||
+			dmxdev->dvr_in_exit || src->error);
+
+		if (ret < 0)
+			break;
+
+		spin_lock(&dmxdev->dvr_in_lock);
+
+		if (dmxdev->exit || dmxdev->dvr_in_exit) {
+			spin_unlock(&dmxdev->dvr_in_lock);
+			ret = -ENODEV;
+			break;
+		}
+
+		if (src->error) {
+			spin_unlock(&dmxdev->dvr_in_lock);
+			wake_up_all(&src->queue);
+			ret = -EINVAL;
+			break;
+		}
+
+		dmxdev->dvr_processing_input = 1;
+
+		split = (src->pread + todo > src->size) ?
+			src->size - src->pread : 0;
+
+		/*
+		 * In DVR PULL mode, write might block.
+		 * Lock on DVR buffer is released before calling to
+		 * write, if DVR was released meanwhile, dvr_in_exit is
+		 * prompted. Lock is acquired when updating the read pointer
+		 * again to preserve read/write pointers consistency.
+		 *
+		 * In protected input mode, DVR input buffer is not mapped
+		 * to kernel memory. Underlying demux implementation
+		 * should trigger HW to read from DVR input buffer
+		 * based on current read offset.
+		 */
+		if (split > 0) {
+			data_start = (dmxdev->demux->dvr_input_protected) ?
+						NULL : (src->data + src->pread);
+
+			spin_unlock(&dmxdev->dvr_in_lock);
+			ret = dmxdev->demux->write(dmxdev->demux,
+						data_start,
+						split);
+
+			if (ret < 0) {
+				pr_err("dmxdev: dvr write error %d\n", ret);
+				continue;
+			}
+
+			if (dmxdev->dvr_in_exit) {
+				ret = -ENODEV;
+				break;
+			}
+
+			spin_lock(&dmxdev->dvr_in_lock);
+
+			todo -= ret;
+			bytes_written += ret;
+			DVB_RINGBUFFER_SKIP(src, ret);
+			if (ret < split) {
+				dmxdev->dvr_processing_input = 0;
+				spin_unlock(&dmxdev->dvr_in_lock);
+				wake_up_all(&src->queue);
+				continue;
+			}
+		}
+
+		data_start = (dmxdev->demux->dvr_input_protected) ?
+			NULL : (src->data + src->pread);
+
+		spin_unlock(&dmxdev->dvr_in_lock);
+		ret = dmxdev->demux->write(dmxdev->demux,
+			data_start, todo);
+
+		if (ret < 0) {
+			pr_err("dmxdev: dvr write error %d\n", ret);
+			continue;
+		}
+
+		if (dmxdev->dvr_in_exit) {
+			ret = -ENODEV;
+			break;
+		}
+
+		spin_lock(&dmxdev->dvr_in_lock);
+
+		todo -= ret;
+		bytes_written += ret;
+		DVB_RINGBUFFER_SKIP(src, ret);
+		dmxdev->dvr_processing_input = 0;
+		spin_unlock(&dmxdev->dvr_in_lock);
+
+		wake_up_all(&src->queue);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return bytes_written;
+}
+
+static int dvr_input_thread_entry(void *arg)
+{
+	struct dmxdev *dmxdev = arg;
+	struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer;
+	struct dvr_command dvr_cmd;
+	int leftover = 0;
+	int ret;
+
+	while (1) {
+		/* wait for input */
+		ret = wait_event_interruptible(
+			cmdbuf->queue,
+			(!cmdbuf->data) ||
+			(dvb_ringbuffer_avail(cmdbuf) >= sizeof(dvr_cmd)) ||
+			(dmxdev->dvr_in_exit));
+
+		if (ret < 0)
+			break;
+
+		spin_lock(&dmxdev->dvr_in_lock);
+
+		if (!cmdbuf->data || dmxdev->exit || dmxdev->dvr_in_exit) {
+			spin_unlock(&dmxdev->dvr_in_lock);
+			break;
+		}
+
+		dvb_ringbuffer_read(cmdbuf, (u8 *)&dvr_cmd, sizeof(dvr_cmd));
+
+		spin_unlock(&dmxdev->dvr_in_lock);
+
+		if (dvr_cmd.type == DVR_DATA_FEED_CMD) {
+			dvr_cmd.cmd.data_feed_count += leftover;
+
+			ret = dvb_dvr_feed_cmd(dmxdev, &dvr_cmd);
+			if (ret < 0) {
+				pr_debug("%s: DVR data feed failed, ret=%d\n",
+					__func__, ret);
+				continue;
+			}
+
+			leftover = dvr_cmd.cmd.data_feed_count - ret;
+		} else {
+			/*
+			 * For EOS, try to process leftover data in the input
+			 * buffer.
+			 */
+			if (dvr_cmd.cmd.oobcmd.type == DMX_OOB_CMD_EOS) {
+				struct dvr_command feed_cmd;
+
+				feed_cmd.type = DVR_DATA_FEED_CMD;
+				feed_cmd.cmd.data_feed_count =
+					dvb_ringbuffer_avail(
+						&dmxdev->dvr_input_buffer);
+				dvb_dvr_feed_cmd(dmxdev, &feed_cmd);
+			}
+
+			dvb_dvr_oob_cmd(dmxdev, &dvr_cmd.cmd.oobcmd);
+		}
+	}
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (!kthread_should_stop()) {
+		schedule();
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+	set_current_state(TASK_RUNNING);
+
+	return 0;
+}
+
 static int dvb_dvr_open(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 	struct dmx_frontend *front;
+	void *mem;
 
-	dprintk("function : %s\n", __func__);
+	pr_debug("function : %s(%X)\n", __func__, (file->f_flags & O_ACCMODE));
 
 	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
@@ -144,21 +835,28 @@
 	}
 
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		void *mem;
 		if (!dvbdev->readers) {
 			mutex_unlock(&dmxdev->mutex);
 			return -EBUSY;
 		}
-		mem = vmalloc(DVR_BUFFER_SIZE);
+		mem = vmalloc_user(DVR_BUFFER_SIZE);
 		if (!mem) {
 			mutex_unlock(&dmxdev->mutex);
 			return -ENOMEM;
 		}
 		dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
-		dvbdev->readers--;
-	}
+		dvb_dmxdev_flush_events(&dmxdev->dvr_output_events);
+		dmxdev->dvr_output_events.event_mask.disable_mask = 0;
+		dmxdev->dvr_output_events.event_mask.no_wakeup_mask = 0;
+		dmxdev->dvr_output_events.event_mask.wakeup_threshold = 1;
+		dmxdev->dvr_feeds_count = 0;
+		dmxdev->dvr_buffer_mode = DMX_BUFFER_MODE_INTERNAL;
+		dmxdev->dvr_priv_buff_handle = NULL;
 
-	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+		dvbdev->readers--;
+	} else if (!dvbdev->writers) {
+		dmxdev->dvr_in_exit = 0;
+		dmxdev->dvr_processing_input = 0;
 		dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
 
 		if (!dmxdev->demux->write) {
@@ -172,9 +870,51 @@
 			mutex_unlock(&dmxdev->mutex);
 			return -EINVAL;
 		}
+
+		mem = vmalloc_user(DVR_BUFFER_SIZE);
+		if (!mem) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ENOMEM;
+		}
+
 		dmxdev->demux->disconnect_frontend(dmxdev->demux);
 		dmxdev->demux->connect_frontend(dmxdev->demux, front);
+		dmxdev->dvr_input_buffer_mode = DMX_BUFFER_MODE_INTERNAL;
+
+		dvb_ringbuffer_init(&dmxdev->dvr_input_buffer,
+							mem,
+							DVR_BUFFER_SIZE);
+
+		dmxdev->demux->dvr_input.priv_handle = NULL;
+		dmxdev->demux->dvr_input.ringbuff = &dmxdev->dvr_input_buffer;
+		dmxdev->demux->dvr_input_protected = 0;
+		mem = vmalloc(DVR_CMDS_BUFFER_SIZE);
+		if (!mem) {
+			vfree(dmxdev->dvr_input_buffer.data);
+			dmxdev->dvr_input_buffer.data = NULL;
+			mutex_unlock(&dmxdev->mutex);
+			return -ENOMEM;
+		}
+		dvb_ringbuffer_init(&dmxdev->dvr_cmd_buffer, mem,
+			DVR_CMDS_BUFFER_SIZE);
+		dvbdev->writers--;
+
+		dmxdev->dvr_input_thread =
+			kthread_run(
+				dvr_input_thread_entry,
+				(void *)dmxdev,
+				"dvr_input");
+
+		if (IS_ERR(dmxdev->dvr_input_thread)) {
+			vfree(dmxdev->dvr_input_buffer.data);
+			vfree(dmxdev->dvr_cmd_buffer.data);
+			dmxdev->dvr_input_buffer.data = NULL;
+			dmxdev->dvr_cmd_buffer.data = NULL;
+			mutex_unlock(&dmxdev->mutex);
+			return -ENOMEM;
+		}
 	}
+
 	dvbdev->users++;
 	mutex_unlock(&dmxdev->mutex);
 	return 0;
@@ -187,11 +927,6 @@
 
 	mutex_lock(&dmxdev->mutex);
 
-	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
-		dmxdev->demux->disconnect_frontend(dmxdev->demux);
-		dmxdev->demux->connect_frontend(dmxdev->demux,
-						dmxdev->dvr_orig_fe);
-	}
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
 		dvbdev->readers++;
 		if (dmxdev->dvr_buffer.data) {
@@ -200,12 +935,100 @@
 			spin_lock_irq(&dmxdev->lock);
 			dmxdev->dvr_buffer.data = NULL;
 			spin_unlock_irq(&dmxdev->lock);
+			wake_up_all(&dmxdev->dvr_buffer.queue);
+
+			if (dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_INTERNAL)
+				vfree(mem);
+		}
+
+		if ((dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_EXTERNAL) &&
+			dmxdev->dvr_priv_buff_handle) {
+			dmxdev->demux->unmap_buffer(dmxdev->demux,
+					dmxdev->dvr_priv_buff_handle);
+			dmxdev->dvr_priv_buff_handle = NULL;
+		}
+	} else {
+		int i;
+
+		spin_lock(&dmxdev->dvr_in_lock);
+		dmxdev->dvr_in_exit = 1;
+		spin_unlock(&dmxdev->dvr_in_lock);
+
+		wake_up_all(&dmxdev->dvr_cmd_buffer.queue);
+
+		/*
+		 * There might be dmx filters reading now from DVR
+		 * device, in PULL mode, they might be also stalled
+		 * on output, signal to them that DVR is exiting.
+		 */
+		if (dmxdev->playback_mode == DMX_PB_MODE_PULL) {
+			wake_up_all(&dmxdev->dvr_buffer.queue);
+
+			for (i = 0; i < dmxdev->filternum; i++)
+				if (dmxdev->filter[i].state == DMXDEV_STATE_GO)
+					wake_up_all(
+					&dmxdev->filter[i].buffer.queue);
+		}
+
+		/* notify kernel demux that we are canceling */
+		if (dmxdev->demux->write_cancel)
+			dmxdev->demux->write_cancel(dmxdev->demux);
+
+		/*
+		 * Now stop dvr-input thread so that no one
+		 * would process data from dvr input buffer any more
+		 * before it gets freed.
+		 */
+		kthread_stop(dmxdev->dvr_input_thread);
+
+		dvbdev->writers++;
+		dmxdev->demux->disconnect_frontend(dmxdev->demux);
+		dmxdev->demux->connect_frontend(dmxdev->demux,
+						dmxdev->dvr_orig_fe);
+
+		if (dmxdev->dvr_input_buffer.data) {
+			void *mem = dmxdev->dvr_input_buffer.data;
+			/*
+			 * Ensure all the operations on the DVR input buffer
+			 * are completed before it gets freed.
+			 */
+			mb();
+			spin_lock_irq(&dmxdev->dvr_in_lock);
+			dmxdev->dvr_input_buffer.data = NULL;
+			spin_unlock_irq(&dmxdev->dvr_in_lock);
+
+			if (dmxdev->dvr_input_buffer_mode ==
+				DMX_BUFFER_MODE_INTERNAL)
+				vfree(mem);
+		}
+
+		if ((dmxdev->dvr_input_buffer_mode ==
+			DMX_BUFFER_MODE_EXTERNAL) &&
+			(dmxdev->demux->dvr_input.priv_handle)) {
+			if (!dmxdev->demux->dvr_input_protected)
+				dmxdev->demux->unmap_buffer(dmxdev->demux,
+					dmxdev->demux->dvr_input.priv_handle);
+			dmxdev->demux->dvr_input.priv_handle = NULL;
+		}
+
+		if (dmxdev->dvr_cmd_buffer.data) {
+			void *mem = dmxdev->dvr_cmd_buffer.data;
+			/*
+			 * Ensure all the operations on the DVR command buffer
+			 * are completed before it gets freed.
+			 */
+			mb();
+			spin_lock_irq(&dmxdev->dvr_in_lock);
+			dmxdev->dvr_cmd_buffer.data = NULL;
+			spin_unlock_irq(&dmxdev->dvr_in_lock);
 			vfree(mem);
 		}
 	}
 	/* TODO */
 	dvbdev->users--;
 	if (dvbdev->users == 1 && dmxdev->exit == 1) {
+		fops_put(file->f_op);
+		file->f_op = NULL;
 		mutex_unlock(&dmxdev->mutex);
 		wake_up(&dvbdev->wait_queue);
 	} else
@@ -214,17 +1037,21 @@
 	return 0;
 }
 
-static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
-			     size_t count, loff_t *ppos)
+
+static int dvb_dvr_mmap(struct file *filp, struct vm_area_struct *vma)
 {
-	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_device *dvbdev = filp->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
+	struct dvb_ringbuffer *buffer;
+	enum dmx_buffer_mode buffer_mode;
+	int vma_size;
+	int buffer_size;
 	int ret;
 
-	if (!dmxdev->demux->write)
-		return -EOPNOTSUPP;
-	if ((file->f_flags & O_ACCMODE) != O_WRONLY)
+	if (((filp->f_flags & O_ACCMODE) == O_RDONLY) &&
+		(vma->vm_flags & VM_WRITE))
 		return -EINVAL;
+
 	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
@@ -232,58 +1059,693 @@
 		mutex_unlock(&dmxdev->mutex);
 		return -ENODEV;
 	}
-	ret = dmxdev->demux->write(dmxdev->demux, buf, count);
+
+	if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
+		buffer = &dmxdev->dvr_buffer;
+		buffer_mode = dmxdev->dvr_buffer_mode;
+	} else {
+		buffer = &dmxdev->dvr_input_buffer;
+		buffer_mode = dmxdev->dvr_input_buffer_mode;
+	}
+
+	if (buffer_mode == DMX_BUFFER_MODE_EXTERNAL) {
+		mutex_unlock(&dmxdev->mutex);
+		return -EINVAL;
+	}
+
+	vma_size = vma->vm_end - vma->vm_start;
+
+	/* Make sure requested mapping is not larger than buffer size */
+	buffer_size = buffer->size + (PAGE_SIZE-1);
+	buffer_size = buffer_size & ~(PAGE_SIZE-1);
+
+	if (vma_size != buffer_size) {
+		mutex_unlock(&dmxdev->mutex);
+		return -EINVAL;
+	}
+
+	ret = remap_vmalloc_range(vma, buffer->data, 0);
+	if (ret) {
+		mutex_unlock(&dmxdev->mutex);
+		return ret;
+	}
+
+	vma->vm_flags |= VM_DONTDUMP;
+	vma->vm_flags |= VM_DONTEXPAND;
+
 	mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
+static void dvb_dvr_queue_data_feed(struct dmxdev *dmxdev, size_t count)
+{
+	struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer;
+	struct dvr_command *dvr_cmd;
+	int last_dvr_cmd;
+
+	spin_lock(&dmxdev->dvr_in_lock);
+
+	/* Peek at the last DVR command queued, try to coalesce FEED commands */
+	if (dvb_ringbuffer_avail(cmdbuf) >= sizeof(*dvr_cmd)) {
+		last_dvr_cmd = cmdbuf->pwrite - sizeof(*dvr_cmd);
+		if (last_dvr_cmd < 0)
+			last_dvr_cmd += cmdbuf->size;
+
+		dvr_cmd = (struct dvr_command *)&cmdbuf->data[last_dvr_cmd];
+		if (dvr_cmd->type == DVR_DATA_FEED_CMD) {
+			dvr_cmd->cmd.data_feed_count += count;
+			spin_unlock(&dmxdev->dvr_in_lock);
+			return;
+		}
+	}
+
+	/*
+	 * We assume command buffer is large enough so that overflow should not
+	 * happen. Overflow to the command buffer means data previously written
+	 * to the input buffer is 'orphan' - does not have a matching FEED
+	 * command. Issue a warning if this ever happens.
+	 * Orphan data might still be processed if EOS is issued.
+	 */
+	if (dvb_ringbuffer_free(cmdbuf) < sizeof(*dvr_cmd)) {
+		pr_err("%s: DVR command buffer overflow\n", __func__);
+		spin_unlock(&dmxdev->dvr_in_lock);
+		return;
+	}
+
+	dvr_cmd = (struct dvr_command *)&cmdbuf->data[cmdbuf->pwrite];
+	dvr_cmd->type = DVR_DATA_FEED_CMD;
+	dvr_cmd->cmd.data_feed_count = count;
+	DVB_RINGBUFFER_PUSH(cmdbuf, sizeof(*dvr_cmd));
+	spin_unlock(&dmxdev->dvr_in_lock);
+
+	wake_up_all(&cmdbuf->queue);
+}
+
+static int dvb_dvr_external_input_only(struct dmxdev *dmxdev)
+{
+	struct dmx_caps caps;
+	int is_external_only;
+	int flags;
+	size_t tsp_size;
+
+	if (dmxdev->demux->get_tsp_size)
+		tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux);
+	else
+		tsp_size = 188;
+
+	/*
+	 * For backward compatibility, default assumes that
+	 * external only buffers are not supported.
+	 */
+	flags = 0;
+	if (dmxdev->demux->get_caps) {
+		dmxdev->demux->get_caps(dmxdev->demux, &caps);
+
+		if (tsp_size == 188)
+			flags = caps.playback_188_tsp.flags;
+		else
+			flags = caps.playback_192_tsp.flags;
+	}
+
+	if (!(flags & DMX_BUFFER_INTERNAL_SUPPORT) &&
+		(flags & DMX_BUFFER_EXTERNAL_SUPPORT))
+		is_external_only = 1;
+	else
+		is_external_only = 0;
+
+	return is_external_only;
+}
+
+static int dvb_dvr_verify_buffer_size(struct dmxdev *dmxdev,
+	unsigned int f_flags,
+	unsigned long size)
+{
+	struct dmx_caps caps;
+	int tsp_size;
+
+	if (!dmxdev->demux->get_caps)
+		return 1;
+
+	if (dmxdev->demux->get_tsp_size)
+		tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux);
+	else
+		tsp_size = 188;
+
+	dmxdev->demux->get_caps(dmxdev->demux, &caps);
+	if ((f_flags & O_ACCMODE) == O_RDONLY)
+		return (tsp_size == 188 && dvb_dmxdev_verify_buffer_size(size,
+				caps.recording_188_tsp.max_size,
+				caps.recording_188_tsp.size_alignment)) ||
+			(tsp_size == 192 && dvb_dmxdev_verify_buffer_size(size,
+				caps.recording_192_tsp.max_size,
+				caps.recording_192_tsp.size_alignment));
+
+	return (tsp_size == 188 && dvb_dmxdev_verify_buffer_size(size,
+		caps.playback_188_tsp.max_size,
+		caps.playback_188_tsp.size_alignment)) ||
+		(tsp_size == 192 && dvb_dmxdev_verify_buffer_size(size,
+			caps.playback_192_tsp.max_size,
+			caps.playback_192_tsp.size_alignment));
+}
+
+static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
+	struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
+	struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer;
+	int ret;
+	size_t todo;
+	ssize_t free_space;
+
+	if (!dmxdev->demux->write)
+		return -EOPNOTSUPP;
+
+	if (!dvb_dvr_verify_buffer_size(dmxdev, file->f_flags, src->size) ||
+		((file->f_flags & O_ACCMODE) == O_RDONLY) ||
+		!src->data || !cmdbuf->data ||
+		(dvb_dvr_external_input_only(dmxdev) &&
+		 (dmxdev->dvr_input_buffer_mode == DMX_BUFFER_MODE_INTERNAL)))
+		return -EINVAL;
+
+	if ((file->f_flags & O_NONBLOCK) &&
+		(dvb_ringbuffer_free(src) == 0))
+		return -EWOULDBLOCK;
+
+	ret = 0;
+	for (todo = count; todo > 0; todo -= ret) {
+		ret = wait_event_interruptible(src->queue,
+			(dvb_ringbuffer_free(src)) ||
+			!src->data || !cmdbuf->data ||
+			(src->error != 0) || dmxdev->dvr_in_exit);
+
+		if (ret < 0)
+			return ret;
+
+		if (mutex_lock_interruptible(&dmxdev->mutex))
+			return -ERESTARTSYS;
+
+		if ((!src->data) || (!cmdbuf->data)) {
+			mutex_unlock(&dmxdev->mutex);
+			return 0;
+		}
+
+		if (dmxdev->exit || dmxdev->dvr_in_exit) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ENODEV;
+		}
+
+		if (src->error) {
+			ret = src->error;
+			dvb_ringbuffer_flush(src);
+			mutex_unlock(&dmxdev->mutex);
+			wake_up_all(&src->queue);
+			return ret;
+		}
+
+		free_space = dvb_ringbuffer_free(src);
+
+		if (free_space > todo)
+			free_space = todo;
+
+		ret = dvb_ringbuffer_write_user(src, buf, free_space);
+
+		if (ret < 0) {
+			mutex_unlock(&dmxdev->mutex);
+			return ret;
+		}
+
+		buf += ret;
+
+		dvb_dvr_queue_data_feed(dmxdev, ret);
+
+		mutex_unlock(&dmxdev->mutex);
+	}
+
+	return (count - todo) ? (count - todo) : ret;
+}
+
+static int dvb_dmxdev_flush_data(struct dmxdev_filter *filter, size_t length)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	struct dvb_ringbuffer *buffer = &filter->buffer;
+	struct dmxdev_events_queue *events = &filter->events;
+
+	if (filter->type == DMXDEV_TYPE_PES &&
+		filter->params.pes.output == DMX_OUT_TS_TAP) {
+		buffer = &filter->dev->dvr_buffer;
+		events = &filter->dev->dvr_output_events;
+	}
+
+	/*
+	 * Drop 'length' pending data bytes from the ringbuffer and update
+	 * event queue accordingly, similarly to dvb_dmxdev_release_data().
+	 */
+	spin_lock_irqsave(&filter->dev->lock, flags);
+	DVB_RINGBUFFER_SKIP(buffer, length);
+	buffer->error = 0;
+	dvb_dmxdev_flush_events(events);
+	events->current_event_start_offset = buffer->pwrite;
+	spin_unlock_irqrestore(&filter->dev->lock, flags);
+
+	if (filter->type == DMXDEV_TYPE_PES) {
+		struct dmxdev_feed *feed;
+
+		feed = list_first_entry(&filter->feed.ts,
+			struct dmxdev_feed, next);
+
+		if (feed->ts->flush_buffer)
+			return feed->ts->flush_buffer(feed->ts, length);
+	} else if (filter->type == DMXDEV_TYPE_SEC &&
+		filter->feed.sec.feed->flush_buffer) {
+		return filter->feed.sec.feed->flush_buffer(
+			filter->feed.sec.feed, length);
+	}
+
+	return ret;
+}
+
+static inline void dvb_dmxdev_auto_flush_buffer(struct dmxdev_filter *filter,
+	struct dvb_ringbuffer *buf)
+{
+	size_t flush_len;
+
+	/*
+	 * When buffer overflowed, demux-dev marked the buffer in
+	 * error state. If auto-flush is enabled discard current
+	 * pending data in buffer.
+	 */
+	if (overflow_auto_flush) {
+		flush_len = dvb_ringbuffer_avail(buf);
+		dvb_dmxdev_flush_data(filter, flush_len);
+	}
+}
+
 static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
 			    loff_t *ppos)
 {
+	ssize_t res;
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
+	unsigned long flags;
 
 	if (dmxdev->exit)
 		return -ENODEV;
 
-	return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
-				      file->f_flags & O_NONBLOCK,
-				      buf, count, ppos);
+	if (!dvb_dvr_verify_buffer_size(dmxdev, file->f_flags,
+		dmxdev->dvr_buffer.size))
+		return -EINVAL;
+
+	res = dvb_dmxdev_buffer_read(NULL, &dmxdev->dvr_buffer,
+				file->f_flags & O_NONBLOCK,
+				buf, count, ppos);
+
+	if (res > 0) {
+		dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, res);
+		spin_lock_irqsave(&dmxdev->lock, flags);
+		dvb_dmxdev_update_events(&dmxdev->dvr_output_events, res);
+		spin_unlock_irqrestore(&dmxdev->lock, flags);
+
+		/*
+		 * in PULL mode, we might be stalling on
+		 * event queue, so need to wake-up waiters
+		 */
+		if (dmxdev->playback_mode == DMX_PB_MODE_PULL)
+			wake_up_all(&dmxdev->dvr_buffer.queue);
+	} else if (res == -EOVERFLOW) {
+		dvb_dmxdev_auto_flush_buffer(dmxdev->dvr_feed,
+			&dmxdev->dvr_buffer);
+	}
+
+	return res;
+}
+
+/*
+ * dvb_dvr_push_oob_cmd
+ *
+ * Note: this function assume dmxdev->mutex was taken, so command buffer cannot
+ * be released during its operation.
+ */
+static int dvb_dvr_push_oob_cmd(struct dmxdev *dmxdev, unsigned int f_flags,
+		struct dmx_oob_command *cmd)
+{
+	struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer;
+	struct dvr_command *dvr_cmd;
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY ||
+		dmxdev->source < DMX_SOURCE_DVR0)
+		return -EPERM;
+
+	if (dvb_ringbuffer_free(cmdbuf) < sizeof(*dvr_cmd))
+		return -ENOMEM;
+
+	dvr_cmd = (struct dvr_command *)&cmdbuf->data[cmdbuf->pwrite];
+	dvr_cmd->type = DVR_OOB_CMD;
+	dvr_cmd->cmd.oobcmd = *cmd;
+	DVB_RINGBUFFER_PUSH(cmdbuf, sizeof(*dvr_cmd));
+	wake_up_all(&cmdbuf->queue);
+
+	return 0;
+}
+
+static int dvb_dvr_flush_buffer(struct dmxdev *dmxdev, unsigned int f_flags)
+{
+	size_t flush_len;
+	int ret;
+
+	if ((f_flags & O_ACCMODE) != O_RDONLY)
+		return -EINVAL;
+
+	flush_len = dvb_ringbuffer_avail(&dmxdev->dvr_buffer);
+	ret = dvb_dmxdev_flush_data(dmxdev->dvr_feed, flush_len);
+
+	return ret;
 }
 
 static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
-				      unsigned long size)
+						unsigned int f_flags,
+						unsigned long size)
 {
-	struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
+	struct dvb_ringbuffer *buf;
 	void *newmem;
 	void *oldmem;
+	spinlock_t *lock;
+	enum dmx_buffer_mode buffer_mode;
 
-	dprintk("function : %s\n", __func__);
+	pr_debug("function : %s\n", __func__);
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY) {
+		buf = &dmxdev->dvr_buffer;
+		lock = &dmxdev->lock;
+		buffer_mode = dmxdev->dvr_buffer_mode;
+	} else {
+		buf = &dmxdev->dvr_input_buffer;
+		lock = &dmxdev->dvr_in_lock;
+		buffer_mode = dmxdev->dvr_input_buffer_mode;
+	}
 
 	if (buf->size == size)
 		return 0;
-	if (!size)
+	if (!size || (buffer_mode == DMX_BUFFER_MODE_EXTERNAL))
 		return -EINVAL;
 
-	newmem = vmalloc(size);
+	newmem = vmalloc_user(size);
 	if (!newmem)
 		return -ENOMEM;
 
 	oldmem = buf->data;
 
-	spin_lock_irq(&dmxdev->lock);
+	spin_lock_irq(lock);
+
+	if (((f_flags & O_ACCMODE) != O_RDONLY) &&
+		(dmxdev->dvr_processing_input)) {
+		spin_unlock_irq(lock);
+		vfree(oldmem);
+		return -EBUSY;
+	}
+
 	buf->data = newmem;
 	buf->size = size;
 
 	/* reset and not flush in case the buffer shrinks */
 	dvb_ringbuffer_reset(buf);
-	spin_unlock_irq(&dmxdev->lock);
+
+	spin_unlock_irq(lock);
 
 	vfree(oldmem);
 
 	return 0;
 }
 
+static int dvb_dvr_set_buffer_mode(struct dmxdev *dmxdev,
+			unsigned int f_flags, enum dmx_buffer_mode mode)
+{
+	struct dvb_ringbuffer *buf;
+	spinlock_t *lock;
+	enum dmx_buffer_mode *buffer_mode;
+	void **buff_handle;
+	void *oldmem;
+	int *is_protected;
+
+	if ((mode != DMX_BUFFER_MODE_INTERNAL) &&
+		(mode != DMX_BUFFER_MODE_EXTERNAL))
+		return -EINVAL;
+
+	if ((mode == DMX_BUFFER_MODE_EXTERNAL) &&
+		(!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer))
+		return -EINVAL;
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY) {
+		buf = &dmxdev->dvr_buffer;
+		lock = &dmxdev->lock;
+		buffer_mode = &dmxdev->dvr_buffer_mode;
+		buff_handle = &dmxdev->dvr_priv_buff_handle;
+		is_protected = NULL;
+	} else {
+		buf = &dmxdev->dvr_input_buffer;
+		lock = &dmxdev->dvr_in_lock;
+		buffer_mode = &dmxdev->dvr_input_buffer_mode;
+		buff_handle = &dmxdev->demux->dvr_input.priv_handle;
+		is_protected = &dmxdev->demux->dvr_input_protected;
+	}
+
+	if (mode == *buffer_mode)
+		return 0;
+
+	oldmem = buf->data;
+	spin_lock_irq(lock);
+	buf->data = NULL;
+	spin_unlock_irq(lock);
+
+	*buffer_mode = mode;
+
+	if (mode == DMX_BUFFER_MODE_INTERNAL) {
+		/* switched from external to internal */
+		if (*buff_handle) {
+			dmxdev->demux->unmap_buffer(dmxdev->demux,
+				*buff_handle);
+			*buff_handle = NULL;
+		}
+
+		if (is_protected)
+			*is_protected = 0;
+
+		/* set default internal buffer */
+		dvb_dvr_set_buffer_size(dmxdev, f_flags, DVR_BUFFER_SIZE);
+	} else if (oldmem) {
+		/* switched from internal to external */
+		vfree(oldmem);
+	}
+
+	return 0;
+}
+
+static int dvb_dvr_set_buffer(struct dmxdev *dmxdev,
+			unsigned int f_flags, struct dmx_buffer *dmx_buffer)
+{
+	struct dvb_ringbuffer *buf;
+	spinlock_t *lock;
+	enum dmx_buffer_mode buffer_mode;
+	void **buff_handle;
+	void *newmem;
+	void *oldmem;
+	int *is_protected;
+	struct dmx_caps caps;
+
+	if (dmxdev->demux->get_caps)
+		dmxdev->demux->get_caps(dmxdev->demux, &caps);
+	else
+		caps.caps = 0;
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY) {
+		buf = &dmxdev->dvr_buffer;
+		lock = &dmxdev->lock;
+		buffer_mode = dmxdev->dvr_buffer_mode;
+		buff_handle = &dmxdev->dvr_priv_buff_handle;
+		is_protected = NULL;
+	} else {
+		buf = &dmxdev->dvr_input_buffer;
+		lock = &dmxdev->dvr_in_lock;
+		buffer_mode = dmxdev->dvr_input_buffer_mode;
+		buff_handle = &dmxdev->demux->dvr_input.priv_handle;
+		is_protected = &dmxdev->demux->dvr_input_protected;
+		if (!(caps.caps & DMX_CAP_SECURED_INPUT_PLAYBACK) &&
+			dmx_buffer->is_protected)
+			return -EINVAL;
+	}
+
+	if (!dmx_buffer->size ||
+		(buffer_mode == DMX_BUFFER_MODE_INTERNAL))
+		return -EINVAL;
+
+	oldmem = *buff_handle;
+
+	/*
+	 * Protected buffer is relevant only for DVR input buffer
+	 * when DVR device is opened for write. In such case,
+	 * buffer is mapped only if the buffer is not protected one.
+	 */
+	if (!is_protected || !dmx_buffer->is_protected) {
+		if (dmxdev->demux->map_buffer(dmxdev->demux, dmx_buffer,
+					buff_handle, &newmem))
+			return -ENOMEM;
+	} else {
+		newmem = NULL;
+		*buff_handle = NULL;
+	}
+
+	spin_lock_irq(lock);
+	buf->data = newmem;
+	buf->size = dmx_buffer->size;
+	if (is_protected)
+		*is_protected = dmx_buffer->is_protected;
+	dvb_ringbuffer_reset(buf);
+	spin_unlock_irq(lock);
+
+	if (oldmem)
+		dmxdev->demux->unmap_buffer(dmxdev->demux, oldmem);
+
+	return 0;
+}
+
+static int dvb_dvr_get_event(struct dmxdev *dmxdev,
+				unsigned int f_flags,
+				struct dmx_filter_event *event)
+{
+	int res = 0;
+
+	if (!((f_flags & O_ACCMODE) == O_RDONLY))
+		return -EINVAL;
+
+	spin_lock_irq(&dmxdev->lock);
+
+	if (dmxdev->dvr_buffer.error == -EOVERFLOW) {
+		event->type = DMX_EVENT_BUFFER_OVERFLOW;
+		dmxdev->dvr_buffer.error = 0;
+	} else {
+		res = dvb_dmxdev_remove_event(&dmxdev->dvr_output_events,
+			event);
+		if (res) {
+			spin_unlock_irq(&dmxdev->lock);
+			return res;
+		}
+	}
+
+	spin_unlock_irq(&dmxdev->lock);
+
+	if (event->type == DMX_EVENT_BUFFER_OVERFLOW)
+		dvb_dmxdev_auto_flush_buffer(dmxdev->dvr_feed,
+			&dmxdev->dvr_buffer);
+
+	/*
+	 * in PULL mode, we might be stalling on
+	 * event queue, so need to wake-up waiters
+	 */
+	if (dmxdev->playback_mode == DMX_PB_MODE_PULL)
+		wake_up_all(&dmxdev->dvr_buffer.queue);
+
+	return res;
+}
+
+static int dvb_dvr_get_buffer_status(struct dmxdev *dmxdev,
+				unsigned int f_flags,
+				struct dmx_buffer_status *dmx_buffer_status)
+{
+	struct dvb_ringbuffer *buf;
+	spinlock_t *lock;
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY) {
+		buf = &dmxdev->dvr_buffer;
+		lock = &dmxdev->lock;
+	} else {
+		buf = &dmxdev->dvr_input_buffer;
+		lock = &dmxdev->dvr_in_lock;
+	}
+
+	spin_lock_irq(lock);
+
+	dmx_buffer_status->error = buf->error;
+	dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
+	dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
+	dmx_buffer_status->read_offset = buf->pread;
+	dmx_buffer_status->write_offset = buf->pwrite;
+	dmx_buffer_status->size = buf->size;
+	buf->error = 0;
+
+	spin_unlock_irq(lock);
+
+	if (dmx_buffer_status->error == -EOVERFLOW)
+		dvb_dmxdev_auto_flush_buffer(dmxdev->dvr_feed, buf);
+
+	return 0;
+}
+
+static int dvb_dvr_release_data(struct dmxdev *dmxdev,
+					unsigned int f_flags,
+					u32 bytes_count)
+{
+	ssize_t buff_fullness;
+
+	if (!((f_flags & O_ACCMODE) == O_RDONLY))
+		return -EINVAL;
+
+	if (!bytes_count)
+		return 0;
+
+	buff_fullness = dvb_ringbuffer_avail(&dmxdev->dvr_buffer);
+
+	if (bytes_count > buff_fullness)
+		return -EINVAL;
+
+	DVB_RINGBUFFER_SKIP(&dmxdev->dvr_buffer, bytes_count);
+
+	dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, bytes_count);
+	spin_lock_irq(&dmxdev->lock);
+	dvb_dmxdev_update_events(&dmxdev->dvr_output_events, bytes_count);
+	spin_unlock_irq(&dmxdev->lock);
+
+	wake_up_all(&dmxdev->dvr_buffer.queue);
+	return 0;
+}
+
+/*
+ * dvb_dvr_feed_data - Notify new data in DVR input buffer
+ *
+ * @dmxdev - demux device instance
+ * @f_flags - demux device file flag (access mode)
+ * @bytes_count - how many bytes were written to the input buffer
+ *
+ * Note: this function assume dmxdev->mutex was taken, so buffer cannot
+ * be released during its operation.
+ */
+static int dvb_dvr_feed_data(struct dmxdev *dmxdev,
+	unsigned int f_flags,
+	u32 bytes_count)
+{
+	ssize_t free_space;
+	struct dvb_ringbuffer *buffer = &dmxdev->dvr_input_buffer;
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY)
+		return -EINVAL;
+
+	if (!bytes_count)
+		return 0;
+
+	free_space = dvb_ringbuffer_free(buffer);
+
+	if (bytes_count > free_space)
+		return -EINVAL;
+
+	DVB_RINGBUFFER_PUSH(buffer, bytes_count);
+
+	dvb_dvr_queue_data_feed(dmxdev, bytes_count);
+
+	return 0;
+}
+
 static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
 					       *dmxdevfilter, int state)
 {
@@ -301,12 +1763,13 @@
 
 	if (buf->size == size)
 		return 0;
-	if (!size)
+	if (!size ||
+		(dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL))
 		return -EINVAL;
 	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
 		return -EBUSY;
 
-	newmem = vmalloc(size);
+	newmem = vmalloc_user(size);
 	if (!newmem)
 		return -ENOMEM;
 
@@ -325,15 +1788,805 @@
 	return 0;
 }
 
+static int dvb_dmxdev_set_buffer_mode(struct dmxdev_filter *dmxdevfilter,
+					enum dmx_buffer_mode mode)
+{
+	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	void *oldmem;
+
+	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	if ((mode != DMX_BUFFER_MODE_INTERNAL) &&
+		(mode != DMX_BUFFER_MODE_EXTERNAL))
+		return -EINVAL;
+
+	if ((mode == DMX_BUFFER_MODE_EXTERNAL) &&
+		(!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer))
+		return -EINVAL;
+
+	if (mode == dmxdevfilter->buffer_mode)
+		return 0;
+
+	oldmem = buf->data;
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	buf->data = NULL;
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	dmxdevfilter->buffer_mode = mode;
+
+	if (mode == DMX_BUFFER_MODE_INTERNAL) {
+		/* switched from external to internal */
+		if (dmxdevfilter->priv_buff_handle) {
+			dmxdev->demux->unmap_buffer(dmxdev->demux,
+				dmxdevfilter->priv_buff_handle);
+			dmxdevfilter->priv_buff_handle = NULL;
+		}
+	} else if (oldmem) {
+		/* switched from internal to external */
+		vfree(oldmem);
+	}
+
+	return 0;
+}
+
+static int dvb_dmxdev_set_buffer(struct dmxdev_filter *dmxdevfilter,
+					struct dmx_buffer *buffer)
+{
+	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	void *newmem;
+	void *oldmem;
+
+	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	if ((!buffer->size) ||
+		(dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL))
+		return -EINVAL;
+
+	oldmem = dmxdevfilter->priv_buff_handle;
+	if (dmxdev->demux->map_buffer(dmxdev->demux, buffer,
+			&dmxdevfilter->priv_buff_handle, &newmem))
+		return -ENOMEM;
+
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	buf->data = newmem;
+	buf->size = buffer->size;
+	dvb_ringbuffer_reset(buf);
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	if (oldmem)
+		dmxdev->demux->unmap_buffer(dmxdev->demux, oldmem);
+
+	return 0;
+}
+
+static int dvb_dmxdev_set_tsp_out_format(struct dmxdev_filter *dmxdevfilter,
+				enum dmx_tsp_format_t dmx_tsp_format)
+{
+	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	if ((dmx_tsp_format > DMX_TSP_FORMAT_192_HEAD) ||
+		(dmx_tsp_format < DMX_TSP_FORMAT_188))
+		return -EINVAL;
+
+	dmxdevfilter->dmx_tsp_format = dmx_tsp_format;
+
+	return 0;
+}
+
+static int dvb_dmxdev_set_decoder_buffer_size(
+	struct dmxdev_filter *dmxdevfilter,
+	unsigned long size)
+{
+	struct dmx_caps caps;
+	struct dmx_demux *demux = dmxdevfilter->dev->demux;
+
+	if (demux->get_caps) {
+		demux->get_caps(demux, &caps);
+		if (!dvb_dmxdev_verify_buffer_size(size, caps.decoder.max_size,
+			caps.decoder.size_alignment))
+			return -EINVAL;
+	}
+
+	if (size == 0)
+		return -EINVAL;
+
+	if (dmxdevfilter->decoder_buffers.buffers_size == size)
+		return 0;
+
+	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	/*
+	 * In case decoder buffers were already set before to some external
+	 * buffers, setting the decoder buffer size alone implies transition
+	 * to internal buffer mode.
+	 */
+	dmxdevfilter->decoder_buffers.buffers_size = size;
+	dmxdevfilter->decoder_buffers.buffers_num = 0;
+	dmxdevfilter->decoder_buffers.is_linear = 0;
+	return 0;
+}
+
+static int dvb_dmxdev_set_source(struct dmxdev_filter *dmxdevfilter,
+					dmx_source_t *source)
+{
+	int ret = 0;
+	struct dmxdev *dev;
+
+	if (dmxdevfilter->state == DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	dev = dmxdevfilter->dev;
+	if (dev->demux->set_source)
+		ret = dev->demux->set_source(dev->demux, source);
+
+	if (!ret)
+		dev->source = *source;
+
+	return ret;
+}
+
+static int dvb_dmxdev_reuse_decoder_buf(struct dmxdev_filter *dmxdevfilter,
+						int cookie)
+{
+	struct dmxdev_feed *feed;
+
+	if (dmxdevfilter->state != DMXDEV_STATE_GO ||
+		(dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+		(dmxdevfilter->params.pes.output != DMX_OUT_DECODER) ||
+		(dmxdevfilter->events.event_mask.disable_mask &
+			DMX_EVENT_NEW_ES_DATA))
+		return -EPERM;
+
+	/* Only one feed should be in the list in case of decoder */
+	feed = list_first_entry(&dmxdevfilter->feed.ts,
+				struct dmxdev_feed, next);
+	if (feed && feed->ts && feed->ts->reuse_decoder_buffer)
+		return feed->ts->reuse_decoder_buffer(feed->ts, cookie);
+
+	return -ENODEV;
+}
+
+static int dvb_dmxdev_set_event_mask(struct dmxdev_filter *dmxdevfilter,
+				struct dmx_events_mask *event_mask)
+{
+	if (!event_mask ||
+		(event_mask->wakeup_threshold >= DMX_EVENT_QUEUE_SIZE))
+		return -EINVAL;
+
+	if (dmxdevfilter->state == DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	/*
+	 * Overflow event is not allowed to be masked.
+	 * This is because if overflow occurs, demux stops outputting data
+	 * until user is notified. If user is using events to read the data,
+	 * the overflow event must be always enabled or otherwise we would
+	 * never recover from overflow state.
+	 */
+	event_mask->disable_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW;
+	event_mask->no_wakeup_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW;
+
+	dmxdevfilter->events.event_mask = *event_mask;
+
+	return 0;
+}
+
+static int dvb_dmxdev_get_event_mask(struct dmxdev_filter *dmxdevfilter,
+				struct dmx_events_mask *event_mask)
+{
+	if (!event_mask)
+		return -EINVAL;
+
+	*event_mask = dmxdevfilter->events.event_mask;
+
+	return 0;
+}
+
+static int dvb_dmxdev_set_indexing_params(struct dmxdev_filter *dmxdevfilter,
+				struct dmx_indexing_params *idx_params)
+{
+	int found_pid;
+	struct dmxdev_feed *feed;
+	struct dmxdev_feed *ts_feed = NULL;
+	struct dmx_caps caps;
+	int ret = 0;
+
+	if (!dmxdevfilter->dev->demux->get_caps)
+		return -EINVAL;
+
+	dmxdevfilter->dev->demux->get_caps(dmxdevfilter->dev->demux, &caps);
+
+	if (!idx_params ||
+		!(caps.caps & DMX_CAP_VIDEO_INDEXING) ||
+		(dmxdevfilter->state < DMXDEV_STATE_SET) ||
+		(dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+		((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+		 (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+		return -EINVAL;
+
+	if (idx_params->enable && !idx_params->types)
+		return -EINVAL;
+
+	found_pid = 0;
+	list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
+		if (feed->pid == idx_params->pid) {
+			found_pid = 1;
+			ts_feed = feed;
+			ts_feed->idx_params = *idx_params;
+			if ((dmxdevfilter->state == DMXDEV_STATE_GO) &&
+				ts_feed->ts->set_idx_params)
+				ret = ts_feed->ts->set_idx_params(
+						ts_feed->ts, idx_params);
+			break;
+		}
+	}
+
+	if (!found_pid)
+		return -EINVAL;
+
+	return ret;
+}
+
+static int dvb_dmxdev_get_scrambling_bits(struct dmxdev_filter *filter,
+	struct dmx_scrambling_bits *scrambling_bits)
+{
+	struct dmxdev_feed *feed;
+
+	if (!scrambling_bits ||
+		(filter->state != DMXDEV_STATE_GO))
+		return -EINVAL;
+
+	if (filter->type == DMXDEV_TYPE_SEC) {
+		if (filter->feed.sec.feed->get_scrambling_bits)
+			return filter->feed.sec.feed->get_scrambling_bits(
+						filter->feed.sec.feed,
+						&scrambling_bits->value);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(feed, &filter->feed.ts, next) {
+		if (feed->pid == scrambling_bits->pid) {
+			if (feed->ts->get_scrambling_bits)
+				return feed->ts->get_scrambling_bits(feed->ts,
+						&scrambling_bits->value);
+			return -EINVAL;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
+{
+	struct ts_insertion_buffer *ts_buffer =
+		container_of(to_delayed_work(worker),
+			struct ts_insertion_buffer, dwork);
+	struct dmxdev_feed *feed;
+	size_t free_bytes;
+	struct dmx_ts_feed *ts;
+
+	mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+
+	if (ts_buffer->abort ||
+		(ts_buffer->dmxdevfilter->state != DMXDEV_STATE_GO)) {
+		mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+		return;
+	}
+
+	feed = list_first_entry(&ts_buffer->dmxdevfilter->feed.ts,
+				struct dmxdev_feed, next);
+	ts = feed->ts;
+	free_bytes = dvb_ringbuffer_free(&ts_buffer->dmxdevfilter->buffer);
+
+	mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+
+	if (ts_buffer->size < free_bytes)
+		ts->ts_insertion_insert_buffer(ts,
+			ts_buffer->buffer, ts_buffer->size);
+
+	if (ts_buffer->repetition_time && !ts_buffer->abort)
+		schedule_delayed_work(&ts_buffer->dwork,
+				msecs_to_jiffies(ts_buffer->repetition_time));
+}
+
+static void dvb_dmxdev_queue_ts_insertion(
+		struct ts_insertion_buffer *ts_buffer)
+{
+	size_t tsp_size;
+
+	if (ts_buffer->dmxdevfilter->dmx_tsp_format == DMX_TSP_FORMAT_188)
+		tsp_size = 188;
+	else
+		tsp_size = 192;
+
+	if (ts_buffer->size % tsp_size) {
+		pr_err("%s: Wrong buffer alignment, size=%zu, tsp_size=%zu\n",
+			__func__, ts_buffer->size, tsp_size);
+		return;
+	}
+
+	ts_buffer->abort = 0;
+	schedule_delayed_work(&ts_buffer->dwork, 0);
+}
+
+static void dvb_dmxdev_cancel_ts_insertion(
+		struct ts_insertion_buffer *ts_buffer)
+{
+	/*
+	 * This function assumes it is called while mutex
+	 * of demux filter is taken. Since work in workqueue
+	 * captures the filter's mutex to protect against the DB,
+	 * mutex needs to be released before waiting for the work
+	 * to get finished otherwise work in workqueue will
+	 * never be finished.
+	 */
+	if (!mutex_is_locked(&ts_buffer->dmxdevfilter->mutex)) {
+		pr_err("%s: mutex is not locked!\n", __func__);
+		return;
+	}
+
+	ts_buffer->abort = 1;
+
+	mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+	cancel_delayed_work_sync(&ts_buffer->dwork);
+	mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+}
+
+static int dvb_dmxdev_set_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+		struct dmx_set_ts_insertion *params)
+{
+	int ret = 0;
+	int first_buffer;
+	struct dmxdev_feed *feed;
+	struct ts_insertion_buffer *ts_buffer;
+	struct dmx_caps caps;
+
+	if (!dmxdevfilter->dev->demux->get_caps)
+		return -EINVAL;
+
+	dmxdevfilter->dev->demux->get_caps(dmxdevfilter->dev->demux, &caps);
+
+	if (!params ||
+		!params->size ||
+		!(caps.caps & DMX_CAP_TS_INSERTION) ||
+		(dmxdevfilter->state < DMXDEV_STATE_SET) ||
+		(dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+		((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+		 (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+		return -EINVAL;
+
+	ts_buffer = vmalloc(sizeof(struct ts_insertion_buffer));
+	if (!ts_buffer)
+		return -ENOMEM;
+
+	ts_buffer->buffer = vmalloc(params->size);
+	if (!ts_buffer->buffer) {
+		vfree(ts_buffer);
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(ts_buffer->buffer,
+			params->ts_packets, params->size)) {
+		vfree(ts_buffer->buffer);
+		vfree(ts_buffer);
+		return -EFAULT;
+	}
+
+	if (params->repetition_time &&
+		params->repetition_time < DMX_MIN_INSERTION_REPETITION_TIME)
+		params->repetition_time = DMX_MIN_INSERTION_REPETITION_TIME;
+
+	ts_buffer->size = params->size;
+	ts_buffer->identifier = params->identifier;
+	ts_buffer->repetition_time = params->repetition_time;
+	ts_buffer->dmxdevfilter = dmxdevfilter;
+	INIT_DELAYED_WORK(&ts_buffer->dwork, dvb_dmxdev_ts_insertion_work);
+
+	first_buffer = list_empty(&dmxdevfilter->insertion_buffers);
+	list_add_tail(&ts_buffer->next, &dmxdevfilter->insertion_buffers);
+
+	if (dmxdevfilter->state != DMXDEV_STATE_GO)
+		return 0;
+
+	feed = list_first_entry(&dmxdevfilter->feed.ts,
+				struct dmxdev_feed, next);
+
+	if (first_buffer && feed->ts->ts_insertion_init)
+		ret = feed->ts->ts_insertion_init(feed->ts);
+
+	if (!ret) {
+		dvb_dmxdev_queue_ts_insertion(ts_buffer);
+	} else {
+		list_del(&ts_buffer->next);
+		vfree(ts_buffer->buffer);
+		vfree(ts_buffer);
+	}
+
+	return ret;
+}
+
+static int dvb_dmxdev_abort_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+		struct dmx_abort_ts_insertion *params)
+{
+	int ret = 0;
+	int found_buffer;
+	struct dmxdev_feed *feed;
+	struct ts_insertion_buffer *ts_buffer, *tmp;
+	struct dmx_caps caps;
+
+	if (!dmxdevfilter->dev->demux->get_caps)
+		return -EINVAL;
+
+	dmxdevfilter->dev->demux->get_caps(dmxdevfilter->dev->demux, &caps);
+
+	if (!params ||
+		!(caps.caps & DMX_CAP_TS_INSERTION) ||
+		(dmxdevfilter->state < DMXDEV_STATE_SET) ||
+		(dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+		((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+		 (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+		return -EINVAL;
+
+	found_buffer = 0;
+	list_for_each_entry_safe(ts_buffer, tmp,
+			&dmxdevfilter->insertion_buffers, next) {
+		if (ts_buffer->identifier == params->identifier) {
+			list_del(&ts_buffer->next);
+			found_buffer = 1;
+			break;
+		}
+	}
+
+	if (!found_buffer)
+		return -EINVAL;
+
+	if (dmxdevfilter->state == DMXDEV_STATE_GO) {
+		dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+		if (list_empty(&dmxdevfilter->insertion_buffers)) {
+			feed = list_first_entry(&dmxdevfilter->feed.ts,
+						struct dmxdev_feed, next);
+			if (feed->ts->ts_insertion_terminate)
+				ret = feed->ts->ts_insertion_terminate(
+							feed->ts);
+		}
+	}
+
+	vfree(ts_buffer->buffer);
+	vfree(ts_buffer);
+
+	return ret;
+}
+
+static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter,
+				int required_space, int wait)
+{
+	struct dmxdev_filter *dmxdevfilter = filter->priv;
+	struct dvb_ringbuffer *src;
+	struct dmxdev_events_queue *events;
+	int ret;
+
+	if (!dmxdevfilter) {
+		pr_err("%s: NULL demux filter object!\n", __func__);
+		return -ENODEV;
+	}
+
+	if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) {
+		src = &dmxdevfilter->buffer;
+		events = &dmxdevfilter->events;
+	} else {
+		src = &dmxdevfilter->dev->dvr_buffer;
+		events = &dmxdevfilter->dev->dvr_output_events;
+	}
+
+	do {
+		ret = 0;
+
+		if (dmxdevfilter->dev->dvr_in_exit)
+			return -ENODEV;
+
+		spin_lock(&dmxdevfilter->dev->lock);
+
+		if ((!src->data) ||
+			(dmxdevfilter->state != DMXDEV_STATE_GO))
+			ret = -EINVAL;
+		else if (src->error)
+			ret = src->error;
+
+		if (ret) {
+			spin_unlock(&dmxdevfilter->dev->lock);
+			return ret;
+		}
+
+		if ((required_space <= dvb_ringbuffer_free(src)) &&
+			(!dvb_dmxdev_events_is_full(events))) {
+			spin_unlock(&dmxdevfilter->dev->lock);
+			return 0;
+		}
+
+		spin_unlock(&dmxdevfilter->dev->lock);
+
+		if (!wait)
+			return -ENOSPC;
+
+		ret = wait_event_interruptible(src->queue,
+				(!src->data) ||
+				((dvb_ringbuffer_free(src) >= required_space) &&
+				 (!dvb_dmxdev_events_is_full(events))) ||
+				(src->error != 0) ||
+				(dmxdevfilter->state != DMXDEV_STATE_GO) ||
+				dmxdevfilter->dev->dvr_in_exit);
+
+		if (ret < 0)
+			return ret;
+	} while (1);
+}
+
+static int dvb_dmxdev_sec_fullness_callback(
+				struct dmx_section_filter *filter,
+				int required_space, int wait)
+{
+	struct dmxdev_filter *dmxdevfilter = filter->priv;
+	struct dvb_ringbuffer *src;
+	struct dmxdev_events_queue *events;
+	int ret;
+
+	if (!dmxdevfilter) {
+		pr_err("%s: NULL demux filter object!\n", __func__);
+		return -ENODEV;
+	}
+
+	src = &dmxdevfilter->buffer;
+	events = &dmxdevfilter->events;
+
+	do {
+		ret = 0;
+
+		if (dmxdevfilter->dev->dvr_in_exit)
+			return -ENODEV;
+
+		spin_lock(&dmxdevfilter->dev->lock);
+
+		if ((!src->data) ||
+			(dmxdevfilter->state != DMXDEV_STATE_GO))
+			ret = -EINVAL;
+		else if (src->error)
+			ret = src->error;
+
+		if (ret) {
+			spin_unlock(&dmxdevfilter->dev->lock);
+			return ret;
+		}
+
+		if ((required_space <= dvb_ringbuffer_free(src)) &&
+			(!dvb_dmxdev_events_is_full(events))) {
+			spin_unlock(&dmxdevfilter->dev->lock);
+			return 0;
+		}
+
+		spin_unlock(&dmxdevfilter->dev->lock);
+
+		if (!wait)
+			return -ENOSPC;
+
+		ret = wait_event_interruptible(src->queue,
+				(!src->data) ||
+				((dvb_ringbuffer_free(src) >= required_space) &&
+				 (!dvb_dmxdev_events_is_full(events))) ||
+				(src->error != 0) ||
+				(dmxdevfilter->state != DMXDEV_STATE_GO) ||
+				dmxdevfilter->dev->dvr_in_exit);
+
+		if (ret < 0)
+			return ret;
+	} while (1);
+}
+
+static int dvb_dmxdev_set_playback_mode(struct dmxdev_filter *dmxdevfilter,
+					enum dmx_playback_mode_t playback_mode)
+{
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	struct dmx_caps caps;
+
+	if (dmxdev->demux->get_caps)
+		dmxdev->demux->get_caps(dmxdev->demux, &caps);
+	else
+		caps.caps = 0;
+
+	if ((playback_mode != DMX_PB_MODE_PUSH) &&
+		(playback_mode != DMX_PB_MODE_PULL))
+		return -EINVAL;
+
+	if (dmxdev->demux->set_playback_mode == NULL)
+		return -EINVAL;
+
+	if (((dmxdev->source < DMX_SOURCE_DVR0) ||
+		 !(caps.caps & DMX_CAP_PULL_MODE)) &&
+		 (playback_mode == DMX_PB_MODE_PULL))
+		return -EPERM;
+
+	if (dmxdevfilter->state == DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	dmxdev->playback_mode = playback_mode;
+
+	return dmxdev->demux->set_playback_mode(
+				dmxdev->demux,
+				dmxdev->playback_mode,
+				dvb_dmxdev_ts_fullness_callback,
+				dvb_dmxdev_sec_fullness_callback);
+}
+
+static int dvb_dmxdev_flush_buffer(struct dmxdev_filter *filter)
+{
+	size_t flush_len;
+	int ret;
+
+	if (filter->state != DMXDEV_STATE_GO)
+		return -EINVAL;
+
+	flush_len = dvb_ringbuffer_avail(&filter->buffer);
+	ret = dvb_dmxdev_flush_data(filter, flush_len);
+
+	return ret;
+}
+
+static int dvb_dmxdev_get_buffer_status(
+		struct dmxdev_filter *dmxdevfilter,
+		struct dmx_buffer_status *dmx_buffer_status)
+{
+	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+
+	/*
+	 * Note: Taking the dmxdevfilter->dev->lock spinlock is required only
+	 * when getting the status of the Demux-userspace data ringbuffer .
+	 * In case we are getting the status of a decoder buffer, taking this
+	 * spinlock is not required and in fact might lead to a deadlock.
+	 */
+	if ((dmxdevfilter->type == DMXDEV_TYPE_PES) &&
+		(dmxdevfilter->params.pes.output == DMX_OUT_DECODER)) {
+		struct dmxdev_feed *feed;
+		int ret;
+
+		/* Only one feed should be in the list in case of decoder */
+		feed = list_first_entry(&dmxdevfilter->feed.ts,
+					struct dmxdev_feed, next);
+
+		/* Ask for status of decoder's buffer from underlying HW */
+		if (feed->ts->get_decoder_buff_status)
+			ret = feed->ts->get_decoder_buff_status(
+					feed->ts,
+					dmx_buffer_status);
+		else
+			ret = -ENODEV;
+
+		return ret;
+	}
+
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+
+	if (!buf->data) {
+		spin_unlock_irq(&dmxdevfilter->dev->lock);
+		return -EINVAL;
+	}
+
+	dmx_buffer_status->error = buf->error;
+	dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
+	dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
+	dmx_buffer_status->read_offset = buf->pread;
+	dmx_buffer_status->write_offset = buf->pwrite;
+	dmx_buffer_status->size = buf->size;
+	buf->error = 0;
+
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	if (dmx_buffer_status->error == -EOVERFLOW)
+		dvb_dmxdev_auto_flush_buffer(dmxdevfilter, buf);
+
+	return 0;
+}
+
+static int dvb_dmxdev_release_data(struct dmxdev_filter *dmxdevfilter,
+					u32 bytes_count)
+{
+	ssize_t buff_fullness;
+
+	if (!dmxdevfilter->buffer.data)
+		return -EINVAL;
+
+	if (!bytes_count)
+		return 0;
+
+	buff_fullness = dvb_ringbuffer_avail(&dmxdevfilter->buffer);
+
+	if (bytes_count > buff_fullness)
+		return -EINVAL;
+
+	DVB_RINGBUFFER_SKIP(&dmxdevfilter->buffer, bytes_count);
+
+	dvb_dmxdev_notify_data_read(dmxdevfilter, bytes_count);
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	dvb_dmxdev_update_events(&dmxdevfilter->events, bytes_count);
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	wake_up_all(&dmxdevfilter->buffer.queue);
+
+	return 0;
+}
+
+static int dvb_dmxdev_get_event(struct dmxdev_filter *dmxdevfilter,
+					struct dmx_filter_event *event)
+{
+	int res = 0;
+
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+
+	/* Check first for filter overflow */
+	if (dmxdevfilter->buffer.error == -EOVERFLOW) {
+		event->type = DMX_EVENT_BUFFER_OVERFLOW;
+	} else {
+		res = dvb_dmxdev_remove_event(&dmxdevfilter->events, event);
+		if (res) {
+			spin_unlock_irq(&dmxdevfilter->dev->lock);
+			return res;
+		}
+	}
+
+	/* clear buffer error now that user was notified */
+	if (event->type == DMX_EVENT_BUFFER_OVERFLOW ||
+		event->type == DMX_EVENT_SECTION_TIMEOUT)
+		dmxdevfilter->buffer.error = 0;
+
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	if (event->type == DMX_EVENT_BUFFER_OVERFLOW)
+		dvb_dmxdev_auto_flush_buffer(dmxdevfilter,
+			&dmxdevfilter->buffer);
+
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+
+	/*
+	 * If no-data events are enabled on this filter,
+	 * the events can be removed from the queue when
+	 * user gets them.
+	 * For filters with data events enabled, the event is removed
+	 * from the queue only when the respective data is read.
+	 */
+	if (event->type != DMX_EVENT_BUFFER_OVERFLOW &&
+		dmxdevfilter->events.data_read_event_masked)
+		dmxdevfilter->events.read_index =
+			dvb_dmxdev_advance_event_idx(
+				dmxdevfilter->events.read_index);
+
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	/*
+	 * in PULL mode, we might be stalling on
+	 * event queue, so need to wake-up waiters
+	 */
+	if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL)
+		wake_up_all(&dmxdevfilter->buffer.queue);
+
+	return res;
+}
+
 static void dvb_dmxdev_filter_timeout(unsigned long data)
 {
 	struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
+	struct dmx_filter_event event;
 
 	dmxdevfilter->buffer.error = -ETIMEDOUT;
 	spin_lock_irq(&dmxdevfilter->dev->lock);
 	dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
+	event.type = DMX_EVENT_SECTION_TIMEOUT;
+	dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
 	spin_unlock_irq(&dmxdevfilter->dev->lock);
-	wake_up(&dmxdevfilter->buffer.queue);
+	wake_up_all(&dmxdevfilter->buffer.queue);
 }
 
 static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
@@ -355,31 +2608,77 @@
 				       struct dmx_section_filter *filter)
 {
 	struct dmxdev_filter *dmxdevfilter = filter->priv;
-	int ret;
+	struct dmx_filter_event event;
+	ssize_t free;
 
-	if (dmxdevfilter->buffer.error) {
-		wake_up(&dmxdevfilter->buffer.queue);
-		return 0;
+
+	if (!dmxdevfilter) {
+		pr_err("%s: null filter.\n", __func__);
+		return -EINVAL;
 	}
+
 	spin_lock(&dmxdevfilter->dev->lock);
-	if (dmxdevfilter->state != DMXDEV_STATE_GO) {
+
+	if (dmxdevfilter->buffer.error ||
+		dmxdevfilter->state != DMXDEV_STATE_GO ||
+		dmxdevfilter->eos_state) {
 		spin_unlock(&dmxdevfilter->dev->lock);
 		return 0;
 	}
-	del_timer(&dmxdevfilter->timer);
-	dprintk("dmxdev: section callback %*ph\n", 6, buffer1);
-	ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
-				      buffer1_len);
-	if (ret == buffer1_len) {
-		ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
-					      buffer2_len);
+
+	/* Discard section data if event cannot be notified */
+	if (!(dmxdevfilter->events.event_mask.disable_mask &
+		DMX_EVENT_NEW_SECTION) &&
+		dvb_dmxdev_events_is_full(&dmxdevfilter->events)) {
+		spin_unlock(&dmxdevfilter->dev->lock);
+		return 0;
 	}
-	if (ret < 0)
-		dmxdevfilter->buffer.error = ret;
+
+	if ((buffer1_len + buffer2_len) == 0) {
+		if (buffer1 == NULL && buffer2 == NULL) {
+			/* Section was dropped due to CRC error */
+			event.type = DMX_EVENT_SECTION_CRC_ERROR;
+			dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+
+			spin_unlock(&dmxdevfilter->dev->lock);
+			wake_up_all(&dmxdevfilter->buffer.queue);
+		} else {
+			spin_unlock(&dmxdevfilter->dev->lock);
+		}
+
+		return 0;
+	}
+
+	event.params.section.base_offset = dmxdevfilter->buffer.pwrite;
+	event.params.section.start_offset = dmxdevfilter->buffer.pwrite;
+
+	del_timer(&dmxdevfilter->timer);
+
+	/* Verify output buffer has sufficient space, or report overflow */
+	free = dvb_ringbuffer_free(&dmxdevfilter->buffer);
+	if (free < (buffer1_len + buffer2_len)) {
+		pr_debug("%s: section filter overflow (pid=%u)\n",
+			__func__, dmxdevfilter->params.sec.pid);
+		dmxdevfilter->buffer.error = -EOVERFLOW;
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&dmxdevfilter->buffer.queue);
+		return 0;
+	}
+
+	dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len);
+	dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len);
+
+	event.type = DMX_EVENT_NEW_SECTION;
+	event.params.section.total_length = buffer1_len + buffer2_len;
+	event.params.section.actual_length =
+		event.params.section.total_length;
+
+	dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+
 	if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
 		dmxdevfilter->state = DMXDEV_STATE_DONE;
 	spin_unlock(&dmxdevfilter->dev->lock);
-	wake_up(&dmxdevfilter->buffer.queue);
+	wake_up_all(&dmxdevfilter->buffer.queue);
 	return 0;
 }
 
@@ -389,31 +2688,401 @@
 {
 	struct dmxdev_filter *dmxdevfilter = feed->priv;
 	struct dvb_ringbuffer *buffer;
-	int ret;
+	struct dmxdev_events_queue *events;
+	struct dmx_filter_event event;
+	ssize_t free;
 
+	if (!dmxdevfilter) {
+		pr_err("%s: null filter (feed->is_filtering=%d)\n",
+			__func__, feed->is_filtering);
+		return -EINVAL;
+	}
 	spin_lock(&dmxdevfilter->dev->lock);
-	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
+
+	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER ||
+		dmxdevfilter->state != DMXDEV_STATE_GO ||
+		dmxdevfilter->eos_state) {
 		spin_unlock(&dmxdevfilter->dev->lock);
 		return 0;
 	}
 
-	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
-	    || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+	if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) {
 		buffer = &dmxdevfilter->buffer;
-	else
+		events = &dmxdevfilter->events;
+	} else {
 		buffer = &dmxdevfilter->dev->dvr_buffer;
+		events = &dmxdevfilter->dev->dvr_output_events;
+	}
+
 	if (buffer->error) {
 		spin_unlock(&dmxdevfilter->dev->lock);
-		wake_up(&buffer->queue);
+		wake_up_all(&buffer->queue);
+		return buffer->error;
+	}
+
+	if (!events->current_event_data_size)
+		events->current_event_start_offset = buffer->pwrite;
+
+	/* Verify output buffer has sufficient space, or report overflow */
+	free = dvb_ringbuffer_free(buffer);
+	if (free < (buffer1_len + buffer2_len)) {
+		pr_debug("%s: buffer overflow error, pid=%u\n",
+			__func__, dmxdevfilter->params.pes.pid);
+		buffer->error = -EOVERFLOW;
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+
+		return -EOVERFLOW;
+	}
+
+	if (buffer1_len + buffer2_len) {
+		dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
+		dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
+
+		events->current_event_data_size += (buffer1_len + buffer2_len);
+
+		if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP ||
+			dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+			&& events->current_event_data_size >=
+				dmxdevfilter->params.pes.rec_chunk_size) {
+			event.type = DMX_EVENT_NEW_REC_CHUNK;
+			event.params.recording_chunk.offset =
+				events->current_event_start_offset;
+			event.params.recording_chunk.size =
+				events->current_event_data_size;
+
+			dvb_dmxdev_add_event(events, &event);
+			events->current_event_data_size = 0;
+		}
+	}
+
+	spin_unlock(&dmxdevfilter->dev->lock);
+	wake_up_all(&buffer->queue);
+	return 0;
+}
+
+static int dvb_dmxdev_section_event_cb(struct dmx_section_filter *filter,
+			struct dmx_data_ready *dmx_data_ready)
+{
+	int res = 0;
+	struct dmxdev_filter *dmxdevfilter = filter->priv;
+	struct dmx_filter_event event;
+	ssize_t free;
+
+	if (!dmxdevfilter) {
+		pr_err("%s: null filter. event type=%d (length=%d) will be discarded\n",
+			__func__, dmx_data_ready->status,
+			dmx_data_ready->data_length);
+		return -EINVAL;
+	}
+
+	spin_lock(&dmxdevfilter->dev->lock);
+
+	if (dmxdevfilter->buffer.error == -ETIMEDOUT ||
+		dmxdevfilter->state != DMXDEV_STATE_GO ||
+		dmxdevfilter->eos_state) {
+		spin_unlock(&dmxdevfilter->dev->lock);
 		return 0;
 	}
-	ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
-	if (ret == buffer1_len)
-		ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
-	if (ret < 0)
-		buffer->error = ret;
+
+	if (dmx_data_ready->data_length == 0) {
+		if (dmx_data_ready->status == DMX_CRC_ERROR) {
+			/* Section was dropped due to CRC error */
+			event.type = DMX_EVENT_SECTION_CRC_ERROR;
+			dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+
+			spin_unlock(&dmxdevfilter->dev->lock);
+			wake_up_all(&dmxdevfilter->buffer.queue);
+		} else if (dmx_data_ready->status == DMX_OK_EOS) {
+			event.type = DMX_EVENT_EOS;
+			dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+			spin_unlock(&dmxdevfilter->dev->lock);
+			wake_up_all(&dmxdevfilter->buffer.queue);
+		} else if (dmx_data_ready->status == DMX_OK_MARKER) {
+			event.type = DMX_EVENT_MARKER;
+			event.params.marker.id = dmx_data_ready->marker.id;
+			dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+			spin_unlock(&dmxdevfilter->dev->lock);
+			wake_up_all(&dmxdevfilter->buffer.queue);
+		} else if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+			event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+			event.params.scrambling_status =
+				dmx_data_ready->scrambling_bits;
+			dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+			spin_unlock(&dmxdevfilter->dev->lock);
+			wake_up_all(&dmxdevfilter->buffer.queue);
+		} else if (dmx_data_ready->status == DMX_OVERRUN_ERROR) {
+			pr_debug("dmxdev: section filter overflow (pid=%u)\n",
+				dmxdevfilter->params.sec.pid);
+			/* Set buffer error to notify user overflow occurred */
+			dmxdevfilter->buffer.error = -EOVERFLOW;
+			spin_unlock(&dmxdevfilter->dev->lock);
+			wake_up_all(&dmxdevfilter->buffer.queue);
+		} else {
+			spin_unlock(&dmxdevfilter->dev->lock);
+		}
+		return 0;
+	}
+
+	event.type = DMX_EVENT_NEW_SECTION;
+	event.params.section.base_offset = dmxdevfilter->buffer.pwrite;
+	event.params.section.start_offset = dmxdevfilter->buffer.pwrite;
+	event.params.section.total_length = dmx_data_ready->data_length;
+	event.params.section.actual_length = dmx_data_ready->data_length;
+
+	if (dmx_data_ready->status == DMX_MISSED_ERROR)
+		event.params.section.flags = DMX_FILTER_CC_ERROR;
+	else
+		event.params.section.flags = 0;
+
+	free = dvb_ringbuffer_free(&dmxdevfilter->buffer);
+	if (free < dmx_data_ready->data_length) {
+		pr_err("%s: invalid data length: data_length=%d > free=%zd\n",
+			__func__, dmx_data_ready->data_length, free);
+	} else {
+		res = dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+		DVB_RINGBUFFER_PUSH(&dmxdevfilter->buffer,
+			dmx_data_ready->data_length);
+	}
+
 	spin_unlock(&dmxdevfilter->dev->lock);
-	wake_up(&buffer->queue);
+	wake_up_all(&dmxdevfilter->buffer.queue);
+
+	return res;
+}
+
+static int dvb_dmxdev_ts_event_cb(struct dmx_ts_feed *feed,
+			struct dmx_data_ready *dmx_data_ready)
+{
+	struct dmxdev_filter *dmxdevfilter = feed->priv;
+	struct dvb_ringbuffer *buffer;
+	struct dmxdev_events_queue *events;
+	struct dmx_filter_event event;
+	ssize_t free;
+
+	if (!dmxdevfilter) {
+		pr_err("%s: null filter (feed->is_filtering=%d) event type=%d (length=%d) will be discarded\n",
+			__func__, feed->is_filtering,
+			dmx_data_ready->status,
+			dmx_data_ready->data_length);
+		return -EINVAL;
+	}
+
+	spin_lock(&dmxdevfilter->dev->lock);
+
+	if (dmxdevfilter->state != DMXDEV_STATE_GO ||
+		dmxdevfilter->eos_state) {
+		spin_unlock(&dmxdevfilter->dev->lock);
+		return 0;
+	}
+
+	if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) {
+		buffer = &dmxdevfilter->buffer;
+		events = &dmxdevfilter->events;
+	} else {
+		buffer = &dmxdevfilter->dev->dvr_buffer;
+		events = &dmxdevfilter->dev->dvr_output_events;
+	}
+
+	if (!buffer->error && dmx_data_ready->status == DMX_OVERRUN_ERROR) {
+		pr_debug("dmxdev: %s filter buffer overflow (pid=%u)\n",
+			dmxdevfilter->params.pes.output == DMX_OUT_DECODER ?
+				"decoder" : "",
+			dmxdevfilter->params.pes.pid);
+		/* Set buffer error to notify user overflow occurred */
+		buffer->error = -EOVERFLOW;
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
+	if (dmx_data_ready->status == DMX_OK_EOS) {
+		/* Report partial recording chunk */
+		if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP ||
+			dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+			&& events->current_event_data_size) {
+			event.type = DMX_EVENT_NEW_REC_CHUNK;
+			event.params.recording_chunk.offset =
+				events->current_event_start_offset;
+			event.params.recording_chunk.size =
+				events->current_event_data_size;
+			events->current_event_start_offset =
+				(events->current_event_start_offset +
+				events->current_event_data_size) %
+				buffer->size;
+			events->current_event_data_size = 0;
+			dvb_dmxdev_add_event(events, &event);
+		}
+
+		dmxdevfilter->eos_state = 1;
+		pr_debug("dmxdev: DMX_OK_EOS - entering EOS state\n");
+		event.type = DMX_EVENT_EOS;
+		dvb_dmxdev_add_event(events, &event);
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
+	if (dmx_data_ready->status == DMX_OK_MARKER) {
+		pr_debug("dmxdev: DMX_OK_MARKER - id=%llu\n",
+			dmx_data_ready->marker.id);
+		event.type = DMX_EVENT_MARKER;
+		event.params.marker.id = dmx_data_ready->marker.id;
+		dvb_dmxdev_add_event(events, &event);
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
+	if (dmx_data_ready->status == DMX_OK_PCR) {
+		pr_debug("dmxdev: event callback DMX_OK_PCR\n");
+		event.type = DMX_EVENT_NEW_PCR;
+		event.params.pcr.pcr = dmx_data_ready->pcr.pcr;
+		event.params.pcr.stc = dmx_data_ready->pcr.stc;
+		if (dmx_data_ready->pcr.disc_indicator_set)
+			event.params.pcr.flags =
+				DMX_FILTER_DISCONTINUITY_INDICATOR;
+		else
+			event.params.pcr.flags = 0;
+
+		dvb_dmxdev_add_event(events, &event);
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
+	if (dmx_data_ready->status == DMX_OK_IDX) {
+		pr_debug("dmxdev: event callback DMX_OK_IDX\n");
+		event.type = DMX_EVENT_NEW_INDEX_ENTRY;
+		event.params.index = dmx_data_ready->idx_event;
+
+		dvb_dmxdev_add_event(events, &event);
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
+	if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+		event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+		event.params.scrambling_status =
+			dmx_data_ready->scrambling_bits;
+		dvb_dmxdev_add_event(events, &event);
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
+	if (dmx_data_ready->status == DMX_OK_DECODER_BUF) {
+		event.type = DMX_EVENT_NEW_ES_DATA;
+		event.params.es_data.buf_handle = dmx_data_ready->buf.handle;
+		event.params.es_data.cookie = dmx_data_ready->buf.cookie;
+		event.params.es_data.offset = dmx_data_ready->buf.offset;
+		event.params.es_data.data_len = dmx_data_ready->buf.len;
+		event.params.es_data.pts_valid = dmx_data_ready->buf.pts_exists;
+		event.params.es_data.pts = dmx_data_ready->buf.pts;
+		event.params.es_data.dts_valid = dmx_data_ready->buf.dts_exists;
+		event.params.es_data.dts = dmx_data_ready->buf.dts;
+		event.params.es_data.stc = dmx_data_ready->buf.stc;
+		event.params.es_data.transport_error_indicator_counter =
+				dmx_data_ready->buf.tei_counter;
+		event.params.es_data.continuity_error_counter =
+				dmx_data_ready->buf.cont_err_counter;
+		event.params.es_data.ts_packets_num =
+				dmx_data_ready->buf.ts_packets_num;
+		event.params.es_data.ts_dropped_bytes =
+				dmx_data_ready->buf.ts_dropped_bytes;
+		dvb_dmxdev_add_event(events, &event);
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
+	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
+	free = dvb_ringbuffer_free(buffer);
+	if (free < dmx_data_ready->data_length) {
+		pr_err("%s: invalid data length: data_length=%d > free=%zd\n",
+			__func__, dmx_data_ready->data_length, free);
+
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
+	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP) {
+		if (dmx_data_ready->status == DMX_OK &&
+			!events->current_event_data_size) {
+			events->current_event_start_offset = buffer->pwrite;
+		} else if (dmx_data_ready->status == DMX_OK_PES_END) {
+			event.type = DMX_EVENT_NEW_PES;
+
+			event.params.pes.base_offset =
+				events->current_event_start_offset;
+			event.params.pes.start_offset =
+				(events->current_event_start_offset +
+				dmx_data_ready->pes_end.start_gap) %
+				buffer->size;
+
+			event.params.pes.actual_length =
+				dmx_data_ready->pes_end.actual_length;
+			event.params.pes.total_length =
+				events->current_event_data_size;
+
+			event.params.pes.flags = 0;
+			if (dmx_data_ready->pes_end.disc_indicator_set)
+				event.params.pes.flags |=
+					DMX_FILTER_DISCONTINUITY_INDICATOR;
+			if (dmx_data_ready->pes_end.pes_length_mismatch)
+				event.params.pes.flags |=
+					DMX_FILTER_PES_LENGTH_ERROR;
+
+			event.params.pes.stc = dmx_data_ready->pes_end.stc;
+			event.params.pes.transport_error_indicator_counter =
+				dmx_data_ready->pes_end.tei_counter;
+			event.params.pes.continuity_error_counter =
+				dmx_data_ready->pes_end.cont_err_counter;
+			event.params.pes.ts_packets_num =
+				dmx_data_ready->pes_end.ts_packets_num;
+
+			/* Do not report zero length PES */
+			if (event.params.pes.total_length)
+				dvb_dmxdev_add_event(events, &event);
+
+			events->current_event_data_size = 0;
+		}
+	} else if (!events->current_event_data_size) {
+		events->current_event_start_offset = buffer->pwrite;
+	}
+
+	events->current_event_data_size += dmx_data_ready->data_length;
+	DVB_RINGBUFFER_PUSH(buffer, dmx_data_ready->data_length);
+
+	if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP) ||
+		(dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)) {
+		while (events->current_event_data_size >=
+			dmxdevfilter->params.pes.rec_chunk_size) {
+			event.type = DMX_EVENT_NEW_REC_CHUNK;
+			event.params.recording_chunk.offset =
+				events->current_event_start_offset;
+			event.params.recording_chunk.size =
+				dmxdevfilter->params.pes.rec_chunk_size;
+			events->current_event_data_size =
+				events->current_event_data_size -
+				dmxdevfilter->params.pes.rec_chunk_size;
+			events->current_event_start_offset =
+				(events->current_event_start_offset +
+				dmxdevfilter->params.pes.rec_chunk_size) %
+				buffer->size;
+
+			dvb_dmxdev_add_event(events, &event);
+		}
+	}
+	spin_unlock(&dmxdevfilter->dev->lock);
+	wake_up_all(&buffer->queue);
 	return 0;
 }
 
@@ -427,11 +3096,18 @@
 	switch (dmxdevfilter->type) {
 	case DMXDEV_TYPE_SEC:
 		del_timer(&dmxdevfilter->timer);
-		dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
+		dmxdevfilter->feed.sec.feed->stop_filtering(
+			dmxdevfilter->feed.sec.feed);
 		break;
 	case DMXDEV_TYPE_PES:
-		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
+		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
+			if (dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP) {
+				dmxdevfilter->dev->dvr_feeds_count--;
+				if (!dmxdevfilter->dev->dvr_feeds_count)
+					dmxdevfilter->dev->dvr_feed = NULL;
+			}
 			feed->ts->stop_filtering(feed->ts);
+		}
 		break;
 	default:
 		return -EINVAL;
@@ -449,7 +3125,8 @@
 
 	switch (filter->type) {
 	case DMXDEV_TYPE_SEC:
-		return filter->feed.sec->start_filtering(filter->feed.sec);
+		return filter->feed.sec.feed->start_filtering(
+			filter->feed.sec.feed);
 	case DMXDEV_TYPE_PES:
 		list_for_each_entry(feed, &filter->feed.ts, next) {
 			ret = feed->ts->start_filtering(feed->ts);
@@ -483,7 +3160,7 @@
 		}
 
 	filter->dev->demux->release_section_feed(dmxdev->demux,
-						 filter->feed.sec);
+						 filter->feed.sec.feed);
 
 	return 0;
 }
@@ -492,25 +3169,38 @@
 {
 	struct dmxdev_feed *feed;
 	struct dmx_demux *demux;
+	struct ts_insertion_buffer *ts_buffer;
 
 	if (dmxdevfilter->state < DMXDEV_STATE_GO)
 		return 0;
 
 	switch (dmxdevfilter->type) {
 	case DMXDEV_TYPE_SEC:
-		if (!dmxdevfilter->feed.sec)
+		if (!dmxdevfilter->feed.sec.feed)
 			break;
 		dvb_dmxdev_feed_stop(dmxdevfilter);
 		if (dmxdevfilter->filter.sec)
-			dmxdevfilter->feed.sec->
-			    release_filter(dmxdevfilter->feed.sec,
+			dmxdevfilter->feed.sec.feed->
+			    release_filter(dmxdevfilter->feed.sec.feed,
 					   dmxdevfilter->filter.sec);
 		dvb_dmxdev_feed_restart(dmxdevfilter);
-		dmxdevfilter->feed.sec = NULL;
+		dmxdevfilter->feed.sec.feed = NULL;
 		break;
 	case DMXDEV_TYPE_PES:
 		dvb_dmxdev_feed_stop(dmxdevfilter);
 		demux = dmxdevfilter->dev->demux;
+
+		if (!list_empty(&dmxdevfilter->insertion_buffers)) {
+			feed = list_first_entry(&dmxdevfilter->feed.ts,
+				struct dmxdev_feed, next);
+
+			list_for_each_entry(ts_buffer,
+					&dmxdevfilter->insertion_buffers, next)
+				dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+			if (feed->ts->ts_insertion_terminate)
+				feed->ts->ts_insertion_terminate(feed->ts);
+		}
+
 		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
 			demux->release_ts_feed(demux, feed->ts);
 			feed->ts = NULL;
@@ -522,7 +3212,13 @@
 		return -EINVAL;
 	}
 
-	dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+	dvb_dmxdev_flush_output(&dmxdevfilter->buffer, &dmxdevfilter->events);
+	dvb_ringbuffer_reset(&dmxdevfilter->buffer);
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	wake_up_all(&dmxdevfilter->buffer.queue);
+
 	return 0;
 }
 
@@ -589,12 +3285,76 @@
 	tsfeed = feed->ts;
 	tsfeed->priv = filter;
 
-	ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
+	if (filter->params.pes.output == DMX_OUT_TS_TAP) {
+		tsfeed->buffer.ringbuff = &dmxdev->dvr_buffer;
+		tsfeed->buffer.priv_handle = dmxdev->dvr_priv_buff_handle;
+		if (!dmxdev->dvr_feeds_count)
+			dmxdev->dvr_feed = filter;
+		dmxdev->dvr_feeds_count++;
+	} else if (filter->params.pes.output == DMX_OUT_DECODER) {
+		tsfeed->buffer.ringbuff = &filter->buffer;
+		tsfeed->decoder_buffers = &filter->decoder_buffers;
+		tsfeed->buffer.priv_handle = filter->priv_buff_handle;
+	} else {
+		tsfeed->buffer.ringbuff = &filter->buffer;
+		tsfeed->buffer.priv_handle = filter->priv_buff_handle;
+	}
+
+	if (tsfeed->data_ready_cb) {
+		ret = tsfeed->data_ready_cb(tsfeed, dvb_dmxdev_ts_event_cb);
+
+		if (ret < 0) {
+			dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+			return ret;
+		}
+	}
+
+	ret = tsfeed->set(tsfeed, feed->pid,
+					ts_type, ts_pes,
+					filter->decoder_buffers.buffers_size,
+					timeout);
 	if (ret < 0) {
 		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
 		return ret;
 	}
 
+	if (tsfeed->set_tsp_out_format)
+		tsfeed->set_tsp_out_format(tsfeed, filter->dmx_tsp_format);
+
+	if (tsfeed->set_secure_mode)
+		tsfeed->set_secure_mode(tsfeed, &filter->sec_mode);
+
+	if (tsfeed->set_cipher_ops)
+		tsfeed->set_cipher_ops(tsfeed, &feed->cipher_ops);
+
+	if ((para->pes_type == DMX_PES_VIDEO0) ||
+	    (para->pes_type == DMX_PES_VIDEO1) ||
+	    (para->pes_type == DMX_PES_VIDEO2) ||
+	    (para->pes_type == DMX_PES_VIDEO3)) {
+		if (tsfeed->set_video_codec) {
+			ret = tsfeed->set_video_codec(tsfeed,
+							para->video_codec);
+
+			if (ret < 0) {
+				dmxdev->demux->release_ts_feed(dmxdev->demux,
+								tsfeed);
+				return ret;
+			}
+		}
+	}
+
+	if ((filter->params.pes.output == DMX_OUT_TS_TAP) ||
+		(filter->params.pes.output == DMX_OUT_TSDEMUX_TAP))
+		if (tsfeed->set_idx_params) {
+			ret = tsfeed->set_idx_params(
+					tsfeed, &feed->idx_params);
+			if (ret) {
+				dmxdev->demux->release_ts_feed(dmxdev->demux,
+					tsfeed);
+				return ret;
+			}
+		}
+
 	ret = tsfeed->start_filtering(tsfeed);
 	if (ret < 0) {
 		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
@@ -604,12 +3364,50 @@
 	return 0;
 }
 
+static int dvb_filter_external_buffer_only(struct dmxdev *dmxdev,
+	struct dmxdev_filter *filter)
+{
+	struct dmx_caps caps;
+	int is_external_only;
+	int flags;
+
+	/*
+	 * For backward compatibility, default assumes that
+	 * external only buffers are not supported.
+	 */
+	flags = 0;
+	if (dmxdev->demux->get_caps) {
+		dmxdev->demux->get_caps(dmxdev->demux, &caps);
+
+		if (filter->type == DMXDEV_TYPE_SEC)
+			flags = caps.section.flags;
+		else if (filter->params.pes.output == DMX_OUT_DECODER)
+			/* For decoder filters dmxdev buffer is not required */
+			flags = 0;
+		else if (filter->params.pes.output == DMX_OUT_TAP)
+			flags = caps.pes.flags;
+		else if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188)
+			flags = caps.recording_188_tsp.flags;
+		else
+			flags = caps.recording_192_tsp.flags;
+	}
+
+	if (!(flags & DMX_BUFFER_INTERNAL_SUPPORT) &&
+		(flags & DMX_BUFFER_EXTERNAL_SUPPORT))
+		is_external_only = 1;
+	else
+		is_external_only = 0;
+
+	return is_external_only;
+}
+
 static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
 {
 	struct dmxdev *dmxdev = filter->dev;
 	struct dmxdev_feed *feed;
 	void *mem;
 	int ret, i;
+	size_t tsp_size;
 
 	if (filter->state < DMXDEV_STATE_SET)
 		return -EINVAL;
@@ -617,34 +3415,64 @@
 	if (filter->state >= DMXDEV_STATE_GO)
 		dvb_dmxdev_filter_stop(filter);
 
+	if (!dvb_filter_verify_buffer_size(filter))
+		return -EINVAL;
+
 	if (!filter->buffer.data) {
-		mem = vmalloc(filter->buffer.size);
+		/*
+		 * dmxdev buffer in decoder filters is not really used
+		 * to exchange data with applications. Decoder buffers
+		 * can be set using DMX_SET_DECODER_BUFFER, which
+		 * would not update the filter->buffer.data at all.
+		 * Therefore we should not treat this filter as
+		 * other regular filters and should not fail here
+		 * even if user sets the buffer in deocder
+		 * filter as external buffer.
+		 */
+		if (filter->type == DMXDEV_TYPE_PES &&
+			(filter->params.pes.output == DMX_OUT_DECODER ||
+			filter->params.pes.output == DMX_OUT_TS_TAP))
+			filter->buffer_mode = DMX_BUFFER_MODE_INTERNAL;
+
+		if (!(filter->type == DMXDEV_TYPE_PES &&
+			filter->params.pes.output == DMX_OUT_TS_TAP) &&
+			(filter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL ||
+			dvb_filter_external_buffer_only(dmxdev, filter)))
+			return -ENOMEM;
+
+		mem = vmalloc_user(filter->buffer.size);
 		if (!mem)
 			return -ENOMEM;
 		spin_lock_irq(&filter->dev->lock);
 		filter->buffer.data = mem;
 		spin_unlock_irq(&filter->dev->lock);
+	} else if ((filter->buffer_mode == DMX_BUFFER_MODE_INTERNAL) &&
+			dvb_filter_external_buffer_only(dmxdev, filter)) {
+		return -ENOMEM;
 	}
 
-	dvb_ringbuffer_flush(&filter->buffer);
+	filter->eos_state = 0;
+
+	spin_lock_irq(&filter->dev->lock);
+	dvb_dmxdev_flush_output(&filter->buffer, &filter->events);
+	spin_unlock_irq(&filter->dev->lock);
 
 	switch (filter->type) {
 	case DMXDEV_TYPE_SEC:
 	{
 		struct dmx_sct_filter_params *para = &filter->params.sec;
 		struct dmx_section_filter **secfilter = &filter->filter.sec;
-		struct dmx_section_feed **secfeed = &filter->feed.sec;
+		struct dmx_section_feed **secfeed = &filter->feed.sec.feed;
 
 		*secfilter = NULL;
 		*secfeed = NULL;
 
-
 		/* find active filter/feed with same PID */
 		for (i = 0; i < dmxdev->filternum; i++) {
 			if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
 			    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
 			    dmxdev->filter[i].params.sec.pid == para->pid) {
-				*secfeed = dmxdev->filter[i].feed.sec;
+				*secfeed = dmxdev->filter[i].feed.sec.feed;
 				break;
 			}
 		}
@@ -652,22 +3480,44 @@
 		/* if no feed found, try to allocate new one */
 		if (!*secfeed) {
 			ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
-								   secfeed,
-								   dvb_dmxdev_section_callback);
+						secfeed,
+						dvb_dmxdev_section_callback);
 			if (ret < 0) {
-				printk("DVB (%s): could not alloc feed\n",
+				pr_err("DVB (%s): could not alloc feed\n",
 				       __func__);
 				return ret;
 			}
 
+			if ((*secfeed)->data_ready_cb) {
+				ret = (*secfeed)->data_ready_cb(
+						*secfeed,
+						dvb_dmxdev_section_event_cb);
+
+				if (ret < 0) {
+					pr_err(
+						"DVB (%s): could not set event cb\n",
+						__func__);
+					dvb_dmxdev_feed_restart(filter);
+					return ret;
+				}
+			}
+
 			ret = (*secfeed)->set(*secfeed, para->pid, 32768,
 					      (para->flags & DMX_CHECK_CRC) ? 1 : 0);
 			if (ret < 0) {
-				printk("DVB (%s): could not set feed\n",
-				       __func__);
+				pr_err("DVB (%s): could not set feed\n",
+					__func__);
 				dvb_dmxdev_feed_restart(filter);
 				return ret;
 			}
+
+			if ((*secfeed)->set_secure_mode)
+				(*secfeed)->set_secure_mode(*secfeed,
+					&filter->sec_mode);
+
+			if ((*secfeed)->set_cipher_ops)
+				(*secfeed)->set_cipher_ops(*secfeed,
+					&filter->feed.sec.cipher_ops);
 		} else {
 			dvb_dmxdev_feed_stop(filter);
 		}
@@ -675,12 +3525,14 @@
 		ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
 		if (ret < 0) {
 			dvb_dmxdev_feed_restart(filter);
-			filter->feed.sec->start_filtering(*secfeed);
-			dprintk("could not get filter\n");
+			filter->feed.sec.feed->start_filtering(*secfeed);
+			pr_debug("could not get filter\n");
 			return ret;
 		}
 
 		(*secfilter)->priv = filter;
+		(*secfilter)->buffer.ringbuff = &filter->buffer;
+		(*secfilter)->buffer.priv_handle = filter->priv_buff_handle;
 
 		memcpy(&((*secfilter)->filter_value[3]),
 		       &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
@@ -696,8 +3548,12 @@
 		(*secfilter)->filter_mask[2] = 0;
 
 		filter->todo = 0;
+		filter->events.data_read_event_masked =
+			filter->events.event_mask.disable_mask &
+			DMX_EVENT_NEW_SECTION;
 
-		ret = filter->feed.sec->start_filtering(filter->feed.sec);
+		ret = filter->feed.sec.feed->start_filtering(
+				filter->feed.sec.feed);
 		if (ret < 0)
 			return ret;
 
@@ -705,19 +3561,93 @@
 		break;
 	}
 	case DMXDEV_TYPE_PES:
+		if (filter->params.pes.rec_chunk_size <
+			DMX_REC_BUFF_CHUNK_MIN_SIZE)
+			filter->params.pes.rec_chunk_size =
+				DMX_REC_BUFF_CHUNK_MIN_SIZE;
+
+		if (filter->params.pes.rec_chunk_size >=
+			filter->buffer.size)
+			filter->params.pes.rec_chunk_size =
+				filter->buffer.size >> 2;
+
+		/* Align rec-chunk based on output format */
+		if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188)
+			tsp_size = 188;
+		else
+			tsp_size = 192;
+
+		filter->params.pes.rec_chunk_size /= tsp_size;
+		filter->params.pes.rec_chunk_size *= tsp_size;
+
+		if (filter->params.pes.output == DMX_OUT_TS_TAP)
+			dmxdev->dvr_output_events.data_read_event_masked =
+			 dmxdev->dvr_output_events.event_mask.disable_mask &
+			 DMX_EVENT_NEW_REC_CHUNK;
+		else if (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+			filter->events.data_read_event_masked =
+				filter->events.event_mask.disable_mask &
+				DMX_EVENT_NEW_REC_CHUNK;
+		else if (filter->params.pes.output == DMX_OUT_TAP)
+			filter->events.data_read_event_masked =
+				filter->events.event_mask.disable_mask &
+				DMX_EVENT_NEW_PES;
+		else
+			filter->events.data_read_event_masked = 1;
+
+		ret = 0;
 		list_for_each_entry(feed, &filter->feed.ts, next) {
 			ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
-			if (ret < 0) {
-				dvb_dmxdev_filter_stop(filter);
-				return ret;
+			if (ret)
+				break;
+		}
+
+		if (!ret)
+			break;
+
+		/* cleanup feeds that were started before the failure */
+		list_for_each_entry(feed, &filter->feed.ts, next) {
+			if (!feed->ts)
+				continue;
+			feed->ts->stop_filtering(feed->ts);
+			dmxdev->demux->release_ts_feed(dmxdev->demux, feed->ts);
+			feed->ts = NULL;
+
+			if (filter->params.pes.output == DMX_OUT_TS_TAP) {
+				filter->dev->dvr_feeds_count--;
+				if (!filter->dev->dvr_feeds_count)
+					filter->dev->dvr_feed = NULL;
 			}
 		}
-		break;
+		return ret;
+
 	default:
 		return -EINVAL;
 	}
 
 	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+
+	if ((filter->type == DMXDEV_TYPE_PES) &&
+		!list_empty(&filter->insertion_buffers)) {
+		struct ts_insertion_buffer *ts_buffer;
+
+		feed = list_first_entry(&filter->feed.ts,
+			struct dmxdev_feed, next);
+
+		ret = 0;
+		if (feed->ts->ts_insertion_init)
+			ret = feed->ts->ts_insertion_init(feed->ts);
+		if (!ret) {
+			list_for_each_entry(ts_buffer,
+				&filter->insertion_buffers, next)
+				dvb_dmxdev_queue_ts_insertion(
+					ts_buffer);
+		} else {
+			pr_err("%s: ts_insertion_init failed, err %d\n",
+				__func__, ret);
+		}
+	}
+
 	return 0;
 }
 
@@ -747,11 +3677,28 @@
 	mutex_init(&dmxdevfilter->mutex);
 	file->private_data = dmxdevfilter;
 
+	memset(&dmxdevfilter->decoder_buffers,
+			0,
+			sizeof(dmxdevfilter->decoder_buffers));
+	dmxdevfilter->decoder_buffers.buffers_size =
+		DMX_DEFAULT_DECODER_BUFFER_SIZE;
+	dmxdevfilter->buffer_mode = DMX_BUFFER_MODE_INTERNAL;
+	dmxdevfilter->priv_buff_handle = NULL;
 	dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
+	dvb_dmxdev_flush_events(&dmxdevfilter->events);
+	dmxdevfilter->events.event_mask.disable_mask = DMX_EVENT_NEW_ES_DATA;
+	dmxdevfilter->events.event_mask.no_wakeup_mask = 0;
+	dmxdevfilter->events.event_mask.wakeup_threshold = 1;
+
 	dmxdevfilter->type = DMXDEV_TYPE_NONE;
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
 	init_timer(&dmxdevfilter->timer);
 
+	dmxdevfilter->sec_mode.is_secured = 0;
+
+	INIT_LIST_HEAD(&dmxdevfilter->insertion_buffers);
+
+	dmxdevfilter->dmx_tsp_format = DMX_TSP_FORMAT_188;
 	dvbdev->users++;
 
 	mutex_unlock(&dmxdev->mutex);
@@ -761,23 +3708,40 @@
 static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
 				  struct dmxdev_filter *dmxdevfilter)
 {
+	struct ts_insertion_buffer *ts_buffer, *tmp;
+
 	mutex_lock(&dmxdev->mutex);
 	mutex_lock(&dmxdevfilter->mutex);
 
 	dvb_dmxdev_filter_stop(dmxdevfilter);
 	dvb_dmxdev_filter_reset(dmxdevfilter);
 
+	list_for_each_entry_safe(ts_buffer, tmp,
+			&dmxdevfilter->insertion_buffers, next) {
+		list_del(&ts_buffer->next);
+		vfree(ts_buffer->buffer);
+		vfree(ts_buffer);
+	}
+
 	if (dmxdevfilter->buffer.data) {
 		void *mem = dmxdevfilter->buffer.data;
 
 		spin_lock_irq(&dmxdev->lock);
 		dmxdevfilter->buffer.data = NULL;
 		spin_unlock_irq(&dmxdev->lock);
-		vfree(mem);
+		if (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL)
+			vfree(mem);
+	}
+
+	if ((dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) &&
+		dmxdevfilter->priv_buff_handle) {
+		dmxdev->demux->unmap_buffer(dmxdev->demux,
+			dmxdevfilter->priv_buff_handle);
+		dmxdevfilter->priv_buff_handle = NULL;
 	}
 
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
-	wake_up(&dmxdevfilter->buffer.queue);
+	wake_up_all(&dmxdevfilter->buffer.queue);
 	mutex_unlock(&dmxdevfilter->mutex);
 	mutex_unlock(&dmxdev->mutex);
 	return 0;
@@ -795,6 +3759,7 @@
 			      struct dmxdev_filter *filter, u16 pid)
 {
 	struct dmxdev_feed *feed;
+	int ret = 0;
 
 	if ((filter->type != DMXDEV_TYPE_PES) ||
 	    (filter->state < DMXDEV_STATE_SET))
@@ -810,28 +3775,45 @@
 		return -ENOMEM;
 
 	feed->pid = pid;
-	list_add(&feed->next, &filter->feed.ts);
+	feed->cipher_ops.operations_count = 0;
+	feed->idx_params.enable = 0;
 
 	if (filter->state >= DMXDEV_STATE_GO)
-		return dvb_dmxdev_start_feed(dmxdev, filter, feed);
+		ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
 
-	return 0;
+	if (!ret)
+		list_add(&feed->next, &filter->feed.ts);
+	else
+		kfree(feed);
+
+	return ret;
 }
 
 static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
 				  struct dmxdev_filter *filter, u16 pid)
 {
+	int feed_count;
 	struct dmxdev_feed *feed, *tmp;
 
 	if ((filter->type != DMXDEV_TYPE_PES) ||
 	    (filter->state < DMXDEV_STATE_SET))
 		return -EINVAL;
 
+	feed_count = 0;
+	list_for_each_entry(tmp, &filter->feed.ts, next)
+		feed_count++;
+
+	if (feed_count <= 1)
+		return -EINVAL;
+
 	list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
-		if ((feed->pid == pid) && (feed->ts != NULL)) {
-			feed->ts->stop_filtering(feed->ts);
-			filter->dev->demux->release_ts_feed(filter->dev->demux,
-							    feed->ts);
+		if (feed->pid == pid) {
+			if (feed->ts != NULL) {
+				feed->ts->stop_filtering(feed->ts);
+				filter->dev->demux->release_ts_feed(
+							filter->dev->demux,
+							feed->ts);
+			}
 			list_del(&feed->next);
 			kfree(feed);
 		}
@@ -844,7 +3826,7 @@
 				 struct dmxdev_filter *dmxdevfilter,
 				 struct dmx_sct_filter_params *params)
 {
-	dprintk("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n",
+	pr_debug("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n",
 		__func__, params->pid, params->flags, params->timeout);
 
 	dvb_dmxdev_filter_stop(dmxdevfilter);
@@ -853,6 +3835,7 @@
 	memcpy(&dmxdevfilter->params.sec,
 	       params, sizeof(struct dmx_sct_filter_params));
 	invert_mode(&dmxdevfilter->params.sec.filter);
+	dmxdevfilter->feed.sec.cipher_ops.operations_count = 0;
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
 
 	if (params->flags & DMX_IMMEDIATE_START)
@@ -861,6 +3844,99 @@
 	return 0;
 }
 
+static int dvb_dmxdev_set_secure_mode(
+	struct dmxdev *dmxdev,
+	struct dmxdev_filter *filter,
+	struct dmx_secure_mode *sec_mode)
+{
+	if (!dmxdev || !filter || !sec_mode)
+		return -EINVAL;
+
+	if (filter->state == DMXDEV_STATE_GO) {
+		pr_err("%s: invalid filter state\n", __func__);
+		return -EBUSY;
+	}
+
+	pr_debug("%s: secure=%d\n", __func__, sec_mode->is_secured);
+
+	filter->sec_mode = *sec_mode;
+
+	return 0;
+}
+
+static int dvb_dmxdev_set_cipher(struct dmxdev *dmxdev,
+	struct dmxdev_filter *filter,
+	struct dmx_cipher_operations *cipher_ops)
+{
+	struct dmxdev_feed *feed;
+	struct dmxdev_feed *ts_feed = NULL;
+	struct dmxdev_sec_feed *sec_feed = NULL;
+	struct dmx_caps caps;
+
+	if (!dmxdev || !dmxdev->demux->get_caps)
+		return -EINVAL;
+
+	dmxdev->demux->get_caps(dmxdev->demux, &caps);
+
+	if (!filter || !cipher_ops ||
+		(cipher_ops->operations_count > caps.num_cipher_ops) ||
+		(cipher_ops->operations_count >
+			DMX_MAX_CIPHER_OPERATIONS_COUNT))
+		return -EINVAL;
+
+	pr_debug("%s: pid=%d, operations=%d\n", __func__,
+		cipher_ops->pid, cipher_ops->operations_count);
+
+	if (filter->state < DMXDEV_STATE_SET ||
+		filter->state > DMXDEV_STATE_GO) {
+		pr_err("%s: invalid filter state\n", __func__);
+		return -EPERM;
+	}
+
+	if (!filter->sec_mode.is_secured && cipher_ops->operations_count) {
+		pr_err("%s: secure mode must be enabled to set cipher ops\n",
+			__func__);
+		return -EPERM;
+	}
+
+	switch (filter->type) {
+	case DMXDEV_TYPE_PES:
+		list_for_each_entry(feed, &filter->feed.ts, next) {
+			if (feed->pid == cipher_ops->pid) {
+				ts_feed = feed;
+				ts_feed->cipher_ops = *cipher_ops;
+				if (filter->state == DMXDEV_STATE_GO &&
+					ts_feed->ts->set_cipher_ops)
+					ts_feed->ts->set_cipher_ops(
+						ts_feed->ts, cipher_ops);
+				break;
+			}
+		}
+		break;
+	case DMXDEV_TYPE_SEC:
+		if (filter->params.sec.pid == cipher_ops->pid) {
+			sec_feed = &filter->feed.sec;
+			sec_feed->cipher_ops = *cipher_ops;
+			if (filter->state == DMXDEV_STATE_GO &&
+				sec_feed->feed->set_cipher_ops)
+				sec_feed->feed->set_cipher_ops(sec_feed->feed,
+						cipher_ops);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (!ts_feed && !sec_feed) {
+		pr_err("%s: pid %d is undefined for this filter\n",
+			__func__, cipher_ops->pid);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
 				     struct dmxdev_filter *dmxdevfilter,
 				     struct dmx_pes_filter_params *params)
@@ -891,6 +3967,55 @@
 	return 0;
 }
 
+static int dvb_dmxdev_set_decoder_buffer(struct dmxdev *dmxdev,
+		struct dmxdev_filter *filter,
+		struct dmx_decoder_buffers *buffs)
+{
+	int i;
+	struct dmx_decoder_buffers *dec_buffs;
+	struct dmx_caps caps;
+
+	if (!dmxdev || !filter || !buffs)
+		return -EINVAL;
+
+	dec_buffs = &filter->decoder_buffers;
+	if (!dmxdev->demux->get_caps)
+		return -EINVAL;
+
+	dmxdev->demux->get_caps(dmxdev->demux, &caps);
+	if (!dvb_dmxdev_verify_buffer_size(buffs->buffers_size,
+			caps.decoder.max_size, caps.decoder.size_alignment))
+		return -EINVAL;
+
+	if ((buffs->buffers_size == 0) ||
+		(buffs->is_linear &&
+		 ((buffs->buffers_num <= 1) ||
+		  (buffs->buffers_num > DMX_MAX_DECODER_BUFFER_NUM))))
+		return -EINVAL;
+
+	if (buffs->buffers_num == 0) {
+		/* Internal mode - linear buffers not supported in this mode */
+		if (!(caps.decoder.flags & DMX_BUFFER_INTERNAL_SUPPORT) ||
+			buffs->is_linear)
+			return -EINVAL;
+	} else {
+		/* External buffer(s) mode */
+		if ((!(caps.decoder.flags & DMX_BUFFER_LINEAR_GROUP_SUPPORT) &&
+			buffs->buffers_num > 1) ||
+			!(caps.decoder.flags & DMX_BUFFER_EXTERNAL_SUPPORT) ||
+			buffs->buffers_num > caps.decoder.max_buffer_num)
+			return -EINVAL;
+
+		dec_buffs->is_linear = buffs->is_linear;
+		dec_buffs->buffers_num = buffs->buffers_num;
+		dec_buffs->buffers_size = buffs->buffers_size;
+		for (i = 0; i < dec_buffs->buffers_num; i++)
+			dec_buffs->handles[i] = buffs->handles[i];
+	}
+
+	return 0;
+}
+
 static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
 				   struct file *file, char __user *buf,
 				   size_t count, loff_t *ppos)
@@ -902,7 +4027,7 @@
 		hcount = 3 + dfil->todo;
 		if (hcount > count)
 			hcount = count;
-		result = dvb_dmxdev_buffer_read(&dfil->buffer,
+		result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
 						file->f_flags & O_NONBLOCK,
 						buf, hcount, ppos);
 		if (result < 0) {
@@ -923,7 +4048,7 @@
 	}
 	if (count > dfil->todo)
 		count = dfil->todo;
-	result = dvb_dmxdev_buffer_read(&dfil->buffer,
+	result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
 					file->f_flags & O_NONBLOCK,
 					buf, count, ppos);
 	if (result < 0)
@@ -942,12 +4067,36 @@
 	if (mutex_lock_interruptible(&dmxdevfilter->mutex))
 		return -ERESTARTSYS;
 
+	if (dmxdevfilter->eos_state &&
+		dvb_ringbuffer_empty(&dmxdevfilter->buffer)) {
+		mutex_unlock(&dmxdevfilter->mutex);
+		return 0;
+	}
+
 	if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
 		ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
 	else
-		ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
-					     file->f_flags & O_NONBLOCK,
-					     buf, count, ppos);
+		ret = dvb_dmxdev_buffer_read(dmxdevfilter,
+					&dmxdevfilter->buffer,
+					file->f_flags & O_NONBLOCK,
+					buf, count, ppos);
+
+	if (ret > 0) {
+		dvb_dmxdev_notify_data_read(dmxdevfilter, ret);
+		spin_lock_irq(&dmxdevfilter->dev->lock);
+		dvb_dmxdev_update_events(&dmxdevfilter->events, ret);
+		spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+		/*
+		 * in PULL mode, we might be stalling on
+		 * event queue, so need to wake-up waiters
+		 */
+		if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL)
+			wake_up_all(&dmxdevfilter->buffer.queue);
+	} else if (ret == -EOVERFLOW) {
+		dvb_dmxdev_auto_flush_buffer(dmxdevfilter,
+			&dmxdevfilter->buffer);
+	}
 
 	mutex_unlock(&dmxdevfilter->mutex);
 	return ret;
@@ -1013,6 +4162,43 @@
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
+	case DMX_SET_BUFFER_MODE:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_buffer_mode(dmxdevfilter,
+				*(enum dmx_buffer_mode *)parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_BUFFER:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_buffer(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_GET_BUFFER_STATUS:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_get_buffer_status(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_RELEASE_DATA:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_release_data(dmxdevfilter, arg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
 	case DMX_GET_PES_PIDS:
 		if (!dmxdev->demux->get_pes_pids) {
 			ret = -EINVAL;
@@ -1021,9 +4207,6 @@
 		dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
 		break;
 
-#if 0
-	/* Not used upstream and never documented */
-
 	case DMX_GET_CAPS:
 		if (!dmxdev->demux->get_caps) {
 			ret = -EINVAL;
@@ -1033,13 +4216,65 @@
 		break;
 
 	case DMX_SET_SOURCE:
-		if (!dmxdev->demux->set_source) {
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_source(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_TS_PACKET_FORMAT:
+		if (!dmxdev->demux->set_tsp_format) {
 			ret = -EINVAL;
 			break;
 		}
-		ret = dmxdev->demux->set_source(dmxdev->demux, parg);
+
+		if (dmxdevfilter->state >= DMXDEV_STATE_GO) {
+			ret = -EBUSY;
+			break;
+		}
+		ret = dmxdev->demux->set_tsp_format(
+				dmxdev->demux,
+				*(enum dmx_tsp_format_t *)parg);
 		break;
-#endif
+
+	case DMX_SET_TS_OUT_FORMAT:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+
+		ret = dvb_dmxdev_set_tsp_out_format(dmxdevfilter,
+				*(enum dmx_tsp_format_t *)parg);
+
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_DECODER_BUFFER_SIZE:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+
+		ret = dvb_dmxdev_set_decoder_buffer_size(dmxdevfilter, arg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_PLAYBACK_MODE:
+		ret = dvb_dmxdev_set_playback_mode(
+				dmxdevfilter,
+				*(enum dmx_playback_mode_t *)parg);
+		break;
+
+	case DMX_GET_EVENT:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_get_event(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
 
 	case DMX_GET_STC:
 		if (!dmxdev->demux->get_stc) {
@@ -1070,8 +4305,109 @@
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
+	case DMX_SET_DECODER_BUFFER:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		ret = dvb_dmxdev_set_decoder_buffer(dmxdev, dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_SECURE_MODE:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		ret = dvb_dmxdev_set_secure_mode(dmxdev, dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_CIPHER:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		ret = dvb_dmxdev_set_cipher(dmxdev, dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_REUSE_DECODER_BUFFER:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_reuse_decoder_buf(dmxdevfilter, arg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_EVENTS_MASK:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_event_mask(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_GET_EVENTS_MASK:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_get_event_mask(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_INDEXING_PARAMS:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_indexing_params(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_TS_INSERTION:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_ts_insertion(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_ABORT_TS_INSERTION:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_abort_ts_insertion(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_GET_SCRAMBLING_BITS:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_get_scrambling_bits(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_FLUSH_BUFFER:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_flush_buffer(dmxdevfilter);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
 	default:
-		ret = -EINVAL;
+		pr_err("%s: unknown ioctl code (0x%x)\n",
+			__func__, cmd);
+		ret = -ENOIOCTLCMD;
 		break;
 	}
 	mutex_unlock(&dmxdev->mutex);
@@ -1084,13 +4420,78 @@
 	return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
 }
 
+#ifdef CONFIG_COMPAT
+
+struct dmx_set_ts_insertion32 {
+	__u32 identifier;
+	__u32 repetition_time;
+	compat_uptr_t ts_packets;
+	compat_size_t size;
+};
+
+static long dmx_set_ts_insertion32_wrapper(struct file *file, unsigned int cmd,
+	    unsigned long arg)
+{
+	int ret;
+	struct dmx_set_ts_insertion32 dmx_ts_insert32;
+	struct dmx_set_ts_insertion dmx_ts_insert;
+
+	ret = copy_from_user(&dmx_ts_insert32, (void __user *)arg,
+		sizeof(dmx_ts_insert32));
+	if (ret) {
+		pr_err(
+			"%s: copy dmx_set_ts_insertion32 from user failed, ret=%d\n",
+			__func__, ret);
+		return -EFAULT;
+	}
+
+	memset(&dmx_ts_insert, 0, sizeof(dmx_ts_insert));
+	dmx_ts_insert.identifier = dmx_ts_insert32.identifier;
+	dmx_ts_insert.repetition_time = dmx_ts_insert32.repetition_time;
+	dmx_ts_insert.ts_packets = compat_ptr(dmx_ts_insert32.ts_packets);
+	dmx_ts_insert.size = dmx_ts_insert32.size;
+
+	ret = dvb_demux_do_ioctl(file, DMX_SET_TS_INSERTION, &dmx_ts_insert);
+
+	return ret;
+}
+
+#define DMX_SET_TS_INSERTION32 _IOW('o', 70, struct dmx_set_ts_insertion32)
+
+/*
+ * compat ioctl is called whenever compatibility is required, i.e when a 32bit
+ * process calls an ioctl for a 64bit kernel.
+ */
+static long dvb_demux_compat_ioctl(struct file *file, unsigned int cmd,
+			    unsigned long arg)
+{
+	long ret = 0;
+
+	switch (cmd) {
+	case DMX_SET_TS_INSERTION32:
+		ret = dmx_set_ts_insertion32_wrapper(file, cmd, arg);
+		break;
+	case DMX_SET_TS_INSERTION:
+		pr_err("%s: 64bit ioctl code (0x%lx) used by 32bit userspace\n",
+			__func__, DMX_SET_TS_INSERTION);
+		ret = -ENOIOCTLCMD;
+		break;
+	default:
+		/* use regular ioctl */
+		ret = dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
+	}
+
+	return ret;
+}
+#endif
+
 static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
 {
 	struct dmxdev_filter *dmxdevfilter = file->private_data;
 	unsigned int mask = 0;
 
-	if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
-		return POLLERR;
+	if (!dmxdevfilter)
+		return -EINVAL;
 
 	poll_wait(file, &dmxdevfilter->buffer.queue, wait);
 
@@ -1099,20 +4500,80 @@
 	    dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
 		return 0;
 
-	if (dmxdevfilter->buffer.error)
-		mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+	if (dmxdevfilter->buffer.error) {
+		mask |= (POLLIN | POLLRDNORM | POLLERR);
+		if (dmxdevfilter->buffer.error == -EOVERFLOW)
+			mask |= POLLPRI;
+	}
 
 	if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
-		mask |= (POLLIN | POLLRDNORM | POLLPRI);
+		mask |= (POLLIN | POLLRDNORM);
+
+	if (dmxdevfilter->events.wakeup_events_counter >=
+		dmxdevfilter->events.event_mask.wakeup_threshold)
+		mask |= POLLPRI;
 
 	return mask;
 }
 
+static int dvb_demux_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct dmxdev_filter *dmxdevfilter = filp->private_data;
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	int ret;
+	int vma_size;
+	int buffer_size;
+
+	vma_size = vma->vm_end - vma->vm_start;
+
+	if (vma->vm_flags & VM_WRITE)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&dmxdev->mutex))
+		return -ERESTARTSYS;
+
+	if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+		mutex_unlock(&dmxdev->mutex);
+		return -ERESTARTSYS;
+	}
+
+	if ((!dmxdevfilter->buffer.data) ||
+		(dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL)) {
+		mutex_unlock(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdev->mutex);
+		return -EINVAL;
+	}
+
+	/* Make sure requested mapping is not larger than buffer size */
+	buffer_size = dmxdevfilter->buffer.size + (PAGE_SIZE-1);
+	buffer_size = buffer_size & ~(PAGE_SIZE-1);
+
+	if (vma_size != buffer_size) {
+		mutex_unlock(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdev->mutex);
+		return -EINVAL;
+	}
+
+	ret = remap_vmalloc_range(vma, dmxdevfilter->buffer.data, 0);
+	if (ret) {
+		mutex_unlock(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdev->mutex);
+		return ret;
+	}
+
+	vma->vm_flags |= VM_DONTDUMP;
+	vma->vm_flags |= VM_DONTEXPAND;
+
+	mutex_unlock(&dmxdevfilter->mutex);
+	mutex_unlock(&dmxdev->mutex);
+
+	return 0;
+}
+
 static int dvb_demux_release(struct inode *inode, struct file *file)
 {
 	struct dmxdev_filter *dmxdevfilter = file->private_data;
 	struct dmxdev *dmxdev = dmxdevfilter->dev;
-
 	int ret;
 
 	ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
@@ -1120,6 +4581,8 @@
 	mutex_lock(&dmxdev->mutex);
 	dmxdev->dvbdev->users--;
 	if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
+		fops_put(file->f_op);
+		file->f_op = NULL;
 		mutex_unlock(&dmxdev->mutex);
 		wake_up(&dmxdev->dvbdev->wait_queue);
 	} else
@@ -1136,6 +4599,10 @@
 	.release = dvb_demux_release,
 	.poll = dvb_demux_poll,
 	.llseek = default_llseek,
+	.mmap = dvb_demux_mmap,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = dvb_demux_compat_ioctl,
+#endif
 };
 
 static const struct dvb_device dvbdev_demux = {
@@ -1161,11 +4628,44 @@
 
 	switch (cmd) {
 	case DMX_SET_BUFFER_SIZE:
-		ret = dvb_dvr_set_buffer_size(dmxdev, arg);
+		ret = dvb_dvr_set_buffer_size(dmxdev, file->f_flags, arg);
+		break;
+
+	case DMX_SET_BUFFER_MODE:
+		ret = dvb_dvr_set_buffer_mode(dmxdev, file->f_flags,
+			*(enum dmx_buffer_mode *)parg);
+		break;
+
+	case DMX_SET_BUFFER:
+		ret = dvb_dvr_set_buffer(dmxdev, file->f_flags, parg);
+		break;
+
+	case DMX_GET_BUFFER_STATUS:
+		ret = dvb_dvr_get_buffer_status(dmxdev, file->f_flags, parg);
+		break;
+
+	case DMX_RELEASE_DATA:
+		ret = dvb_dvr_release_data(dmxdev, file->f_flags, arg);
+		break;
+
+	case DMX_FEED_DATA:
+		ret = dvb_dvr_feed_data(dmxdev, file->f_flags, arg);
+		break;
+
+	case DMX_GET_EVENT:
+		ret = dvb_dvr_get_event(dmxdev, file->f_flags, parg);
+		break;
+
+	case DMX_PUSH_OOB_COMMAND:
+		ret = dvb_dvr_push_oob_cmd(dmxdev, file->f_flags, parg);
+		break;
+
+	case DMX_FLUSH_BUFFER:
+		ret = dvb_dvr_flush_buffer(dmxdev, file->f_flags);
 		break;
 
 	default:
-		ret = -EINVAL;
+		ret = -ENOIOCTLCMD;
 		break;
 	}
 	mutex_unlock(&dmxdev->mutex);
@@ -1173,32 +4673,50 @@
 }
 
 static long dvb_dvr_ioctl(struct file *file,
-			 unsigned int cmd, unsigned long arg)
+			unsigned int cmd, unsigned long arg)
 {
 	return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
 }
 
+#ifdef CONFIG_COMPAT
+static long dvb_dvr_compat_ioctl(struct file *file, unsigned int cmd,
+			unsigned long arg)
+{
+	return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
+}
+#endif
+
 static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 	unsigned int mask = 0;
 
-	dprintk("function : %s\n", __func__);
-
-	if (dmxdev->exit)
-		return POLLERR;
-
-	poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
+	pr_debug("function : %s\n", __func__);
 
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		if (dmxdev->dvr_buffer.error)
-			mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+		poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
+
+		if (dmxdev->dvr_buffer.error) {
+			mask |= (POLLIN | POLLRDNORM | POLLERR);
+			if (dmxdev->dvr_buffer.error == -EOVERFLOW)
+				mask |= POLLPRI;
+		}
 
 		if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
-			mask |= (POLLIN | POLLRDNORM | POLLPRI);
-	} else
-		mask |= (POLLOUT | POLLWRNORM | POLLPRI);
+			mask |= (POLLIN | POLLRDNORM);
+
+		if (dmxdev->dvr_output_events.wakeup_events_counter >=
+			dmxdev->dvr_output_events.event_mask.wakeup_threshold)
+			mask |= POLLPRI;
+	} else {
+		poll_wait(file, &dmxdev->dvr_input_buffer.queue, wait);
+		if (dmxdev->dvr_input_buffer.error)
+			mask |= (POLLOUT | POLLRDNORM | POLLPRI | POLLERR);
+
+		if (dvb_ringbuffer_free(&dmxdev->dvr_input_buffer))
+			mask |= (POLLOUT | POLLRDNORM | POLLPRI);
+	}
 
 	return mask;
 }
@@ -1207,7 +4725,11 @@
 	.owner = THIS_MODULE,
 	.read = dvb_dvr_read,
 	.write = dvb_dvr_write,
+	.mmap = dvb_dvr_mmap,
 	.unlocked_ioctl = dvb_dvr_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = dvb_dvr_compat_ioctl,
+#endif
 	.open = dvb_dvr_open,
 	.release = dvb_dvr_release,
 	.poll = dvb_dvr_poll,
@@ -1223,9 +4745,94 @@
 #endif
 	.fops = &dvb_dvr_fops
 };
+
+
+/**
+ * debugfs service to print active filters information.
+ */
+static int dvb_dmxdev_dbgfs_print(struct seq_file *s, void *p)
+{
+	int i;
+	struct dmxdev *dmxdev = s->private;
+	struct dmxdev_filter *filter;
+	int active_count = 0;
+	struct dmx_buffer_status buffer_status;
+	struct dmx_scrambling_bits scrambling_bits;
+	static const char * const pes_feeds[] = {"DEC", "PES", "DVR", "REC"};
+	int ret;
+
+	if (!dmxdev)
+		return 0;
+
+	for (i = 0; i < dmxdev->filternum; i++) {
+		filter = &dmxdev->filter[i];
+		if (filter->state >= DMXDEV_STATE_GO) {
+			active_count++;
+
+			seq_printf(s, "filter_%02d - ", i);
+
+			if (filter->type == DMXDEV_TYPE_SEC) {
+				seq_puts(s, "type: SEC, ");
+				seq_printf(s, "PID %04d ",
+						filter->params.sec.pid);
+				scrambling_bits.pid = filter->params.sec.pid;
+			} else {
+				seq_printf(s, "type: %s, ",
+					pes_feeds[filter->params.pes.output]);
+				seq_printf(s, "PID: %04d ",
+						filter->params.pes.pid);
+				scrambling_bits.pid = filter->params.pes.pid;
+			}
+
+			dvb_dmxdev_get_scrambling_bits(filter,
+				&scrambling_bits);
+
+			if (filter->type == DMXDEV_TYPE_PES &&
+				filter->params.pes.output == DMX_OUT_TS_TAP)
+				ret = dvb_dvr_get_buffer_status(dmxdev,
+					O_RDONLY, &buffer_status);
+			else
+				ret = dvb_dmxdev_get_buffer_status(filter,
+					&buffer_status);
+			if (!ret) {
+				seq_printf(s, "size: %08d, ",
+					buffer_status.size);
+				seq_printf(s, "fullness: %08d, ",
+					buffer_status.fullness);
+				seq_printf(s, "error: %d, ",
+					buffer_status.error);
+			}
+
+			seq_printf(s, "scramble: %d, ",
+				scrambling_bits.value);
+			seq_printf(s, "secured: %d\n",
+				filter->sec_mode.is_secured);
+		}
+	}
+
+	if (!active_count)
+		seq_puts(s, "No active filters\n");
+
+	return 0;
+}
+
+static int dvb_dmxdev_dbgfs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dvb_dmxdev_dbgfs_print, inode->i_private);
+}
+
+static const struct file_operations dbgfs_filters_fops = {
+	.open = dvb_dmxdev_dbgfs_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
 int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
 {
 	int i;
+	struct dmx_caps caps;
 
 	if (dmxdev->demux->open(dmxdev->demux) < 0)
 		return -EUSERS;
@@ -1234,8 +4841,12 @@
 	if (!dmxdev->filter)
 		return -ENOMEM;
 
+	dmxdev->playback_mode = DMX_PB_MODE_PUSH;
+	dmxdev->demux->dvr_input_protected = 0;
+
 	mutex_init(&dmxdev->mutex);
 	spin_lock_init(&dmxdev->lock);
+	spin_lock_init(&dmxdev->dvr_in_lock);
 	for (i = 0; i < dmxdev->filternum; i++) {
 		dmxdev->filter[i].dev = dmxdev;
 		dmxdev->filter[i].buffer.data = NULL;
@@ -1244,11 +4855,24 @@
 	}
 
 	dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
-			    DVB_DEVICE_DEMUX, dmxdev->filternum);
+			    DVB_DEVICE_DEMUX, 0);
 	dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
-			    dmxdev, DVB_DEVICE_DVR, dmxdev->filternum);
+			    dmxdev, DVB_DEVICE_DVR, 0);
 
 	dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
+	dvb_ringbuffer_init(&dmxdev->dvr_input_buffer, NULL, 8192);
+
+	/* Disable auto buffer flushing if plugin does not allow it */
+	if (dmxdev->demux->get_caps) {
+		dmxdev->demux->get_caps(dmxdev->demux, &caps);
+		if (!(caps.caps & DMX_CAP_AUTO_BUFFER_FLUSH))
+			overflow_auto_flush = 0;
+	}
+
+	if (dmxdev->demux->debugfs_demux_dir)
+		debugfs_create_file("filters", 0444,
+			dmxdev->demux->debugfs_demux_dir, dmxdev,
+			&dbgfs_filters_fops);
 
 	return 0;
 }
diff --git a/drivers/media/dvb-core/dmxdev.h b/drivers/media/dvb-core/dmxdev.h
index 48c6cf9..ad007f4 100644
--- a/drivers/media/dvb-core/dmxdev.h
+++ b/drivers/media/dvb-core/dmxdev.h
@@ -33,7 +33,7 @@
 #include <linux/string.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-
+#include <linux/kthread.h>
 #include <linux/dvb/dmx.h>
 
 #include "dvbdev.h"
@@ -57,10 +57,87 @@
 
 struct dmxdev_feed {
 	u16 pid;
+	struct dmx_indexing_params idx_params;
+	struct dmx_cipher_operations cipher_ops;
 	struct dmx_ts_feed *ts;
 	struct list_head next;
 };
 
+struct dmxdev_sec_feed {
+	struct dmx_section_feed *feed;
+	struct dmx_cipher_operations cipher_ops;
+};
+
+struct dmxdev_events_queue {
+	/*
+	 * indices used to manage events queue.
+	 * read_index advanced when relevant data is read
+	 * from the buffer.
+	 * notified_index is the index from which next events
+	 * are returned.
+	 * read_index <= notified_index <= write_index
+	 *
+	 * If user reads the data without getting the respective
+	 * event first, the read/notified indices are updated
+	 * automatically to reflect the actual data that exist
+	 * in the buffer.
+	 */
+	u32 read_index;
+	u32 write_index;
+	u32 notified_index;
+
+	/* Bytes read by user without having respective event in the queue */
+	u32 bytes_read_no_event;
+
+	/* internal tracking of PES and recording events */
+	u32 current_event_data_size;
+	u32 current_event_start_offset;
+
+	/* current setting of the events masking */
+	struct dmx_events_mask event_mask;
+
+	/*
+	 * indicates if an event used for data-reading from demux
+	 * filter is enabled or not. These are events on which
+	 * user may wait for before calling read() on the demux filter.
+	 */
+	int data_read_event_masked;
+
+	/*
+	 * holds the current number of pending events in the
+	 * events queue that are considered as a wake-up source
+	 */
+	u32 wakeup_events_counter;
+
+	struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE];
+};
+
+#define DMX_MIN_INSERTION_REPETITION_TIME	25 /* in msec */
+struct ts_insertion_buffer {
+	/* work scheduled for insertion of this buffer */
+	struct delayed_work dwork;
+
+	struct list_head next;
+
+	/* buffer holding TS packets for insertion */
+	char *buffer;
+
+	/* buffer size */
+	size_t size;
+
+	/* buffer ID from user */
+	u32 identifier;
+
+	/* repetition time for the buffer insertion */
+	u32 repetition_time;
+
+	/* the recording filter to which this buffer belongs */
+	struct dmxdev_filter *dmxdevfilter;
+
+	/* indication whether insertion should be aborted */
+	int abort;
+};
+
 struct dmxdev_filter {
 	union {
 		struct dmx_section_filter *sec;
@@ -69,7 +146,7 @@
 	union {
 		/* list of TS and PES feeds (struct dmxdev_feed) */
 		struct list_head ts;
-		struct dmx_section_feed *sec;
+		struct dmxdev_sec_feed sec;
 	} feed;
 
 	union {
@@ -77,19 +154,37 @@
 		struct dmx_pes_filter_params pes;
 	} params;
 
+	struct dmxdev_events_queue events;
+
 	enum dmxdev_type type;
 	enum dmxdev_state state;
 	struct dmxdev *dev;
 	struct dvb_ringbuffer buffer;
+	void *priv_buff_handle;
+	enum dmx_buffer_mode buffer_mode;
 
 	struct mutex mutex;
 
+	/* for recording output */
+	enum dmx_tsp_format_t dmx_tsp_format;
+	u32 rec_chunk_size;
+
+	/* list of buffers used for insertion (struct ts_insertion_buffer) */
+	struct list_head insertion_buffers;
+
+	/* End-of-stream indication has been received */
+	int eos_state;
+
 	/* only for sections */
 	struct timer_list timer;
 	int todo;
 	u8 secheader[3];
-};
 
+	struct dmx_secure_mode sec_mode;
+
+	/* Decoder buffer(s) related */
+	struct dmx_decoder_buffers decoder_buffers;
+};
 
 struct dmxdev {
 	struct dvb_device *dvbdev;
@@ -100,18 +195,52 @@
 
 	int filternum;
 	int capabilities;
+#define DMXDEV_CAP_DUPLEX	0x01
+
+	enum dmx_playback_mode_t playback_mode;
+	dmx_source_t source;
 
 	unsigned int exit:1;
-#define DMXDEV_CAP_DUPLEX 1
+	unsigned int dvr_in_exit:1;
+	unsigned int dvr_processing_input:1;
+
 	struct dmx_frontend *dvr_orig_fe;
 
 	struct dvb_ringbuffer dvr_buffer;
+	void *dvr_priv_buff_handle;
+	enum dmx_buffer_mode dvr_buffer_mode;
+	struct dmxdev_events_queue dvr_output_events;
+	struct dmxdev_filter *dvr_feed;
+	int dvr_feeds_count;
+
+	struct dvb_ringbuffer dvr_input_buffer;
+	enum dmx_buffer_mode dvr_input_buffer_mode;
+	struct task_struct *dvr_input_thread;
+	/* DVR commands (data feed / OOB command) queue */
+	struct dvb_ringbuffer dvr_cmd_buffer;
+
 #define DVR_BUFFER_SIZE (10*188*1024)
 
 	struct mutex mutex;
 	spinlock_t lock;
+	spinlock_t dvr_in_lock;
 };
 
+enum dvr_cmd {
+	DVR_DATA_FEED_CMD,
+	DVR_OOB_CMD
+};
+
+struct dvr_command {
+	enum dvr_cmd type;
+	union {
+		struct dmx_oob_command oobcmd;
+		size_t data_feed_count;
+	} cmd;
+};
+
+#define DVR_CMDS_BUFFER_SIZE (sizeof(struct dvr_command)*500)
+
 
 int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
 void dvb_dmxdev_release(struct dmxdev *dmxdev);
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
index a0cf7b0..474684f 100644
--- a/drivers/media/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -55,11 +55,151 @@
 MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
 		 "when set to 0, drop packets with the TEI bit set (1 by default)");
 
+/* counter advancing for each new dvb-demux device */
+static int dvb_demux_index;
+
+static int dvb_demux_performancecheck;
+module_param(dvb_demux_performancecheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_performancecheck,
+		"enable transport stream performance check, reported through debugfs");
+
 #define dprintk_tscheck(x...) do {                              \
 		if (dvb_demux_tscheck && printk_ratelimit())    \
 			printk(x);                              \
 	} while (0)
 
+static const struct dvb_dmx_video_patterns mpeg2_seq_hdr = {
+	{0x00, 0x00, 0x01, 0xB3},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_MPEG_SEQ_HEADER
+};
+
+static const struct dvb_dmx_video_patterns mpeg2_gop = {
+	{0x00, 0x00, 0x01, 0xB8},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_MPEG_GOP
+};
+
+static const struct dvb_dmx_video_patterns mpeg2_iframe = {
+	{0x00, 0x00, 0x01, 0x00, 0x00, 0x08},
+	{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38},
+	6,
+	DMX_IDX_MPEG_I_FRAME_START
+};
+
+static const struct dvb_dmx_video_patterns mpeg2_pframe = {
+	{0x00, 0x00, 0x01, 0x00, 0x00, 0x10},
+	{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38},
+	6,
+	DMX_IDX_MPEG_P_FRAME_START
+};
+
+static const struct dvb_dmx_video_patterns mpeg2_bframe = {
+	{0x00, 0x00, 0x01, 0x00, 0x00, 0x18},
+	{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38},
+	6,
+	DMX_IDX_MPEG_B_FRAME_START
+};
+
+static const struct dvb_dmx_video_patterns h264_sps = {
+	{0x00, 0x00, 0x01, 0x07},
+	{0xFF, 0xFF, 0xFF, 0x1F},
+	4,
+	DMX_IDX_H264_SPS
+};
+
+static const struct dvb_dmx_video_patterns h264_pps = {
+	{0x00, 0x00, 0x01, 0x08},
+	{0xFF, 0xFF, 0xFF, 0x1F},
+	4,
+	DMX_IDX_H264_PPS
+};
+
+static const struct dvb_dmx_video_patterns h264_idr = {
+	{0x00, 0x00, 0x01, 0x05, 0x80},
+	{0xFF, 0xFF, 0xFF, 0x1F, 0x80},
+	5,
+	DMX_IDX_H264_IDR_START
+};
+
+static const struct dvb_dmx_video_patterns h264_non_idr = {
+	{0x00, 0x00, 0x01, 0x01, 0x80},
+	{0xFF, 0xFF, 0xFF, 0x1F, 0x80},
+	5,
+	DMX_IDX_H264_NON_IDR_START
+};
+
+/*
+ *  Forbidden (1 bit) + NAL idc (2 bits) + NAL type (5 bits)
+ *  I-Slice NAL idc = 3, NAL type = 5, 01100101 mask 0x7F
+ */
+static const struct dvb_dmx_video_patterns h264_idr_islice = {
+	{0x00, 0x00, 0x01, 0x65, 0x80},
+	{0xFF, 0xFF, 0xFF, 0x7F, 0x80},
+	5,
+	DMX_IDX_H264_IDR_ISLICE_START
+};
+
+/*
+ *  Forbidden (1 bit) + NAL idc (2 bits) + NAL type (5 bits)
+ *  P-Slice NAL idc = 2, NAL type = 1, 01000001 mask 0x7F
+ */
+static const struct dvb_dmx_video_patterns h264_non_idr_pslice = {
+	{0x00, 0x00, 0x01, 0x41, 0x80},
+	{0xFF, 0xFF, 0xFF, 0x7F, 0x80},
+	5,
+	DMX_IDX_H264_NON_IDR_PSLICE_START
+};
+
+/*
+ *  Forbidden (1 bit) + NAL idc (2 bits) + NAL type (5 bits)
+ *  B-Slice NAL idc = 0, NAL type = 1, 00000001  mask 0x7F
+ */
+static const struct dvb_dmx_video_patterns h264_non_idr_bslice = {
+	{0x00, 0x00, 0x01, 0x01, 0x80},
+	{0xFF, 0xFF, 0xFF, 0x7F, 0x80},
+	5,
+	DMX_IDX_H264_NON_IDR_BSLICE_START
+};
+
+static const struct dvb_dmx_video_patterns h264_non_access_unit_del = {
+	{0x00, 0x00, 0x01, 0x09},
+	{0xFF, 0xFF, 0xFF, 0x1F},
+	4,
+	DMX_IDX_H264_ACCESS_UNIT_DEL
+};
+
+static const struct dvb_dmx_video_patterns h264_non_sei = {
+	{0x00, 0x00, 0x01, 0x06},
+	{0xFF, 0xFF, 0xFF, 0x1F},
+	4,
+	DMX_IDX_H264_SEI
+};
+
+static const struct dvb_dmx_video_patterns vc1_seq_hdr = {
+	{0x00, 0x00, 0x01, 0x0F},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_VC1_SEQ_HEADER
+};
+
+static const struct dvb_dmx_video_patterns vc1_entry_point = {
+	{0x00, 0x00, 0x01, 0x0E},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_VC1_ENTRY_POINT
+};
+
+static const struct dvb_dmx_video_patterns vc1_frame = {
+	{0x00, 0x00, 0x01, 0x0D},
+	{0xFF, 0xFF, 0xFF, 0xFF},
+	4,
+	DMX_IDX_VC1_FRAME_START
+};
+
+
 /******************************************************************************
  * static inlined helper functions
  ******************************************************************************/
@@ -69,9 +209,9 @@
 	return 3 + ((buf[1] & 0x0f) << 8) + buf[2];
 }
 
-static inline u16 ts_pid(const u8 *buf)
+static inline u8 ts_scrambling_ctrl(const u8 *buf)
 {
-	return ((buf[1] & 0x1f) << 8) + buf[2];
+	return (buf[3] >> 6) & 0x3;
 }
 
 static inline u8 payload(const u8 *tsp)
@@ -100,37 +240,355 @@
 	memcpy(d, s, len);
 }
 
+static u32 dvb_dmx_calc_time_delta(ktime_t past_time)
+{
+	ktime_t curr_time = ktime_get();
+	s64 delta_time_us = ktime_us_delta(curr_time, past_time);
+
+	return (u32)delta_time_us;
+}
+
 /******************************************************************************
  * Software filter functions
  ******************************************************************************/
 
+/*
+ * Check if two patterns are identical, taking mask into consideration.
+ * @pattern1: the first byte pattern to compare.
+ * @pattern2: the second byte pattern to compare.
+ * @mask: the bit mask to use.
+ * @pattern_size: the length of both patterns and the mask, in bytes.
+ *
+ * Return: 1 if patterns match, 0 otherwise.
+ */
+static inline int dvb_dmx_patterns_match(const u8 *pattern1, const u8 *pattern2,
+					const u8 *mask, size_t pattern_size)
+{
+	int i;
+
+	/*
+	 * Assumption: it is OK to access pattern1, pattern2 and mask.
+	 * This function performs no sanity checks to keep things fast.
+	 */
+
+	for (i = 0; i < pattern_size; i++)
+		if ((pattern1[i] & mask[i]) != (pattern2[i] & mask[i]))
+			return 0;
+
+	return 1;
+}
+
+/*
+ * dvb_dmx_video_pattern_search -
+ * search for framing patterns in a given buffer.
+ *
+ * Optimized version: first search for a common substring, e.g. 0x00 0x00 0x01.
+ * If this string is found, go over all the given patterns (all must start
+ * with this string) and search for their ending in the buffer.
+ *
+ * Assumption: the patterns we look for do not spread over more than two
+ * buffers.
+ *
+ * @paterns: the full patterns information to look for.
+ * @patterns_num: the number of patterns to look for.
+ * @buf: the buffer to search.
+ * @buf_size: the size of the buffer to search. we search the entire buffer.
+ * @prefix_size_masks: a bit mask (per pattern) of possible prefix sizes to use
+ * when searching for a pattern that started at the last buffer.
+ * Updated in this function for use in the next lookup.
+ * @results: lookup results (offset, type, used_prefix_size) per found pattern,
+ * up to DVB_DMX_MAX_FOUND_PATTERNS.
+ *
+ * Return:
+ *   Number of patterns found (up to DVB_DMX_MAX_FOUND_PATTERNS).
+ *   0 if pattern was not found.
+ *   error value on failure.
+ */
+int dvb_dmx_video_pattern_search(
+		const struct dvb_dmx_video_patterns
+			*patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM],
+		int patterns_num,
+		const u8 *buf,
+		size_t buf_size,
+		struct dvb_dmx_video_prefix_size_masks *prefix_size_masks,
+		struct dvb_dmx_video_patterns_results *results)
+{
+	int i, j;
+	unsigned int current_size;
+	u32 prefix;
+	int found = 0;
+	int start_offset = 0;
+	/* the starting common substring to look for */
+	u8 string[] = {0x00, 0x00, 0x01};
+	/* the mask for the starting string */
+	u8 string_mask[] = {0xFF, 0xFF, 0xFF};
+	/* the size of the starting string (in bytes) */
+	size_t string_size = 3;
+
+	if ((patterns == NULL) || (patterns_num <= 0) || (buf == NULL))
+		return -EINVAL;
+
+	memset(results, 0, sizeof(struct dvb_dmx_video_patterns_results));
+
+	/*
+	 * handle prefix - disregard string, simply check all patterns,
+	 * looking for a matching suffix at the very beginning of the buffer.
+	 */
+	for (j = 0; (j < patterns_num) && !found; j++) {
+		prefix = prefix_size_masks->size_mask[j];
+		current_size = 32;
+		while (prefix) {
+			if (prefix & (0x1 << (current_size - 1))) {
+				/*
+				 * check that we don't look further
+				 * than buf_size boundary
+				 */
+				if ((int)(patterns[j]->size - current_size) >
+						buf_size)
+					break;
+
+				if (dvb_dmx_patterns_match(
+					(patterns[j]->pattern + current_size),
+					buf, (patterns[j]->mask + current_size),
+					(patterns[j]->size - current_size))) {
+
+					/*
+					 * pattern found using prefix at the
+					 * very beginning of the buffer, so
+					 * offset is 0, but we already zeroed
+					 * everything in the beginning of the
+					 * function. that's why the next line
+					 * is commented.
+					 */
+					/* results->info[found].offset = 0; */
+					results->info[found].type =
+							patterns[j]->type;
+					results->info[found].used_prefix_size =
+							current_size;
+					found++;
+					/*
+					 * save offset to start looking from
+					 * in the buffer, to avoid reusing the
+					 * data of a pattern we already found.
+					 */
+					start_offset = (patterns[j]->size -
+							current_size);
+
+					if (found >= DVB_DMX_MAX_FOUND_PATTERNS)
+						goto next_prefix_lookup;
+					/*
+					 * we don't want to search for the same
+					 * pattern with several possible prefix
+					 * sizes if we have already found it,
+					 * so we break from the inner loop.
+					 * since we incremented 'found', we
+					 * will not search for additional
+					 * patterns using a prefix - that would
+					 * imply ambiguous patterns where one
+					 * pattern can be included in another.
+					 * the for loop will exit.
+					 */
+					break;
+				}
+			}
+			prefix &= ~(0x1 << (current_size - 1));
+			current_size--;
+		}
+	}
+
+	/*
+	 * Search buffer for entire pattern, starting with the string.
+	 * Note the external for loop does not execute if buf_size is
+	 * smaller than string_size (the cast to int is required, since
+	 * size_t is unsigned).
+	 */
+	for (i = start_offset; i < (int)(buf_size - string_size + 1); i++) {
+		if (dvb_dmx_patterns_match(string, (buf + i), string_mask,
+							string_size)) {
+			/* now search for patterns: */
+			for (j = 0; j < patterns_num; j++) {
+				/* avoid overflow to next buffer */
+				if ((i + patterns[j]->size) > buf_size)
+					continue;
+
+				if (dvb_dmx_patterns_match(
+					(patterns[j]->pattern + string_size),
+					(buf + i + string_size),
+					(patterns[j]->mask + string_size),
+					(patterns[j]->size - string_size))) {
+
+					results->info[found].offset = i;
+					results->info[found].type =
+						patterns[j]->type;
+					/*
+					 * save offset to start next prefix
+					 * lookup, to avoid reusing the data
+					 * of any pattern we already found.
+					 */
+					if ((i + patterns[j]->size) >
+							start_offset)
+						start_offset = (i +
+							patterns[j]->size);
+					/*
+					 * did not use a prefix to find this
+					 * pattern, but we zeroed everything
+					 * in the beginning of the function.
+					 * So no need to zero used_prefix_size
+					 * for results->info[found]
+					 */
+
+					found++;
+					if (found >= DVB_DMX_MAX_FOUND_PATTERNS)
+						goto next_prefix_lookup;
+					/*
+					 * theoretically we don't have to break
+					 * here, but we don't want to search
+					 * for the other matching patterns on
+					 * the very same same place in the
+					 * buffer. That would mean the
+					 * (pattern & mask) combinations are
+					 * not unique. So we break from inner
+					 * loop and move on to the next place
+					 * in the buffer.
+					 */
+					break;
+				}
+			}
+		}
+	}
+
+next_prefix_lookup:
+	/* check for possible prefix sizes for the next buffer */
+	for (j = 0; j < patterns_num; j++) {
+		prefix_size_masks->size_mask[j] = 0;
+		for (i = 1; i < patterns[j]->size; i++) {
+			/*
+			 * avoid looking outside of the buffer
+			 * or reusing previously used data.
+			 */
+			if (i > (buf_size - start_offset))
+				break;
+
+			if (dvb_dmx_patterns_match(patterns[j]->pattern,
+					(buf + buf_size - i),
+					patterns[j]->mask, i)) {
+				prefix_size_masks->size_mask[j] |=
+						(1 << (i - 1));
+			}
+		}
+	}
+
+	return found;
+}
+EXPORT_SYMBOL(dvb_dmx_video_pattern_search);
+
+/**
+ * dvb_dmx_notify_section_event() - Notify demux event for all filters of a
+ * specified section feed.
+ *
+ * @feed:		dvb_demux_feed object
+ * @event:		demux event to notify
+ * @should_lock:	specifies whether the function should lock the demux
+ *
+ * Caller is responsible for locking the demux properly, either by doing the
+ * locking itself and setting 'should_lock' to 0, or have the function do it
+ * by setting 'should_lock' to 1.
+ */
+int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed,
+	struct dmx_data_ready *event, int should_lock)
+{
+	struct dvb_demux_filter *f;
+
+	if (feed == NULL || event == NULL || feed->type != DMX_TYPE_SEC)
+		return -EINVAL;
+
+	if (!should_lock && !spin_is_locked(&feed->demux->lock))
+		return -EINVAL;
+
+	if (should_lock)
+		spin_lock(&feed->demux->lock);
+
+	f = feed->filter;
+	while (f && feed->feed.sec.is_filtering) {
+		feed->data_ready_cb.sec(&f->filter, event);
+		f = f->next;
+	}
+
+	if (should_lock)
+		spin_unlock(&feed->demux->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(dvb_dmx_notify_section_event);
+
+static int dvb_dmx_check_pes_end(struct dvb_demux_feed *feed)
+{
+	struct dmx_data_ready data;
+
+	if (!feed->pusi_seen)
+		return 0;
+
+	data.status = DMX_OK_PES_END;
+	data.data_length = 0;
+	data.pes_end.start_gap = 0;
+	data.pes_end.actual_length = feed->peslen;
+	data.pes_end.disc_indicator_set = 0;
+	data.pes_end.pes_length_mismatch = 0;
+	data.pes_end.stc = 0;
+	data.pes_end.tei_counter = feed->pes_tei_counter;
+	data.pes_end.cont_err_counter = feed->pes_cont_err_counter;
+	data.pes_end.ts_packets_num = feed->pes_ts_packets_num;
+
+	return feed->data_ready_cb.ts(&feed->feed.ts, &data);
+}
+
 static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
 					   const u8 *buf)
 {
 	int count = payload(buf);
 	int p;
-	//int ccok;
-	//u8 cc;
+	int ccok;
+	u8 cc;
+	int ret;
 
 	if (count == 0)
 		return -1;
 
 	p = 188 - count;
 
-	/*
 	cc = buf[3] & 0x0f;
-	ccok = ((feed->cc + 1) & 0x0f) == cc;
+	if (feed->first_cc)
+		ccok = 1;
+	else
+		ccok = ((feed->cc + 1) & 0x0f) == cc;
+
+	feed->first_cc = 0;
 	feed->cc = cc;
-	if (!ccok)
-		printk("missed packet!\n");
-	*/
 
-	if (buf[1] & 0x40)	// PUSI ?
-		feed->peslen = 0xfffa;
+	/* PUSI ? */
+	if (buf[1] & 0x40) {
+		dvb_dmx_check_pes_end(feed);
+		feed->pusi_seen = 1;
+		feed->peslen = 0;
+		feed->pes_tei_counter = 0;
+		feed->pes_cont_err_counter = 0;
+		feed->pes_ts_packets_num = 0;
+	}
 
-	feed->peslen += count;
+	if (feed->pusi_seen == 0)
+		return 0;
 
-	return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts);
+	ret = feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts);
+
+	/* Verify TS packet was copied successfully */
+	if (!ret) {
+		feed->pes_cont_err_counter += !ccok;
+		feed->pes_tei_counter += (buf[1] & 0x80) ? 1 : 0;
+		feed->pes_ts_packets_num++;
+		feed->peslen += count;
+	}
+
+	return ret;
 }
 
 static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
@@ -169,10 +627,28 @@
 		return 0;
 
 	if (sec->check_crc) {
+		ktime_t pre_crc_time = ktime_set(0, 0);
+
+		if (dvb_demux_performancecheck)
+			pre_crc_time = ktime_get();
+
 		section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
 		if (section_syntax_indicator &&
-		    demux->check_crc32(feed, sec->secbuf, sec->seclen))
+		    demux->check_crc32(feed, sec->secbuf, sec->seclen)) {
+			if (dvb_demux_performancecheck)
+				demux->total_crc_time +=
+					dvb_dmx_calc_time_delta(pre_crc_time);
+
+			/* Notify on CRC error */
+			feed->cb.sec(NULL, 0, NULL, 0,
+				&f->filter);
+
 			return -1;
+		}
+
+		if (dvb_demux_performancecheck)
+			demux->total_crc_time +=
+				dvb_dmx_calc_time_delta(pre_crc_time);
 	}
 
 	do {
@@ -287,7 +763,7 @@
 	return 0;
 }
 
-static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
+static int dvb_dmx_swfilter_section_one_packet(struct dvb_demux_feed *feed,
 					   const u8 *buf)
 {
 	u8 p, count;
@@ -302,7 +778,16 @@
 	p = 188 - count;	/* payload start */
 
 	cc = buf[3] & 0x0f;
-	ccok = ((feed->cc + 1) & 0x0f) == cc;
+	if (feed->first_cc)
+		ccok = 1;
+	else
+		ccok = ((feed->cc + 1) & 0x0f) == cc;
+
+	/* discard TS packets holding sections with TEI bit set */
+	if (buf[1] & 0x80)
+		return -EINVAL;
+
+	feed->first_cc = 0;
 	feed->cc = cc;
 
 	if (buf[3] & 0x20) {
@@ -356,28 +841,668 @@
 	return 0;
 }
 
-static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
-						const u8 *buf)
+/*
+ * dvb_dmx_swfilter_section_packet - wrapper for section filtering of single
+ * TS packet.
+ *
+ * @feed: dvb demux feed
+ * @buf: buffer containing the TS packet
+ * @should_lock: specifies demux locking semantics: if not set, proper demux
+ * locking is expected to have been done by the caller.
+ *
+ * Return error status
+ */
+int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
+	   const u8 *buf, int should_lock)
 {
+	int ret;
+
+	if (!should_lock && !spin_is_locked(&feed->demux->lock)) {
+		pr_err("%s: demux spinlock should have been locked\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (should_lock)
+		spin_lock(&feed->demux->lock);
+
+	ret = dvb_dmx_swfilter_section_one_packet(feed, buf);
+
+	if (should_lock)
+		spin_unlock(&feed->demux->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_section_packet);
+
+static int dvb_demux_idx_event_sort(struct dmx_index_event_info *curr,
+	struct dmx_index_event_info *new)
+{
+	if (curr->match_tsp_num > new->match_tsp_num)
+		return 0;
+
+	if (curr->match_tsp_num < new->match_tsp_num)
+		return 1;
+	/*
+	 * In case TSP numbers are equal, sort according to event type giving
+	 * priority to PUSI events first, then RAI and finally framing events.
+	 */
+	if ((curr->type & DMX_IDX_RAI && new->type & DMX_IDX_PUSI) ||
+		(!(curr->type & DMX_IDX_PUSI) && !(curr->type & DMX_IDX_RAI) &&
+			new->type & (DMX_IDX_PUSI | DMX_IDX_RAI)))
+		return 0;
+
+	return 1;
+}
+
+static int dvb_demux_save_idx_event(struct dvb_demux_feed *feed,
+		struct dmx_index_event_info *idx_event,
+		int traverse_from_tail)
+{
+	struct dmx_index_entry *idx_entry;
+	struct dmx_index_entry *curr_entry;
+	struct list_head *pos;
+
+	/* get entry from free list */
+	if (list_empty(&feed->rec_info->idx_info.free_list)) {
+		pr_err("%s: index free list is empty\n", __func__);
+		return -ENOMEM;
+	}
+
+	idx_entry = list_first_entry(&feed->rec_info->idx_info.free_list,
+					struct dmx_index_entry, next);
+	list_del(&idx_entry->next);
+
+	idx_entry->event = *idx_event;
+
+	pos = &feed->rec_info->idx_info.ready_list;
+	if (traverse_from_tail) {
+		list_for_each_entry_reverse(curr_entry,
+			&feed->rec_info->idx_info.ready_list, next) {
+			if (dvb_demux_idx_event_sort(&curr_entry->event,
+				idx_event)) {
+				pos = &curr_entry->next;
+				break;
+			}
+		}
+	} else {
+		list_for_each_entry(curr_entry,
+			&feed->rec_info->idx_info.ready_list, next) {
+			if (!dvb_demux_idx_event_sort(&curr_entry->event,
+				idx_event)) {
+				pos = &curr_entry->next;
+				break;
+			}
+		}
+	}
+
+	if (traverse_from_tail)
+		list_add(&idx_entry->next, pos);
+	else
+		list_add_tail(&idx_entry->next, pos);
+
+	return 0;
+}
+
+int dvb_demux_push_idx_event(struct dvb_demux_feed *feed,
+		struct dmx_index_event_info *idx_event, int should_lock)
+{
+	int ret;
+
+	if (!should_lock && !spin_is_locked(&feed->demux->lock))
+		return -EINVAL;
+
+	if (should_lock)
+		spin_lock(&feed->demux->lock);
+	ret = dvb_demux_save_idx_event(feed, idx_event, 1);
+	if (should_lock)
+		spin_unlock(&feed->demux->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(dvb_demux_push_idx_event);
+
+static inline void dvb_dmx_notify_indexing(struct dvb_demux_feed *feed)
+{
+	struct dmx_data_ready dmx_data_ready;
+	struct dmx_index_entry *curr_entry;
+	struct list_head *n, *pos;
+
+	dmx_data_ready.status = DMX_OK_IDX;
+
+	list_for_each_safe(pos, n, &feed->rec_info->idx_info.ready_list) {
+		curr_entry = list_entry(pos, struct dmx_index_entry, next);
+
+		if ((feed->rec_info->idx_info.min_pattern_tsp_num == (u64)-1) ||
+			(curr_entry->event.match_tsp_num <=
+			 feed->rec_info->idx_info.min_pattern_tsp_num)) {
+			dmx_data_ready.idx_event = curr_entry->event;
+			feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready);
+			list_del(&curr_entry->next);
+			list_add_tail(&curr_entry->next,
+				&feed->rec_info->idx_info.free_list);
+		}
+	}
+}
+
+void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed, int should_lock)
+{
+	if (!should_lock && !spin_is_locked(&feed->demux->lock))
+		return;
+
+	if (should_lock)
+		spin_lock(&feed->demux->lock);
+	dvb_dmx_notify_indexing(feed);
+	if (should_lock)
+		spin_unlock(&feed->demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_notify_idx_events);
+
+static void dvb_dmx_process_pattern_result(struct dvb_demux_feed *feed,
+		struct dvb_dmx_video_patterns_results *patterns, int pattern,
+		u64 curr_stc, u64 prev_stc,
+		u64 curr_match_tsp, u64 prev_match_tsp,
+		u64 curr_pusi_tsp, u64 prev_pusi_tsp)
+{
+	int mpeg_frame_start;
+	int h264_frame_start;
+	int vc1_frame_start;
+	int seq_start;
+	u64 frame_end_in_seq;
+	struct dmx_index_event_info idx_event;
+
+	idx_event.pid = feed->pid;
+	if (patterns->info[pattern].used_prefix_size) {
+		idx_event.match_tsp_num = prev_match_tsp;
+		idx_event.last_pusi_tsp_num = prev_pusi_tsp;
+		idx_event.stc = prev_stc;
+	} else {
+		idx_event.match_tsp_num = curr_match_tsp;
+		idx_event.last_pusi_tsp_num = curr_pusi_tsp;
+		idx_event.stc = curr_stc;
+	}
+
+	/* notify on frame-end if needed */
+	if (feed->prev_frame_valid) {
+		if (feed->prev_frame_type & DMX_IDX_MPEG_I_FRAME_START) {
+			idx_event.type = DMX_IDX_MPEG_I_FRAME_END;
+			frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END;
+		} else if (feed->prev_frame_type & DMX_IDX_MPEG_P_FRAME_START) {
+			idx_event.type = DMX_IDX_MPEG_P_FRAME_END;
+			frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END;
+		} else if (feed->prev_frame_type & DMX_IDX_MPEG_B_FRAME_START) {
+			idx_event.type = DMX_IDX_MPEG_B_FRAME_END;
+			frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END;
+		} else if (feed->prev_frame_type & DMX_IDX_H264_IDR_START) {
+			idx_event.type = DMX_IDX_H264_IDR_END;
+			frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+		} else if (feed->prev_frame_type & DMX_IDX_H264_NON_IDR_START) {
+			idx_event.type = DMX_IDX_H264_NON_IDR_END;
+			frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+		} else if (feed->prev_frame_type &
+			   DMX_IDX_H264_IDR_ISLICE_START) {
+			idx_event.type = DMX_IDX_H264_IDR_END;
+			frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+		} else if (feed->prev_frame_type &
+			   DMX_IDX_H264_NON_IDR_PSLICE_START) {
+			idx_event.type = DMX_IDX_H264_NON_IDR_END;
+			frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+		} else if (feed->prev_frame_type &
+			   DMX_IDX_H264_NON_IDR_BSLICE_START) {
+			idx_event.type = DMX_IDX_H264_NON_IDR_END;
+			frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+		} else {
+			idx_event.type = DMX_IDX_VC1_FRAME_END;
+			frame_end_in_seq = DMX_IDX_VC1_FIRST_SEQ_FRAME_END;
+		}
+
+		if (feed->idx_params.types & idx_event.type)
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+
+		if (feed->first_frame_in_seq_notified &&
+			feed->idx_params.types & frame_end_in_seq) {
+			idx_event.type = frame_end_in_seq;
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+			feed->first_frame_in_seq_notified = 0;
+		}
+	}
+
+	seq_start = patterns->info[pattern].type &
+		(DMX_IDX_MPEG_SEQ_HEADER | DMX_IDX_H264_SPS |
+		 DMX_IDX_VC1_SEQ_HEADER);
+
+	/* did we find start of sequence/SPS? */
+	if (seq_start) {
+		feed->first_frame_in_seq = 1;
+		feed->first_frame_in_seq_notified = 0;
+		feed->prev_frame_valid = 0;
+		idx_event.type = patterns->info[pattern].type;
+		if (feed->idx_params.types & idx_event.type)
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+		return;
+	}
+
+	mpeg_frame_start = patterns->info[pattern].type &
+		(DMX_IDX_MPEG_I_FRAME_START |
+		 DMX_IDX_MPEG_P_FRAME_START |
+		 DMX_IDX_MPEG_B_FRAME_START);
+
+	h264_frame_start = patterns->info[pattern].type &
+		(DMX_IDX_H264_IDR_START | DMX_IDX_H264_NON_IDR_START);
+
+	vc1_frame_start = patterns->info[pattern].type &
+		DMX_IDX_VC1_FRAME_START;
+
+	if (!mpeg_frame_start && !h264_frame_start && !vc1_frame_start) {
+		/* neither sequence nor frame, notify on the entry if needed */
+		idx_event.type = patterns->info[pattern].type;
+		if (feed->idx_params.types & idx_event.type)
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+		feed->prev_frame_valid = 0;
+		return;
+	}
+
+	/* notify on first frame in sequence/sps if needed */
+	if (feed->first_frame_in_seq) {
+		feed->first_frame_in_seq = 0;
+		feed->first_frame_in_seq_notified = 1;
+		if (mpeg_frame_start)
+			idx_event.type = DMX_IDX_MPEG_FIRST_SEQ_FRAME_START;
+		else if (h264_frame_start)
+			idx_event.type = DMX_IDX_H264_FIRST_SPS_FRAME_START;
+		else
+			idx_event.type = DMX_IDX_VC1_FIRST_SEQ_FRAME_START;
+
+		if (feed->idx_params.types & idx_event.type)
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+	}
+
+	/* notify on frame start if needed */
+	idx_event.type = patterns->info[pattern].type;
+	if (feed->idx_params.types & idx_event.type)
+		dvb_demux_save_idx_event(feed, &idx_event, 1);
+
+	feed->prev_frame_valid = 1;
+	feed->prev_frame_type = patterns->info[pattern].type;
+}
+
+void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed,
+		struct dvb_dmx_video_patterns_results *patterns, int pattern,
+		u64 curr_stc, u64 prev_stc,
+		u64 curr_match_tsp, u64 prev_match_tsp,
+		u64 curr_pusi_tsp, u64 prev_pusi_tsp)
+{
+	spin_lock(&feed->demux->lock);
+	dvb_dmx_process_pattern_result(feed,
+		patterns, pattern,
+		curr_stc, prev_stc,
+		curr_match_tsp, prev_match_tsp,
+		curr_pusi_tsp, prev_pusi_tsp);
+	spin_unlock(&feed->demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_process_idx_pattern);
+
+static void dvb_dmx_index(struct dvb_demux_feed *feed,
+		const u8 *buf,
+		const u8 timestamp[TIMESTAMP_LEN])
+{
+	int i;
+	int p;
+	u64 stc;
+	int found_patterns;
+	int count = payload(buf);
+	u64 min_pattern_tsp_num;
+	struct dvb_demux_feed *tmp_feed;
+	struct dvb_demux *demux = feed->demux;
+	struct dmx_index_event_info idx_event;
+	struct dvb_dmx_video_patterns_results patterns;
+
+	if (feed->demux->convert_ts)
+		feed->demux->convert_ts(feed, timestamp, &stc);
+	else
+		stc = 0;
+
+	idx_event.pid = feed->pid;
+	idx_event.stc = stc;
+	idx_event.match_tsp_num = feed->rec_info->ts_output_count;
+
+	/* PUSI ? */
+	if (buf[1] & 0x40) {
+		feed->curr_pusi_tsp_num = feed->rec_info->ts_output_count;
+		if (feed->idx_params.types & DMX_IDX_PUSI) {
+			idx_event.type = DMX_IDX_PUSI;
+			idx_event.last_pusi_tsp_num =
+				feed->curr_pusi_tsp_num;
+			dvb_demux_save_idx_event(feed, &idx_event, 1);
+		}
+	}
+
+	/*
+	 * if we still did not encounter a TS packet with PUSI indication,
+	 * we cannot report index entries yet as we need to provide
+	 * the TS packet number with PUSI indication preceding the TS
+	 * packet pointed by the reported index entry.
+	 */
+	if (feed->curr_pusi_tsp_num == (u64)-1) {
+		dvb_dmx_notify_indexing(feed);
+		return;
+	}
+
+	if ((feed->idx_params.types & DMX_IDX_RAI) && /* index RAI? */
+		(buf[3] & 0x20) && /* adaptation field exists? */
+		(buf[4] > 0) && /* adaptation field len > 0 ? */
+		(buf[5] & 0x40)) { /* RAI is set? */
+		idx_event.type = DMX_IDX_RAI;
+		idx_event.last_pusi_tsp_num =
+			feed->curr_pusi_tsp_num;
+		dvb_demux_save_idx_event(feed, &idx_event, 1);
+	}
+
+	/*
+	 * if no pattern search is required, or the TS packet has no payload,
+	 * pattern search is not executed.
+	 */
+	if (!feed->pattern_num || !count) {
+		dvb_dmx_notify_indexing(feed);
+		return;
+	}
+
+	p = 188 - count; /* payload start */
+
+	found_patterns =
+		dvb_dmx_video_pattern_search(feed->patterns,
+				feed->pattern_num, &buf[p], count,
+				&feed->prefix_size, &patterns);
+
+	for (i = 0; i < found_patterns; i++)
+		dvb_dmx_process_pattern_result(feed, &patterns, i,
+			stc, feed->prev_stc,
+			feed->rec_info->ts_output_count, feed->prev_tsp_num,
+			feed->curr_pusi_tsp_num, feed->prev_pusi_tsp_num);
+
+	feed->prev_tsp_num = feed->rec_info->ts_output_count;
+	feed->prev_pusi_tsp_num = feed->curr_pusi_tsp_num;
+	feed->prev_stc = stc;
+	feed->last_pattern_tsp_num = feed->rec_info->ts_output_count;
+
+	/*
+	 * it is possible to have a TS packet that has a prefix of
+	 * a video pattern but the video pattern is not identified yet
+	 * until we get the next TS packet of that PID. When we get
+	 * the next TS packet of that PID, pattern-search would
+	 * detect that we have a new index entry that starts in the
+	 * previous TS packet.
+	 * In order to notify the user on index entries with match_tsp_num
+	 * in ascending order, index events with match_tsp_num up to
+	 * the last_pattern_tsp_num are notified now to the user,
+	 * the rest can't be notified now as we might hit the above
+	 * scenario and cause the events not to be notified with
+	 * ascending order of match_tsp_num.
+	 */
+	if (feed->rec_info->idx_info.pattern_search_feeds_num == 1) {
+		/*
+		 * optimization for case we have only one PID
+		 * with video pattern search, in this case
+		 * min_pattern_tsp_num is simply updated to the new
+		 * TS packet number of the PID with pattern search.
+		 */
+		feed->rec_info->idx_info.min_pattern_tsp_num =
+			feed->last_pattern_tsp_num;
+		dvb_dmx_notify_indexing(feed);
+		return;
+	}
+
+	/*
+	 * if we have more than one PID with pattern search,
+	 * min_pattern_tsp_num needs to be updated now based on
+	 * last_pattern_tsp_num of all PIDs with pattern search.
+	 */
+	min_pattern_tsp_num = (u64)-1;
+	i = feed->rec_info->idx_info.pattern_search_feeds_num;
+	list_for_each_entry(tmp_feed, &demux->feed_list, list_head) {
+		if ((tmp_feed->state != DMX_STATE_GO) ||
+			(tmp_feed->type != DMX_TYPE_TS) ||
+			(tmp_feed->feed.ts.buffer.ringbuff !=
+			 feed->feed.ts.buffer.ringbuff))
+			continue;
+
+		if ((tmp_feed->last_pattern_tsp_num != (u64)-1) &&
+			((min_pattern_tsp_num == (u64)-1) ||
+			 (tmp_feed->last_pattern_tsp_num <
+			  min_pattern_tsp_num)))
+			min_pattern_tsp_num = tmp_feed->last_pattern_tsp_num;
+
+		if (tmp_feed->pattern_num) {
+			i--;
+			if (i == 0)
+				break;
+		}
+	}
+
+	feed->rec_info->idx_info.min_pattern_tsp_num = min_pattern_tsp_num;
+
+	/* notify all index entries up to min_pattern_tsp_num */
+	dvb_dmx_notify_indexing(feed);
+}
+
+static inline void dvb_dmx_swfilter_output_packet(
+	struct dvb_demux_feed *feed,
+	const u8 *buf,
+	const u8 timestamp[TIMESTAMP_LEN])
+{
+	/*
+	 * if we output 192 packet with timestamp at head of packet,
+	 * output the timestamp now before the 188 TS packet
+	 */
+	if (feed->tsp_out_format == DMX_TSP_FORMAT_192_HEAD)
+		feed->cb.ts(timestamp, TIMESTAMP_LEN, NULL,
+			0, &feed->feed.ts);
+
+	feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
+
+	/*
+	 * if we output 192 packet with timestamp at tail of packet,
+	 * output the timestamp now after the 188 TS packet
+	 */
+	if (feed->tsp_out_format == DMX_TSP_FORMAT_192_TAIL)
+		feed->cb.ts(timestamp, TIMESTAMP_LEN, NULL,
+			0, &feed->feed.ts);
+
+	if (feed->idx_params.enable)
+		dvb_dmx_index(feed, buf, timestamp);
+
+	feed->rec_info->ts_output_count++;
+}
+
+static inline void dvb_dmx_configure_decoder_fullness(
+						struct dvb_demux *demux,
+						int initialize)
+{
+	struct dvb_demux_feed *feed;
+	int j;
+
+	for (j = 0; j < demux->feednum; j++) {
+		feed = &demux->feed[j];
+
+		if ((feed->state != DMX_STATE_GO) ||
+			(feed->type != DMX_TYPE_TS) ||
+			!(feed->ts_type & TS_DECODER))
+			continue;
+
+		if (initialize) {
+			if (demux->decoder_fullness_init)
+				demux->decoder_fullness_init(feed);
+		} else {
+			if (demux->decoder_fullness_abort)
+				demux->decoder_fullness_abort(feed);
+		}
+	}
+}
+
+static inline int dvb_dmx_swfilter_buffer_check(
+					struct dvb_demux *demux,
+					u16 pid)
+{
+	int desired_space;
+	int ret;
+	struct dmx_ts_feed *ts;
+	struct dvb_demux_filter *f;
+	struct dvb_demux_feed *feed;
+	int was_locked;
+	int i, j;
+
+	if (likely(spin_is_locked(&demux->lock)))
+		was_locked = 1;
+	else
+		was_locked = 0;
+
+	/*
+	 * Check that there's enough free space for data output.
+	 * If there no space, wait for it (block).
+	 * Since this function is called while spinlock
+	 * is acquired, the lock should be released first.
+	 * Once we get control back, lock is acquired back
+	 * and checks that the filter is still valid.
+	 */
+	for (j = 0; j < demux->feednum; j++) {
+		feed = &demux->feed[j];
+
+		if (demux->sw_filter_abort)
+			return -ENODEV;
+
+		if ((feed->state != DMX_STATE_GO) ||
+			((feed->pid != pid) && (feed->pid != 0x2000)))
+			continue;
+
+		if (feed->secure_mode.is_secured &&
+			!dvb_dmx_is_rec_feed(feed))
+			return 0;
+
+		if (feed->type == DMX_TYPE_TS) {
+			desired_space = 192; /* upper bound */
+			ts = &feed->feed.ts;
+
+			if (feed->ts_type & TS_PACKET) {
+				if (likely(was_locked))
+					spin_unlock(&demux->lock);
+
+				ret = demux->buffer_ctrl.ts(ts,
+					desired_space, 1);
+
+				if (likely(was_locked))
+					spin_lock(&demux->lock);
+
+				if (ret < 0)
+					continue;
+			}
+
+			if (demux->sw_filter_abort)
+				return -ENODEV;
+
+			if (!ts->is_filtering)
+				continue;
+
+			if ((feed->ts_type & TS_DECODER) &&
+				(demux->decoder_fullness_wait)) {
+				if (likely(was_locked))
+					spin_unlock(&demux->lock);
+
+				ret = demux->decoder_fullness_wait(
+								feed,
+								desired_space);
+
+				if (likely(was_locked))
+					spin_lock(&demux->lock);
+
+				if (ret < 0)
+					continue;
+			}
+
+			continue;
+		}
+
+		/* else - section case */
+		desired_space = feed->feed.sec.tsfeedp + 188; /* upper bound */
+		for (i = 0; i < demux->filternum; i++) {
+			if (demux->sw_filter_abort)
+				return -EPERM;
+
+			if (!feed->feed.sec.is_filtering)
+				continue;
+
+			f = &demux->filter[i];
+			if (f->feed != feed)
+				continue;
+
+			if (likely(was_locked))
+				spin_unlock(&demux->lock);
+
+			ret = demux->buffer_ctrl.sec(&f->filter,
+				desired_space, 1);
+
+			if (likely(was_locked))
+				spin_lock(&demux->lock);
+
+			if (ret < 0)
+				break;
+		}
+	}
+
+	return 0;
+}
+
+static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
+			const u8 *buf, const u8 timestamp[TIMESTAMP_LEN])
+{
+	u16 pid = ts_pid(buf);
+	u8 scrambling_bits = ts_scrambling_ctrl(buf);
+	struct dmx_data_ready dmx_data_ready;
+
+	/*
+	 * Notify on scrambling status change only when we move
+	 * from clear (0) to non-clear and vise-versa
+	 */
+	if ((scrambling_bits && !feed->scrambling_bits) ||
+		(!scrambling_bits && feed->scrambling_bits)) {
+		dmx_data_ready.status = DMX_OK_SCRAMBLING_STATUS;
+		dmx_data_ready.data_length = 0;
+		dmx_data_ready.scrambling_bits.pid = pid;
+		dmx_data_ready.scrambling_bits.old_value =
+			feed->scrambling_bits;
+		dmx_data_ready.scrambling_bits.new_value = scrambling_bits;
+
+		if (feed->type == DMX_TYPE_SEC)
+			dvb_dmx_notify_section_event(feed, &dmx_data_ready, 0);
+		else if (feed->feed.ts.is_filtering)
+			feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready);
+	}
+
+	feed->scrambling_bits = scrambling_bits;
+
 	switch (feed->type) {
 	case DMX_TYPE_TS:
 		if (!feed->feed.ts.is_filtering)
 			break;
 		if (feed->ts_type & TS_PACKET) {
-			if (feed->ts_type & TS_PAYLOAD_ONLY)
-				dvb_dmx_swfilter_payload(feed, buf);
-			else
-				feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
+			if (feed->ts_type & TS_PAYLOAD_ONLY) {
+				if (!feed->secure_mode.is_secured)
+					dvb_dmx_swfilter_payload(feed, buf);
+			} else {
+				dvb_dmx_swfilter_output_packet(feed,
+						buf, timestamp);
+			}
 		}
-		if (feed->ts_type & TS_DECODER)
+		if ((feed->ts_type & TS_DECODER) &&
+			!feed->secure_mode.is_secured)
 			if (feed->demux->write_to_decoder)
 				feed->demux->write_to_decoder(feed, buf, 188);
 		break;
 
 	case DMX_TYPE_SEC:
-		if (!feed->feed.sec.is_filtering)
+		if (!feed->feed.sec.is_filtering ||
+			feed->secure_mode.is_secured)
 			break;
-		if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
+		if (dvb_dmx_swfilter_section_one_packet(feed, buf) < 0)
 			feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
 		break;
 
@@ -391,7 +1516,8 @@
 	((f)->feed.ts.is_filtering) &&					\
 	(((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
 
-static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
+static void dvb_dmx_swfilter_one_packet(struct dvb_demux *demux, const u8 *buf,
+				const u8 timestamp[TIMESTAMP_LEN])
 {
 	struct dvb_demux_feed *feed;
 	u16 pid = ts_pid(buf);
@@ -412,12 +1538,11 @@
 					* 188 * 8;
 				/* convert to 1024 basis */
 				speed_bytes = 1000 * div64_u64(speed_bytes,
-						1024);
+							       1024);
 				speed_timedelta = ktime_ms_delta(cur_time,
 							demux->speed_last_time);
-				printk(KERN_INFO "TS speed %llu Kbits/sec \n",
-						div64_u64(speed_bytes,
-							speed_timedelta));
+				pr_info("TS speed %llu Kbits/sec\n",
+				div64_u64(speed_bytes, speed_timedelta));
 			}
 
 			demux->speed_last_time = cur_time;
@@ -426,11 +1551,12 @@
 	}
 
 	if (buf[1] & 0x80) {
-		dprintk_tscheck("TEI detected. "
-				"PID=0x%x data1=0x%x\n",
-				pid, buf[1]);
-		/* data in this packet can't be trusted - drop it unless
-		 * module option dvb_demux_feed_err_pkts is set */
+		dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", pid,
+			buf[1]);
+		/*
+		 * data in this packet can't be trusted - drop it unless
+		 * module option dvb_demux_feed_err_pkts is set
+		 */
 		if (!dvb_demux_feed_err_pkts)
 			return;
 	} else /* if TEI bit is set, pid may be wrong- skip pkt counter */
@@ -439,10 +1565,12 @@
 			if (pid < MAX_PID) {
 				if (buf[3] & 0x10)
 					demux->cnt_storage[pid] =
-						(demux->cnt_storage[pid] + 1) & 0xf;
+						(demux->cnt_storage[pid] + 1) &
+						0xf;
 
 				if ((buf[3] & 0xf) != demux->cnt_storage[pid]) {
-					dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n",
+					dprintk_tscheck(
+						"TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n",
 						pid, demux->cnt_storage[pid],
 						buf[3] & 0xf);
 					demux->cnt_storage[pid] = buf[3] & 0xf;
@@ -451,48 +1579,76 @@
 			/* end check */
 		}
 
+	if (demux->playback_mode == DMX_PB_MODE_PULL)
+		if (dvb_dmx_swfilter_buffer_check(demux, pid) < 0)
+			return;
+
 	list_for_each_entry(feed, &demux->feed_list, list_head) {
 		if ((feed->pid != pid) && (feed->pid != 0x2000))
 			continue;
 
-		/* copy each packet only once to the dvr device, even
-		 * if a PID is in multiple filters (e.g. video + PCR) */
+		/*
+		 * copy each packet only once to the dvr device, even
+		 * if a PID is in multiple filters (e.g. video + PCR)
+		 */
 		if ((DVR_FEED(feed)) && (dvr_done++))
 			continue;
 
 		if (feed->pid == pid)
-			dvb_dmx_swfilter_packet_type(feed, buf);
-		else if (feed->pid == 0x2000)
-			feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
+			dvb_dmx_swfilter_packet_type(feed, buf, timestamp);
+		else if ((feed->pid == 0x2000) &&
+			     (feed->feed.ts.is_filtering))
+			dvb_dmx_swfilter_output_packet(feed, buf, timestamp);
 	}
 }
 
+void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+				const u8 timestamp[TIMESTAMP_LEN])
+{
+	spin_lock(&demux->lock);
+	dvb_dmx_swfilter_one_packet(demux, buf, timestamp);
+	spin_unlock(&demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
+
 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
 			      size_t count)
 {
-	unsigned long flags;
+	ktime_t pre_time = ktime_set(0, 0);
+	u8 timestamp[TIMESTAMP_LEN] = {0};
 
-	spin_lock_irqsave(&demux->lock, flags);
+	if (dvb_demux_performancecheck)
+		pre_time = ktime_get();
+
+	spin_lock(&demux->lock);
+
+	demux->sw_filter_abort = 0;
+	dvb_dmx_configure_decoder_fullness(demux, 1);
 
 	while (count--) {
 		if (buf[0] == 0x47)
-			dvb_dmx_swfilter_packet(demux, buf);
+			dvb_dmx_swfilter_one_packet(demux, buf, timestamp);
 		buf += 188;
 	}
 
-	spin_unlock_irqrestore(&demux->lock, flags);
-}
+	spin_unlock(&demux->lock);
 
+	if (dvb_demux_performancecheck)
+		demux->total_process_time += dvb_dmx_calc_time_delta(pre_time);
+}
 EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
 
 static inline int find_next_packet(const u8 *buf, int pos, size_t count,
-				   const int pktsize)
+				   const int pktsize, const int leadingbytes)
 {
 	int start = pos, lost;
 
 	while (pos < count) {
-		if (buf[pos] == 0x47 ||
-		    (pktsize == 204 && buf[pos] == 0xB8))
+		if ((buf[pos] == 0x47 && !leadingbytes) ||
+		    (pktsize == 204 && buf[pos] == 0xB8) ||
+			(pktsize == 192 && leadingbytes &&
+			 (pos+leadingbytes < count) &&
+				buf[pos+leadingbytes] == 0x47))
 			break;
 		pos++;
 	}
@@ -501,8 +1657,11 @@
 	if (lost) {
 		/* This garbage is part of a valid packet? */
 		int backtrack = pos - pktsize;
+
 		if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
-		    (pktsize == 204 && buf[backtrack] == 0xB8)))
+		    (pktsize == 204 && buf[backtrack] == 0xB8) ||
+			(pktsize == 192 &&
+			buf[backtrack+leadingbytes] == 0x47)))
 			return backtrack;
 	}
 
@@ -511,13 +1670,20 @@
 
 /* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
 static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
-		size_t count, const int pktsize)
+		size_t count, const int pktsize, const int leadingbytes)
 {
 	int p = 0, i, j;
 	const u8 *q;
-	unsigned long flags;
+	ktime_t pre_time;
+	u8 timestamp[TIMESTAMP_LEN];
 
-	spin_lock_irqsave(&demux->lock, flags);
+	if (dvb_demux_performancecheck)
+		pre_time = ktime_get();
+
+	spin_lock(&demux->lock);
+
+	demux->sw_filter_abort = 0;
+	dvb_dmx_configure_decoder_fullness(demux, 1);
 
 	if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
 		i = demux->tsbufp;
@@ -528,14 +1694,36 @@
 			goto bailout;
 		}
 		memcpy(&demux->tsbuf[i], buf, j);
-		if (demux->tsbuf[0] == 0x47) /* double check */
-			dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+
+		if (pktsize == 192) {
+			if (leadingbytes)
+				memcpy(timestamp, &demux->tsbuf[p],
+					TIMESTAMP_LEN);
+			else
+				memcpy(timestamp, &demux->tsbuf[188],
+					TIMESTAMP_LEN);
+		} else {
+			memset(timestamp, 0, TIMESTAMP_LEN);
+		}
+
+		if (pktsize == 192 &&
+			leadingbytes &&
+			demux->tsbuf[leadingbytes] == 0x47)  /* double check */
+			dvb_dmx_swfilter_one_packet(demux,
+				demux->tsbuf + TIMESTAMP_LEN, timestamp);
+		else if (demux->tsbuf[0] == 0x47) /* double check */
+			dvb_dmx_swfilter_one_packet(demux,
+					demux->tsbuf, timestamp);
 		demux->tsbufp = 0;
 		p += j;
 	}
 
 	while (1) {
-		p = find_next_packet(buf, p, count, pktsize);
+		p = find_next_packet(buf, p, count, pktsize, leadingbytes);
+
+		if (demux->sw_filter_abort)
+			goto bailout;
+
 		if (p >= count)
 			break;
 		if (count - p < pktsize)
@@ -548,7 +1736,19 @@
 			demux->tsbuf[0] = 0x47;
 			q = demux->tsbuf;
 		}
-		dvb_dmx_swfilter_packet(demux, q);
+
+		if (pktsize == 192) {
+			if (leadingbytes) {
+				q = &buf[p+leadingbytes];
+				memcpy(timestamp, &buf[p], TIMESTAMP_LEN);
+			} else {
+				memcpy(timestamp, &buf[p+188], TIMESTAMP_LEN);
+			}
+		} else {
+			memset(timestamp, 0, TIMESTAMP_LEN);
+		}
+
+		dvb_dmx_swfilter_one_packet(demux, q, timestamp);
 		p += pktsize;
 	}
 
@@ -561,33 +1761,65 @@
 	}
 
 bailout:
-	spin_unlock_irqrestore(&demux->lock, flags);
+	spin_unlock(&demux->lock);
+
+	if (dvb_demux_performancecheck)
+		demux->total_process_time += dvb_dmx_calc_time_delta(pre_time);
 }
 
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
-	_dvb_dmx_swfilter(demux, buf, count, 188);
+	_dvb_dmx_swfilter(demux, buf, count, 188, 0);
 }
 EXPORT_SYMBOL(dvb_dmx_swfilter);
 
 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
-	_dvb_dmx_swfilter(demux, buf, count, 204);
+	_dvb_dmx_swfilter(demux, buf, count, 204, 0);
 }
 EXPORT_SYMBOL(dvb_dmx_swfilter_204);
 
 void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&demux->lock, flags);
+	spin_lock(&demux->lock);
 
 	demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts);
 
-	spin_unlock_irqrestore(&demux->lock, flags);
+	spin_unlock(&demux->lock);
 }
 EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
 
+void dvb_dmx_swfilter_format(
+			struct dvb_demux *demux,
+			const u8 *buf,
+			size_t count,
+			enum dmx_tsp_format_t tsp_format)
+{
+	switch (tsp_format) {
+	case DMX_TSP_FORMAT_188:
+		_dvb_dmx_swfilter(demux, buf, count, 188, 0);
+		break;
+
+	case DMX_TSP_FORMAT_192_TAIL:
+		_dvb_dmx_swfilter(demux, buf, count, 192, 0);
+		break;
+
+	case DMX_TSP_FORMAT_192_HEAD:
+		_dvb_dmx_swfilter(demux, buf, count, 192, TIMESTAMP_LEN);
+		break;
+
+	case DMX_TSP_FORMAT_204:
+		_dvb_dmx_swfilter(demux, buf, count, 204, 0);
+		break;
+
+	default:
+		pr_err("%s: invalid TS packet format (format=%d)\n", __func__,
+			tsp_format);
+		break;
+	}
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_format);
+
 static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
 {
 	int i;
@@ -620,6 +1852,311 @@
 	return &demux->feed[i];
 }
 
+const struct dvb_dmx_video_patterns *dvb_dmx_get_pattern(u64 dmx_idx_pattern)
+{
+	switch (dmx_idx_pattern) {
+	case DMX_IDX_MPEG_SEQ_HEADER:
+		return &mpeg2_seq_hdr;
+
+	case DMX_IDX_MPEG_GOP:
+		return &mpeg2_gop;
+
+	case DMX_IDX_MPEG_I_FRAME_START:
+		return &mpeg2_iframe;
+
+	case DMX_IDX_MPEG_P_FRAME_START:
+		return &mpeg2_pframe;
+
+	case DMX_IDX_MPEG_B_FRAME_START:
+		return &mpeg2_bframe;
+
+	case DMX_IDX_H264_SPS:
+		return &h264_sps;
+
+	case DMX_IDX_H264_PPS:
+		return &h264_pps;
+
+	case DMX_IDX_H264_IDR_START:
+		return &h264_idr;
+
+	case DMX_IDX_H264_NON_IDR_START:
+		return &h264_non_idr;
+
+	case DMX_IDX_H264_IDR_ISLICE_START:
+		return &h264_idr_islice;
+
+	case DMX_IDX_H264_NON_IDR_PSLICE_START:
+		return &h264_non_idr_pslice;
+
+	case DMX_IDX_H264_NON_IDR_BSLICE_START:
+		return &h264_non_idr_bslice;
+
+	case DMX_IDX_H264_ACCESS_UNIT_DEL:
+		return &h264_non_access_unit_del;
+
+	case DMX_IDX_H264_SEI:
+		return &h264_non_sei;
+
+	case DMX_IDX_VC1_SEQ_HEADER:
+		return &vc1_seq_hdr;
+
+	case DMX_IDX_VC1_ENTRY_POINT:
+		return &vc1_entry_point;
+
+	case DMX_IDX_VC1_FRAME_START:
+		return &vc1_frame;
+
+	default:
+		return NULL;
+	}
+}
+EXPORT_SYMBOL(dvb_dmx_get_pattern);
+
+static void dvb_dmx_init_idx_state(struct dvb_demux_feed *feed)
+{
+	feed->prev_tsp_num = (u64)-1;
+	feed->curr_pusi_tsp_num = (u64)-1;
+	feed->prev_pusi_tsp_num = (u64)-1;
+	feed->prev_frame_valid = 0;
+	feed->first_frame_in_seq = 0;
+	feed->first_frame_in_seq_notified = 0;
+	feed->last_pattern_tsp_num = (u64)-1;
+	feed->pattern_num = 0;
+	memset(&feed->prefix_size, 0,
+		sizeof(struct dvb_dmx_video_prefix_size_masks));
+
+	if (feed->idx_params.types &
+		(DMX_IDX_MPEG_SEQ_HEADER |
+		 DMX_IDX_MPEG_FIRST_SEQ_FRAME_START |
+		 DMX_IDX_MPEG_FIRST_SEQ_FRAME_END)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_SEQ_HEADER);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types & DMX_IDX_MPEG_GOP)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_GOP);
+		feed->pattern_num++;
+	}
+
+	/* MPEG2 I-frame */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_MPEG_I_FRAME_START | DMX_IDX_MPEG_I_FRAME_END |
+		  DMX_IDX_MPEG_P_FRAME_END | DMX_IDX_MPEG_B_FRAME_END |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_I_FRAME_START);
+		feed->pattern_num++;
+	}
+
+	/* MPEG2 P-frame */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_MPEG_P_FRAME_START | DMX_IDX_MPEG_P_FRAME_END |
+		  DMX_IDX_MPEG_I_FRAME_END | DMX_IDX_MPEG_B_FRAME_END |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_P_FRAME_START);
+		feed->pattern_num++;
+	}
+
+	/* MPEG2 B-frame */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_MPEG_B_FRAME_START | DMX_IDX_MPEG_B_FRAME_END |
+		  DMX_IDX_MPEG_I_FRAME_END | DMX_IDX_MPEG_P_FRAME_END |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_MPEG_B_FRAME_START);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_H264_SPS |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_START |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_SPS);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types & DMX_IDX_H264_PPS)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_PPS);
+		feed->pattern_num++;
+	}
+
+	/* H264 IDR */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_H264_IDR_START | DMX_IDX_H264_IDR_END |
+		  DMX_IDX_H264_NON_IDR_END |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_START |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_IDR_START);
+		feed->pattern_num++;
+	}
+
+	/* H264 non-IDR */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_H264_NON_IDR_START | DMX_IDX_H264_NON_IDR_END |
+		  DMX_IDX_H264_IDR_END |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_START |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_START);
+		feed->pattern_num++;
+	}
+
+	/* H264 IDR ISlice */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_H264_IDR_ISLICE_START | DMX_IDX_H264_IDR_END |
+		  DMX_IDX_H264_NON_IDR_END |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_START |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_IDR_ISLICE_START);
+		feed->pattern_num++;
+	}
+	/* H264 non-IDR PSlice */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_H264_NON_IDR_PSLICE_START | DMX_IDX_H264_NON_IDR_END |
+		  DMX_IDX_H264_IDR_END |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_START |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_PSLICE_START);
+		feed->pattern_num++;
+	}
+	/* H264 non-IDR BSlice */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_H264_NON_IDR_BSLICE_START | DMX_IDX_H264_NON_IDR_END |
+		  DMX_IDX_H264_IDR_END |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_START |
+		  DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_BSLICE_START);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types & DMX_IDX_H264_ACCESS_UNIT_DEL)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_ACCESS_UNIT_DEL);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types & DMX_IDX_H264_SEI)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_H264_SEI);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_VC1_SEQ_HEADER |
+		  DMX_IDX_VC1_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_VC1_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_VC1_SEQ_HEADER);
+		feed->pattern_num++;
+	}
+
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types & DMX_IDX_VC1_ENTRY_POINT)) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_VC1_ENTRY_POINT);
+		feed->pattern_num++;
+	}
+
+	/* VC1 frame */
+	if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+		(feed->idx_params.types &
+		 (DMX_IDX_VC1_FRAME_START | DMX_IDX_VC1_FRAME_END |
+		  DMX_IDX_VC1_FIRST_SEQ_FRAME_START |
+		  DMX_IDX_VC1_FIRST_SEQ_FRAME_END))) {
+		feed->patterns[feed->pattern_num] =
+			dvb_dmx_get_pattern(DMX_IDX_VC1_FRAME_START);
+		feed->pattern_num++;
+	}
+
+	if (feed->pattern_num)
+		feed->rec_info->idx_info.pattern_search_feeds_num++;
+}
+
+static struct dvb_demux_rec_info *dvb_dmx_alloc_rec_info(
+					struct dmx_ts_feed *ts_feed)
+{
+	int i;
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+	struct dvb_demux_rec_info *rec_info;
+	struct dvb_demux_feed *tmp_feed;
+
+	/* check if this feed share recording buffer with other active feeds */
+	list_for_each_entry(tmp_feed, &demux->feed_list, list_head) {
+		if ((tmp_feed->state == DMX_STATE_GO) &&
+			(tmp_feed->type == DMX_TYPE_TS) &&
+			(tmp_feed != feed) &&
+			(tmp_feed->feed.ts.buffer.ringbuff ==
+			 ts_feed->buffer.ringbuff)) {
+			/* indexing information is shared between the feeds */
+			tmp_feed->rec_info->ref_count++;
+			return tmp_feed->rec_info;
+		}
+	}
+
+	/* Need to allocate a new indexing info */
+	for (i = 0; i < demux->feednum; i++)
+		if (!demux->rec_info_pool[i].ref_count)
+			break;
+
+	if (i == demux->feednum)
+		return NULL;
+
+	rec_info = &demux->rec_info_pool[i];
+	rec_info->ref_count++;
+	INIT_LIST_HEAD(&rec_info->idx_info.free_list);
+	INIT_LIST_HEAD(&rec_info->idx_info.ready_list);
+
+	for (i = 0; i < DMX_IDX_EVENT_QUEUE_SIZE; i++)
+		list_add(&rec_info->idx_info.events[i].next,
+			&rec_info->idx_info.free_list);
+
+	rec_info->ts_output_count = 0;
+	rec_info->idx_info.min_pattern_tsp_num = (u64)-1;
+	rec_info->idx_info.pattern_search_feeds_num = 0;
+	rec_info->idx_info.indexing_feeds_num = 0;
+
+	return rec_info;
+}
+
+static void dvb_dmx_free_rec_info(struct dmx_ts_feed *ts_feed)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+
+	if (!feed->rec_info || !feed->rec_info->ref_count) {
+		pr_err("%s: invalid idx info state\n", __func__);
+		return;
+	}
+
+	feed->rec_info->ref_count--;
+}
+
 static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
 {
 	struct dvb_demux_feed *entry;
@@ -635,7 +2172,7 @@
 {
 	spin_lock_irq(&feed->demux->lock);
 	if (dvb_demux_feed_find(feed)) {
-		printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
+		pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n",
 		       __func__, feed->type, feed->state, feed->pid);
 		goto out;
 	}
@@ -649,7 +2186,7 @@
 {
 	spin_lock_irq(&feed->demux->lock);
 	if (!(dvb_demux_feed_find(feed))) {
-		printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
+		pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n",
 		       __func__, feed->type, feed->state, feed->pid);
 		goto out;
 	}
@@ -733,7 +2270,34 @@
 		return -ENODEV;
 	}
 
-	if ((ret = demux->start_feed(feed)) < 0) {
+	feed->first_cc = 1;
+	feed->scrambling_bits = 0;
+
+	if ((feed->ts_type & TS_PACKET) &&
+		!(feed->ts_type & TS_PAYLOAD_ONLY)) {
+		feed->rec_info = dvb_dmx_alloc_rec_info(ts_feed);
+		if (!feed->rec_info) {
+			mutex_unlock(&demux->mutex);
+			return -ENOMEM;
+		}
+		if (feed->idx_params.enable) {
+			dvb_dmx_init_idx_state(feed);
+			feed->rec_info->idx_info.indexing_feeds_num++;
+			if (demux->set_indexing)
+				demux->set_indexing(feed);
+		}
+	} else {
+		feed->pattern_num = 0;
+		feed->rec_info = NULL;
+	}
+
+	ret = demux->start_feed(feed);
+	if (ret < 0) {
+		if ((feed->ts_type & TS_PACKET) &&
+		    !(feed->ts_type & TS_PAYLOAD_ONLY)) {
+			dvb_dmx_free_rec_info(ts_feed);
+			feed->rec_info = NULL;
+		}
 		mutex_unlock(&demux->mutex);
 		return ret;
 	}
@@ -771,11 +2335,337 @@
 	ts_feed->is_filtering = 0;
 	feed->state = DMX_STATE_ALLOCATED;
 	spin_unlock_irq(&demux->lock);
+
+	if (feed->rec_info) {
+		if (feed->pattern_num)
+			feed->rec_info->idx_info.pattern_search_feeds_num--;
+		if (feed->idx_params.enable)
+			feed->rec_info->idx_info.indexing_feeds_num--;
+		dvb_dmx_free_rec_info(ts_feed);
+		feed->rec_info = NULL;
+	}
+
 	mutex_unlock(&demux->mutex);
 
 	return ret;
 }
 
+static int dmx_ts_feed_decoder_buff_status(struct dmx_ts_feed *ts_feed,
+			struct dmx_buffer_status *dmx_buffer_status)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+	int ret;
+
+	mutex_lock(&demux->mutex);
+
+	if (feed->state < DMX_STATE_GO) {
+		mutex_unlock(&demux->mutex);
+		return -EINVAL;
+	}
+
+	if (!demux->decoder_buffer_status) {
+		mutex_unlock(&demux->mutex);
+		return -ENODEV;
+	}
+
+	ret = demux->decoder_buffer_status(feed, dmx_buffer_status);
+
+	mutex_unlock(&demux->mutex);
+
+	return ret;
+}
+
+static int dmx_ts_feed_reuse_decoder_buffer(struct dmx_ts_feed *ts_feed,
+						int cookie)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+	int ret;
+
+	mutex_lock(&demux->mutex);
+
+	if (feed->state < DMX_STATE_GO) {
+		mutex_unlock(&demux->mutex);
+		return -EINVAL;
+	}
+
+	if (!demux->reuse_decoder_buffer) {
+		mutex_unlock(&demux->mutex);
+		return -ENODEV;
+	}
+
+	ret = demux->reuse_decoder_buffer(feed, cookie);
+
+	mutex_unlock(&demux->mutex);
+
+	return ret;
+}
+
+static int dmx_ts_feed_data_ready_cb(struct dmx_ts_feed *feed,
+				dmx_ts_data_ready_cb callback)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if (dvbdmxfeed->state == DMX_STATE_GO) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+
+	dvbdmxfeed->data_ready_cb.ts = callback;
+
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+static int dmx_ts_set_secure_mode(struct dmx_ts_feed *feed,
+				struct dmx_secure_mode *secure_mode)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
+		return -ERESTARTSYS;
+
+	if (dvbdmxfeed->state == DMX_STATE_GO) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EBUSY;
+	}
+
+	dvbdmxfeed->secure_mode = *secure_mode;
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+static int dmx_ts_set_cipher_ops(struct dmx_ts_feed *feed,
+				struct dmx_cipher_operations *cipher_ops)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
+		return -ERESTARTSYS;
+
+	if ((dvbdmxfeed->state == DMX_STATE_GO) &&
+		dvbdmx->set_cipher_op)
+		ret = dvbdmx->set_cipher_op(dvbdmxfeed, cipher_ops);
+
+	if (!ret)
+		dvbdmxfeed->cipher_ops = *cipher_ops;
+
+	mutex_unlock(&dvbdmx->mutex);
+	return ret;
+}
+
+static int dmx_ts_set_video_codec(
+	struct dmx_ts_feed *ts_feed,
+	enum dmx_video_codec video_codec)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+
+	feed->video_codec = video_codec;
+
+	return 0;
+}
+
+static int dmx_ts_set_idx_params(struct dmx_ts_feed *ts_feed,
+	struct dmx_indexing_params *idx_params)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *dvbdmx = feed->demux;
+	int idx_enabled;
+	int ret = 0;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if ((feed->state == DMX_STATE_GO) &&
+		!feed->rec_info) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+
+	idx_enabled = feed->idx_params.enable;
+	feed->idx_params = *idx_params;
+
+	if (feed->state == DMX_STATE_GO) {
+		spin_lock_irq(&dvbdmx->lock);
+		if (feed->pattern_num)
+			feed->rec_info->idx_info.pattern_search_feeds_num--;
+		if (idx_enabled && !idx_params->enable)
+			feed->rec_info->idx_info.indexing_feeds_num--;
+		if (!idx_enabled && idx_params->enable)
+			feed->rec_info->idx_info.indexing_feeds_num++;
+		dvb_dmx_init_idx_state(feed);
+		spin_unlock_irq(&dvbdmx->lock);
+
+		if (dvbdmx->set_indexing)
+			ret = dvbdmx->set_indexing(feed);
+	}
+
+	mutex_unlock(&dvbdmx->mutex);
+
+	return ret;
+}
+
+static int dvbdmx_ts_feed_oob_cmd(struct dmx_ts_feed *ts_feed,
+		struct dmx_oob_command *cmd)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dmx_data_ready data;
+	struct dvb_demux *dvbdmx = feed->demux;
+	int ret = 0;
+	int secure_non_rec = feed->secure_mode.is_secured &&
+		!dvb_dmx_is_rec_feed(feed);
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if (feed->state != DMX_STATE_GO) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+
+	/* Decoder & non-recording secure feeds are handled by plug-in */
+	if ((feed->ts_type & TS_DECODER) || secure_non_rec) {
+		if (feed->demux->oob_command)
+			ret = feed->demux->oob_command(feed, cmd);
+	}
+
+	if (!(feed->ts_type & (TS_PAYLOAD_ONLY | TS_PACKET)) ||
+		secure_non_rec) {
+		mutex_unlock(&dvbdmx->mutex);
+		return ret;
+	}
+
+	data.data_length = 0;
+
+	switch (cmd->type) {
+	case DMX_OOB_CMD_EOS:
+		if (feed->ts_type & TS_PAYLOAD_ONLY)
+			dvb_dmx_check_pes_end(feed);
+
+		data.status = DMX_OK_EOS;
+		ret = feed->data_ready_cb.ts(&feed->feed.ts, &data);
+		break;
+
+	case DMX_OOB_CMD_MARKER:
+		data.status = DMX_OK_MARKER;
+		data.marker.id = cmd->params.marker.id;
+		ret = feed->data_ready_cb.ts(&feed->feed.ts, &data);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&dvbdmx->mutex);
+	return ret;
+}
+
+static int dvbdmx_ts_get_scrambling_bits(struct dmx_ts_feed *ts_feed,
+			u8 *value)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+
+	spin_lock(&demux->lock);
+
+	if (!ts_feed->is_filtering) {
+		spin_unlock(&demux->lock);
+		return -EINVAL;
+	}
+
+	*value = feed->scrambling_bits;
+	spin_unlock(&demux->lock);
+
+	return 0;
+}
+
+static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
+			char *data, size_t size)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+
+	spin_lock(&demux->lock);
+	if (!ts_feed->is_filtering) {
+		spin_unlock(&demux->lock);
+		return 0;
+	}
+
+	feed->cb.ts(data, size, NULL, 0, ts_feed);
+
+	spin_unlock(&demux->lock);
+
+	return 0;
+}
+
+static int dmx_ts_set_tsp_out_format(
+	struct dmx_ts_feed *ts_feed,
+	enum dmx_tsp_format_t tsp_format)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *dvbdmx = feed->demux;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if (feed->state == DMX_STATE_GO) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+
+	feed->tsp_out_format = tsp_format;
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+/**
+ * dvbdmx_ts_reset_pes_state() - Reset the current PES length and PES counters
+ *
+ * @feed: dvb demux feed object
+ */
+void dvbdmx_ts_reset_pes_state(struct dvb_demux_feed *feed)
+{
+	unsigned long flags;
+
+	/*
+	 * Reset PES state.
+	 * PUSI seen indication is kept so we can get partial PES.
+	 */
+	spin_lock_irqsave(&feed->demux->lock, flags);
+
+	feed->peslen = 0;
+	feed->pes_tei_counter = 0;
+	feed->pes_cont_err_counter = 0;
+	feed->pes_ts_packets_num = 0;
+
+	spin_unlock_irqrestore(&feed->demux->lock, flags);
+}
+EXPORT_SYMBOL(dvbdmx_ts_reset_pes_state);
+
+static int dvbdmx_ts_flush_buffer(struct dmx_ts_feed *ts_feed, size_t length)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&demux->mutex))
+		return -ERESTARTSYS;
+
+	dvbdmx_ts_reset_pes_state(feed);
+
+	if ((feed->ts_type & TS_DECODER) && demux->flush_decoder_buffer)
+		/* Call decoder specific flushing if one exists */
+		ret = demux->flush_decoder_buffer(feed, length);
+
+	mutex_unlock(&demux->mutex);
+	return ret;
+}
+
 static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
 				   struct dmx_ts_feed **ts_feed,
 				   dmx_ts_cb callback)
@@ -795,8 +2685,21 @@
 	feed->cb.ts = callback;
 	feed->demux = demux;
 	feed->pid = 0xffff;
-	feed->peslen = 0xfffa;
+	feed->peslen = 0;
+	feed->pes_tei_counter = 0;
+	feed->pes_ts_packets_num = 0;
+	feed->pes_cont_err_counter = 0;
+	feed->secure_mode.is_secured = 0;
 	feed->buffer = NULL;
+	feed->tsp_out_format = DMX_TSP_FORMAT_188;
+	feed->idx_params.enable = 0;
+
+	/* default behaviour - pass first PES data even if it is
+	 * partial PES data from previous PES that we didn't receive its header.
+	 * Override this to 0 in your start_feed function in order to handle
+	 * first PES differently.
+	 */
+	feed->pusi_seen = 1;
 
 	(*ts_feed) = &feed->feed.ts;
 	(*ts_feed)->parent = dmx;
@@ -805,6 +2708,22 @@
 	(*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
 	(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
 	(*ts_feed)->set = dmx_ts_feed_set;
+	(*ts_feed)->set_video_codec = dmx_ts_set_video_codec;
+	(*ts_feed)->set_idx_params = dmx_ts_set_idx_params;
+	(*ts_feed)->set_tsp_out_format = dmx_ts_set_tsp_out_format;
+	(*ts_feed)->get_decoder_buff_status = dmx_ts_feed_decoder_buff_status;
+	(*ts_feed)->reuse_decoder_buffer = dmx_ts_feed_reuse_decoder_buffer;
+	(*ts_feed)->data_ready_cb = dmx_ts_feed_data_ready_cb;
+	(*ts_feed)->notify_data_read = NULL;
+	(*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
+	(*ts_feed)->set_cipher_ops = dmx_ts_set_cipher_ops;
+	(*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd;
+	(*ts_feed)->get_scrambling_bits = dvbdmx_ts_get_scrambling_bits;
+	(*ts_feed)->ts_insertion_init = NULL;
+	(*ts_feed)->ts_insertion_terminate = NULL;
+	(*ts_feed)->ts_insertion_insert_buffer =
+		dvbdmx_ts_insertion_insert_buffer;
+	(*ts_feed)->flush_buffer = dvbdmx_ts_flush_buffer;
 
 	if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
 		feed->state = DMX_STATE_FREE;
@@ -840,7 +2759,7 @@
 
 	feed->state = DMX_STATE_FREE;
 	feed->filter->state = DMX_STATE_FREE;
-
+	ts_feed->priv = NULL;
 	dvb_demux_feed_del(feed);
 
 	feed->pid = 0xffff;
@@ -966,6 +2885,8 @@
 	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
 	dvbdmxfeed->feed.sec.secbufp = 0;
 	dvbdmxfeed->feed.sec.seclen = 0;
+	dvbdmxfeed->first_cc = 1;
+	dvbdmxfeed->scrambling_bits = 0;
 
 	if (!dvbdmx->start_feed) {
 		mutex_unlock(&dvbdmx->mutex);
@@ -996,6 +2917,11 @@
 
 	mutex_lock(&dvbdmx->mutex);
 
+	if (dvbdmxfeed->state < DMX_STATE_GO) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+
 	if (!dvbdmx->stop_feed) {
 		mutex_unlock(&dvbdmx->mutex);
 		return -ENODEV;
@@ -1012,6 +2938,66 @@
 	return ret;
 }
 
+
+static int dmx_section_feed_data_ready_cb(struct dmx_section_feed *feed,
+				dmx_section_data_ready_cb callback)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if (dvbdmxfeed->state == DMX_STATE_GO) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+
+	dvbdmxfeed->data_ready_cb.sec = callback;
+
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+static int dmx_section_set_secure_mode(struct dmx_section_feed *feed,
+				struct dmx_secure_mode *secure_mode)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if (dvbdmxfeed->state == DMX_STATE_GO) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EBUSY;
+	}
+
+	dvbdmxfeed->secure_mode = *secure_mode;
+	mutex_unlock(&dvbdmx->mutex);
+	return 0;
+}
+
+static int dmx_section_set_cipher_ops(struct dmx_section_feed *feed,
+				struct dmx_cipher_operations *cipher_ops)
+{
+	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&dvbdmx->mutex))
+		return -ERESTARTSYS;
+
+	if ((dvbdmxfeed->state == DMX_STATE_GO) &&
+		dvbdmx->set_cipher_op) {
+		ret = dvbdmx->set_cipher_op(dvbdmxfeed, cipher_ops);
+	}
+
+	if (!ret)
+		dvbdmxfeed->cipher_ops = *cipher_ops;
+
+	mutex_unlock(&dvbdmx->mutex);
+	return ret;
+}
+
 static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
 					   struct dmx_section_filter *filter)
 {
@@ -1045,12 +3031,82 @@
 		f->next = f->next->next;
 	}
 
+	filter->priv = NULL;
 	dvbdmxfilter->state = DMX_STATE_FREE;
 	spin_unlock_irq(&dvbdmx->lock);
 	mutex_unlock(&dvbdmx->mutex);
 	return 0;
 }
 
+static int dvbdmx_section_feed_oob_cmd(struct dmx_section_feed *section_feed,
+		struct dmx_oob_command *cmd)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed;
+	struct dvb_demux *dvbdmx = feed->demux;
+	struct dmx_data_ready data;
+	int ret = 0;
+
+	data.data_length = 0;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	if (feed->state != DMX_STATE_GO) {
+		mutex_unlock(&dvbdmx->mutex);
+		return -EINVAL;
+	}
+
+	/* Secure section feeds are handled by the plug-in */
+	if (feed->secure_mode.is_secured) {
+		if (feed->demux->oob_command)
+			ret = feed->demux->oob_command(feed, cmd);
+		else
+			ret = 0;
+
+		mutex_unlock(&dvbdmx->mutex);
+		return ret;
+	}
+
+	switch (cmd->type) {
+	case DMX_OOB_CMD_EOS:
+		data.status = DMX_OK_EOS;
+		break;
+
+	case DMX_OOB_CMD_MARKER:
+		data.status = DMX_OK_MARKER;
+		data.marker.id = cmd->params.marker.id;
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (!ret)
+		ret = dvb_dmx_notify_section_event(feed, &data, 1);
+
+	mutex_unlock(&dvbdmx->mutex);
+	return ret;
+}
+
+static int dvbdmx_section_get_scrambling_bits(
+	struct dmx_section_feed *section_feed, u8 *value)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed;
+	struct dvb_demux *demux = feed->demux;
+
+	spin_lock(&demux->lock);
+
+	if (!section_feed->is_filtering) {
+		spin_unlock(&demux->lock);
+		return -EINVAL;
+	}
+
+	*value = feed->scrambling_bits;
+	spin_unlock(&demux->lock);
+
+	return 0;
+}
+
 static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
 					struct dmx_section_feed **feed,
 					dmx_section_cb callback)
@@ -1070,11 +3126,14 @@
 	dvbdmxfeed->cb.sec = callback;
 	dvbdmxfeed->demux = dvbdmx;
 	dvbdmxfeed->pid = 0xffff;
+	dvbdmxfeed->secure_mode.is_secured = 0;
+	dvbdmxfeed->tsp_out_format = DMX_TSP_FORMAT_188;
 	dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
 	dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
 	dvbdmxfeed->feed.sec.tsfeedp = 0;
 	dvbdmxfeed->filter = NULL;
 	dvbdmxfeed->buffer = NULL;
+	dvbdmxfeed->idx_params.enable = 0;
 
 	(*feed) = &dvbdmxfeed->feed.sec;
 	(*feed)->is_filtering = 0;
@@ -1086,6 +3145,13 @@
 	(*feed)->start_filtering = dmx_section_feed_start_filtering;
 	(*feed)->stop_filtering = dmx_section_feed_stop_filtering;
 	(*feed)->release_filter = dmx_section_feed_release_filter;
+	(*feed)->data_ready_cb = dmx_section_feed_data_ready_cb;
+	(*feed)->notify_data_read = NULL;
+	(*feed)->set_secure_mode = dmx_section_set_secure_mode;
+	(*feed)->set_cipher_ops = dmx_section_set_cipher_ops;
+	(*feed)->oob_command = dvbdmx_section_feed_oob_cmd;
+	(*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits;
+	(*feed)->flush_buffer = NULL;
 
 	mutex_unlock(&dvbdmx->mutex);
 	return 0;
@@ -1108,7 +3174,7 @@
 	dvbdmxfeed->buffer = NULL;
 #endif
 	dvbdmxfeed->state = DMX_STATE_FREE;
-
+	feed->priv = NULL;
 	dvb_demux_feed_del(dvbdmxfeed);
 
 	dvbdmxfeed->pid = 0xffff;
@@ -1144,23 +3210,18 @@
 	return 0;
 }
 
-static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
+static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
 {
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-	void *p;
 
-	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
+	if (!demux->frontend || !buf || demux->dvr_input_protected ||
+		(demux->frontend->source != DMX_MEMORY_FE))
 		return -EINVAL;
-
-	p = memdup_user(buf, count);
-	if (IS_ERR(p))
-		return PTR_ERR(p);
-	if (mutex_lock_interruptible(&dvbdemux->mutex)) {
-		kfree(p);
+	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
-	}
-	dvb_dmx_swfilter(dvbdemux, p, count);
-	kfree(p);
+
+	dvb_dmx_swfilter_format(dvbdemux, buf, count, dvbdemux->tsp_format);
+
 	mutex_unlock(&dvbdemux->mutex);
 
 	if (signal_pending(current))
@@ -1168,6 +3229,40 @@
 	return count;
 }
 
+static int dvbdmx_write_cancel(struct dmx_demux *demux)
+{
+	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+
+	spin_lock_irq(&dvbdmx->lock);
+
+	/* cancel any pending wait for decoder's buffers */
+	dvbdmx->sw_filter_abort = 1;
+	dvbdmx->tsbufp = 0;
+	dvb_dmx_configure_decoder_fullness(dvbdmx, 0);
+
+	spin_unlock_irq(&dvbdmx->lock);
+
+	return 0;
+}
+
+static int dvbdmx_set_playback_mode(struct dmx_demux *demux,
+				 enum dmx_playback_mode_t mode,
+				 dmx_ts_fullness ts_fullness_callback,
+				 dmx_section_fullness sec_fullness_callback)
+{
+	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	dvbdmx->playback_mode = mode;
+	dvbdmx->buffer_ctrl.ts = ts_fullness_callback;
+	dvbdmx->buffer_ctrl.sec = sec_fullness_callback;
+
+	mutex_unlock(&dvbdmx->mutex);
+
+	return 0;
+}
+
 static int dvbdmx_add_frontend(struct dmx_demux *demux,
 			       struct dmx_frontend *frontend)
 {
@@ -1225,7 +3320,7 @@
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
 
 	mutex_lock(&dvbdemux->mutex);
-
+	dvbdemux->sw_filter_abort = 0;
 	demux->frontend = NULL;
 	mutex_unlock(&dvbdemux->mutex);
 	return 0;
@@ -1235,7 +3330,50 @@
 {
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
 
-	memcpy(pids, dvbdemux->pids, 5 * sizeof(u16));
+    /* 4 Demux Instances each with group of 5 pids */
+	memcpy(pids, dvbdemux->pids, DMX_PES_OTHER*sizeof(u16));
+	return 0;
+}
+
+static int dvbdmx_get_tsp_size(struct dmx_demux *demux)
+{
+	int tsp_size;
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	mutex_lock(&dvbdemux->mutex);
+	tsp_size = dvbdemux->ts_packet_size;
+	mutex_unlock(&dvbdemux->mutex);
+
+	return tsp_size;
+}
+
+static int dvbdmx_set_tsp_format(
+	struct dmx_demux *demux,
+	enum dmx_tsp_format_t tsp_format)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	if ((tsp_format > DMX_TSP_FORMAT_204) ||
+		(tsp_format < DMX_TSP_FORMAT_188))
+		return -EINVAL;
+
+	mutex_lock(&dvbdemux->mutex);
+
+	dvbdemux->tsp_format = tsp_format;
+	switch (tsp_format) {
+	case DMX_TSP_FORMAT_188:
+		dvbdemux->ts_packet_size = 188;
+		break;
+	case DMX_TSP_FORMAT_192_TAIL:
+	case DMX_TSP_FORMAT_192_HEAD:
+		dvbdemux->ts_packet_size = 192;
+		break;
+	case DMX_TSP_FORMAT_204:
+		dvbdemux->ts_packet_size = 204;
+		break;
+	}
+
+	mutex_unlock(&dvbdemux->mutex);
 	return 0;
 }
 
@@ -1257,13 +3395,50 @@
 		dvbdemux->filter = NULL;
 		return -ENOMEM;
 	}
+
+	dvbdemux->rec_info_pool = vmalloc(dvbdemux->feednum *
+		sizeof(struct dvb_demux_rec_info));
+	if (!dvbdemux->rec_info_pool) {
+		vfree(dvbdemux->feed);
+		vfree(dvbdemux->filter);
+		dvbdemux->feed = NULL;
+		dvbdemux->filter = NULL;
+		return -ENOMEM;
+	}
+
+	dvbdemux->sw_filter_abort = 0;
+	dvbdemux->total_process_time = 0;
+	dvbdemux->total_crc_time = 0;
+	snprintf(dvbdemux->alias,
+			MAX_DVB_DEMUX_NAME_LEN,
+			"demux%d",
+			dvb_demux_index++);
+
+	dvbdemux->dmx.debugfs_demux_dir =
+		debugfs_create_dir(dvbdemux->alias, NULL);
+
+	if (dvbdemux->dmx.debugfs_demux_dir != NULL) {
+		debugfs_create_u32(
+			"total_processing_time", 0664,
+			dvbdemux->dmx.debugfs_demux_dir,
+			&dvbdemux->total_process_time);
+
+		debugfs_create_u32(
+			"total_crc_time", 0664,
+			dvbdemux->dmx.debugfs_demux_dir,
+			&dvbdemux->total_crc_time);
+	}
+
 	for (i = 0; i < dvbdemux->filternum; i++) {
 		dvbdemux->filter[i].state = DMX_STATE_FREE;
 		dvbdemux->filter[i].index = i;
 	}
+
 	for (i = 0; i < dvbdemux->feednum; i++) {
 		dvbdemux->feed[i].state = DMX_STATE_FREE;
 		dvbdemux->feed[i].index = i;
+
+		dvbdemux->rec_info_pool[i].ref_count = 0;
 	}
 
 	dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
@@ -1283,6 +3458,9 @@
 	dvbdemux->recording = 0;
 	dvbdemux->tsbufp = 0;
 
+	dvbdemux->tsp_format = DMX_TSP_FORMAT_188;
+	dvbdemux->ts_packet_size = 188;
+
 	if (!dvbdemux->check_crc32)
 		dvbdemux->check_crc32 = dvb_dmx_crc32;
 
@@ -1294,10 +3472,14 @@
 	dmx->open = dvbdmx_open;
 	dmx->close = dvbdmx_close;
 	dmx->write = dvbdmx_write;
+	dmx->write_cancel = dvbdmx_write_cancel;
+	dmx->set_playback_mode = dvbdmx_set_playback_mode;
 	dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
 	dmx->release_ts_feed = dvbdmx_release_ts_feed;
 	dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
 	dmx->release_section_feed = dvbdmx_release_section_feed;
+	dmx->map_buffer = NULL;
+	dmx->unmap_buffer = NULL;
 
 	dmx->add_frontend = dvbdmx_add_frontend;
 	dmx->remove_frontend = dvbdmx_remove_frontend;
@@ -1306,6 +3488,9 @@
 	dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
 	dmx->get_pes_pids = dvbdmx_get_pes_pids;
 
+	dmx->set_tsp_format = dvbdmx_set_tsp_format;
+	dmx->get_tsp_size = dvbdmx_get_tsp_size;
+
 	mutex_init(&dvbdemux->mutex);
 	spin_lock_init(&dvbdemux->lock);
 
@@ -1316,9 +3501,14 @@
 
 void dvb_dmx_release(struct dvb_demux *dvbdemux)
 {
+	if (dvbdemux->dmx.debugfs_demux_dir != NULL)
+		debugfs_remove_recursive(dvbdemux->dmx.debugfs_demux_dir);
+
+	dvb_demux_index--;
 	vfree(dvbdemux->cnt_storage);
 	vfree(dvbdemux->filter);
 	vfree(dvbdemux->feed);
+	vfree(dvbdemux->rec_info_pool);
 }
 
 EXPORT_SYMBOL(dvb_dmx_release);
diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h
index 5ed3cab..7ba053d 100644
--- a/drivers/media/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb-core/dvb_demux.h
@@ -27,6 +27,7 @@
 #include <linux/timer.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
+#include <linux/debugfs.h>
 
 #include "demux.h"
 
@@ -44,6 +45,8 @@
 
 #define MAX_PID 0x1fff
 
+#define TIMESTAMP_LEN	4
+
 #define SPEED_PKTS_INTERVAL 50000
 
 struct dvb_demux_filter {
@@ -64,6 +67,92 @@
 
 #define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
 
+
+struct dmx_index_entry {
+	struct dmx_index_event_info event;
+	struct list_head next;
+};
+
+#define DMX_IDX_EVENT_QUEUE_SIZE	DMX_EVENT_QUEUE_SIZE
+
+struct dvb_demux_rec_info {
+	/* Reference counter for number of feeds using this information */
+	int ref_count;
+
+	/* Counter for number of TS packets output to recording buffer */
+	u64 ts_output_count;
+
+	/* Indexing information */
+	struct {
+		/*
+		 * Minimum TS packet number encountered in recording filter
+		 * among all feeds that search for video patterns
+		 */
+		u64 min_pattern_tsp_num;
+
+		/* Number of indexing-enabled feeds */
+		u8 indexing_feeds_num;
+
+		/* Number of feeds with video pattern search request */
+		u8 pattern_search_feeds_num;
+
+		/* Index entries pool */
+		struct dmx_index_entry events[DMX_IDX_EVENT_QUEUE_SIZE];
+
+		/* List of free entries that can be used for new index events */
+		struct list_head free_list;
+
+		/* List holding ready index entries not notified to user yet */
+		struct list_head ready_list;
+	} idx_info;
+};
+
+#define DVB_DMX_MAX_PATTERN_LEN			6
+struct dvb_dmx_video_patterns {
+	/* the byte pattern to look for */
+	u8 pattern[DVB_DMX_MAX_PATTERN_LEN];
+
+	/* the byte mask to use (same length as pattern) */
+	u8 mask[DVB_DMX_MAX_PATTERN_LEN];
+
+	/* the length of the pattern, in bytes */
+	size_t size;
+
+	/* the type of the pattern. One of DMX_IDX_* definitions */
+	u64 type;
+};
+
+#define DVB_DMX_MAX_FOUND_PATTERNS					20
+#define DVB_DMX_MAX_SEARCH_PATTERN_NUM				20
+struct dvb_dmx_video_prefix_size_masks {
+	/*
+	 * a bit mask (per pattern) of possible prefix sizes to use
+	 * when searching for a pattern that started in the previous TS packet.
+	 * Updated by dvb_dmx_video_pattern_search for use in the next lookup.
+	 */
+	u32 size_mask[DVB_DMX_MAX_FOUND_PATTERNS];
+};
+
+struct dvb_dmx_video_patterns_results {
+	struct {
+		/*
+		 * The offset in the buffer where the pattern was found.
+		 * If a pattern is found using a prefix (i.e. started on the
+		 * previous buffer), offset is zero.
+		 */
+		u32 offset;
+
+		/*
+		 * The type of the pattern found.
+		 * One of DMX_IDX_* definitions.
+		 */
+		u64 type;
+
+		/* The prefix size that was used to find this pattern */
+		u32 used_prefix_size;
+	} info[DVB_DMX_MAX_FOUND_PATTERNS];
+};
+
 struct dvb_demux_feed {
 	union {
 		struct dmx_ts_feed ts;
@@ -75,6 +164,11 @@
 		dmx_section_cb sec;
 	} cb;
 
+	union {
+		dmx_ts_data_ready_cb ts;
+		dmx_section_data_ready_cb sec;
+	} data_ready_cb;
+
 	struct dvb_demux *demux;
 	void *priv;
 	int type;
@@ -82,6 +176,9 @@
 	u16 pid;
 	u8 *buffer;
 	int buffer_size;
+	enum dmx_tsp_format_t tsp_out_format;
+	struct dmx_secure_mode secure_mode;
+	struct dmx_cipher_operations cipher_ops;
 
 	ktime_t timeout;
 	struct dvb_demux_filter *filter;
@@ -90,12 +187,34 @@
 	enum dmx_ts_pes pes_type;
 
 	int cc;
+	int first_cc;
 	int pusi_seen;		/* prevents feeding of garbage from previous section */
 
+	u8 scrambling_bits;
+
+	struct dvb_demux_rec_info *rec_info;
+	u64 prev_tsp_num;
+	u64 prev_stc;
+	u64 curr_pusi_tsp_num;
+	u64 prev_pusi_tsp_num;
+	int prev_frame_valid;
+	u64 prev_frame_type;
+	int first_frame_in_seq;
+	int first_frame_in_seq_notified;
+	u64 last_pattern_tsp_num;
+	int pattern_num;
+const struct dvb_dmx_video_patterns *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM];
+	struct dvb_dmx_video_prefix_size_masks prefix_size;
 	u16 peslen;
+	u32 pes_tei_counter;
+	u32 pes_cont_err_counter;
+	u32 pes_ts_packets_num;
 
 	struct list_head list_head;
 	unsigned int index;	/* a unique index for each feed (can be used as hardware pid filter index) */
+
+	enum dmx_video_codec video_codec;
+	struct dmx_indexing_params idx_params;
 };
 
 struct dvb_demux {
@@ -107,10 +226,27 @@
 	int (*stop_feed)(struct dvb_demux_feed *feed);
 	int (*write_to_decoder)(struct dvb_demux_feed *feed,
 				 const u8 *buf, size_t len);
+	int (*decoder_fullness_init)(struct dvb_demux_feed *feed);
+	int (*decoder_fullness_wait)(struct dvb_demux_feed *feed,
+				 size_t required_space);
+	int (*decoder_fullness_abort)(struct dvb_demux_feed *feed);
+	int (*decoder_buffer_status)(struct dvb_demux_feed *feed,
+				struct dmx_buffer_status *dmx_buffer_status);
+	int (*reuse_decoder_buffer)(struct dvb_demux_feed *feed,
+				int cookie);
+	int (*set_cipher_op)(struct dvb_demux_feed *feed,
+				struct dmx_cipher_operations *cipher_ops);
 	u32 (*check_crc32)(struct dvb_demux_feed *feed,
 			    const u8 *buf, size_t len);
 	void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
 			 const u8 *src, size_t len);
+	int (*oob_command)(struct dvb_demux_feed *feed,
+		struct dmx_oob_command *cmd);
+	void (*convert_ts)(struct dvb_demux_feed *feed,
+			 const u8 timestamp[TIMESTAMP_LEN],
+			 u64 *timestampIn27Mhz);
+	int (*set_indexing)(struct dvb_demux_feed *feed);
+	int (*flush_decoder_buffer)(struct dvb_demux_feed *feed, size_t length);
 
 	int users;
 #define MAX_DVB_DEMUX_USERS 10
@@ -136,10 +272,35 @@
 
 	ktime_t speed_last_time; /* for TS speed check */
 	uint32_t speed_pkts_cnt; /* for TS speed check */
+
+	enum dmx_tsp_format_t tsp_format;
+	size_t ts_packet_size;
+
+	enum dmx_playback_mode_t playback_mode;
+	int sw_filter_abort;
+
+	struct {
+		dmx_ts_fullness ts;
+		dmx_section_fullness sec;
+	} buffer_ctrl;
+
+	struct dvb_demux_rec_info *rec_info_pool;
+
+	/*
+	 * the following is used for debugfs exposing info
+	 * about dvb demux performance.
+	 */
+#define MAX_DVB_DEMUX_NAME_LEN 10
+	char alias[MAX_DVB_DEMUX_NAME_LEN];
+
+	u32 total_process_time;
+	u32 total_crc_time;
 };
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);
 void dvb_dmx_release(struct dvb_demux *dvbdemux);
+int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf,
+	int should_lock);
 void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
 			      size_t count);
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
@@ -147,5 +308,141 @@
 			  size_t count);
 void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
 			  size_t count);
+void dvb_dmx_swfilter_format(
+			struct dvb_demux *demux, const u8 *buf,
+			size_t count,
+			enum dmx_tsp_format_t tsp_format);
+void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+				const u8 timestamp[TIMESTAMP_LEN]);
+const struct dvb_dmx_video_patterns *dvb_dmx_get_pattern(u64 dmx_idx_pattern);
+int dvb_dmx_video_pattern_search(
+		const struct dvb_dmx_video_patterns
+			*patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM],
+		int patterns_num,
+		const u8 *buf, size_t buf_size,
+		struct dvb_dmx_video_prefix_size_masks *prefix_size_masks,
+		struct dvb_dmx_video_patterns_results *results);
+int dvb_demux_push_idx_event(struct dvb_demux_feed *feed,
+		struct dmx_index_event_info *idx_event, int should_lock);
+void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed,
+		struct dvb_dmx_video_patterns_results *patterns, int pattern,
+		u64 curr_stc, u64 prev_stc,
+		u64 curr_match_tsp, u64 prev_match_tsp,
+		u64 curr_pusi_tsp, u64 prev_pusi_tsp);
+void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed, int should_lock);
+int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed,
+	struct dmx_data_ready *event, int should_lock);
+void dvbdmx_ts_reset_pes_state(struct dvb_demux_feed *feed);
+
+/**
+ * dvb_dmx_is_video_feed - Returns whether the PES feed
+ * is video one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return     1 if feed is video feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_video_feed(struct dvb_demux_feed *feed)
+{
+	if (feed->type != DMX_TYPE_TS)
+		return 0;
+
+	if (feed->ts_type & (~TS_DECODER))
+		return 0;
+
+	if ((feed->pes_type == DMX_PES_VIDEO0) ||
+		(feed->pes_type == DMX_PES_VIDEO1) ||
+		(feed->pes_type == DMX_PES_VIDEO2) ||
+		(feed->pes_type == DMX_PES_VIDEO3))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * dvb_dmx_is_audio_feed - Returns whether the PES feed
+ * is audio one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return     1 if feed is audio feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_audio_feed(struct dvb_demux_feed *feed)
+{
+	if (feed->type != DMX_TYPE_TS)
+		return 0;
+
+	if (feed->ts_type & (~TS_DECODER))
+		return 0;
+
+	if ((feed->pes_type == DMX_PES_AUDIO0) ||
+		(feed->pes_type == DMX_PES_AUDIO1) ||
+		(feed->pes_type == DMX_PES_AUDIO2) ||
+		(feed->pes_type == DMX_PES_AUDIO3))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * dvb_dmx_is_pcr_feed - Returns whether the PES feed
+ * is PCR one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return     1 if feed is PCR feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_pcr_feed(struct dvb_demux_feed *feed)
+{
+	if (feed->type != DMX_TYPE_TS)
+		return 0;
+
+	if (feed->ts_type & (~TS_DECODER))
+		return 0;
+
+	if ((feed->pes_type == DMX_PES_PCR0) ||
+		(feed->pes_type == DMX_PES_PCR1) ||
+		(feed->pes_type == DMX_PES_PCR2) ||
+		(feed->pes_type == DMX_PES_PCR3))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * dvb_dmx_is_sec_feed - Returns whether this is a section feed
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return 1 if feed is a section feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_sec_feed(struct dvb_demux_feed *feed)
+{
+	return (feed->type == DMX_TYPE_SEC);
+}
+
+/**
+ * dvb_dmx_is_rec_feed - Returns whether this is a recording feed
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return 1 if feed is recording feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_rec_feed(struct dvb_demux_feed *feed)
+{
+	if (feed->type != DMX_TYPE_TS)
+		return 0;
+
+	if (feed->ts_type & (TS_DECODER | TS_PAYLOAD_ONLY))
+		return 0;
+
+	return 1;
+}
+
+static inline u16 ts_pid(const u8 *buf)
+{
+	return ((buf[1] & 0x1f) << 8) + buf[2];
+}
+
 
 #endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 9914f69..efb7d52 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -997,7 +997,7 @@
 		netdev_dbg(dev, "start filtering\n");
 		priv->secfeed->start_filtering(priv->secfeed);
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
-		ktime_t timeout = ns_to_ktime(10 * NSEC_PER_MSEC);
+		ktime_t timeout = ktime_set(0, 10*NSEC_PER_MSEC); // 10 msec
 
 		/* we have payloads encapsulated in TS */
 		netdev_dbg(dev, "alloc tsfeed\n");
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c
index 7df7fb3..d4514c1 100644
--- a/drivers/media/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb-core/dvb_ringbuffer.c
@@ -37,6 +37,8 @@
 
 #define PKT_READY 0
 #define PKT_DISPOSED 1
+#define PKT_PENDING 2
+
 
 
 void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
@@ -209,18 +211,19 @@
 }
 
 ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
-				  const u8 __user *buf, size_t len)
+					const u8 __user *buf, size_t len)
 {
-	int status;
 	size_t todo = len;
 	size_t split;
+	ssize_t oldpwrite = rbuf->pwrite;
 
-	split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
+	split = (rbuf->pwrite + len > rbuf->size) ?
+			rbuf->size - rbuf->pwrite :
+			0;
 
 	if (split > 0) {
-		status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
-		if (status)
-			return len - todo;
+		if (copy_from_user(rbuf->data + rbuf->pwrite, buf, split))
+			return -EFAULT;
 		buf += split;
 		todo -= split;
 		/* smp_store_release() for write pointer update to ensure that
@@ -230,9 +233,12 @@
 		 */
 		smp_store_release(&rbuf->pwrite, 0);
 	}
-	status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
-	if (status)
-		return len - todo;
+
+	if (copy_from_user(rbuf->data + rbuf->pwrite, buf, todo)) {
+		/* smp_store_release() for write pointer update */
+		smp_store_release(&rbuf->pwrite, oldpwrite);
+		return -EFAULT;
+	}
 	/* smp_store_release() for write pointer update, see above */
 	smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
 
@@ -253,6 +259,31 @@
 	return status;
 }
 
+ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf, size_t len)
+{
+	ssize_t oldpwrite = rbuf->pwrite;
+
+	DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
+	DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
+	DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_PENDING);
+
+	return oldpwrite;
+}
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_start);
+
+int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx)
+{
+	idx = (idx + 2) % rbuf->size;
+
+	if (rbuf->data[idx] != PKT_PENDING)
+		return -EINVAL;
+
+	rbuf->data[idx] = PKT_READY;
+
+	return 0;
+}
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_close);
+
 ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
 				int offset, u8 __user *buf, size_t len)
 {
@@ -260,6 +291,9 @@
 	size_t split;
 	size_t pktlen;
 
+	if (DVB_RINGBUFFER_PEEK(rbuf, (idx+2)) != PKT_READY)
+		return -EINVAL;
+
 	pktlen = rbuf->data[idx] << 8;
 	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
 	if (offset > pktlen) return -EINVAL;
@@ -280,6 +314,7 @@
 
 	return len;
 }
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_read_user);
 
 ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
 				int offset, u8* buf, size_t len)
@@ -288,6 +323,9 @@
 	size_t split;
 	size_t pktlen;
 
+	if (rbuf->data[(idx + 2) % rbuf->size] != PKT_READY)
+		return -EINVAL;
+
 	pktlen = rbuf->data[idx] << 8;
 	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
 	if (offset > pktlen) return -EINVAL;
@@ -305,6 +343,7 @@
 	memcpy(buf, rbuf->data+idx, todo);
 	return len;
 }
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
 
 void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
 {
@@ -324,6 +363,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
 
 ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
 {
@@ -339,7 +379,10 @@
 		idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
 	}
 
-	consumed = (idx - rbuf->pread) % rbuf->size;
+	if (idx >= rbuf->pread)
+		consumed = idx - rbuf->pread;
+	else
+		consumed = rbuf->size - (rbuf->pread - idx);
 
 	while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
 
@@ -352,6 +395,9 @@
 			return idx;
 		}
 
+		if (curpktstatus == PKT_PENDING)
+			return -EFAULT;
+
 		consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
 		idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
 	}
@@ -359,8 +405,7 @@
 	// no packets available
 	return -1;
 }
-
-
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
 
 EXPORT_SYMBOL(dvb_ringbuffer_init);
 EXPORT_SYMBOL(dvb_ringbuffer_empty);
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h
index bbe9487..900630e 100644
--- a/drivers/media/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb-core/dvb_ringbuffer.h
@@ -124,6 +124,9 @@
  */
 #define DVB_RINGBUFFER_PEEK(rbuf, offs)	\
 			((rbuf)->data[((rbuf)->pread + (offs)) % (rbuf)->size])
+#define DVB_RINGBUFFER_PUSH(rbuf, num)	\
+			((rbuf)->pwrite = (((rbuf)->pwrite+(num))%(rbuf)->size))
+
 
 /**
  * DVB_RINGBUFFER_SKIP - advance read ptr by @num bytes
@@ -274,7 +277,35 @@
  *          in bytes.
  * returns Packet index (if >=0), or -1 if no packets available.
  */
-extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf,
-				       size_t idx, size_t *pktlen);
+extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx,
+				       size_t *pktlen);
+
+
+/**
+ * Start a new packet that will be written directly by the user to the packet
+ * buffer.
+ * The function only writes the header of the packet into the packet buffer,
+ * and the packet is in pending state (can't be read by the reader) until it is
+ * closed using dvb_ringbuffer_pkt_close. You must write the data into the
+ * packet buffer using dvb_ringbuffer_write followed by
+ * dvb_ringbuffer_pkt_close.
+ *
+ * @rbuf: Ringbuffer concerned.
+ * @len: Size of the packet's data
+ * returns Index of the packet's header that was started.
+ */
+extern ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf,
+						size_t len);
+
+/**
+ * Close a packet that was started using dvb_ringbuffer_pkt_start.
+ * The packet will be marked as ready to be ready.
+ *
+ * @rbuf: Ringbuffer concerned.
+ * @idx: Packet index that was returned by dvb_ringbuffer_pkt_start
+ * returns error status, -EINVAL if the provided index is invalid
+ */
+extern int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx);
+
 
 #endif /* _DVB_RINGBUFFER_H_ */
diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig
index d5d873c..484819d 100644
--- a/drivers/media/platform/msm/Kconfig
+++ b/drivers/media/platform/msm/Kconfig
@@ -16,3 +16,5 @@
 source "drivers/media/platform/msm/vidc/Kconfig"
 
 source "drivers/media/platform/msm/sde/Kconfig"
+source "drivers/media/platform/msm/dvb/Kconfig"
+source "drivers/media/platform/msm/broadcast/Kconfig"
diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile
index adeb2aa..e64bcd1 100644
--- a/drivers/media/platform/msm/Makefile
+++ b/drivers/media/platform/msm/Makefile
@@ -5,3 +5,5 @@
 obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/
 obj-y += sde/
 obj-$(CONFIG_SPECTRA_CAMERA) += camera/
+obj-y += broadcast/
+obj-$(CONFIG_DVB_MPQ) += dvb/
diff --git a/drivers/media/platform/msm/broadcast/Kconfig b/drivers/media/platform/msm/broadcast/Kconfig
new file mode 100644
index 0000000..cdd1b20
--- /dev/null
+++ b/drivers/media/platform/msm/broadcast/Kconfig
@@ -0,0 +1,14 @@
+#
+# MSM Broadcast subsystem drivers
+#
+
+config TSPP
+	depends on ARCH_QCOM
+	tristate "TSPP (Transport Stream Packet Processor) Support"
+	---help---
+	Transport Stream Packet Processor v1 is used to offload the
+	processing of MPEG transport streams from the main processor.
+	It is used to process incoming transport streams from TSIF
+	to supports use-cases such as transport stream live play
+	and recording.
+	This can also be compiled as a loadable module.
diff --git a/drivers/media/platform/msm/broadcast/Makefile b/drivers/media/platform/msm/broadcast/Makefile
new file mode 100644
index 0000000..3735bdc
--- /dev/null
+++ b/drivers/media/platform/msm/broadcast/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for MSM Broadcast subsystem drivers.
+#
+obj-$(CONFIG_TSPP) += tspp.o
diff --git a/drivers/media/platform/msm/broadcast/tspp.c b/drivers/media/platform/msm/broadcast/tspp.c
new file mode 100644
index 0000000..43b426de
--- /dev/null
+++ b/drivers/media/platform/msm/broadcast/tspp.c
@@ -0,0 +1,3252 @@
+/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>        /* Just for modules */
+#include <linux/kernel.h>        /* Only for KERN_INFO */
+#include <linux/err.h>           /* Error macros */
+#include <linux/list.h>          /* Linked list */
+#include <linux/cdev.h>
+#include <linux/init.h>          /* Needed for the macros */
+#include <linux/io.h>            /* IO macros */
+#include <linux/device.h>        /* Device drivers need this */
+#include <linux/sched.h>         /* Externally defined globals */
+#include <linux/pm_runtime.h>    /* Runtime power management */
+#include <linux/fs.h>
+#include <linux/uaccess.h>       /* copy_to_user */
+#include <linux/slab.h>          /* kfree, kzalloc */
+#include <linux/ioport.h>        /* XXX_ mem_region */
+#include <linux/dma-mapping.h>   /* dma_XXX */
+#include <linux/dmapool.h>       /* DMA pools */
+#include <linux/delay.h>         /* msleep */
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/poll.h>          /* poll() file op */
+#include <linux/wait.h>          /* wait() macros, sleeping */
+#include <linux/bitops.h>        /* BIT() macro */
+#include <linux/regulator/consumer.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <linux/msm-sps.h>            /* BAM stuff */
+#include <linux/wakelock.h>      /* Locking functions */
+#include <linux/timer.h>         /* Timer services */
+#include <linux/jiffies.h>       /* Jiffies counter */
+#include <linux/qcom_tspp.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/string.h>
+#include <linux/msm-bus.h>
+#include <linux/interrupt.h>	/* tasklet */
+#include <asm/arch_timer.h> /* Timer */
+#include <linux/avtimer_kernel.h> /* Timer */
+
+/*
+ * General defines
+ */
+#define TSPP_TSIF_INSTANCES            2
+#define TSPP_GPIOS_PER_TSIF            4
+#define TSPP_FILTER_TABLES             3
+#define TSPP_MAX_DEVICES               1
+#define TSPP_NUM_CHANNELS              16
+#define TSPP_NUM_PRIORITIES            16
+#define TSPP_NUM_KEYS                  8
+#define INVALID_CHANNEL                0xFFFFFFFF
+#define TSPP_BAM_DEFAULT_IPC_LOGLVL    2
+/*
+ * BAM descriptor FIFO size (in number of descriptors).
+ * Max number of descriptors allowed by SPS which is 8K-1.
+ */
+#define TSPP_SPS_DESCRIPTOR_COUNT      (8 * 1024 - 1)
+#define TSPP_PACKET_LENGTH             188
+#define TSPP_MIN_BUFFER_SIZE           (TSPP_PACKET_LENGTH)
+
+/* Max descriptor buffer size allowed by SPS */
+#define TSPP_MAX_BUFFER_SIZE           (32 * 1024 - 1)
+
+/*
+ * Returns whether to use DMA pool for TSPP output buffers.
+ * For buffers smaller than page size, using DMA pool
+ * provides better memory utilization as dma_alloc_coherent
+ * allocates minimum of page size.
+ */
+#define TSPP_USE_DMA_POOL(buff_size)   ((buff_size) < PAGE_SIZE)
+
+/*
+ * Max allowed TSPP buffers/descriptors.
+ * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
+ */
+#define TSPP_NUM_BUFFERS               (TSPP_SPS_DESCRIPTOR_COUNT - 1)
+#define TSPP_TSIF_DEFAULT_TIME_LIMIT   60
+#define SPS_DESCRIPTOR_SIZE            8
+#define MIN_ACCEPTABLE_BUFFER_COUNT    2
+#define TSPP_DEBUG(msg...)
+
+/*
+ * TSIF register offsets
+ */
+#define TSIF_STS_CTL_OFF               (0x0)
+#define TSIF_TIME_LIMIT_OFF            (0x4)
+#define TSIF_CLK_REF_OFF               (0x8)
+#define TSIF_LPBK_FLAGS_OFF            (0xc)
+#define TSIF_LPBK_DATA_OFF            (0x10)
+#define TSIF_TEST_CTL_OFF             (0x14)
+#define TSIF_TEST_MODE_OFF            (0x18)
+#define TSIF_TEST_RESET_OFF           (0x1c)
+#define TSIF_TEST_EXPORT_OFF          (0x20)
+#define TSIF_TEST_CURRENT_OFF         (0x24)
+#define TSIF_TTS_CTL_OFF	      (0x38)
+
+#define TSIF_DATA_PORT_OFF            (0x100)
+
+/* bits for TSIF_STS_CTL register */
+#define TSIF_STS_CTL_EN_IRQ       BIT(28)
+#define TSIF_STS_CTL_PACK_AVAIL   BIT(27)
+#define TSIF_STS_CTL_1ST_PACKET   BIT(26)
+#define TSIF_STS_CTL_OVERFLOW     BIT(25)
+#define TSIF_STS_CTL_LOST_SYNC    BIT(24)
+#define TSIF_STS_CTL_TIMEOUT      BIT(23)
+#define TSIF_STS_CTL_INV_SYNC     BIT(21)
+#define TSIF_STS_CTL_INV_NULL     BIT(20)
+#define TSIF_STS_CTL_INV_ERROR    BIT(19)
+#define TSIF_STS_CTL_INV_ENABLE   BIT(18)
+#define TSIF_STS_CTL_INV_DATA     BIT(17)
+#define TSIF_STS_CTL_INV_CLOCK    BIT(16)
+#define TSIF_STS_CTL_SPARE        BIT(15)
+#define TSIF_STS_CTL_EN_NULL      BIT(11)
+#define TSIF_STS_CTL_EN_ERROR     BIT(10)
+#define TSIF_STS_CTL_LAST_BIT     BIT(9)
+#define TSIF_STS_CTL_EN_TIME_LIM  BIT(8)
+#define TSIF_STS_CTL_EN_TCR       BIT(7)
+#define TSIF_STS_CTL_TEST_MODE    BIT(6)
+#define TSIF_STS_CTL_MODE_2       BIT(5)
+#define TSIF_STS_CTL_EN_DM        BIT(4)
+#define TSIF_STS_CTL_STOP         BIT(3)
+#define TSIF_STS_CTL_START        BIT(0)
+
+/* bits for TSIF_TTS_CTRL register */
+#define TSIF_TTS_CTL_TTS_ENDIANNESS	BIT(4)
+#define TSIF_TTS_CTL_TTS_SOURCE		BIT(3)
+#define TSIF_TTS_CTL_TTS_LENGTH_1	BIT(1)
+#define TSIF_TTS_CTL_TTS_LENGTH_0	BIT(0)
+
+/*
+ * TSPP register offsets
+ */
+#define TSPP_RST			0x00
+#define TSPP_CLK_CONTROL		0x04
+#define TSPP_CONFIG			0x08
+#define TSPP_CONTROL			0x0C
+#define TSPP_PS_DISABLE			0x10
+#define TSPP_MSG_IRQ_STATUS		0x14
+#define TSPP_MSG_IRQ_MASK		0x18
+#define TSPP_IRQ_STATUS			0x1C
+#define TSPP_IRQ_MASK			0x20
+#define TSPP_IRQ_CLEAR			0x24
+#define TSPP_PIPE_ERROR_STATUS(_n)	(0x28 + (_n << 2))
+#define TSPP_STATUS			0x68
+#define TSPP_CURR_TSP_HEADER		0x6C
+#define TSPP_CURR_PID_FILTER		0x70
+#define TSPP_SYSTEM_KEY(_n)		(0x74 + (_n << 2))
+#define TSPP_CBC_INIT_VAL(_n)		(0x94 + (_n << 2))
+#define TSPP_DATA_KEY_RESET		0x9C
+#define TSPP_KEY_VALID			0xA0
+#define TSPP_KEY_ERROR			0xA4
+#define TSPP_TEST_CTRL			0xA8
+#define TSPP_VERSION			0xAC
+#define TSPP_GENERICS			0xB0
+#define TSPP_NOP			0xB4
+
+/*
+ * Register bit definitions
+ */
+/* TSPP_RST */
+#define TSPP_RST_RESET                    BIT(0)
+
+/* TSPP_CLK_CONTROL	*/
+#define TSPP_CLK_CONTROL_FORCE_CRYPTO     BIT(9)
+#define TSPP_CLK_CONTROL_FORCE_PES_PL     BIT(8)
+#define TSPP_CLK_CONTROL_FORCE_PES_AF     BIT(7)
+#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL   BIT(6)
+#define TSPP_CLK_CONTROL_FORCE_PERF_CNT   BIT(5)
+#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4)
+#define TSPP_CLK_CONTROL_FORCE_TSP_PROC   BIT(3)
+#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2)
+#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1)
+#define TSPP_CLK_CONTROL_SET_CLKON        BIT(0)
+
+/* TSPP_CONFIG	*/
+#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \
+((_b & 0xF) << 8))
+#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF)
+#define TSPP_CONFIG_DUP_WITH_DISC_EN		BIT(7)
+#define TSPP_CONFIG_PES_SYNC_ERROR_MASK   BIT(6)
+#define TSPP_CONFIG_PS_LEN_ERR_MASK       BIT(5)
+#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4)
+#define TSPP_CONFIG_PS_CONT_ERR_MASK      BIT(3)
+#define TSPP_CONFIG_PS_DUP_TSP_MASK       BIT(2)
+#define TSPP_CONFIG_TSP_ERR_IND_MASK      BIT(1)
+#define TSPP_CONFIG_TSP_SYNC_ERR_MASK     BIT(0)
+
+/* TSPP_CONTROL */
+#define TSPP_CONTROL_PID_FILTER_LOCK      BIT(5)
+#define TSPP_CONTROL_FORCE_KEY_CALC       BIT(4)
+#define TSPP_CONTROL_TSP_CONS_SRC_DIS     BIT(3)
+#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS    BIT(2)
+#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS    BIT(1)
+#define TSPP_CONTROL_PERF_COUNT_INIT      BIT(0)
+
+/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */
+#define TSPP_MSG_TSPP_IRQ                 BIT(2)
+#define TSPP_MSG_TSIF_1_IRQ               BIT(1)
+#define TSPP_MSG_TSIF_0_IRQ               BIT(0)
+
+/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
+#define TSPP_IRQ_STATUS_TSP_RD_CMPL		BIT(19)
+#define TSPP_IRQ_STATUS_KEY_ERROR		BIT(18)
+#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD	BIT(17)
+#define TSPP_IRQ_STATUS_KEY_SWITCHED		BIT(16)
+#define TSPP_IRQ_STATUS_PS_BROKEN(_n)		BIT((_n))
+
+/* TSPP_PIPE_ERROR_STATUS */
+#define TSPP_PIPE_PES_SYNC_ERROR		BIT(3)
+#define TSPP_PIPE_PS_LENGTH_ERROR		BIT(2)
+#define TSPP_PIPE_PS_CONTINUITY_ERROR		BIT(1)
+#define TSPP_PIP_PS_LOST_START			BIT(0)
+
+/* TSPP_STATUS			*/
+#define TSPP_STATUS_TSP_PKT_AVAIL		BIT(10)
+#define TSPP_STATUS_TSIF1_DM_REQ		BIT(6)
+#define TSPP_STATUS_TSIF0_DM_REQ		BIT(2)
+#define TSPP_CURR_FILTER_TABLE			BIT(0)
+
+/* TSPP_GENERICS		*/
+#define TSPP_GENERICS_CRYPTO_GEN		BIT(12)
+#define TSPP_GENERICS_MAX_CONS_PIPES		BIT(7)
+#define TSPP_GENERICS_MAX_PIPES			BIT(2)
+#define TSPP_GENERICS_TSIF_1_GEN		BIT(1)
+#define TSPP_GENERICS_TSIF_0_GEN		BIT(0)
+
+/*
+ * TSPP memory regions
+ */
+#define TSPP_PID_FILTER_TABLE0      0x800
+#define TSPP_PID_FILTER_TABLE1      0x880
+#define TSPP_PID_FILTER_TABLE2      0x900
+#define TSPP_GLOBAL_PERFORMANCE     0x980 /* see tspp_global_performance */
+#define TSPP_PIPE_CONTEXT           0x990 /* see tspp_pipe_context */
+#define TSPP_PIPE_PERFORMANCE       0x998 /* see tspp_pipe_performance */
+#define TSPP_TSP_BUFF_WORD(_n)      (0xC10 + (_n << 2))
+#define TSPP_DATA_KEY               0xCD0
+
+struct debugfs_entry {
+	const char *name;
+	mode_t mode;
+	int offset;
+};
+
+static const struct debugfs_entry debugfs_tsif_regs[] = {
+	{"sts_ctl",             0644, TSIF_STS_CTL_OFF},
+	{"time_limit",          0644, TSIF_TIME_LIMIT_OFF},
+	{"clk_ref",             0644, TSIF_CLK_REF_OFF},
+	{"lpbk_flags",          0644, TSIF_LPBK_FLAGS_OFF},
+	{"lpbk_data",           0644, TSIF_LPBK_DATA_OFF},
+	{"test_ctl",            0644, TSIF_TEST_CTL_OFF},
+	{"test_mode",           0644, TSIF_TEST_MODE_OFF},
+	{"test_reset",          0200, TSIF_TEST_RESET_OFF},
+	{"test_export",         0644, TSIF_TEST_EXPORT_OFF},
+	{"test_current",        0444, TSIF_TEST_CURRENT_OFF},
+	{"data_port",           0400, TSIF_DATA_PORT_OFF},
+	{"tts_source",          0600, TSIF_TTS_CTL_OFF},
+};
+
+static const struct debugfs_entry debugfs_tspp_regs[] = {
+	{"rst",                 0644, TSPP_RST},
+	{"clk_control",         0644, TSPP_CLK_CONTROL},
+	{"config",              0644, TSPP_CONFIG},
+	{"control",             0644, TSPP_CONTROL},
+	{"ps_disable",          0644, TSPP_PS_DISABLE},
+	{"msg_irq_status",      0644, TSPP_MSG_IRQ_STATUS},
+	{"msg_irq_mask",        0644, TSPP_MSG_IRQ_MASK},
+	{"irq_status",          0644, TSPP_IRQ_STATUS},
+	{"irq_mask",            0644, TSPP_IRQ_MASK},
+	{"irq_clear",           0644, TSPP_IRQ_CLEAR},
+	/* {"pipe_error_status",S_IRUGO | S_IWUSR, TSPP_PIPE_ERROR_STATUS}, */
+	{"status",              0644, TSPP_STATUS},
+	{"curr_tsp_header",     0644, TSPP_CURR_TSP_HEADER},
+	{"curr_pid_filter",     0644, TSPP_CURR_PID_FILTER},
+	/* {"system_key",       S_IRUGO | S_IWUSR, TSPP_SYSTEM_KEY}, */
+	/* {"cbc_init_val",     S_IRUGO | S_IWUSR, TSPP_CBC_INIT_VAL}, */
+	{"data_key_reset",      0644, TSPP_DATA_KEY_RESET},
+	{"key_valid",           0644, TSPP_KEY_VALID},
+	{"key_error",           0644, TSPP_KEY_ERROR},
+	{"test_ctrl",           0644, TSPP_TEST_CTRL},
+	{"version",             0644, TSPP_VERSION},
+	{"generics",            0644, TSPP_GENERICS},
+	{"pid_filter_table0",   0644, TSPP_PID_FILTER_TABLE0},
+	{"pid_filter_table1",   0644, TSPP_PID_FILTER_TABLE1},
+	{"pid_filter_table2",   0644, TSPP_PID_FILTER_TABLE2},
+	{"tsp_total_num",       0644, TSPP_GLOBAL_PERFORMANCE},
+	{"tsp_ignored_num",     0644, TSPP_GLOBAL_PERFORMANCE + 4},
+	{"tsp_err_ind_num",     0644, TSPP_GLOBAL_PERFORMANCE + 8},
+	{"tsp_sync_err_num",    0644, TSPP_GLOBAL_PERFORMANCE + 16},
+	{"pipe_context",        0644, TSPP_PIPE_CONTEXT},
+	{"pipe_performance",    0644, TSPP_PIPE_PERFORMANCE},
+	{"data_key",            0644, TSPP_DATA_KEY}
+};
+
+struct tspp_pid_filter {
+	u32 filter;			/* see FILTER_ macros */
+	u32 config;			/* see FILTER_ macros */
+};
+
+/* tsp_info */
+#define FILTER_HEADER_ERROR_MASK          BIT(7)
+#define FILTER_TRANS_END_DISABLE          BIT(6)
+#define FILTER_DEC_ON_ERROR_EN            BIT(5)
+#define FILTER_DECRYPT                    BIT(4)
+#define FILTER_HAS_ENCRYPTION(_p)         (_p->config & FILTER_DECRYPT)
+#define FILTER_GET_PIPE_NUMBER0(_p)       (_p->config & 0xF)
+#define FILTER_SET_PIPE_NUMBER0(_p, _b)   (_p->config = \
+			(_p->config & ~0xF) | (_b & 0xF))
+#define FILTER_GET_PIPE_PROCESS0(_p)      ((_p->filter >> 30) & 0x3)
+#define FILTER_SET_PIPE_PROCESS0(_p, _b)  (_p->filter = \
+			(_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30))
+#define FILTER_GET_PIPE_PID(_p)           ((_p->filter >> 13) & 0x1FFF)
+#define FILTER_SET_PIPE_PID(_p, _b)       (_p->filter = \
+			(_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13))
+#define FILTER_GET_PID_MASK(_p)           (_p->filter & 0x1FFF)
+#define FILTER_SET_PID_MASK(_p, _b)       (_p->filter = \
+			(_p->filter & ~0x1FFF) | (_b & 0x1FFF))
+#define FILTER_GET_PIPE_PROCESS1(_p)      ((_p->config >> 30) & 0x3)
+#define FILTER_SET_PIPE_PROCESS1(_p, _b)  (_p->config = \
+			(_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30))
+#define FILTER_GET_KEY_NUMBER(_p)         ((_p->config >> 8) & 0x7)
+#define FILTER_SET_KEY_NUMBER(_p, _b)     (_p->config = \
+			(_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8))
+
+struct tspp_global_performance_regs {
+	u32 tsp_total;
+	u32 tsp_ignored;
+	u32 tsp_error;
+	u32 tsp_sync;
+};
+
+struct tspp_pipe_context_regs {
+	u16 pes_bytes_left;
+	u16 count;
+	u32 tsif_suffix;
+} __packed;
+#define CONTEXT_GET_STATE(_a)					(_a & 0x3)
+#define CONTEXT_UNSPEC_LENGTH					BIT(11)
+#define CONTEXT_GET_CONT_COUNT(_a)			((_a >> 12) & 0xF)
+
+#define MSEC_TO_JIFFIES(msec)			((msec) * HZ / 1000)
+
+struct tspp_pipe_performance_regs {
+	u32 tsp_total;
+	u32 ps_duplicate_tsp;
+	u32 tsp_no_payload;
+	u32 tsp_broken_ps;
+	u32 ps_total_num;
+	u32 ps_continuity_error;
+	u32 ps_length_error;
+	u32 pes_sync_error;
+};
+
+struct tspp_tsif_device {
+	void __iomem *base;
+	u32 time_limit;
+	u32 ref_count;
+	enum tspp_tsif_mode mode;
+	int clock_inverse;
+	int data_inverse;
+	int sync_inverse;
+	int enable_inverse;
+	u32 tsif_irq;
+
+	/* debugfs */
+	struct dentry *dent_tsif;
+	struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
+	u32 stat_rx;
+	u32 stat_overflow;
+	u32 stat_lost_sync;
+	u32 stat_timeout;
+	enum tsif_tts_source tts_source;
+	u32 lpass_timer_enable;
+};
+
+enum tspp_buf_state {
+	TSPP_BUF_STATE_EMPTY,	/* buffer has been allocated, but not waiting */
+	TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
+	TSPP_BUF_STATE_DATA,    /* buffer is not empty and can be read */
+	TSPP_BUF_STATE_LOCKED   /* buffer is being read by a client */
+};
+
+struct tspp_mem_buffer {
+	struct tspp_mem_buffer *next;
+	struct sps_mem_buffer sps;
+	struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
+	enum tspp_buf_state state;
+	size_t filled;          /* how much data this buffer is holding */
+	int read_index;         /* where to start reading data from */
+};
+
+/* this represents each char device 'channel' */
+struct tspp_channel {
+	struct tspp_device *pdev; /* can use container_of instead? */
+	struct sps_pipe *pipe;
+	struct sps_connect config;
+	struct sps_register_event event;
+	struct tspp_mem_buffer *data;    /* list of buffers */
+	struct tspp_mem_buffer *read;    /* first buffer ready to be read */
+	struct tspp_mem_buffer *waiting; /* first outstanding transfer */
+	struct tspp_mem_buffer *locked;  /* buffer currently being read */
+	wait_queue_head_t in_queue; /* set when data is received */
+	u32 id;           /* channel id (0-15) */
+	int used;         /* is this channel in use? */
+	int key;          /* which encryption key index is used */
+	u32 buffer_size;  /* size of the sps transfer buffers */
+	u32 max_buffers;  /* how many buffers should be allocated */
+	u32 buffer_count; /* how many buffers are actually allocated */
+	u32 filter_count; /* how many filters have been added to this channel */
+	u32 int_freq;     /* generate interrupts every x descriptors */
+	enum tspp_source src;
+	enum tspp_mode mode;
+	tspp_notifier *notifier; /* used only with kernel api */
+	void *notify_data;       /* data to be passed with the notifier */
+	u32 expiration_period_ms; /* notification on partially filled buffers */
+	struct timer_list expiration_timer;
+	struct dma_pool *dma_pool;
+	tspp_memfree *memfree;   /* user defined memory free function */
+	void *user_info; /* user cookie passed to memory alloc/free function */
+};
+
+struct tspp_pid_filter_table {
+	struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
+};
+
+struct tspp_key_entry {
+	u32 even_lsb;
+	u32 even_msb;
+	u32 odd_lsb;
+	u32 odd_msb;
+};
+
+struct tspp_key_table {
+	struct tspp_key_entry entry[TSPP_NUM_KEYS];
+};
+
+struct tspp_pinctrl {
+	struct pinctrl *pinctrl;
+
+	struct pinctrl_state *disabled;
+	struct pinctrl_state *tsif0_mode1;
+	struct pinctrl_state *tsif0_mode2;
+	struct pinctrl_state *tsif1_mode1;
+	struct pinctrl_state *tsif1_mode2;
+	struct pinctrl_state *dual_mode1;
+	struct pinctrl_state *dual_mode2;
+
+	bool tsif0_active;
+	bool tsif1_active;
+};
+
+/* this represents the actual hardware device */
+struct tspp_device {
+	struct list_head devlist; /* list of all devices */
+	struct platform_device *pdev;
+	void __iomem *base;
+	uint32_t tsif_bus_client;
+	unsigned int tspp_irq;
+	unsigned int bam_irq;
+	unsigned long bam_handle;
+	struct sps_bam_props bam_props;
+	struct wakeup_source ws;
+	spinlock_t spinlock;
+	struct tasklet_struct tlet;
+	struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
+	/* clocks */
+	struct clk *tsif_pclk;
+	struct clk *tsif_ref_clk;
+	/* regulators */
+	struct regulator *tsif_vreg;
+	/* data */
+	struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
+	struct tspp_channel channels[TSPP_NUM_CHANNELS];
+	struct tspp_key_table *tspp_key_table;
+	struct tspp_global_performance_regs *tspp_global_performance;
+	struct tspp_pipe_context_regs *tspp_pipe_context;
+	struct tspp_pipe_performance_regs *tspp_pipe_performance;
+	bool req_irqs;
+	/* pinctrl */
+	struct mutex mutex;
+	struct tspp_pinctrl pinctrl;
+	unsigned int tts_source; /* Time stamp source type LPASS timer/TCR */
+
+	struct dentry *dent;
+	struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
+};
+
+static int tspp_key_entry;
+static u32 channel_id;  /* next channel id number to assign */
+
+static LIST_HEAD(tspp_devices);
+
+/*** IRQ ***/
+static irqreturn_t tspp_isr(int irq, void *dev)
+{
+	struct tspp_device *device = dev;
+	u32 status, mask;
+	u32 data;
+
+	status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
+	mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
+	status &= mask;
+
+	if (!status) {
+		dev_warn(&device->pdev->dev, "Spurious interrupt");
+		return IRQ_NONE;
+	}
+
+	/* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
+
+	if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
+		/* read the key error info */
+		data = readl_relaxed(device->base + TSPP_KEY_ERROR);
+		dev_info(&device->pdev->dev, "key error 0x%x", data);
+	}
+	if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
+		data = readl_relaxed(device->base + TSPP_KEY_VALID);
+		dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
+	}
+	if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
+		dev_info(&device->pdev->dev, "key switched");
+
+	if (status & 0xffff)
+		dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
+
+	writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
+
+	/*
+	 * Before returning IRQ_HANDLED to the generic interrupt handling
+	 * framework need to make sure all operations including clearing of
+	 * interrupt status registers in the hardware is performed.
+	 * Thus a barrier after clearing the interrupt status register
+	 * is required to guarantee that the interrupt status register has
+	 * really been cleared by the time we return from this handler.
+	 */
+	wmb();
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t tsif_isr(int irq, void *dev)
+{
+	struct tspp_tsif_device *tsif_device = dev;
+	u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
+
+	if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
+			 TSIF_STS_CTL_OVERFLOW |
+			 TSIF_STS_CTL_LOST_SYNC |
+			 TSIF_STS_CTL_TIMEOUT)))
+		return IRQ_NONE;
+
+	if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
+		tsif_device->stat_overflow++;
+
+	if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
+		tsif_device->stat_lost_sync++;
+
+	if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
+		tsif_device->stat_timeout++;
+
+	iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
+
+	/*
+	 * Before returning IRQ_HANDLED to the generic interrupt handling
+	 * framework need to make sure all operations including clearing of
+	 * interrupt status registers in the hardware is performed.
+	 * Thus a barrier after clearing the interrupt status register
+	 * is required to guarantee that the interrupt status register has
+	 * really been cleared by the time we return from this handler.
+	 */
+	wmb();
+	return IRQ_HANDLED;
+}
+
+/*** callbacks ***/
+static void tspp_sps_complete_cb(struct sps_event_notify *notify)
+{
+	struct tspp_device *pdev;
+
+	if (!notify || !notify->user)
+		return;
+
+	pdev = notify->user;
+	tasklet_schedule(&pdev->tlet);
+}
+
+static void tspp_expiration_timer(unsigned long data)
+{
+	struct tspp_device *pdev = (struct tspp_device *)data;
+
+	if (pdev)
+		tasklet_schedule(&pdev->tlet);
+}
+
+/*** tasklet ***/
+static void tspp_sps_complete_tlet(unsigned long data)
+{
+	int i;
+	int complete;
+	unsigned long flags;
+	struct sps_iovec iovec;
+	struct tspp_channel *channel;
+	struct tspp_device *device = (struct tspp_device *)data;
+
+	spin_lock_irqsave(&device->spinlock, flags);
+
+	for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
+		complete = 0;
+		channel = &device->channels[i];
+
+		if (!channel->used || !channel->waiting)
+			continue;
+
+		/* stop the expiration timer */
+		if (channel->expiration_period_ms)
+			del_timer(&channel->expiration_timer);
+
+		/* get completions */
+		while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
+			if (sps_get_iovec(channel->pipe, &iovec) != 0) {
+				pr_err("tspp: Error in iovec on channel %i",
+					channel->id);
+				break;
+			}
+			if (iovec.size == 0)
+				break;
+
+			if (DESC_FULL_ADDR(iovec.flags, iovec.addr)
+			    != channel->waiting->sps.phys_base)
+				pr_err("tspp: buffer mismatch %pa",
+					&channel->waiting->sps.phys_base);
+
+			complete = 1;
+			channel->waiting->state = TSPP_BUF_STATE_DATA;
+			channel->waiting->filled = iovec.size;
+			channel->waiting->read_index = 0;
+
+			if (channel->src == TSPP_SOURCE_TSIF0)
+				device->tsif[0].stat_rx++;
+			else if (channel->src == TSPP_SOURCE_TSIF1)
+				device->tsif[1].stat_rx++;
+
+			/* update the pointers */
+			channel->waiting = channel->waiting->next;
+		}
+
+		/* wake any waiting processes */
+		if (complete) {
+			wake_up_interruptible(&channel->in_queue);
+
+			/* call notifiers */
+			if (channel->notifier)
+				channel->notifier(channel->id,
+					channel->notify_data);
+		}
+
+		/* restart expiration timer */
+		if (channel->expiration_period_ms)
+			mod_timer(&channel->expiration_timer,
+				jiffies +
+				MSEC_TO_JIFFIES(
+					channel->expiration_period_ms));
+	}
+
+	spin_unlock_irqrestore(&device->spinlock, flags);
+}
+
+static int tspp_config_gpios(struct tspp_device *device,
+				enum tspp_source source,
+				int enable)
+{
+	int ret;
+	struct pinctrl_state *s;
+	struct tspp_pinctrl *p = &device->pinctrl;
+	bool mode2;
+
+	/*
+	 * TSIF devices are handled separately, however changing of the pinctrl
+	 * state must be protected from race condition.
+	 */
+	if (mutex_lock_interruptible(&device->mutex))
+		return -ERESTARTSYS;
+
+	switch (source) {
+	case TSPP_SOURCE_TSIF0:
+		mode2 = device->tsif[0].mode == TSPP_TSIF_MODE_2;
+		if (enable == p->tsif1_active) {
+			if (enable)
+				/* Both tsif enabled */
+				s = mode2 ? p->dual_mode2 : p->dual_mode1;
+			else
+				/* Both tsif disabled */
+				s = p->disabled;
+		} else if (enable) {
+			/* Only tsif0 is enabled */
+			s = mode2 ? p->tsif0_mode2 : p->tsif0_mode1;
+		} else {
+			/* Only tsif1 is enabled */
+			s = mode2 ? p->tsif1_mode2 : p->tsif1_mode1;
+		}
+
+		ret = pinctrl_select_state(p->pinctrl, s);
+		if (!ret)
+			p->tsif0_active = enable;
+		break;
+	case TSPP_SOURCE_TSIF1:
+		mode2 = device->tsif[1].mode == TSPP_TSIF_MODE_2;
+		if (enable == p->tsif0_active) {
+			if (enable)
+				/* Both tsif enabled */
+				s = mode2 ? p->dual_mode2 : p->dual_mode1;
+			else
+				/* Both tsif disabled */
+				s = p->disabled;
+		} else if (enable) {
+			/* Only tsif1 is enabled */
+			s = mode2 ? p->tsif1_mode2 : p->tsif1_mode1;
+		} else {
+			/* Only tsif0 is enabled */
+			s = mode2 ? p->tsif0_mode2 : p->tsif0_mode1;
+		}
+
+		ret = pinctrl_select_state(p->pinctrl, s);
+		if (!ret)
+			p->tsif1_active = enable;
+		break;
+	default:
+		pr_err("%s: invalid source %d\n", __func__, source);
+		mutex_unlock(&device->mutex);
+		return -EINVAL;
+	}
+
+	if (ret)
+		pr_err("%s: failed to change pinctrl state, ret=%d\n",
+			__func__, ret);
+
+	mutex_unlock(&device->mutex);
+	return ret;
+}
+
+static int tspp_get_pinctrl(struct tspp_device *device)
+{
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *state;
+
+	pinctrl = devm_pinctrl_get(&device->pdev->dev);
+	if (IS_ERR_OR_NULL(pinctrl)) {
+		pr_err("%s: Unable to get pinctrl handle\n", __func__);
+		return -EINVAL;
+	}
+	device->pinctrl.pinctrl = pinctrl;
+
+	state = pinctrl_lookup_state(pinctrl, "disabled");
+	if (IS_ERR_OR_NULL(state)) {
+		pr_err("%s: Unable to find state %s\n",
+			__func__, "disabled");
+		return -EINVAL;
+	}
+	device->pinctrl.disabled = state;
+
+	state = pinctrl_lookup_state(pinctrl, "tsif0-mode1");
+	if (IS_ERR_OR_NULL(state)) {
+		pr_err("%s: Unable to find state %s\n",
+			__func__, "tsif0-mode1");
+		return -EINVAL;
+	}
+	device->pinctrl.tsif0_mode1 = state;
+
+	state = pinctrl_lookup_state(pinctrl, "tsif0-mode2");
+	if (IS_ERR_OR_NULL(state)) {
+		pr_err("%s: Unable to find state %s\n",
+			__func__, "tsif0-mode2");
+		return -EINVAL;
+	}
+	device->pinctrl.tsif0_mode2 = state;
+
+	state = pinctrl_lookup_state(pinctrl, "tsif1-mode1");
+	if (IS_ERR_OR_NULL(state)) {
+		pr_err("%s: Unable to find state %s\n",
+			__func__, "tsif1-mode1");
+		return -EINVAL;
+	}
+	device->pinctrl.tsif1_mode1 = state;
+
+	state = pinctrl_lookup_state(pinctrl, "tsif1-mode2");
+	if (IS_ERR_OR_NULL(state)) {
+		pr_err("%s: Unable to find state %s\n",
+			__func__, "tsif1-mode2");
+		return -EINVAL;
+	}
+	device->pinctrl.tsif1_mode2 = state;
+
+	state = pinctrl_lookup_state(pinctrl, "dual-tsif-mode1");
+	if (IS_ERR_OR_NULL(state)) {
+		pr_err("%s: Unable to find state %s\n",
+			__func__, "dual-tsif-mode1");
+		return -EINVAL;
+	}
+	device->pinctrl.dual_mode1 = state;
+
+	state = pinctrl_lookup_state(pinctrl, "dual-tsif-mode2");
+	if (IS_ERR_OR_NULL(state)) {
+		pr_err("%s: Unable to find state %s\n",
+			__func__, "dual-tsif-mode2");
+		return -EINVAL;
+	}
+	device->pinctrl.dual_mode2 = state;
+
+	device->pinctrl.tsif0_active = false;
+	device->pinctrl.tsif1_active = false;
+
+	return 0;
+}
+
+
+/*** Clock functions ***/
+static int tspp_clock_start(struct tspp_device *device)
+{
+	int rc;
+
+	if (device == NULL) {
+		pr_err("tspp: Can't start clocks, invalid device\n");
+		return -EINVAL;
+	}
+
+	if (device->tsif_bus_client) {
+		rc = msm_bus_scale_client_update_request(
+					device->tsif_bus_client, 1);
+		if (rc) {
+			pr_err("tspp: Can't enable bus\n");
+			return -EBUSY;
+		}
+	}
+
+	if (device->tsif_vreg) {
+		rc = regulator_set_voltage(device->tsif_vreg,
+					RPMH_REGULATOR_LEVEL_OFF,
+					RPMH_REGULATOR_LEVEL_MAX);
+		if (rc) {
+			pr_err("Unable to set CX voltage.\n");
+			if (device->tsif_bus_client)
+				msm_bus_scale_client_update_request(
+					device->tsif_bus_client, 0);
+			return rc;
+		}
+	}
+
+	if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
+		pr_err("tspp: Can't start pclk");
+
+		if (device->tsif_vreg) {
+			regulator_set_voltage(device->tsif_vreg,
+					RPMH_REGULATOR_LEVEL_OFF,
+					RPMH_REGULATOR_LEVEL_MAX);
+		}
+
+		if (device->tsif_bus_client)
+			msm_bus_scale_client_update_request(
+				device->tsif_bus_client, 0);
+		return -EBUSY;
+	}
+
+	if (device->tsif_ref_clk &&
+		clk_prepare_enable(device->tsif_ref_clk) != 0) {
+		pr_err("tspp: Can't start ref clk");
+		clk_disable_unprepare(device->tsif_pclk);
+		if (device->tsif_vreg) {
+			regulator_set_voltage(device->tsif_vreg,
+					RPMH_REGULATOR_LEVEL_OFF,
+					RPMH_REGULATOR_LEVEL_MAX);
+		}
+
+		if (device->tsif_bus_client)
+			msm_bus_scale_client_update_request(
+				device->tsif_bus_client, 0);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void tspp_clock_stop(struct tspp_device *device)
+{
+	int rc;
+
+	if (device == NULL) {
+		pr_err("tspp: Can't stop clocks, invalid device\n");
+		return;
+	}
+
+	if (device->tsif_pclk)
+		clk_disable_unprepare(device->tsif_pclk);
+
+	if (device->tsif_ref_clk)
+		clk_disable_unprepare(device->tsif_ref_clk);
+
+	if (device->tsif_vreg) {
+		rc = regulator_set_voltage(device->tsif_vreg,
+					RPMH_REGULATOR_LEVEL_OFF,
+					RPMH_REGULATOR_LEVEL_MAX);
+		if (rc)
+			pr_err("Unable to set CX voltage.\n");
+	}
+
+	if (device->tsif_bus_client) {
+		rc = msm_bus_scale_client_update_request(
+					device->tsif_bus_client, 0);
+		if (rc)
+			pr_err("tspp: Can't disable bus\n");
+	}
+}
+
+/*** TSIF functions ***/
+static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
+{
+	int start_hardware = 0;
+	u32 ctl;
+	u32 tts_ctl;
+	int retval;
+
+	if (tsif_device->ref_count == 0) {
+		start_hardware = 1;
+	} else if (tsif_device->ref_count > 0) {
+		ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
+		if ((ctl & TSIF_STS_CTL_START) != 1) {
+			/* this hardware should already be running */
+			pr_warn("tspp: tsif hw not started but ref count > 0");
+			start_hardware = 1;
+		}
+	}
+
+	if (start_hardware) {
+		ctl = TSIF_STS_CTL_EN_IRQ |
+				TSIF_STS_CTL_EN_DM |
+				TSIF_STS_CTL_PACK_AVAIL |
+				TSIF_STS_CTL_OVERFLOW |
+				TSIF_STS_CTL_LOST_SYNC;
+
+		if (tsif_device->clock_inverse)
+			ctl |= TSIF_STS_CTL_INV_CLOCK;
+
+		if (tsif_device->data_inverse)
+			ctl |= TSIF_STS_CTL_INV_DATA;
+
+		if (tsif_device->sync_inverse)
+			ctl |= TSIF_STS_CTL_INV_SYNC;
+
+		if (tsif_device->enable_inverse)
+			ctl |= TSIF_STS_CTL_INV_ENABLE;
+
+		switch (tsif_device->mode) {
+		case TSPP_TSIF_MODE_LOOPBACK:
+			ctl |= TSIF_STS_CTL_EN_NULL |
+					TSIF_STS_CTL_EN_ERROR |
+					TSIF_STS_CTL_TEST_MODE;
+			break;
+		case TSPP_TSIF_MODE_1:
+			ctl |= TSIF_STS_CTL_EN_TIME_LIM;
+			if (tsif_device->tts_source != TSIF_TTS_LPASS_TIMER)
+				ctl |= TSIF_STS_CTL_EN_TCR;
+			break;
+		case TSPP_TSIF_MODE_2:
+			ctl |= TSIF_STS_CTL_EN_TIME_LIM |
+					TSIF_STS_CTL_MODE_2;
+			if (tsif_device->tts_source != TSIF_TTS_LPASS_TIMER)
+				ctl |= TSIF_STS_CTL_EN_TCR;
+			break;
+		default:
+			pr_warn("tspp: unknown tsif mode 0x%x",
+				tsif_device->mode);
+		}
+		/* Set 4bytes Time Stamp for TCR */
+		if (tsif_device->tts_source == TSIF_TTS_LPASS_TIMER) {
+			if (tsif_device->lpass_timer_enable == 0) {
+				retval = avcs_core_open();
+				if (retval < 0) {
+					pr_warn("tspp: avcs open fail:%d\n",
+						retval);
+					return retval;
+				}
+				retval = avcs_core_disable_power_collapse(1);
+				if (retval  < 0) {
+					pr_warn("tspp: avcs power enable:%d\n",
+						retval);
+					return retval;
+				}
+				tsif_device->lpass_timer_enable = 1;
+			}
+
+			tts_ctl	= readl_relaxed(tsif_device->base +
+						TSIF_TTS_CTL_OFF);
+			tts_ctl = 0;
+			/* Set LPASS Timer TTS source */
+			tts_ctl |= TSIF_TTS_CTL_TTS_SOURCE;
+			 /* Set 4 byte TTS */
+			tts_ctl |= TSIF_TTS_CTL_TTS_LENGTH_0;
+
+			writel_relaxed(tts_ctl, tsif_device->base +
+				       TSIF_TTS_CTL_OFF);
+			/* write TTS control register */
+			wmb();
+			tts_ctl	= readl_relaxed(tsif_device->base +
+						TSIF_TTS_CTL_OFF);
+		}
+
+		writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
+		/* write Status control register */
+		wmb();
+		writel_relaxed(tsif_device->time_limit,
+			  tsif_device->base + TSIF_TIME_LIMIT_OFF);
+		/* assure register configuration is done before starting TSIF */
+		wmb();
+		writel_relaxed(ctl | TSIF_STS_CTL_START,
+			  tsif_device->base + TSIF_STS_CTL_OFF);
+		/* assure TSIF start configuration */
+		wmb();
+	}
+
+	ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
+	if (!(ctl & TSIF_STS_CTL_START))
+		return -EBUSY;
+
+	tsif_device->ref_count++;
+	return 0;
+}
+
+static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
+{
+	if (tsif_device->ref_count == 0) {
+		if (tsif_device->lpass_timer_enable == 1) {
+			if (avcs_core_disable_power_collapse(0) == 0)
+				tsif_device->lpass_timer_enable = 0;
+		}
+		return;
+	}
+
+	tsif_device->ref_count--;
+
+	if (tsif_device->ref_count == 0) {
+		writel_relaxed(TSIF_STS_CTL_STOP,
+			tsif_device->base + TSIF_STS_CTL_OFF);
+		/* assure TSIF stop configuration */
+		wmb();
+	}
+}
+
+/*** local TSPP functions ***/
+static int tspp_channels_in_use(struct tspp_device *pdev)
+{
+	int i;
+	int count = 0;
+
+	for (i = 0; i < TSPP_NUM_CHANNELS; i++)
+		count += (pdev->channels[i].used ? 1 : 0);
+
+	return count;
+}
+
+static struct tspp_device *tspp_find_by_id(int id)
+{
+	struct tspp_device *dev;
+
+	list_for_each_entry(dev, &tspp_devices, devlist) {
+		if (dev->pdev->id == id)
+			return dev;
+	}
+	return NULL;
+}
+
+static int tspp_get_key_entry(void)
+{
+	int i;
+
+	for (i = 0; i < TSPP_NUM_KEYS; i++) {
+		if (!(tspp_key_entry & (1 << i))) {
+			tspp_key_entry |= (1 << i);
+			return i;
+		}
+	}
+	return 1 < TSPP_NUM_KEYS;
+}
+
+static void tspp_free_key_entry(int entry)
+{
+	if (entry > TSPP_NUM_KEYS) {
+		pr_err("tspp_free_key_entry: index out of bounds");
+		return;
+	}
+
+	tspp_key_entry &= ~(1 << entry);
+}
+
+static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
+	u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user)
+{
+	if (size < TSPP_MIN_BUFFER_SIZE ||
+		size > TSPP_MAX_BUFFER_SIZE) {
+		pr_err("tspp: bad buffer size %i", size);
+		return -ENOMEM;
+	}
+
+	if (alloc) {
+		TSPP_DEBUG("tspp using alloc function");
+		desc->virt_base = alloc(channel_id, size,
+			&desc->phys_base, user);
+	} else {
+		if (!dma_pool)
+			desc->virt_base = dma_alloc_coherent(NULL, size,
+				&desc->phys_base, GFP_KERNEL);
+		else
+			desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL,
+				&desc->phys_base);
+
+		if (desc->virt_base == 0) {
+			pr_err("tspp: dma buffer allocation failed %i\n", size);
+			return -ENOMEM;
+		}
+	}
+
+	desc->size = size;
+	return 0;
+}
+
+static int tspp_queue_buffer(struct tspp_channel *channel,
+	struct tspp_mem_buffer *buffer)
+{
+	int rc;
+	u32 flags = 0;
+
+	/* make sure the interrupt frequency is valid */
+	if (channel->int_freq < 1)
+		channel->int_freq = 1;
+
+	/* generate interrupt according to requested frequency */
+	if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
+		flags = SPS_IOVEC_FLAG_INT;
+
+	/* start the transfer */
+	rc = sps_transfer_one(channel->pipe,
+		buffer->sps.phys_base,
+		buffer->sps.size,
+		flags ? channel->pdev : NULL,
+		flags);
+	if (rc < 0)
+		return rc;
+
+	buffer->state = TSPP_BUF_STATE_WAITING;
+
+	return 0;
+}
+
+static int tspp_global_reset(struct tspp_device *pdev)
+{
+	u32 i, val;
+
+	/* stop all TSIFs */
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
+		pdev->tsif[i].ref_count = 1; /* allows stopping hw */
+		tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
+		pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
+		pdev->tsif[i].clock_inverse = 0;
+		pdev->tsif[i].data_inverse = 0;
+		pdev->tsif[i].sync_inverse = 0;
+		pdev->tsif[i].enable_inverse = 0;
+		pdev->tsif[i].lpass_timer_enable = 0;
+	}
+	writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
+	/* assure state is reset before continuing with configuration */
+	wmb();
+
+	/* TSPP tables */
+	for (i = 0; i < TSPP_FILTER_TABLES; i++)
+		memset_io(pdev->filters[i],
+			0, sizeof(struct tspp_pid_filter_table));
+
+	/* disable all filters */
+	val = (2 << TSPP_NUM_CHANNELS) - 1;
+	writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
+
+	/* TSPP registers */
+	val = readl_relaxed(pdev->base + TSPP_CONTROL);
+	writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
+		pdev->base + TSPP_CONTROL);
+	/* assure tspp performance count clock is set to 0 */
+	wmb();
+	memset_io(pdev->tspp_global_performance, 0,
+		sizeof(struct tspp_global_performance_regs));
+	memset_io(pdev->tspp_pipe_context, 0,
+		sizeof(struct tspp_pipe_context_regs));
+	memset_io(pdev->tspp_pipe_performance, 0,
+		sizeof(struct tspp_pipe_performance_regs));
+	/* assure tspp pipe context registers are set to 0 */
+	wmb();
+	writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
+		pdev->base + TSPP_CONTROL);
+	/* assure tspp performance count clock  is reset */
+	wmb();
+
+	val = readl_relaxed(pdev->base + TSPP_CONFIG);
+	val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
+			TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
+			TSPP_CONFIG_PS_CONT_ERR_MASK);
+	TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
+	writel_relaxed(val, pdev->base + TSPP_CONFIG);
+	writel_relaxed(0x0007ffff, pdev->base + TSPP_IRQ_MASK);
+	writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
+	writel_relaxed(0, pdev->base + TSPP_RST);
+	/* assure tspp reset clear */
+	wmb();
+
+	tspp_key_entry = 0;
+
+	return 0;
+}
+
+static void tspp_channel_init(struct tspp_channel *channel,
+	struct tspp_device *pdev)
+{
+	channel->pdev = pdev;
+	channel->data = NULL;
+	channel->read = NULL;
+	channel->waiting = NULL;
+	channel->locked = NULL;
+	channel->id = channel_id++;
+	channel->used = 0;
+	channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
+	channel->max_buffers = TSPP_NUM_BUFFERS;
+	channel->buffer_count = 0;
+	channel->filter_count = 0;
+	channel->int_freq = 1;
+	channel->src = TSPP_SOURCE_NONE;
+	channel->mode = TSPP_MODE_DISABLED;
+	channel->notifier = NULL;
+	channel->notify_data = NULL;
+	channel->expiration_period_ms = 0;
+	channel->memfree = NULL;
+	channel->user_info = NULL;
+	init_waitqueue_head(&channel->in_queue);
+}
+
+static void tspp_set_tsif_mode(struct tspp_channel *channel,
+	enum tspp_tsif_mode mode)
+{
+	int index;
+
+	switch (channel->src) {
+	case TSPP_SOURCE_TSIF0:
+		index = 0;
+		break;
+	case TSPP_SOURCE_TSIF1:
+		index = 1;
+		break;
+	default:
+		pr_warn("tspp: can't set mode for non-tsif source %d",
+			channel->src);
+		return;
+	}
+	channel->pdev->tsif[index].mode = mode;
+}
+
+static void tspp_set_signal_inversion(struct tspp_channel *channel,
+					int clock_inverse, int data_inverse,
+					int sync_inverse, int enable_inverse)
+{
+	int index;
+
+	switch (channel->src) {
+	case TSPP_SOURCE_TSIF0:
+		index = 0;
+		break;
+	case TSPP_SOURCE_TSIF1:
+		index = 1;
+		break;
+	default:
+		return;
+	}
+	channel->pdev->tsif[index].clock_inverse = clock_inverse;
+	channel->pdev->tsif[index].data_inverse = data_inverse;
+	channel->pdev->tsif[index].sync_inverse = sync_inverse;
+	channel->pdev->tsif[index].enable_inverse = enable_inverse;
+}
+
+static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
+{
+	u32 alignment;
+
+	switch (mode) {
+	case TSPP_MODE_RAW:
+		/* must be a multiple of 192 */
+		alignment = (TSPP_PACKET_LENGTH + 4);
+		if (size % alignment)
+			return 0;
+		return 1;
+
+	case TSPP_MODE_RAW_NO_SUFFIX:
+		/* must be a multiple of 188 */
+		alignment = TSPP_PACKET_LENGTH;
+		if (size % alignment)
+			return 0;
+		return 1;
+
+	case TSPP_MODE_DISABLED:
+	case TSPP_MODE_PES:
+	default:
+		/* no alignment requirement */
+		return 1;
+	}
+
+}
+
+static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
+{
+	u32 new_size;
+	u32 alignment;
+
+	switch (mode) {
+	case TSPP_MODE_RAW:
+		/* must be a multiple of 192 */
+		alignment = (TSPP_PACKET_LENGTH + 4);
+		break;
+
+	case TSPP_MODE_RAW_NO_SUFFIX:
+		/* must be a multiple of 188 */
+		alignment = TSPP_PACKET_LENGTH;
+		break;
+
+	case TSPP_MODE_DISABLED:
+	case TSPP_MODE_PES:
+	default:
+		/* no alignment requirement - give the user what he asks for */
+		alignment = 1;
+		break;
+	}
+	/* align up */
+	new_size = (((size + alignment - 1) / alignment) * alignment);
+	return new_size;
+}
+
+static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
+{
+	int i;
+	struct tspp_mem_buffer *pbuf, *temp;
+
+	pbuf = channel->data;
+	for (i = 0; i < channel->buffer_count; i++) {
+		if (pbuf->desc.phys_base) {
+			if (channel->memfree) {
+				channel->memfree(channel_id,
+					pbuf->desc.size,
+					pbuf->desc.virt_base,
+					pbuf->desc.phys_base,
+					channel->user_info);
+			} else {
+				if (!channel->dma_pool)
+					dma_free_coherent(
+						&channel->pdev->pdev->dev,
+						pbuf->desc.size,
+						pbuf->desc.virt_base,
+						pbuf->desc.phys_base);
+				else
+					dma_pool_free(channel->dma_pool,
+						pbuf->desc.virt_base,
+						pbuf->desc.phys_base);
+			}
+			pbuf->desc.phys_base = 0;
+		}
+		pbuf->desc.virt_base = 0;
+		pbuf->state = TSPP_BUF_STATE_EMPTY;
+		temp = pbuf;
+		pbuf = pbuf->next;
+		kfree(temp);
+	}
+}
+
+static int msm_tspp_req_irqs(struct tspp_device *device)
+{
+	int rc;
+	int i;
+	int j;
+
+	rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
+		dev_name(&device->pdev->dev), device);
+	if (rc) {
+		dev_err(&device->pdev->dev,
+			"failed to request TSPP IRQ %d : %d",
+			device->tspp_irq, rc);
+		return rc;
+	}
+
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
+		rc = request_irq(device->tsif[i].tsif_irq,
+			tsif_isr, IRQF_SHARED, dev_name(&device->pdev->dev),
+			&device->tsif[i]);
+		if (rc) {
+			dev_err(&device->pdev->dev,
+				"failed to request TSIF%d IRQ: %d",
+				i, rc);
+			goto failed;
+		}
+	}
+	device->req_irqs = true;
+	return 0;
+
+failed:
+	free_irq(device->tspp_irq, device);
+	for (j = 0; j < i; j++)
+		free_irq(device->tsif[j].tsif_irq, device);
+
+	return rc;
+}
+
+static inline void msm_tspp_free_irqs(struct tspp_device *device)
+{
+	int i;
+
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
+		if (device->tsif[i].tsif_irq)
+			free_irq(device->tsif[i].tsif_irq,  &device->tsif[i]);
+	}
+
+	if (device->tspp_irq)
+		free_irq(device->tspp_irq, device);
+	device->req_irqs = false;
+}
+
+/*** TSPP API functions ***/
+
+/**
+ * tspp_open_stream - open a TSPP stream for use.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @source: stream source parameters.
+ *
+ * Return  error status
+ *
+ */
+int tspp_open_stream(u32 dev, u32 channel_id,
+			struct tspp_select_source *source)
+{
+	u32 val;
+	int rc;
+	struct tspp_device *pdev;
+	struct tspp_channel *channel;
+	bool req_irqs = false;
+
+	TSPP_DEBUG("tspp_open_stream %i %i %i %i",
+		dev, channel_id, source->source, source->mode);
+
+	if (dev >= TSPP_MAX_DEVICES) {
+		pr_err("tspp: device id out of range");
+		return -ENODEV;
+	}
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_str: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+	channel->src = source->source;
+	tspp_set_tsif_mode(channel, source->mode);
+	tspp_set_signal_inversion(channel, source->clk_inverse,
+			source->data_inverse, source->sync_inverse,
+			source->enable_inverse);
+
+	/* Request IRQ resources on first open */
+	if (!pdev->req_irqs && (source->source == TSPP_SOURCE_TSIF0 ||
+		source->source == TSPP_SOURCE_TSIF1)) {
+		rc = msm_tspp_req_irqs(pdev);
+		if (rc) {
+			pr_err("tspp: error requesting irqs\n");
+			return rc;
+		}
+		req_irqs = true;
+	}
+
+	switch (source->source) {
+	case TSPP_SOURCE_TSIF0:
+		if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
+			rc = -EBUSY;
+			pr_err("tspp: error enabling tsif0 GPIOs\n");
+			goto free_irq;
+		}
+		/* make sure TSIF0 is running & enabled */
+		if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
+			rc = -EBUSY;
+			pr_err("tspp: error starting tsif0");
+			goto free_irq;
+		}
+		if (pdev->tsif[0].ref_count == 1) {
+			val = readl_relaxed(pdev->base + TSPP_CONTROL);
+			writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
+				pdev->base + TSPP_CONTROL);
+			/* Assure BAM TS PKT packet processing is enabled */
+			wmb();
+		}
+		break;
+	case TSPP_SOURCE_TSIF1:
+		if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
+			rc = -EBUSY;
+			pr_err("tspp: error enabling tsif1 GPIOs\n");
+			goto free_irq;
+		}
+		/* make sure TSIF1 is running & enabled */
+		if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
+			rc = -EBUSY;
+			pr_err("tspp: error starting tsif1");
+			goto free_irq;
+		}
+		if (pdev->tsif[1].ref_count == 1) {
+			val = readl_relaxed(pdev->base + TSPP_CONTROL);
+			writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
+				pdev->base + TSPP_CONTROL);
+			/* Assure BAM TS PKT packet processing is enabled */
+			wmb();
+		}
+		break;
+	case TSPP_SOURCE_MEM:
+		break;
+	default:
+		pr_err("tspp: channel %i invalid source %i",
+			channel->id, source->source);
+		return -EBUSY;
+	}
+
+	return 0;
+
+free_irq:
+	/* Free irqs only if were requested during opening of this stream */
+	if (req_irqs)
+		msm_tspp_free_irqs(pdev);
+	return rc;
+}
+EXPORT_SYMBOL(tspp_open_stream);
+
+/**
+ * tspp_close_stream - close a TSPP stream.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
+int tspp_close_stream(u32 dev, u32 channel_id)
+{
+	u32 val;
+	u32 prev_ref_count = 0;
+	struct tspp_device *pdev;
+	struct tspp_channel *channel;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_cs: can't find device %i", dev);
+		return -EBUSY;
+	}
+	channel = &pdev->channels[channel_id];
+
+	switch (channel->src) {
+	case TSPP_SOURCE_TSIF0:
+		prev_ref_count = pdev->tsif[0].ref_count;
+		tspp_stop_tsif(&pdev->tsif[0]);
+		if (tspp_config_gpios(pdev, channel->src, 0) != 0)
+			pr_err("tspp: error disabling tsif0 GPIOs\n");
+
+		if (prev_ref_count == 1) {
+			val = readl_relaxed(pdev->base + TSPP_CONTROL);
+			writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
+				pdev->base + TSPP_CONTROL);
+			/* Assure BAM TS PKT packet processing is disabled */
+			wmb();
+		}
+		break;
+	case TSPP_SOURCE_TSIF1:
+		prev_ref_count = pdev->tsif[1].ref_count;
+		tspp_stop_tsif(&pdev->tsif[1]);
+		if (tspp_config_gpios(pdev, channel->src, 0) != 0)
+			pr_err("tspp: error disabling tsif0 GPIOs\n");
+
+		if (prev_ref_count == 1) {
+			val = readl_relaxed(pdev->base + TSPP_CONTROL);
+			writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
+				pdev->base + TSPP_CONTROL);
+			/* Assure BAM TS PKT packet processing is disabled */
+			wmb();
+		}
+		break;
+	case TSPP_SOURCE_MEM:
+		break;
+	case TSPP_SOURCE_NONE:
+		break;
+	}
+
+	channel->src = TSPP_SOURCE_NONE;
+
+	/* Free requested interrupts to save power */
+	if ((pdev->tsif[0].ref_count + pdev->tsif[1].ref_count) == 0 &&
+		prev_ref_count)
+		msm_tspp_free_irqs(pdev);
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_close_stream);
+
+static int tspp_init_sps_device(struct tspp_device *dev)
+{
+	int ret;
+
+	ret = sps_register_bam_device(&dev->bam_props, &dev->bam_handle);
+	if (ret) {
+		pr_err("tspp: failed to register bam device, err-%d\n", ret);
+		return ret;
+	}
+
+	ret = sps_device_reset(dev->bam_handle);
+	if (ret) {
+		sps_deregister_bam_device(dev->bam_handle);
+		pr_err("tspp: error resetting bam device, err=%d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * tspp_open_channel - open a TSPP channel.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
+int tspp_open_channel(u32 dev, u32 channel_id)
+{
+	int rc = 0;
+	struct sps_connect *config;
+	struct sps_register_event *event;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_oc: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+
+	if (channel->used) {
+		pr_err("tspp channel already in use");
+		return -EBUSY;
+	}
+
+	config = &channel->config;
+	event = &channel->event;
+
+	/* start the clocks if needed */
+	if (tspp_channels_in_use(pdev) == 0) {
+		rc = tspp_clock_start(pdev);
+		if (rc)
+			return rc;
+
+		if (pdev->bam_handle == SPS_DEV_HANDLE_INVALID) {
+			rc = tspp_init_sps_device(pdev);
+			if (rc) {
+				pr_err("tspp: failed to init sps device, err=%d\n",
+					rc);
+				tspp_clock_stop(pdev);
+				return rc;
+			}
+		}
+
+		__pm_stay_awake(&pdev->ws);
+	}
+
+	/* mark it as used */
+	channel->used = 1;
+
+	/* start the bam  */
+	channel->pipe = sps_alloc_endpoint();
+	if (channel->pipe == 0) {
+		pr_err("tspp: error allocating endpoint");
+		rc = -ENOMEM;
+		goto err_sps_alloc;
+	}
+
+	/* get default configuration */
+	sps_get_config(channel->pipe, config);
+
+	config->source = pdev->bam_handle;
+	config->destination = SPS_DEV_HANDLE_MEM;
+	config->mode = SPS_MODE_SRC;
+	config->options =
+		SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
+		SPS_O_STREAMING | /* streaming mode */
+		SPS_O_DESC_DONE | /* interrupt on end of descriptor */
+		SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
+		SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
+	config->src_pipe_index = channel->id;
+	config->desc.size =
+		TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
+	config->desc.base = dma_alloc_coherent(&pdev->pdev->dev,
+						config->desc.size,
+						&config->desc.phys_base,
+						GFP_KERNEL);
+	if (config->desc.base == 0) {
+		pr_err("tspp: error allocating sps descriptors");
+		rc = -ENOMEM;
+		goto err_desc_alloc;
+	}
+
+	memset(config->desc.base, 0, config->desc.size);
+
+	rc = sps_connect(channel->pipe, config);
+	if (rc) {
+		pr_err("tspp: error connecting bam");
+		goto err_connect;
+	}
+
+	event->mode = SPS_TRIGGER_CALLBACK;
+	event->options = SPS_O_DESC_DONE;
+	event->callback = tspp_sps_complete_cb;
+	event->xfer_done = NULL;
+	event->user = pdev;
+
+	rc = sps_register_event(channel->pipe, event);
+	if (rc) {
+		pr_err("tspp: error registering event");
+		goto err_event;
+	}
+
+	init_timer(&channel->expiration_timer);
+	channel->expiration_timer.function = tspp_expiration_timer;
+	channel->expiration_timer.data = (unsigned long)pdev;
+	channel->expiration_timer.expires = 0xffffffffL;
+
+	rc = pm_runtime_get(&pdev->pdev->dev);
+	if (rc < 0) {
+		dev_err(&pdev->pdev->dev,
+			"Runtime PM: Unable to wake up tspp device, rc = %d",
+			rc);
+	}
+	return 0;
+
+err_event:
+	sps_disconnect(channel->pipe);
+err_connect:
+	dma_free_coherent(&pdev->pdev->dev, config->desc.size,
+		config->desc.base, config->desc.phys_base);
+err_desc_alloc:
+	sps_free_endpoint(channel->pipe);
+err_sps_alloc:
+	channel->used = 0;
+	return rc;
+}
+EXPORT_SYMBOL(tspp_open_channel);
+
+/**
+ * tspp_close_channel - close a TSPP channel.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
+int tspp_close_channel(u32 dev, u32 channel_id)
+{
+	int i;
+	int id;
+	int table_idx;
+	u32 val;
+	unsigned long flags;
+
+	struct sps_connect *config;
+	struct tspp_device *pdev;
+	struct tspp_channel *channel;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_close: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+
+	/* if the channel is not used, we are done */
+	if (!channel->used)
+		return 0;
+
+	/*
+	 * Need to protect access to used and waiting fields, as they are
+	 * used by the tasklet which is invoked from interrupt context
+	 */
+	spin_lock_irqsave(&pdev->spinlock, flags);
+	channel->used = 0;
+	channel->waiting = NULL;
+	spin_unlock_irqrestore(&pdev->spinlock, flags);
+
+	if (channel->expiration_period_ms)
+		del_timer(&channel->expiration_timer);
+
+	channel->notifier = NULL;
+	channel->notify_data = NULL;
+	channel->expiration_period_ms = 0;
+
+	config = &channel->config;
+	pdev = channel->pdev;
+
+	/* disable pipe (channel) */
+	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
+	writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
+	/* Assure PS_DISABLE register is set */
+	wmb();
+
+	/* unregister all filters for this channel */
+	for (table_idx = 0; table_idx < TSPP_FILTER_TABLES; table_idx++) {
+		for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
+			struct tspp_pid_filter *filter =
+				&pdev->filters[table_idx]->filter[i];
+			id = FILTER_GET_PIPE_NUMBER0(filter);
+			if (id == channel->id) {
+				if (FILTER_HAS_ENCRYPTION(filter))
+					tspp_free_key_entry(
+						FILTER_GET_KEY_NUMBER(filter));
+				filter->config = 0;
+				filter->filter = 0;
+			}
+		}
+	}
+	channel->filter_count = 0;
+
+	/* disconnect the bam */
+	if (sps_disconnect(channel->pipe) != 0)
+		pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
+
+	/* destroy the buffers */
+	dma_free_coherent(&pdev->pdev->dev, config->desc.size,
+		config->desc.base, config->desc.phys_base);
+
+	sps_free_endpoint(channel->pipe);
+
+	tspp_destroy_buffers(channel_id, channel);
+
+	dma_pool_destroy(channel->dma_pool);
+	channel->dma_pool = NULL;
+
+	channel->src = TSPP_SOURCE_NONE;
+	channel->mode = TSPP_MODE_DISABLED;
+	channel->memfree = NULL;
+	channel->user_info = NULL;
+	channel->buffer_count = 0;
+	channel->data = NULL;
+	channel->read = NULL;
+	channel->locked = NULL;
+
+	if (tspp_channels_in_use(pdev) == 0) {
+		sps_deregister_bam_device(pdev->bam_handle);
+		pdev->bam_handle = SPS_DEV_HANDLE_INVALID;
+
+		__pm_relax(&pdev->ws);
+		tspp_clock_stop(pdev);
+	}
+
+	pm_runtime_put(&pdev->pdev->dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_close_channel);
+
+/**
+ * tspp_get_ref_clk_counter - return the TSIF clock reference (TCR) counter.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @source: The TSIF source from which the counter should be read
+ * @tcr_counter: the value of TCR counter
+ *
+ * Return  error status
+ *
+ * TCR increments at a rate equal to 27 MHz/256 = 105.47 kHz.
+ * If source is neither TSIF 0 or TSIF1 0 is returned.
+ */
+int tspp_get_ref_clk_counter(u32 dev, enum tspp_source source, u32 *tcr_counter)
+{
+	struct tspp_device *pdev;
+	struct tspp_tsif_device *tsif_device;
+
+	if (!tcr_counter)
+		return -EINVAL;
+
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_get_ref_clk_counter: can't find device %i\n", dev);
+		return -ENODEV;
+	}
+
+	switch (source) {
+	case TSPP_SOURCE_TSIF0:
+		tsif_device = &pdev->tsif[0];
+		break;
+
+	case TSPP_SOURCE_TSIF1:
+		tsif_device = &pdev->tsif[1];
+		break;
+
+	default:
+		tsif_device = NULL;
+		break;
+	}
+
+	if (tsif_device && tsif_device->ref_count)
+		*tcr_counter = ioread32(tsif_device->base + TSIF_CLK_REF_OFF);
+	else
+		*tcr_counter = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_get_ref_clk_counter);
+
+/**
+ * tspp_get_lpass_time_counter - return the LPASS  Timer counter value.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @source: The TSIF source from which the counter should be read
+ * @tcr_counter: the value of TCR counter
+ *
+ * Return  error status
+ *
+ * If source is neither TSIF 0 or TSIF1 0 is returned.
+ */
+int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source,
+			u64 *lpass_time_counter)
+{
+	struct tspp_device *pdev;
+	struct tspp_tsif_device *tsif_device;
+
+	if (!lpass_time_counter)
+		return -EINVAL;
+
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_get_lpass_time_counter: can't find device %i\n",
+		       dev);
+		return -ENODEV;
+	}
+
+	switch (source) {
+	case TSPP_SOURCE_TSIF0:
+		tsif_device = &pdev->tsif[0];
+		break;
+
+	case TSPP_SOURCE_TSIF1:
+		tsif_device = &pdev->tsif[1];
+		break;
+
+	default:
+		tsif_device = NULL;
+		break;
+	}
+
+	if (tsif_device && tsif_device->ref_count) {
+		if (avcs_core_query_timer(lpass_time_counter) < 0) {
+			pr_err("tspp_get_lpass_time_counter: read error\n");
+			*lpass_time_counter = 0;
+			return -ENETRESET;
+		}
+	} else
+		*lpass_time_counter = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_get_lpass_time_counter);
+
+/**
+ * tspp_get_tts_source - Return the TTS source value.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @tts_source:Updated TTS source type
+ *
+ * Return  error status
+ *
+ */
+int tspp_get_tts_source(u32 dev, int *tts_source)
+{
+	struct tspp_device *pdev;
+
+	if (tts_source == NULL)
+		return -EINVAL;
+
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_get_tts_source: can't find device %i\n",
+		       dev);
+		return -ENODEV;
+	}
+
+	*tts_source = pdev->tts_source;
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_get_tts_source);
+
+/**
+ * tspp_add_filter - add a TSPP filter to a channel.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @filter: TSPP filter parameters
+ *
+ * Return  error status
+ *
+ */
+int tspp_add_filter(u32 dev, u32 channel_id,
+	struct tspp_filter *filter)
+{
+	int i, rc;
+	int other_channel;
+	int entry;
+	u32 val, pid, enabled;
+	struct tspp_device *pdev;
+	struct tspp_pid_filter p;
+	struct tspp_channel *channel;
+
+	TSPP_DEBUG("tspp: add filter");
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_add: can't find device %i", dev);
+		return -ENODEV;
+	}
+
+	channel = &pdev->channels[channel_id];
+
+	if (filter->source > TSPP_SOURCE_MEM) {
+		pr_err("tspp invalid source");
+		return -ENOSR;
+	}
+
+	if (filter->priority >= TSPP_NUM_PRIORITIES) {
+		pr_err("tspp invalid filter priority");
+		return -ENOSR;
+	}
+
+	channel->mode = filter->mode;
+	/*
+	 * if buffers are already allocated, verify they fulfil
+	 * the alignment requirements.
+	 */
+	if ((channel->buffer_count > 0) &&
+	   (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
+		pr_warn("tspp: buffers allocated with incorrect alignment\n");
+
+	if (filter->mode == TSPP_MODE_PES) {
+		for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
+			struct tspp_pid_filter *tspp_filter =
+				&pdev->filters[channel->src]->filter[i];
+			pid = FILTER_GET_PIPE_PID((tspp_filter));
+			enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
+			if (enabled && (pid == filter->pid)) {
+				other_channel =
+					FILTER_GET_PIPE_NUMBER0(tspp_filter);
+				pr_err("tspp: pid 0x%x already in use by channel %i",
+					filter->pid, other_channel);
+				return -EBADSLT;
+			}
+		}
+	}
+
+	/* make sure this priority is not already in use */
+	enabled = FILTER_GET_PIPE_PROCESS0(
+		(&(pdev->filters[channel->src]->filter[filter->priority])));
+	if (enabled) {
+		pr_err("tspp: filter priority %i source %i is already enabled\n",
+			filter->priority, channel->src);
+		return -ENOSR;
+	}
+
+	if (channel->mode == TSPP_MODE_PES) {
+		/*
+		 * if we are already processing in PES mode, disable pipe
+		 * (channel) and filter to be updated
+		 */
+		val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
+		writel_relaxed(val | (1 << channel->id),
+			pdev->base + TSPP_PS_DISABLE);
+		/* Assure PS_DISABLE register is set */
+		wmb();
+	}
+
+	/* update entry */
+	p.filter = 0;
+	p.config = FILTER_TRANS_END_DISABLE;
+	FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
+	FILTER_SET_PIPE_PID((&p), filter->pid);
+	FILTER_SET_PID_MASK((&p), filter->mask);
+	FILTER_SET_PIPE_NUMBER0((&p), channel->id);
+	FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
+	if (filter->decrypt) {
+		entry = tspp_get_key_entry();
+		if (entry == -1) {
+			pr_err("tspp: no more keys available!");
+		} else {
+			p.config |= FILTER_DECRYPT;
+			FILTER_SET_KEY_NUMBER((&p), entry);
+		}
+	}
+
+	pdev->filters[channel->src]->
+		filter[filter->priority].config = p.config;
+	pdev->filters[channel->src]->
+		filter[filter->priority].filter = p.filter;
+
+	/*
+	 * allocate buffers if needed (i.e. if user did has not already called
+	 * tspp_allocate_buffers() explicitly).
+	 */
+	if (channel->buffer_count == 0) {
+		channel->buffer_size =
+		tspp_align_buffer_size_by_mode(channel->buffer_size,
+							channel->mode);
+		rc = tspp_allocate_buffers(dev, channel->id,
+					channel->max_buffers,
+					channel->buffer_size,
+					channel->int_freq, NULL, NULL, NULL);
+		if (rc != 0) {
+			pr_err("tspp: tspp_allocate_buffers failed\n");
+			return rc;
+		}
+	}
+
+	/* reenable pipe */
+	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
+	writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
+	/* Assure PS_DISABLE register is reset */
+	wmb();
+	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
+
+	channel->filter_count++;
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_add_filter);
+
+/**
+ * tspp_remove_filter - remove a TSPP filter from a channel.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @filter: TSPP filter parameters
+ *
+ * Return  error status
+ *
+ */
+int tspp_remove_filter(u32 dev, u32 channel_id,
+	struct tspp_filter *filter)
+{
+	int entry;
+	u32 val;
+	struct tspp_device *pdev;
+	int src;
+	struct tspp_pid_filter *tspp_filter;
+	struct tspp_channel *channel;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	if (!filter) {
+		pr_err("tspp: NULL filter pointer");
+		return -EINVAL;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_remove: can't find device %i", dev);
+		return -ENODEV;
+	}
+	if (filter->priority >= TSPP_NUM_PRIORITIES) {
+		pr_err("tspp invalid filter priority");
+		return -ENOSR;
+	}
+	channel = &pdev->channels[channel_id];
+
+	src = channel->src;
+	if ((src == TSPP_SOURCE_TSIF0) || (src == TSPP_SOURCE_TSIF1))
+		tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
+	else {
+		pr_err("tspp_remove: wrong source type %d", src);
+		return -EINVAL;
+	}
+
+
+	/* disable pipe (channel) */
+	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
+	writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
+	/* Assure PS_DISABLE register is set */
+	wmb();
+
+	/* update data keys */
+	if (tspp_filter->config & FILTER_DECRYPT) {
+		entry = FILTER_GET_KEY_NUMBER(tspp_filter);
+		tspp_free_key_entry(entry);
+	}
+
+	/* update pid table */
+	tspp_filter->config = 0;
+	tspp_filter->filter = 0;
+
+	channel->filter_count--;
+
+	/* reenable pipe */
+	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
+	writel_relaxed(val & ~(1 << channel->id),
+		pdev->base + TSPP_PS_DISABLE);
+	/* Assure PS_DISABLE register is reset */
+	wmb();
+	val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_remove_filter);
+
+/**
+ * tspp_set_key - set TSPP key in key table.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @key: TSPP key parameters
+ *
+ * Return  error status
+ *
+ */
+int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
+{
+	int i;
+	int id;
+	int key_index;
+	int data;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_set: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+
+	/* read the key index used by this channel */
+	for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
+		struct tspp_pid_filter *tspp_filter =
+			&(pdev->filters[channel->src]->filter[i]);
+		id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
+		if (id == channel->id) {
+			if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
+				key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
+				break;
+			}
+		}
+	}
+	if (i == TSPP_NUM_PRIORITIES) {
+		pr_err("tspp: no encryption on this channel");
+		return -ENOKEY;
+	}
+
+	if (key->parity == TSPP_KEY_PARITY_EVEN) {
+		pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
+		pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
+	} else {
+		pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
+		pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
+	}
+	data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_set_key);
+
+/**
+ * tspp_register_notification - register TSPP channel notification function.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @notify: notification function
+ * @userdata: user data to pass to notification function
+ * @timer_ms: notification for partially filled buffers
+ *
+ * Return  error status
+ *
+ */
+int tspp_register_notification(u32 dev, u32 channel_id,
+	tspp_notifier *notify, void *userdata, u32 timer_ms)
+{
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_reg: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+	channel->notifier = notify;
+	channel->notify_data = userdata;
+	channel->expiration_period_ms = timer_ms;
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_register_notification);
+
+/**
+ * tspp_unregister_notification - unregister TSPP channel notification function.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
+int tspp_unregister_notification(u32 dev, u32 channel_id)
+{
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_unreg: can't find device %i", dev);
+		return -ENODEV;
+	}
+	channel = &pdev->channels[channel_id];
+	channel->notifier = NULL;
+	channel->notify_data = 0;
+	return 0;
+}
+EXPORT_SYMBOL(tspp_unregister_notification);
+
+/**
+ * tspp_get_buffer - get TSPP data buffer.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ *
+ * Return  error status
+ *
+ */
+const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
+{
+	struct tspp_mem_buffer *buffer;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+	unsigned long flags;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return NULL;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp_get: can't find device %i", dev);
+		return NULL;
+	}
+
+	spin_lock_irqsave(&pdev->spinlock, flags);
+
+	channel = &pdev->channels[channel_id];
+
+	if (!channel->read) {
+		spin_unlock_irqrestore(&pdev->spinlock, flags);
+		pr_warn("tspp: no buffer to get on channel %i!",
+			channel->id);
+		return NULL;
+	}
+
+	buffer = channel->read;
+	/* see if we have any buffers ready to read */
+	if (buffer->state != TSPP_BUF_STATE_DATA) {
+		spin_unlock_irqrestore(&pdev->spinlock, flags);
+		return NULL;
+	}
+
+	if (buffer->state == TSPP_BUF_STATE_DATA) {
+		/* mark the buffer as busy */
+		buffer->state = TSPP_BUF_STATE_LOCKED;
+
+		/* increment the pointer along the list */
+		channel->read = channel->read->next;
+	}
+
+	spin_unlock_irqrestore(&pdev->spinlock, flags);
+
+	return &buffer->desc;
+}
+EXPORT_SYMBOL(tspp_get_buffer);
+
+/**
+ * tspp_release_buffer - release TSPP data buffer back to TSPP.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @descriptor_id: buffer descriptor ID
+ *
+ * Return  error status
+ *
+ */
+int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
+{
+	int i, found = 0;
+	struct tspp_mem_buffer *buffer;
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+	unsigned long flags;
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("tspp: channel id out of range");
+		return -ECHRNG;
+	}
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp: can't find device %i", dev);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&pdev->spinlock, flags);
+
+	channel = &pdev->channels[channel_id];
+
+	if (descriptor_id > channel->buffer_count)
+		pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
+
+	/* find the correct descriptor */
+	buffer = channel->locked;
+	for (i = 0; i < channel->buffer_count; i++) {
+		if (buffer->desc.id == descriptor_id) {
+			found = 1;
+			break;
+		}
+		buffer = buffer->next;
+	}
+	channel->locked = channel->locked->next;
+
+	if (!found) {
+		spin_unlock_irqrestore(&pdev->spinlock, flags);
+		pr_err("tspp: cant find desc %i", descriptor_id);
+		return -EINVAL;
+	}
+
+	/* make sure the buffer is in the expected state */
+	if (buffer->state != TSPP_BUF_STATE_LOCKED) {
+		spin_unlock_irqrestore(&pdev->spinlock, flags);
+		pr_err("tspp: buffer %i not locked", descriptor_id);
+		return -EINVAL;
+	}
+	/* unlock the buffer and requeue it */
+	buffer->state = TSPP_BUF_STATE_WAITING;
+
+	if (tspp_queue_buffer(channel, buffer))
+		pr_warn("tspp: can't requeue buffer");
+
+	spin_unlock_irqrestore(&pdev->spinlock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_release_buffer);
+
+/**
+ * tspp_allocate_buffers - allocate TSPP data buffers.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
+ * @count: number of buffers to allocate
+ * @size: size of each buffer to allocate
+ * @int_freq: interrupt frequency
+ * @alloc: user defined memory allocator function. Pass NULL for default.
+ * @memfree: user defined memory free function. Pass NULL for default.
+ * @user: user data to pass to the memory allocator/free function
+ *
+ * Return  error status
+ *
+ * The user can optionally call this function explicitly to allocate the TSPP
+ * data buffers. Alternatively, if the user did not call this function, it
+ * is called implicitly by tspp_add_filter().
+ */
+int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
+			u32 int_freq, tspp_allocator *alloc,
+			tspp_memfree *memfree, void *user)
+{
+	struct tspp_channel *channel;
+	struct tspp_device *pdev;
+	struct tspp_mem_buffer *last = NULL;
+
+	TSPP_DEBUG("tspp_allocate_buffers");
+
+	if (channel_id >= TSPP_NUM_CHANNELS) {
+		pr_err("%s: channel id out of range", __func__);
+		return -ECHRNG;
+	}
+
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("%s: can't find device %i", __func__, dev);
+		return -ENODEV;
+	}
+
+	if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
+		pr_err("%s: tspp requires a minimum of %i buffers\n",
+			__func__, MIN_ACCEPTABLE_BUFFER_COUNT);
+		return -EINVAL;
+	}
+
+	if (count > TSPP_NUM_BUFFERS) {
+		pr_err("%s: tspp requires a maximum of %i buffers\n",
+			__func__, TSPP_NUM_BUFFERS);
+		return -EINVAL;
+	}
+
+	channel = &pdev->channels[channel_id];
+
+	/* allow buffer allocation only if there was no previous buffer
+	 * allocation for this channel.
+	 */
+	if (channel->buffer_count > 0) {
+		pr_err("%s: buffers already allocated for channel %u",
+			__func__, channel_id);
+		return -EINVAL;
+	}
+
+	channel->max_buffers = count;
+
+	/* set up interrupt frequency */
+	if (int_freq > channel->max_buffers) {
+		int_freq = channel->max_buffers;
+		pr_warn("%s: setting interrupt frequency to %u\n",
+			__func__, int_freq);
+	}
+	channel->int_freq = int_freq;
+	/*
+	 * it is the responsibility of the caller to tspp_allocate_buffers(),
+	 * whether it's the user or the driver, to make sure the size parameter
+	 * is compatible to the channel mode.
+	 */
+	channel->buffer_size = size;
+
+	/* save user defined memory free function for later use */
+	channel->memfree = memfree;
+	channel->user_info = user;
+
+	/*
+	 * For small buffers, create a DMA pool so that memory
+	 * is not wasted through dma_alloc_coherent.
+	 */
+	if (TSPP_USE_DMA_POOL(channel->buffer_size)) {
+		channel->dma_pool = dma_pool_create("tspp",
+			&pdev->pdev->dev, channel->buffer_size, 0, 0);
+		if (!channel->dma_pool) {
+			pr_err("%s: Can't allocate memory pool\n", __func__);
+			return -ENOMEM;
+		}
+	} else {
+		channel->dma_pool = NULL;
+	}
+
+
+	for (channel->buffer_count = 0;
+		channel->buffer_count < channel->max_buffers;
+		channel->buffer_count++) {
+
+		/* allocate the descriptor */
+		struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
+			kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
+		if (!desc) {
+			pr_warn("%s: Can't allocate desc %i",
+				__func__, channel->buffer_count);
+			break;
+		}
+
+		desc->desc.id = channel->buffer_count;
+		/* allocate the buffer */
+		if (tspp_alloc_buffer(channel_id, &desc->desc,
+			channel->buffer_size, channel->dma_pool,
+			alloc, user) != 0) {
+			kfree(desc);
+			pr_warn("%s: Can't allocate buffer %i",
+				__func__, channel->buffer_count);
+			break;
+		}
+
+		/* add the descriptor to the list */
+		desc->filled = 0;
+		desc->read_index = 0;
+		if (!channel->data) {
+			channel->data = desc;
+			desc->next = channel->data;
+		} else {
+			if (last != NULL)
+				last->next = desc;
+		}
+		last = desc;
+		desc->next = channel->data;
+
+		/* prepare the sps descriptor */
+		desc->sps.phys_base = desc->desc.phys_base;
+		desc->sps.base = desc->desc.virt_base;
+		desc->sps.size = desc->desc.size;
+
+		/* start the transfer */
+		if (tspp_queue_buffer(channel, desc))
+			pr_err("%s: can't queue buffer %i",
+				__func__, desc->desc.id);
+	}
+
+	if (channel->buffer_count < channel->max_buffers) {
+		/*
+		 * we failed to allocate the requested number of buffers.
+		 * we don't allow a partial success, so need to clean up here.
+		 */
+		tspp_destroy_buffers(channel_id, channel);
+		channel->buffer_count = 0;
+
+		dma_pool_destroy(channel->dma_pool);
+		channel->dma_pool = NULL;
+		return -ENOMEM;
+	}
+
+	channel->waiting = channel->data;
+	channel->read = channel->data;
+	channel->locked = channel->data;
+
+	/* Now that buffers are scheduled to HW, kick data expiration timer */
+	if (channel->expiration_period_ms)
+		mod_timer(&channel->expiration_timer,
+			jiffies +
+			MSEC_TO_JIFFIES(
+				channel->expiration_period_ms));
+
+	return 0;
+}
+EXPORT_SYMBOL(tspp_allocate_buffers);
+
+/*** debugfs ***/
+static int debugfs_iomem_x32_set(void *data, u64 val)
+{
+	int rc;
+	int clock_started = 0;
+	struct tspp_device *pdev;
+
+	pdev = tspp_find_by_id(0);
+	if (!pdev) {
+		pr_err("%s: can't find device 0\n", __func__);
+		return 0;
+	}
+
+	if (tspp_channels_in_use(pdev) == 0) {
+		rc = tspp_clock_start(pdev);
+		if (rc) {
+			pr_err("%s: tspp_clock_start failed %d\n",
+				__func__, rc);
+			return 0;
+		}
+		clock_started = 1;
+	}
+
+	writel_relaxed(val, data);
+	/* Assure register write */
+	wmb();
+
+	if (clock_started)
+		tspp_clock_stop(pdev);
+	return 0;
+}
+
+static int debugfs_iomem_x32_get(void *data, u64 *val)
+{
+	int rc;
+	int clock_started = 0;
+	struct tspp_device *pdev;
+
+	pdev = tspp_find_by_id(0);
+	if (!pdev) {
+		pr_err("%s: can't find device 0\n", __func__);
+		*val = 0;
+		return 0;
+	}
+
+	if (tspp_channels_in_use(pdev) == 0) {
+		rc = tspp_clock_start(pdev);
+		if (rc) {
+			pr_err("%s: tspp_clock_start failed %d\n",
+				__func__, rc);
+			*val = 0;
+			return 0;
+		}
+		clock_started = 1;
+	}
+
+	*val = readl_relaxed(data);
+
+	if (clock_started)
+		tspp_clock_stop(pdev);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
+			debugfs_iomem_x32_set, "0x%08llx");
+
+static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
+	int instance)
+{
+	char name[10];
+
+	snprintf(name, 10, "tsif%i", instance);
+	tsif_device->dent_tsif = debugfs_create_dir(
+	      name, NULL);
+	if (tsif_device->dent_tsif) {
+		int i;
+		void __iomem *base = tsif_device->base;
+
+		for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
+			tsif_device->debugfs_tsif_regs[i] =
+			   debugfs_create_file(
+				debugfs_tsif_regs[i].name,
+				debugfs_tsif_regs[i].mode,
+				tsif_device->dent_tsif,
+				base + debugfs_tsif_regs[i].offset,
+				&fops_iomem_x32);
+		}
+
+		debugfs_create_u32(
+			"stat_rx_chunks", 0664,
+			tsif_device->dent_tsif,
+			&tsif_device->stat_rx);
+
+		debugfs_create_u32(
+			"stat_overflow", 0664,
+			tsif_device->dent_tsif,
+			&tsif_device->stat_overflow);
+
+		debugfs_create_u32(
+			"stat_lost_sync", 0664,
+			tsif_device->dent_tsif,
+			&tsif_device->stat_lost_sync);
+
+		debugfs_create_u32(
+			"stat_timeout", 0664,
+			tsif_device->dent_tsif,
+			&tsif_device->stat_timeout);
+	}
+}
+
+static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
+{
+	int i;
+
+	debugfs_remove_recursive(tsif_device->dent_tsif);
+	tsif_device->dent_tsif = NULL;
+	for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
+		tsif_device->debugfs_tsif_regs[i] = NULL;
+}
+
+static void tspp_debugfs_init(struct tspp_device *device, int instance)
+{
+	char name[10];
+
+	snprintf(name, 10, "tspp%i", instance);
+	device->dent = debugfs_create_dir(
+	      name, NULL);
+	if (device->dent) {
+		int i;
+		void __iomem *base = device->base;
+
+		for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
+			device->debugfs_regs[i] =
+			   debugfs_create_file(
+				debugfs_tspp_regs[i].name,
+				debugfs_tspp_regs[i].mode,
+				device->dent,
+				base + debugfs_tspp_regs[i].offset,
+				&fops_iomem_x32);
+	}
+}
+
+static void tspp_debugfs_exit(struct tspp_device *device)
+{
+	int i;
+
+	debugfs_remove_recursive(device->dent);
+	for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
+		device->debugfs_regs[i] = NULL;
+}
+
+static int msm_tspp_map_irqs(struct platform_device *pdev,
+				struct tspp_device *device)
+{
+	int rc;
+
+	/* get IRQ numbers from platform information */
+
+	/* map TSPP IRQ */
+	rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ");
+	if (rc > 0) {
+		device->tspp_irq = rc;
+	} else {
+		dev_err(&pdev->dev, "failed to get TSPP IRQ");
+		return -EINVAL;
+	}
+
+	/* map TSIF IRQs */
+	rc = platform_get_irq_byname(pdev, "TSIF0_IRQ");
+	if (rc > 0) {
+		device->tsif[0].tsif_irq = rc;
+	} else {
+		dev_err(&pdev->dev, "failed to get TSIF0 IRQ");
+		return -EINVAL;
+	}
+
+	rc = platform_get_irq_byname(pdev, "TSIF1_IRQ");
+	if (rc > 0) {
+		device->tsif[1].tsif_irq = rc;
+	} else {
+		dev_err(&pdev->dev, "failed to get TSIF1 IRQ");
+		return -EINVAL;
+	}
+
+	/* map BAM IRQ */
+	rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ");
+	if (rc > 0) {
+		device->bam_irq = rc;
+	} else {
+		dev_err(&pdev->dev, "failed to get TSPP BAM IRQ");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_tspp_probe(struct platform_device *pdev)
+{
+	int rc = -ENODEV;
+	u32 version;
+	u32 i;
+	struct tspp_device *device;
+	struct resource *mem_tsif0;
+	struct resource *mem_tsif1;
+	struct resource *mem_tspp;
+	struct resource *mem_bam;
+	struct msm_bus_scale_pdata *tspp_bus_pdata = NULL;
+	unsigned long rate;
+
+	if (pdev->dev.of_node) {
+		/* ID is always 0 since there is only 1 instance of TSPP */
+		pdev->id = 0;
+		tspp_bus_pdata = msm_bus_cl_get_pdata(pdev);
+	} else {
+		/* must have device tree data */
+		pr_err("tspp: Device tree data not available\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* OK, we will use this device */
+	device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
+	if (!device) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* set up references */
+	device->pdev = pdev;
+	platform_set_drvdata(pdev, device);
+
+	/* setup pin control */
+	rc = tspp_get_pinctrl(device);
+	if (rc) {
+		pr_err("tspp: failed to get pin control data, rc=%d\n", rc);
+		goto err_pinctrl;
+	}
+
+	/* register bus client */
+	if (tspp_bus_pdata) {
+		device->tsif_bus_client =
+			msm_bus_scale_register_client(tspp_bus_pdata);
+		if (!device->tsif_bus_client)
+			pr_err("tspp: Unable to register bus client\n");
+	} else {
+		device->tsif_bus_client = 0;
+	}
+
+	/* map regulators */
+	device->tsif_vreg = devm_regulator_get_optional(&pdev->dev, "vdd_cx");
+	if (IS_ERR_OR_NULL(device->tsif_vreg)) {
+		rc = PTR_ERR(device->tsif_vreg);
+		device->tsif_vreg = NULL;
+		if (rc == -ENODEV) {
+			pr_notice("%s: vdd_cx regulator will not be used\n",
+				__func__);
+		} else {
+			dev_err(&pdev->dev,
+				"failed to get CX regulator, err=%d\n", rc);
+			goto err_regulator;
+		}
+	} else {
+		/* Set an initial voltage and enable the regulator */
+		rc = regulator_set_voltage(device->tsif_vreg,
+					RPMH_REGULATOR_LEVEL_OFF,
+					RPMH_REGULATOR_LEVEL_MAX);
+		if (rc) {
+			dev_err(&pdev->dev, "Unable to set CX voltage.\n");
+			goto err_regulator;
+		}
+
+		rc = regulator_enable(device->tsif_vreg);
+		if (rc) {
+			dev_err(&pdev->dev, "Unable to enable CX regulator.\n");
+			goto err_regulator;
+		}
+	}
+
+	/* map clocks */
+	device->tsif_pclk = clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR_OR_NULL(device->tsif_pclk)) {
+		rc = PTR_ERR(device->tsif_pclk);
+		device->tsif_pclk = NULL;
+		goto err_pclock;
+	}
+
+	device->tsif_ref_clk = clk_get(&pdev->dev, "ref_clk");
+	if (IS_ERR_OR_NULL(device->tsif_ref_clk)) {
+		rc = PTR_ERR(device->tsif_ref_clk);
+		device->tsif_ref_clk = NULL;
+		goto err_refclock;
+	}
+	rate = clk_round_rate(device->tsif_ref_clk, 1);
+	rc = clk_set_rate(device->tsif_ref_clk, rate);
+	if (rc)
+		goto err_res_tsif0;
+
+	/* map I/O memory */
+	mem_tsif0 = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "MSM_TSIF0_PHYS");
+	if (!mem_tsif0) {
+		pr_err("tspp: Missing tsif0 MEM resource\n");
+		rc = -ENXIO;
+		goto err_res_tsif0;
+	}
+	device->tsif[0].base = ioremap(mem_tsif0->start,
+		resource_size(mem_tsif0));
+	if (!device->tsif[0].base) {
+		pr_err("tspp: ioremap failed\n");
+		goto err_map_tsif0;
+	}
+
+	mem_tsif1 = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "MSM_TSIF1_PHYS");
+	if (!mem_tsif1) {
+		dev_err(&pdev->dev, "Missing tsif1 MEM resource\n");
+		rc = -ENXIO;
+		goto err_res_tsif1;
+	}
+	device->tsif[1].base = ioremap(mem_tsif1->start,
+		resource_size(mem_tsif1));
+	if (!device->tsif[1].base) {
+		dev_err(&pdev->dev, "ioremap failed");
+		goto err_map_tsif1;
+	}
+
+	mem_tspp = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "MSM_TSPP_PHYS");
+	if (!mem_tspp) {
+		dev_err(&pdev->dev, "Missing MEM resource");
+		rc = -ENXIO;
+		goto err_res_dev;
+	}
+	device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
+	if (!device->base) {
+		dev_err(&pdev->dev, "ioremap failed");
+		goto err_map_dev;
+	}
+
+	mem_bam = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "MSM_TSPP_BAM_PHYS");
+	if (!mem_bam) {
+		pr_err("tspp: Missing bam MEM resource");
+		rc = -ENXIO;
+		goto err_res_bam;
+	}
+	memset(&device->bam_props, 0, sizeof(device->bam_props));
+	device->bam_props.phys_addr = mem_bam->start;
+	device->bam_props.virt_addr = ioremap(mem_bam->start,
+		resource_size(mem_bam));
+	if (!device->bam_props.virt_addr) {
+		dev_err(&pdev->dev, "ioremap failed");
+		goto err_map_bam;
+	}
+
+	if (msm_tspp_map_irqs(pdev, device))
+		goto err_irq;
+	device->req_irqs = false;
+
+	/* Check whether AV timer time stamps are enabled */
+	if (!of_property_read_u32(pdev->dev.of_node, "qcom,lpass-timer-tts",
+				  &device->tts_source)) {
+		if (device->tts_source == 1)
+			device->tts_source = TSIF_TTS_LPASS_TIMER;
+		else
+			device->tts_source = TSIF_TTS_TCR;
+	} else {
+		device->tts_source = TSIF_TTS_TCR;
+	}
+
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
+		device->tsif[i].tts_source = device->tts_source;
+
+	/* power management */
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	tspp_debugfs_init(device, 0);
+
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
+		tsif_debugfs_init(&device->tsif[i], i);
+
+	wakeup_source_init(&device->ws, dev_name(&pdev->dev));
+
+	/* set up pointers to ram-based 'registers' */
+	device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
+	device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
+	device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
+	device->tspp_key_table = device->base + TSPP_DATA_KEY;
+	device->tspp_global_performance =
+		device->base + TSPP_GLOBAL_PERFORMANCE;
+	device->tspp_pipe_context =
+		device->base + TSPP_PIPE_CONTEXT;
+	device->tspp_pipe_performance =
+		device->base + TSPP_PIPE_PERFORMANCE;
+
+	device->bam_props.summing_threshold = 0x10;
+	device->bam_props.irq = device->bam_irq;
+	device->bam_props.manage = SPS_BAM_MGR_LOCAL;
+	/*add SPS BAM log level*/
+	device->bam_props.ipc_loglevel = TSPP_BAM_DEFAULT_IPC_LOGLVL;
+
+	if (tspp_clock_start(device) != 0) {
+		dev_err(&pdev->dev, "Can't start clocks");
+		goto err_clock;
+	}
+
+	device->bam_handle = SPS_DEV_HANDLE_INVALID;
+
+	spin_lock_init(&device->spinlock);
+	mutex_init(&device->mutex);
+	tasklet_init(&device->tlet, tspp_sps_complete_tlet,
+			(unsigned long)device);
+
+	/* initialize everything to a known state */
+	tspp_global_reset(device);
+
+	version = readl_relaxed(device->base + TSPP_VERSION);
+	/*
+	 * TSPP version can be bits [7:0] or alternatively,
+	 * TSPP major version is bits [31:28].
+	 */
+	if ((version != 0x1) && (((version >> 28) & 0xF) != 0x1))
+		pr_warn("tspp: unrecognized hw version=%i", version);
+
+	/* initialize the channels */
+	for (i = 0; i < TSPP_NUM_CHANNELS; i++)
+		tspp_channel_init(&(device->channels[i]), device);
+
+	/* stop the clocks for power savings */
+	tspp_clock_stop(device);
+
+	/* everything is ok, so add the device to the list */
+	list_add_tail(&(device->devlist), &tspp_devices);
+	return 0;
+
+err_clock:
+	tspp_debugfs_exit(device);
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
+		tsif_debugfs_exit(&device->tsif[i]);
+err_irq:
+	iounmap(device->bam_props.virt_addr);
+err_map_bam:
+err_res_bam:
+	iounmap(device->base);
+err_map_dev:
+err_res_dev:
+	iounmap(device->tsif[1].base);
+err_map_tsif1:
+err_res_tsif1:
+	iounmap(device->tsif[0].base);
+err_map_tsif0:
+err_res_tsif0:
+	if (device->tsif_ref_clk)
+		clk_put(device->tsif_ref_clk);
+err_refclock:
+	if (device->tsif_pclk)
+		clk_put(device->tsif_pclk);
+err_pclock:
+	if (device->tsif_vreg)
+		regulator_disable(device->tsif_vreg);
+err_regulator:
+	if (device->tsif_bus_client)
+		msm_bus_scale_unregister_client(device->tsif_bus_client);
+err_pinctrl:
+	kfree(device);
+
+out:
+	return rc;
+}
+
+static int msm_tspp_remove(struct platform_device *pdev)
+{
+	struct tspp_channel *channel;
+	u32 i;
+
+	struct tspp_device *device = platform_get_drvdata(pdev);
+
+	/* free the buffers, and delete the channels */
+	for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
+		channel = &device->channels[i];
+		tspp_close_channel(device->pdev->id, i);
+	}
+
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
+		tsif_debugfs_exit(&device->tsif[i]);
+
+	mutex_destroy(&device->mutex);
+
+	if (device->tsif_bus_client)
+		msm_bus_scale_unregister_client(device->tsif_bus_client);
+
+	wakeup_source_trash(&device->ws);
+	if (device->req_irqs)
+		msm_tspp_free_irqs(device);
+
+	iounmap(device->bam_props.virt_addr);
+	iounmap(device->base);
+	for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
+		iounmap(device->tsif[i].base);
+
+	if (device->tsif_ref_clk)
+		clk_put(device->tsif_ref_clk);
+
+	if (device->tsif_pclk)
+		clk_put(device->tsif_pclk);
+
+	if (device->tsif_vreg)
+		regulator_disable(device->tsif_vreg);
+
+	pm_runtime_disable(&pdev->dev);
+
+	kfree(device);
+
+	return 0;
+}
+
+/*** power management ***/
+
+static int tspp_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: suspending...");
+	return 0;
+}
+
+static int tspp_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: resuming...");
+	return 0;
+}
+
+static const struct dev_pm_ops tspp_dev_pm_ops = {
+	.runtime_suspend = tspp_runtime_suspend,
+	.runtime_resume = tspp_runtime_resume,
+};
+
+static const struct of_device_id msm_match_table[] = {
+	{.compatible = "qcom,msm_tspp"},
+	{}
+};
+
+static struct platform_driver msm_tspp_driver = {
+	.probe          = msm_tspp_probe,
+	.remove         = msm_tspp_remove,
+	.driver         = {
+		.name   = "msm_tspp",
+		.pm     = &tspp_dev_pm_ops,
+		.of_match_table = msm_match_table,
+	},
+};
+
+
+static int __init mod_init(void)
+{
+	int rc;
+
+	/* register the driver, and check hardware */
+	rc = platform_driver_register(&msm_tspp_driver);
+	if (rc)
+		pr_err("tspp: platform_driver_register failed: %d", rc);
+
+	return rc;
+}
+
+static void __exit mod_exit(void)
+{
+	/* delete low level driver */
+	platform_driver_unregister(&msm_tspp_driver);
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_DESCRIPTION("TSPP platform device");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c
index 7f2c455..1105d2c 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c
@@ -692,7 +692,19 @@
 
 	CDM_CDBG("Waiting for CDM HW resetdone\n");
 	time_left = wait_for_completion_timeout(&cdm_core->reset_complete,
-			msecs_to_jiffies(CAM_CDM_HW_RESET_TIMEOUT));
+		msecs_to_jiffies(CAM_CDM_HW_RESET_TIMEOUT));
+
+	/*
+	 * Check for HW error and recover as a workaround
+	 * Sometimes CDM HW triggers irq with invalid status for
+	 * HW reset command, so ignore reset failure and proceed further
+	 * as a workaround.
+	 */
+	if (time_left <= 0) {
+		pr_err("CDM HW reset Wait failed time_left=%ld\n", time_left);
+		time_left = 1;
+	}
+
 	if (time_left <= 0) {
 		pr_err("CDM HW reset Wait failed rc=%d\n", rc);
 		goto disable_return;
diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c
index 034c782..3d258b4 100644
--- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c
+++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c
@@ -318,37 +318,6 @@
 	cdm_write_genirq,
 };
 
-void cam_cdm_data_alignement_check(void)
-{
-	BUILD_BUG_ON(sizeof(struct cdm_dmi_cmd) !=
-		(CAM_CDM_DWORD * cdm_get_cmd_header_size(CAM_CDM_CMD_DMI)));
-	BUILD_BUG_ON(sizeof(struct cdm_regcontinuous_cmd) !=
-		(CAM_CDM_DWORD *
-		cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)));
-	BUILD_BUG_ON(sizeof(struct cdm_regrandom_cmd) !=
-		(CAM_CDM_DWORD *
-		cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM)));
-	BUILD_BUG_ON(sizeof(struct cdm_indirect_cmd) !=
-		(CAM_CDM_DWORD *
-		cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT)));
-	BUILD_BUG_ON(sizeof(struct cdm_genirq_cmd) !=
-		(CAM_CDM_DWORD *
-		cdm_get_cmd_header_size(CAM_CDM_CMD_GEN_IRQ)));
-	BUILD_BUG_ON(sizeof(struct cdm_wait_event_cmd) !=
-		(CAM_CDM_DWORD *
-		cdm_get_cmd_header_size(CAM_CDM_CMD_WAIT_EVENT)));
-	BUILD_BUG_ON(sizeof(struct cdm_changebase_cmd) !=
-		(CAM_CDM_DWORD *
-		cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE)));
-	BUILD_BUG_ON(sizeof(struct  cdm_perf_ctrl_cmd) !=
-		(CAM_CDM_DWORD *
-		cdm_get_cmd_header_size(CAM_CDM_CMD_PERF_CTRL)));
-	BUILD_BUG_ON(sizeof(struct cdm_dmi_cmd) !=
-		(CAM_CDM_DWORD * cdm_get_cmd_header_size(CAM_CDM_CMD_DMI_32)));
-	BUILD_BUG_ON(sizeof(struct cdm_dmi_cmd) !=
-		(CAM_CDM_DWORD * cdm_get_cmd_header_size(CAM_CDM_CMD_DMI_64)));
-}
-
 int cam_cdm_get_ioremap_from_base(uint32_t hw_base,
 	uint32_t base_array_size,
 	struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK],
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
index 21a61ff..2a0c4a7 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -60,10 +60,6 @@
 		cam_sync_signal(req->out_map_entries[j].sync_id,
 			CAM_SYNC_STATE_SIGNALED_SUCCESS);
 		req->num_out_acked++;
-		trace_printk("Sync success req %lld, reset sync id 0x%x\n",
-			req->request_id,
-			req->out_map_entries[j].sync_id);
-
 		req->out_map_entries[j].sync_id = -1;
 	}
 
@@ -195,8 +191,6 @@
 	req->num_in_acked++;
 	if (req->num_in_acked == req->num_in_map_entries) {
 		apply.request_id = req->request_id;
-		trace_printk("async cb for request :%llu",
-			req->request_id);
 		cam_context_apply_req_to_hw(ctx, &apply);
 	}
 }
@@ -287,8 +281,6 @@
 		list_add_tail(&req->list, &ctx->pending_req_list);
 		spin_unlock(&ctx->lock);
 		for (i = 0; i < req->num_in_map_entries; i++) {
-			trace_printk("register in fence callback: %d\n",
-				req->in_map_entries[i].sync_id);
 			rc = cam_sync_register_callback(
 					cam_context_sync_callback,
 					(void *)ctx,
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
index 17f6973..74a94b2 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -16,6 +16,13 @@
 
 #include "cam_node.h"
 
+static void  __cam_node_handle_shutdown(struct cam_node *node)
+{
+	if (node->hw_mgr_intf.hw_close)
+		node->hw_mgr_intf.hw_close(node->hw_mgr_intf.hw_mgr_priv,
+			NULL);
+}
+
 static int __cam_node_handle_query_cap(struct cam_node *node,
 	struct cam_query_cap_cmd *query)
 {
@@ -408,6 +415,9 @@
 		}
 		break;
 	}
+	case CAM_SD_SHUTDOWN:
+		__cam_node_handle_shutdown(node);
+		break;
 	default:
 		pr_err("Unknown op code %d\n", cmd->op_code);
 		rc = -EINVAL;
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
index 8d9f4a5..9a30d64 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
@@ -1330,15 +1330,22 @@
 	cpas_hw_intf->hw_ops.write = NULL;
 	cpas_hw_intf->hw_ops.process_cmd = cam_cpas_hw_process_cmd;
 
+	cpas_core->work_queue = alloc_workqueue("cam-cpas",
+		WQ_UNBOUND | WQ_MEM_RECLAIM, CAM_CPAS_INFLIGHT_WORKS);
+	if (!cpas_core->work_queue) {
+		rc = -ENOMEM;
+		goto release_mem;
+	}
+
 	internal_ops = &cpas_core->internal_ops;
 	rc = cam_cpas_util_get_internal_ops(pdev, cpas_hw_intf, internal_ops);
-	if (rc != 0)
-		goto release_mem;
+	if (rc)
+		goto release_workq;
 
 	rc = cam_cpas_soc_init_resources(&cpas_hw->soc_info,
 		internal_ops->handle_irq, cpas_hw);
 	if (rc)
-		goto release_mem;
+		goto release_workq;
 
 	soc_private = (struct cam_cpas_private_soc *)
 		cpas_hw->soc_info.soc_private;
@@ -1423,6 +1430,9 @@
 	cam_cpas_util_client_cleanup(cpas_hw);
 deinit_platform_res:
 	cam_cpas_soc_deinit_resources(&cpas_hw->soc_info);
+release_workq:
+	flush_workqueue(cpas_core->work_queue);
+	destroy_workqueue(cpas_core->work_queue);
 release_mem:
 	mutex_destroy(&cpas_hw->hw_mutex);
 	kfree(cpas_core);
@@ -1454,6 +1464,8 @@
 	cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client);
 	cam_cpas_util_client_cleanup(cpas_hw);
 	cam_cpas_soc_deinit_resources(&cpas_hw->soc_info);
+	flush_workqueue(cpas_core->work_queue);
+	destroy_workqueue(cpas_core->work_queue);
 	mutex_destroy(&cpas_hw->hw_mutex);
 	kfree(cpas_core);
 	kfree(cpas_hw);
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
index 52649ec..6d4fafe 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
@@ -17,6 +17,7 @@
 #include "cam_cpas_hw_intf.h"
 
 #define CPAS_MAX_CLIENTS 20
+#define CAM_CPAS_INFLIGHT_WORKS 5
 
 #define CAM_CPAS_GET_CLIENT_IDX(handle) (handle)
 #define CAM_CPAS_GET_CLIENT_HANDLE(indx) (indx)
@@ -169,6 +170,7 @@
  * @ahb_bus_client: AHB Bus client info
  * @axi_ports_list_head: Head pointing to list of AXI ports
  * @internal_ops: CPAS HW internal ops
+ * @work_queue: Work queue handle
  *
  */
 struct cam_cpas {
@@ -182,6 +184,7 @@
 	struct cam_cpas_bus_client ahb_bus_client;
 	struct list_head axi_ports_list_head;
 	struct cam_cpas_internal_ops internal_ops;
+	struct workqueue_struct *work_queue;
 };
 
 int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops);
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
index b774625..aba0caa 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
@@ -327,7 +327,7 @@
 int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
 	struct cam_control *cmd)
 {
-	int rc;
+	int rc = 0;
 
 	if (!cmd) {
 		pr_err("Invalid input cmd\n");
@@ -357,6 +357,8 @@
 
 		break;
 	}
+	case CAM_SD_SHUTDOWN:
+		break;
 	default:
 		pr_err("Unknown op code %d for CPAS\n", cmd->op_code);
 		rc = -EINVAL;
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
index d26c2b6..b901410 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
@@ -12,6 +12,7 @@
 
 #include <linux/delay.h>
 #include <linux/timer.h>
+#include <linux/slab.h>
 
 #include "cam_cpas_hw_intf.h"
 #include "cam_cpas_hw.h"
@@ -105,15 +106,64 @@
 static int cam_cpastop_handle_errlogger(struct cam_cpas *cpas_core,
 	struct cam_hw_soc_info *soc_info)
 {
-	uint32_t reg_value;
+	uint32_t reg_value[4];
 	int i;
+	int size = camnoc_info->error_logger_size;
 	int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
 
-	for (i = 0; i < camnoc_info->error_logger_size; i++) {
-		reg_value = cam_io_r_mb(
+	for (i = 0; (i + 3) < size; i = i + 4) {
+		reg_value[0] = cam_io_r_mb(
 			soc_info->reg_map[camnoc_index].mem_base +
 			camnoc_info->error_logger[i]);
-		pr_err("ErrorLogger[%d] : 0x%x\n", i, reg_value);
+		reg_value[1] = cam_io_r_mb(
+			soc_info->reg_map[camnoc_index].mem_base +
+			camnoc_info->error_logger[i + 1]);
+		reg_value[2] = cam_io_r_mb(
+			soc_info->reg_map[camnoc_index].mem_base +
+			camnoc_info->error_logger[i + 2]);
+		reg_value[3] = cam_io_r_mb(
+			soc_info->reg_map[camnoc_index].mem_base +
+			camnoc_info->error_logger[i + 3]);
+		pr_err("offset[0x%x] values [0x%x] [0x%x] [0x%x] [0x%x]\n",
+			camnoc_info->error_logger[i], reg_value[0],
+			reg_value[1], reg_value[2], reg_value[3]);
+	}
+
+	if ((i + 2) < size) {
+		reg_value[0] = cam_io_r_mb(
+			soc_info->reg_map[camnoc_index].mem_base +
+			camnoc_info->error_logger[i]);
+		reg_value[1] = cam_io_r_mb(
+			soc_info->reg_map[camnoc_index].mem_base +
+			camnoc_info->error_logger[i + 1]);
+		reg_value[2] = cam_io_r_mb(
+			soc_info->reg_map[camnoc_index].mem_base +
+			camnoc_info->error_logger[i + 2]);
+		pr_err("offset[0x%x] values [0x%x] [0x%x] [0x%x]\n",
+			camnoc_info->error_logger[i], reg_value[0],
+			reg_value[1], reg_value[2]);
+		i = i + 3;
+	}
+
+	if ((i + 1) < size) {
+		reg_value[0] = cam_io_r_mb(
+			soc_info->reg_map[camnoc_index].mem_base +
+			camnoc_info->error_logger[i]);
+		reg_value[1] = cam_io_r_mb(
+			soc_info->reg_map[camnoc_index].mem_base +
+			camnoc_info->error_logger[i + 1]);
+		pr_err("offset[0x%x] values [0x%x] [0x%x]\n",
+			camnoc_info->error_logger[i], reg_value[0],
+			reg_value[1]);
+		i = i + 2;
+	}
+
+	if (i < size) {
+		reg_value[0] = cam_io_r_mb(
+			soc_info->reg_map[camnoc_index].mem_base +
+			camnoc_info->error_logger[i]);
+		pr_err("offset[0x%x] values [0x%x]\n",
+			camnoc_info->error_logger[i], reg_value[0]);
 	}
 
 	return 0;
@@ -128,9 +178,10 @@
 	reg_value = cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base +
 		camnoc_info->irq_err[i].err_status.offset);
 
-	pr_err("Dumping ubwc error status : 0x%x\n", reg_value);
+	pr_err("Dumping ubwc error status [%d]: offset[0x%x] value[0x%x]\n",
+		i, camnoc_info->irq_err[i].err_status.offset, reg_value);
 
-	return 0;
+	return reg_value;
 }
 
 static int cam_cpastop_handle_ahb_timeout_err(struct cam_hw_info *cpas_hw)
@@ -172,61 +223,126 @@
 	return 0;
 }
 
-irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data)
+static void cam_cpastop_notify_clients(struct cam_cpas *cpas_core,
+	enum cam_camnoc_hw_irq_type irq_type, uint32_t irq_data)
 {
-	uint32_t irq_status;
-	struct cam_hw_info *cpas_hw = (struct cam_hw_info *)data;
-	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
-	struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
-	int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
+	int i;
+	struct cam_cpas_client *cpas_client;
+
+	CPAS_CDBG("Notify CB : num_clients=%d, registered=%d, started=%d\n",
+		cpas_core->num_clients, cpas_core->registered_clients,
+		cpas_core->streamon_clients);
+
+	for (i = 0; i < cpas_core->num_clients; i++) {
+		if (CAM_CPAS_CLIENT_STARTED(cpas_core, i)) {
+			cpas_client = cpas_core->cpas_client[i];
+			if (cpas_client->data.cam_cpas_client_cb) {
+				CPAS_CDBG("Calling client CB %d : %d 0x%x\n",
+					i, irq_type, irq_data);
+				cpas_client->data.cam_cpas_client_cb(
+					cpas_client->data.client_handle,
+					cpas_client->data.userdata,
+					(enum cam_camnoc_irq_type)irq_type,
+					irq_data);
+			}
+		}
+	}
+}
+
+static void cam_cpastop_work(struct work_struct *work)
+{
+	struct cam_cpas_work_payload *payload;
+	struct cam_hw_info *cpas_hw;
+	struct cam_cpas *cpas_core;
+	struct cam_hw_soc_info *soc_info;
 	int i;
 	enum cam_camnoc_hw_irq_type irq_type;
+	uint32_t irq_data;
 
-	irq_status = cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base +
-		camnoc_info->irq_sbm->sbm_status.offset);
+	payload = container_of(work, struct cam_cpas_work_payload, work);
+	if (!payload) {
+		pr_err("NULL payload");
+		return;
+	}
 
-	pr_err("IRQ callback, irq_status=0x%x\n", irq_status);
+	cpas_hw = payload->hw;
+	cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+	soc_info = &cpas_hw->soc_info;
 
 	for (i = 0; i < camnoc_info->irq_err_size; i++) {
-		if ((irq_status & camnoc_info->irq_err[i].sbm_port) &&
+		if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) &&
 			(camnoc_info->irq_err[i].enable)) {
 			irq_type = camnoc_info->irq_err[i].irq_type;
 			pr_err("Error occurred, type=%d\n", irq_type);
+			irq_data = 0;
 
 			switch (irq_type) {
 			case CAM_CAMNOC_HW_IRQ_SLAVE_ERROR:
-				cam_cpastop_handle_errlogger(cpas_core,
-					soc_info);
+				irq_data = cam_cpastop_handle_errlogger(
+					cpas_core, soc_info);
 				break;
 			case CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR:
 			case CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR:
 			case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR:
 			case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR:
-				cam_cpastop_handle_ubwc_err(cpas_core,
-					soc_info, i);
+				irq_data = cam_cpastop_handle_ubwc_err(
+					cpas_core, soc_info, i);
 				break;
 			case CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT:
-				cam_cpastop_handle_ahb_timeout_err(cpas_hw);
+				irq_data = cam_cpastop_handle_ahb_timeout_err(
+					cpas_hw);
 				break;
 			case CAM_CAMNOC_HW_IRQ_CAMNOC_TEST:
 				CPAS_CDBG("TEST IRQ\n");
 				break;
 			default:
+				pr_err("Invalid IRQ type\n");
 				break;
 			}
 
-			irq_status &= ~camnoc_info->irq_err[i].sbm_port;
+			cam_cpastop_notify_clients(cpas_core, irq_type,
+				irq_data);
+
+			payload->irq_status &=
+				~camnoc_info->irq_err[i].sbm_port;
 		}
 	}
 
-	if (irq_status)
-		pr_err("IRQ not handled, irq_status=0x%x\n", irq_status);
+	if (payload->irq_status)
+		pr_err("IRQ not handled irq_status=0x%x\n",
+			payload->irq_status);
+
+	kfree(payload);
+}
+
+static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data)
+{
+	struct cam_hw_info *cpas_hw = (struct cam_hw_info *)data;
+	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+	struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+	int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
+	struct cam_cpas_work_payload *payload;
+
+	payload = kzalloc(sizeof(struct cam_cpas_work_payload), GFP_ATOMIC);
+	if (!payload)
+		return IRQ_HANDLED;
+
+	payload->irq_status = cam_io_r_mb(
+		soc_info->reg_map[camnoc_index].mem_base +
+		camnoc_info->irq_sbm->sbm_status.offset);
+
+	CPAS_CDBG("IRQ callback, irq_status=0x%x\n", payload->irq_status);
+
+	payload->hw = cpas_hw;
+	INIT_WORK((struct work_struct *)&payload->work, cam_cpastop_work);
 
 	if (TEST_IRQ_ENABLE)
 		cam_cpastop_disable_test_irq(cpas_hw);
 
 	cam_cpastop_reset_irq(cpas_hw);
 
+	queue_work(cpas_core->work_queue, &payload->work);
+
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
index c61204a..d5bb363 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
@@ -195,4 +195,20 @@
 	struct cam_cpas_hw_errata_wa_list *errata_wa_list;
 };
 
+/**
+ * struct cam_cpas_work_payload : Struct for cpas work payload data
+ *
+ * @hw: Pointer to HW info
+ * @irq_status: IRQ status value
+ * @irq_data: IRQ data
+ * @work: Work handle
+ *
+ */
+struct cam_cpas_work_payload {
+	struct cam_hw_info *hw;
+	uint32_t irq_status;
+	uint32_t irq_data;
+	struct work_struct work;
+};
+
 #endif /* _CAM_CPASTOP_HW_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 5a4e6e9..a9064fa 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -123,9 +123,6 @@
 	if (req_isp->num_fence_map_out != 0) {
 		CDBG("%s: move request %lld to active list\n", __func__,
 			req->request_id);
-		if (!list_empty(&ctx->active_req_list))
-			pr_err("%s: More than one entry in active list\n",
-				__func__);
 		list_add_tail(&req->list, &ctx->active_req_list);
 	} else {
 		/* no io config, so the request is completed. */
@@ -281,9 +278,14 @@
 	void *evt_data)
 {
 	int rc = 0;
+	struct cam_context        *ctx = ctx_isp->base;
+
 
 	ctx_isp->frame_id++;
-	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
+	if (list_empty(&ctx->active_req_list))
+		ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
+	else
+		CDBG("%s: Still need to wait for the buf done\n", __func__);
 	CDBG("%s: next substate %d\n", __func__,
 		ctx_isp->substate_activated);
 
@@ -568,10 +570,10 @@
 	if (rc) {
 		pr_err("%s: Can not apply the configuration\n", __func__);
 	} else {
-		spin_lock(&ctx->lock);
+		spin_lock_bh(&ctx->lock);
 		ctx_isp->substate_activated = next_state;
 		CDBG("%s: new state %d\n", __func__, next_state);
-		spin_unlock(&ctx->lock);
+		spin_unlock_bh(&ctx->lock);
 	}
 end:
 	return rc;
@@ -743,13 +745,13 @@
 	CDBG("%s: get free request object......\n", __func__);
 
 	/* get free request */
-	spin_lock(&ctx->lock);
+	spin_lock_bh(&ctx->lock);
 	if (!list_empty(&ctx->free_req_list)) {
 		req = list_first_entry(&ctx->free_req_list,
 				struct cam_ctx_request, list);
 		list_del_init(&req->list);
 	}
-	spin_unlock(&ctx->lock);
+	spin_unlock_bh(&ctx->lock);
 
 	if (!req) {
 		pr_err("%s: No more request obj free\n", __func__);
@@ -827,9 +829,9 @@
 	CDBG("%s: Packet request id 0x%llx\n", __func__,
 		packet->header.request_id);
 
-	spin_lock(&ctx->lock);
+	spin_lock_bh(&ctx->lock);
 	list_add_tail(&req->list, &ctx->pending_req_list);
-	spin_unlock(&ctx->lock);
+	spin_unlock_bh(&ctx->lock);
 
 	CDBG("%s: Preprocessing Config %lld successful\n", __func__,
 		req->request_id);
@@ -837,9 +839,9 @@
 	return rc;
 
 free_req:
-	spin_lock(&ctx->lock);
+	spin_lock_bh(&ctx->lock);
 	list_add_tail(&req->list, &ctx->free_req_list);
-	spin_unlock(&ctx->lock);
+	spin_unlock_bh(&ctx->lock);
 end:
 	return rc;
 }
@@ -1084,9 +1086,9 @@
 		(struct cam_isp_context *) ctx->ctx_priv;
 
 	/* Mask off all the incoming hardware events */
-	spin_lock(&ctx->lock);
+	spin_lock_bh(&ctx->lock);
 	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT;
-	spin_unlock(&ctx->lock);
+	spin_unlock_bh(&ctx->lock);
 	CDBG("%s: next substate %d", __func__, ctx_isp->substate_activated);
 
 	/* stop hw first */
@@ -1206,7 +1208,7 @@
 	struct cam_isp_context *ctx_isp =
 		(struct cam_isp_context *)ctx->ctx_priv;
 
-	spin_lock(&ctx->lock);
+	spin_lock_bh(&ctx->lock);
 	CDBG("%s: Enter: State %d, Substate %d, evt id %d\n",
 		__func__, ctx->state, ctx_isp->substate_activated, evt_id);
 	if (ctx_isp->substate_machine_irq[ctx_isp->substate_activated].
@@ -1219,7 +1221,7 @@
 	}
 	CDBG("%s: Exit: State %d Substate %d\n",
 		__func__, ctx->state, ctx_isp->substate_activated);
-	spin_unlock(&ctx->lock);
+	spin_unlock_bh(&ctx->lock);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c
index 4cebb58..4c819cf 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c
@@ -72,6 +72,7 @@
 	}
 	node = (struct cam_node *) g_isp_dev.sd.token;
 
+	memset(&hw_mgr_intf, 0, sizeof(hw_mgr_intf));
 	rc = cam_isp_hw_mgr_init(pdev->dev.of_node, &hw_mgr_intf);
 	if (rc != 0) {
 		pr_err("%s: Can not initialized ISP HW manager!\n", __func__);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index 739a1e7..f6aab7f 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -449,14 +449,14 @@
 		if (isp_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
 			isp_res->irq_handle = cam_irq_controller_subscribe_irq(
 				core_info->vfe_irq_controller,
-				CAM_IRQ_PRIORITY_2,
+				CAM_IRQ_PRIORITY_1,
 				camif_irq_reg_mask, &core_info->irq_payload,
 				cam_vfe_irq_top_half, cam_ife_mgr_do_tasklet,
 				isp_res->tasklet_info, cam_tasklet_enqueue_cmd);
 		else
 			isp_res->irq_handle = cam_irq_controller_subscribe_irq(
 				core_info->vfe_irq_controller,
-				CAM_IRQ_PRIORITY_2,
+				CAM_IRQ_PRIORITY_1,
 				rdi_irq_reg_mask, &core_info->irq_payload,
 				cam_vfe_irq_top_half, cam_ife_mgr_do_tasklet,
 				isp_res->tasklet_info, cam_tasklet_enqueue_cmd);
@@ -469,7 +469,7 @@
 			pr_err("Error! subscribe irq controller failed\n");
 	} else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) {
 		isp_res->irq_handle = cam_irq_controller_subscribe_irq(
-			core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_1,
+			core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_2,
 			bus_irq_reg_mask, &core_info->irq_payload,
 			core_info->vfe_bus->top_half_handler,
 			cam_ife_mgr_do_tasklet_buf_done,
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index 5e629b6..92a17d8 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -1581,6 +1581,7 @@
 	struct cam_vfe_bus_ver2_priv          *bus_priv;
 	struct cam_irq_controller_reg_info    *reg_info;
 	uint32_t                               irq_mask;
+	int                                    found = 0;
 
 	handler_priv = th_payload->handler_priv;
 	core_info    = handler_priv->core_info;
@@ -1613,6 +1614,8 @@
 			irq_reg_offset[i] - (0xC * 2));
 		evt_payload->irq_reg_val[i] = irq_mask &
 			cam_io_r(handler_priv->mem_base + irq_reg_offset[i]);
+		if (evt_payload->irq_reg_val[i])
+			found = 1;
 		CDBG("irq_status%d = 0x%x\n", i, evt_payload->irq_reg_val[i]);
 	}
 	for (i = 0; i <= CAM_IFE_IRQ_BUS_REG_STATUS2; i++) {
@@ -1628,7 +1631,13 @@
 			reg_info->global_clear_bitmask,
 			reg_info->global_clear_offset);
 
-	th_payload->evt_payload_priv = evt_payload;
+	if (found)
+		th_payload->evt_payload_priv = evt_payload;
+	else {
+		cam_vfe_bus_put_evt_payload(evt_payload->core_info,
+			&evt_payload);
+		rc = -ENOMSG;
+	}
 
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
index 9c030ab..f47b1dc 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
@@ -751,23 +751,17 @@
 	memset(tbl.bufq[idx].hdls, 0,
 		sizeof(int32_t) * CAM_MEM_MMU_MAX_HANDLE);
 
-	CDBG("Ion handle at idx = %d freeing = %pK, fd = %d\n",
-		idx, tbl.bufq[idx].i_hdl, tbl.bufq[idx].fd);
+	CDBG("Ion handle at idx = %d freeing = %pK, fd = %d, imported %d\n",
+		idx, tbl.bufq[idx].i_hdl, tbl.bufq[idx].fd,
+		tbl.bufq[idx].is_imported);
 
-	if (tbl.bufq[idx].i_hdl && !tbl.bufq[idx].is_imported) {
-		CDBG("Freeing up non-imported buffer at fd = %d, hdl = %pK",
-			tbl.bufq[idx].fd,
-			tbl.bufq[idx].i_hdl);
+	if (tbl.bufq[idx].i_hdl) {
 		ion_free(tbl.client, tbl.bufq[idx].i_hdl);
 		tbl.bufq[idx].i_hdl = NULL;
-	} else {
-		CDBG("Not freeing up imported buffer at fd = %d",
-			tbl.bufq[idx].fd);
 	}
 
 	tbl.bufq[idx].fd = -1;
 	tbl.bufq[idx].is_imported = false;
-	tbl.bufq[idx].i_hdl = NULL;
 	tbl.bufq[idx].len = 0;
 	tbl.bufq[idx].num_hdl = 0;
 	mutex_unlock(&tbl.bufq[idx].q_lock);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index 1a8356a..c495088 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -20,6 +20,7 @@
 #include <media/v4l2-event.h>
 #include <media/v4l2-ioctl.h>
 #include <media/cam_req_mgr.h>
+#include <media/cam_defs.h>
 #include "cam_req_mgr_dev.h"
 #include "cam_req_mgr_util.h"
 #include "cam_req_mgr_core.h"
@@ -151,6 +152,9 @@
 
 static int cam_req_mgr_close(struct file *filep)
 {
+	struct v4l2_subdev *sd;
+	struct cam_control cam_ctrl;
+
 	mutex_lock(&g_dev.cam_lock);
 
 	if (g_dev.open_cnt <= 0) {
@@ -158,6 +162,14 @@
 		return -EINVAL;
 	}
 
+	cam_ctrl.op_code = CAM_SD_SHUTDOWN;
+	list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) {
+		if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+			continue;
+		v4l2_subdev_call(sd, core, ioctl, VIDIOC_CAM_CONTROL,
+			&cam_ctrl);
+	}
+
 	g_dev.open_cnt--;
 	v4l2_fh_release(filep);
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
index 648617e..91b68cf 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
@@ -616,6 +616,8 @@
 		}
 	}
 		break;
+	case CAM_SD_SHUTDOWN:
+		break;
 	default:
 		pr_err("%s:%d Invalid Opcode %d\n",
 			__func__, __LINE__, cmd->op_code);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
index 789522d..6764b8a 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
@@ -34,6 +34,8 @@
 	case VIDIOC_MSM_CCI_CFG:
 		rc = cam_cci_core_cfg(sd, arg);
 		break;
+	case VIDIOC_CAM_CONTROL:
+		break;
 	default:
 		pr_err("%s:%d Invalid ioctl cmd: %d\n",
 			__func__, __LINE__, cmd);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
index 8dc65f5..6751fdd 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
@@ -486,6 +486,8 @@
 		}
 	}
 		break;
+	case CAM_SD_SHUTDOWN:
+		break;
 	default:
 		pr_err("%s:%d :Error: Invalid Opcode: %d\n",
 			__func__, __LINE__, cmd->op_code);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 4888e5b..4fc3aa1 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -773,6 +773,8 @@
 		}
 	}
 		break;
+	case CAM_SD_SHUTDOWN:
+		break;
 	default:
 		pr_err("%s:%d :Error: Invalid Opcode: %d\n",
 			__func__, __LINE__, cmd->op_code);
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h
index d1bbe01..ff6b72a 100644
--- a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_reg.h
@@ -92,17 +92,14 @@
 
 /**
  * @INVALID: Invalid state
- * @FW_LOAD_DONE: Firmware load is completed
- * @FW_RESP_DONE: Firmware response is received
- * @FW_START_SENT: firmware start is send
- * @FW_READY: firmware is ready to accept commands
+ * @HFI_DEINIT: HFI is not initialized yet
+ * @HFI_INIT: HFI is initialized
+ * @HFI_READY: HFI is ready to send/receive commands/messages
  */
 enum hfi_state {
-	INVALID,
-	FW_LOAD_DONE,
-	FW_RESP_DONE,
-	FW_START_SENT,
-	FW_READY
+	HFI_DEINIT,
+	HFI_INIT,
+	HFI_READY
 };
 
 /**
@@ -292,6 +289,9 @@
  * @msgpacket_buf: message buffer
  * @hfi_state: State machine for hfi
  * @cmd_q_lock: Lock for command queue
+ * @cmd_q_state: State of command queue
+ * @mutex msg_q_lock: Lock for message queue
+ * @msg_q_state: State of message queue
  * @csr_base: CSR base address
  */
 struct hfi_info {
@@ -301,7 +301,9 @@
 	uint32_t msgpacket_buf[ICP_HFI_MAX_MSG_SIZE_IN_WORDS];
 	uint8_t hfi_state;
 	struct mutex cmd_q_lock;
+	bool cmd_q_state;
 	struct mutex msg_q_lock;
+	bool msg_q_state;
 	void __iomem *csr_base;
 };
 
diff --git a/drivers/media/platform/msm/camera/icp/hfi.c b/drivers/media/platform/msm/camera/icp/hfi.c
index 15e0315..170c8cf 100644
--- a/drivers/media/platform/msm/camera/icp/hfi.c
+++ b/drivers/media/platform/msm/camera/icp/hfi.c
@@ -42,7 +42,7 @@
 #undef  HFI_DBG
 #define HFI_DBG(fmt, args...) pr_debug(fmt, ##args)
 
-struct hfi_info *g_hfi;
+static struct hfi_info *g_hfi;
 unsigned int g_icp_mmu_hdl;
 
 int hfi_write_cmd(void *cmd_ptr)
@@ -59,12 +59,17 @@
 		return -EINVAL;
 	}
 
-	if (!g_hfi || g_hfi->hfi_state < FW_START_SENT) {
-		pr_err("FW not ready yet\n");
+	if (!g_hfi || (g_hfi->hfi_state != HFI_READY)) {
+		pr_err("HFI interface not ready yet\n");
 		return -EIO;
 	}
 
 	mutex_lock(&g_hfi->cmd_q_lock);
+	if (!g_hfi->cmd_q_state) {
+		pr_err("HFI command interface not ready yet\n");
+		mutex_unlock(&g_hfi->cmd_q_lock);
+		return -EIO;
+	}
 
 	q_tbl = (struct hfi_qtbl *)g_hfi->map.qtbl.kva;
 	q = &q_tbl->q_hdr[Q_CMD];
@@ -78,11 +83,10 @@
 		goto err;
 	}
 
-	HFI_DBG("size_in_words : %u\n", size_in_words);
-	HFI_DBG("q->qhdr_write_idx %x\n", q->qhdr_write_idx);
+	HFI_DBG("size_in_words : %u, q->qhdr_write_idx %x\n", size_in_words,
+		q->qhdr_write_idx);
 
 	read_idx = q->qhdr_read_idx;
-
 	empty_space = (q->qhdr_write_idx >= read_idx) ?
 		(q->qhdr_q_size - (q->qhdr_write_idx - read_idx)) :
 		(read_idx - q->qhdr_write_idx);
@@ -115,7 +119,7 @@
 		g_hfi->csr_base + HFI_REG_A5_CSR_HOST2ICPINT);
 err:
 	mutex_unlock(&g_hfi->cmd_q_lock);
-	return 0;
+	return rc;
 }
 
 int hfi_read_message(uint32_t *pmsg, uint8_t q_id)
@@ -132,21 +136,28 @@
 		return -EINVAL;
 	}
 
+	if (!g_hfi || (g_hfi->hfi_state != HFI_READY)) {
+		pr_err("HFI interface not ready yet\n");
+		return -EIO;
+	}
+
 	q_tbl_ptr = (struct hfi_qtbl *)g_hfi->map.qtbl.kva;
 	q = &q_tbl_ptr->q_hdr[q_id];
 
-	if ((g_hfi->hfi_state < FW_START_SENT) ||
-		(q->qhdr_read_idx == q->qhdr_write_idx)) {
+	if (q->qhdr_read_idx == q->qhdr_write_idx) {
 		pr_debug("FW or Q not ready, hfi state : %u, r idx : %u, w idx : %u\n",
 			g_hfi->hfi_state, q->qhdr_read_idx, q->qhdr_write_idx);
 		return -EIO;
 	}
 
 	mutex_lock(&g_hfi->msg_q_lock);
+	if (!g_hfi->msg_q_state) {
+		pr_err("HFI message interface not ready yet\n");
+		mutex_unlock(&g_hfi->msg_q_lock);
+		return -EIO;
+	}
 
-	if (q_id == Q_CMD)
-		read_q = (uint32_t *)g_hfi->map.cmd_q.kva;
-	else if (q_id == Q_MSG)
+	if (q_id == Q_MSG)
 		read_q = (uint32_t *)g_hfi->map.msg_q.kva;
 	else
 		read_q = (uint32_t *)g_hfi->map.dbg_q.kva;
@@ -154,8 +165,8 @@
 	read_ptr = (uint32_t *)(read_q + q->qhdr_read_idx);
 	size_in_words = (*read_ptr) >> BYTE_WORD_SHIFT;
 
-	HFI_DBG("size_in_words : %u\n", size_in_words);
-	HFI_DBG("read_ptr : %pK\n", (void *)read_ptr);
+	HFI_DBG("size_in_words : %u, read_ptr : %pK\n", size_in_words,
+		(void *)read_ptr);
 
 	if ((size_in_words == 0) ||
 		(size_in_words > ICP_HFI_MAX_MSG_SIZE_IN_WORDS)) {
@@ -180,13 +191,12 @@
 	}
 
 	for (i = 0; i < size_in_words; i++)
-		pr_debug("%x\n", read_ptr[i]);
+		HFI_DBG("%x\n", read_ptr[i]);
 
 	q->qhdr_read_idx = new_read_idx;
 err:
 	mutex_unlock(&g_hfi->msg_q_lock);
-	HFI_DBG("Exit\n");
-	return 0;
+	return rc;
 }
 
 void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size)
@@ -307,8 +317,7 @@
 	struct hfi_qtbl *qtbl;
 	struct hfi_qtbl_hdr *qtbl_hdr;
 	struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr;
-	uint32_t hw_version, fw_version;
-	uint32_t status;
+	uint32_t hw_version, fw_version, status = 0;
 
 	if (!g_hfi) {
 		g_hfi = kzalloc(sizeof(struct hfi_info), GFP_KERNEL);
@@ -318,13 +327,12 @@
 		}
 	}
 
-	pr_debug("g_hfi: %pK\n", (void *)g_hfi);
-	if (g_hfi->hfi_state != INVALID) {
+	HFI_DBG("g_hfi: %pK\n", (void *)g_hfi);
+	if (g_hfi->hfi_state != HFI_DEINIT) {
 		pr_err("hfi_init: invalid state\n");
 		return -EINVAL;
 	}
 
-	g_hfi->hfi_state = FW_LOAD_DONE;
 	memcpy(&g_hfi->map, hfi_mem, sizeof(g_hfi->map));
 
 	if (debug) {
@@ -342,11 +350,6 @@
 			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 	}
 
-	mutex_init(&g_hfi->cmd_q_lock);
-	mutex_init(&g_hfi->msg_q_lock);
-
-	g_hfi->csr_base = icp_base;
-
 	qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva;
 	qtbl_hdr = &qtbl->q_tbl_hdr;
 	qtbl_hdr->qtbl_version = 0xFFFFFFFF;
@@ -474,7 +477,7 @@
 		icp_base + HFI_REG_HOST_ICP_INIT_REQUEST);
 
 	hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);
-	pr_debug("hw version : %u[%x]\n", hw_version, hw_version);
+	HFI_DBG("hw version : [%x]\n", hw_version);
 
 	rc = readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
 		status, status != ICP_INIT_RESP_SUCCESS, 15, 200);
@@ -484,14 +487,19 @@
 	}
 
 	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
-	g_hfi->hfi_state = FW_START_SENT;
-
 	HFI_DBG("fw version : %u[%x]\n", fw_version, fw_version);
+
+	g_hfi->csr_base = icp_base;
+	g_hfi->hfi_state = HFI_READY;
+	g_hfi->cmd_q_state = true;
+	g_hfi->msg_q_state = true;
+	mutex_init(&g_hfi->cmd_q_lock);
+	mutex_init(&g_hfi->msg_q_lock);
 	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
 
 	return rc;
 regions_fail:
-	kzfree(g_hfi);
+	kfree(g_hfi);
 alloc_fail:
 	return rc;
 }
@@ -499,6 +507,24 @@
 
 void cam_hfi_deinit(void)
 {
+	if (!g_hfi) {
+		pr_err("hfi path not established yet\n");
+		return;
+	}
+	cam_io_w((uint32_t)INTR_DISABLE,
+		g_hfi->csr_base + HFI_REG_A5_CSR_A2HOSTINTEN);
+
+	mutex_lock(&g_hfi->cmd_q_lock);
+	g_hfi->cmd_q_state = false;
+	mutex_unlock(&g_hfi->cmd_q_lock);
+
+	mutex_lock(&g_hfi->msg_q_lock);
+	g_hfi->msg_q_state = false;
+	mutex_unlock(&g_hfi->msg_q_lock);
+
+	mutex_destroy(&g_hfi->cmd_q_lock);
+	mutex_destroy(&g_hfi->msg_q_lock);
+
 	kfree(g_hfi);
 	g_hfi = NULL;
 }
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c
index f562bb9..39eacd8 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.c
@@ -278,19 +278,22 @@
 
 	rc = cam_cpas_start(core_info->cpas_handle,
 		&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
-	if (rc < 0) {
+	if (rc) {
 		pr_err("cpass start failed: %d\n", rc);
 		return rc;
 	}
+	core_info->cpas_start = true;
 
 	rc = cam_a5_enable_soc_resources(soc_info);
-	if (rc < 0) {
-		pr_err("soc enable is failed\n");
-		rc = cam_cpas_stop(core_info->cpas_handle);
-		return rc;
+	if (rc) {
+		pr_err("soc enable is failed: %d\n", rc);
+		if (cam_cpas_stop(core_info->cpas_handle))
+			pr_err("cpas stop is failed\n");
+		else
+			core_info->cpas_start = false;
 	}
 
-	return 0;
+	return rc;
 }
 
 int cam_a5_deinit_hw(void *device_priv,
@@ -314,14 +317,17 @@
 	}
 
 	rc = cam_a5_disable_soc_resources(soc_info);
-	if (rc < 0)
-		pr_err("soc enable is failed\n");
+	if (rc)
+		pr_err("soc disable is failed: %d\n", rc);
 
-	rc = cam_cpas_stop(core_info->cpas_handle);
-	if (rc < 0)
-		pr_err("cpas stop is failed: %d\n", rc);
+	if (core_info->cpas_start) {
+		if (cam_cpas_stop(core_info->cpas_handle))
+			pr_err("cpas stop is failed\n");
+		else
+			core_info->cpas_start = false;
+	}
 
-	return 0;
+	return rc;
 }
 
 irqreturn_t cam_a5_irq(int irq_num, void *data)
@@ -443,13 +449,20 @@
 			return -EINVAL;
 		}
 
-		rc = cam_cpas_start(core_info->cpas_handle,
-				&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+		if (!core_info->cpas_start) {
+			rc = cam_cpas_start(core_info->cpas_handle,
+					&cpas_vote->ahb_vote,
+					&cpas_vote->axi_vote);
+			core_info->cpas_start = true;
+		}
 		break;
 	}
 
 	case CAM_ICP_A5_CMD_CPAS_STOP:
-		cam_cpas_stop(core_info->cpas_handle);
+		if (core_info->cpas_start) {
+			cam_cpas_stop(core_info->cpas_handle);
+			core_info->cpas_start = false;
+		}
 		break;
 	default:
 		break;
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h
index 8b84270..4aa6b4b 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_core.h
@@ -62,6 +62,7 @@
  * @a5_acquire: Acquire information of A5
  * @irq_cb: IRQ callback
  * @cpas_handle: CPAS handle for A5
+ * @cpast_start: state variable for cpas
  */
 struct cam_a5_device_core_info {
 	struct cam_a5_device_hw_info *a5_hw_info;
@@ -74,6 +75,7 @@
 	struct cam_icp_a5_acquire_dev a5_acquire[8];
 	struct cam_icp_a5_set_irq_cb irq_cb;
 	uint32_t cpas_handle;
+	bool cpas_start;
 };
 
 int cam_a5_init_hw(void *device_priv,
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c
index 641c154..d12b3b6 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/a5_hw/a5_soc.c
@@ -95,7 +95,7 @@
 
 	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
 	if (rc)
-		pr_err("%s: enable platform failed\n", __func__);
+		pr_err("%s: disable platform failed\n", __func__);
 
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c
index 50863a5..91652d7 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.c
@@ -80,15 +80,19 @@
 
 	rc = cam_cpas_start(core_info->cpas_handle,
 			&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
-	if (rc < 0) {
+	if (rc) {
 		pr_err("cpass start failed: %d\n", rc);
 		return rc;
 	}
+	core_info->cpas_start = true;
 
 	rc = cam_bps_enable_soc_resources(soc_info);
-	if (rc < 0) {
-		pr_err("soc enable is failed\n");
-		rc = cam_cpas_stop(core_info->cpas_handle);
+	if (rc) {
+		pr_err("soc enable is failed: %d\n", rc);
+		if (cam_cpas_stop(core_info->cpas_handle))
+			pr_err("cpas stop is failed\n");
+		else
+			core_info->cpas_start = false;
 	}
 
 	return rc;
@@ -115,12 +119,15 @@
 	}
 
 	rc = cam_bps_disable_soc_resources(soc_info);
-	if (rc < 0)
-		pr_err("soc enable is failed\n");
+	if (rc)
+		pr_err("soc disable is failed: %d\n", rc);
 
-	rc = cam_cpas_stop(core_info->cpas_handle);
-	if (rc < 0)
-		pr_err("cpas stop is failed: %d\n", rc);
+	if (core_info->cpas_start) {
+		if (cam_cpas_stop(core_info->cpas_handle))
+			pr_err("cpas stop is failed\n");
+		else
+			core_info->cpas_start = false;
+	}
 
 	return rc;
 }
@@ -169,13 +176,20 @@
 			return -EINVAL;
 		}
 
-		rc = cam_cpas_start(core_info->cpas_handle,
-				&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+		if (!core_info->cpas_start) {
+			rc = cam_cpas_start(core_info->cpas_handle,
+					&cpas_vote->ahb_vote,
+					&cpas_vote->axi_vote);
+			core_info->cpas_start = true;
+		}
 		break;
 	}
 
 	case CAM_ICP_BPS_CMD_CPAS_STOP:
-		cam_cpas_stop(core_info->cpas_handle);
+		if (core_info->cpas_start) {
+			cam_cpas_stop(core_info->cpas_handle);
+			core_info->cpas_start = false;
+		}
 		break;
 	default:
 		break;
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h
index 67e1c03..8a15a7b 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/bps_hw/bps_core.h
@@ -26,6 +26,7 @@
 struct cam_bps_device_core_info {
 	struct cam_bps_device_hw_info *bps_hw_info;
 	uint32_t cpas_handle;
+	bool cpas_start;
 };
 
 int cam_bps_init_hw(void *device_priv,
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 43491a9..677c24e 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -74,166 +74,6 @@
 	return 0;
 }
 
-static int cam_icp_stop_cpas(struct cam_icp_hw_mgr *hw_mgr_priv)
-{
-	struct cam_hw_intf *a5_dev_intf = NULL;
-	struct cam_hw_intf *ipe0_dev_intf = NULL;
-	struct cam_hw_intf *ipe1_dev_intf = NULL;
-	struct cam_hw_intf *bps_dev_intf = NULL;
-	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
-	struct cam_icp_cpas_vote cpas_vote;
-	int rc = 0;
-
-	if (!hw_mgr) {
-		pr_err("Invalid params\n");
-		return -EINVAL;
-	}
-
-	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
-	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
-	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
-
-	if ((!a5_dev_intf) || (!bps_dev_intf) || (!ipe0_dev_intf)) {
-		pr_err("dev intfs are NULL\n");
-		return -EINVAL;
-	}
-
-	rc = a5_dev_intf->hw_ops.process_cmd(
-		a5_dev_intf->hw_priv,
-		CAM_ICP_A5_CMD_CPAS_STOP,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-	if (rc < 0)
-		pr_err("CAM_ICP_A5_CMD_CPAS_STOP is failed: %d\n", rc);
-
-	rc = bps_dev_intf->hw_ops.process_cmd(
-		bps_dev_intf->hw_priv,
-		CAM_ICP_BPS_CMD_CPAS_STOP,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-	if (rc < 0)
-		pr_err("CAM_ICP_BPS_CMD_CPAS_STOP is failed: %d\n", rc);
-
-	rc = ipe0_dev_intf->hw_ops.process_cmd(
-		ipe0_dev_intf->hw_priv,
-		CAM_ICP_IPE_CMD_CPAS_STOP,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-	if (rc < 0)
-		pr_err("CAM_ICP_IPE_CMD_CPAS_STOP is failed: %d\n", rc);
-
-	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
-	if (!ipe1_dev_intf)
-		return rc;
-
-	rc = ipe1_dev_intf->hw_ops.process_cmd(
-		ipe1_dev_intf->hw_priv,
-		CAM_ICP_IPE_CMD_CPAS_STOP,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-	if (rc < 0)
-		pr_err("CAM_ICP_IPE_CMD_CPAS_STOP is failed: %d\n", rc);
-
-	return rc;
-}
-
-static int cam_icp_start_cpas(struct cam_icp_hw_mgr *hw_mgr_priv)
-{
-	struct cam_hw_intf *a5_dev_intf = NULL;
-	struct cam_hw_intf *ipe0_dev_intf = NULL;
-	struct cam_hw_intf *ipe1_dev_intf = NULL;
-	struct cam_hw_intf *bps_dev_intf = NULL;
-	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
-	struct cam_icp_cpas_vote cpas_vote;
-	int rc = 0;
-
-	if (!hw_mgr) {
-		pr_err("Invalid params\n");
-		return -EINVAL;
-	}
-
-	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
-	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
-	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
-
-	if ((!a5_dev_intf) || (!bps_dev_intf) || (!ipe0_dev_intf)) {
-		pr_err("dev intfs are null\n");
-		return -EINVAL;
-	}
-
-	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
-	cpas_vote.ahb_vote.vote.level = CAM_TURBO_VOTE;
-	cpas_vote.axi_vote.compressed_bw = 640000000;
-	cpas_vote.axi_vote.uncompressed_bw = 640000000;
-
-	rc = a5_dev_intf->hw_ops.process_cmd(
-		a5_dev_intf->hw_priv,
-		CAM_ICP_A5_CMD_CPAS_START,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-	if (rc) {
-		pr_err("CAM_ICP_A5_CMD_CPAS_START is failed: %d\n", rc);
-		goto a5_cpas_start_failed;
-	}
-
-	rc = bps_dev_intf->hw_ops.process_cmd(
-		bps_dev_intf->hw_priv,
-		CAM_ICP_BPS_CMD_CPAS_START,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-	if (rc < 0) {
-		pr_err("CAM_ICP_BPS_CMD_CPAS_START is failed: %d\n", rc);
-		goto bps_cpas_start_failed;
-	}
-
-	rc = ipe0_dev_intf->hw_ops.process_cmd(
-		ipe0_dev_intf->hw_priv,
-		CAM_ICP_IPE_CMD_CPAS_START,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-	if (rc < 0) {
-		pr_err("CAM_ICP_IPE_CMD_CPAS_START is failed: %d\n", rc);
-		goto ipe0_cpas_start_failed;
-	}
-
-	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
-	if (!ipe1_dev_intf)
-		return rc;
-
-	rc = ipe1_dev_intf->hw_ops.process_cmd(
-		ipe1_dev_intf->hw_priv,
-		CAM_ICP_IPE_CMD_CPAS_START,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-	if (rc < 0) {
-		pr_err("CAM_ICP_IPE_CMD_CPAS_START is failed: %d\n", rc);
-		goto ipe1_cpas_start_failed;
-	}
-
-	return rc;
-
-ipe1_cpas_start_failed:
-	rc = ipe0_dev_intf->hw_ops.process_cmd(
-		ipe0_dev_intf->hw_priv,
-		CAM_ICP_IPE_CMD_CPAS_STOP,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-ipe0_cpas_start_failed:
-	rc = bps_dev_intf->hw_ops.process_cmd(
-		bps_dev_intf->hw_priv,
-		CAM_ICP_BPS_CMD_CPAS_STOP,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-bps_cpas_start_failed:
-	rc = a5_dev_intf->hw_ops.process_cmd(
-		a5_dev_intf->hw_priv,
-		CAM_ICP_A5_CMD_CPAS_STOP,
-		&cpas_vote,
-		sizeof(struct cam_icp_cpas_vote));
-a5_cpas_start_failed:
-	return rc;
-}
-
 static int cam_icp_mgr_process_cmd(void *priv, void *data)
 {
 	int rc;
@@ -566,7 +406,7 @@
 	return rc;
 }
 
-static int cam_icp_free_hfi_mem(void)
+static void cam_icp_free_hfi_mem(void)
 {
 	cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl);
 	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl);
@@ -574,8 +414,6 @@
 	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q);
 	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q);
 	cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sec_heap);
-
-	return 0;
 }
 
 static int cam_icp_allocate_hfi_mem(void)
@@ -806,18 +644,17 @@
 
 	mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 	if (!hw_mgr->ctx_data[ctx_id].in_use) {
-		pr_err("ctx is already in use: %d\n", ctx_id);
+		ICP_DBG("ctx is not in use: %d\n", ctx_id);
 		mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
-		return -EINVAL;
+		return 0;
 	}
 	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 
-	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	if (task)
 		cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id], task);
 
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 	hw_mgr->ctx_data[ctx_id].in_use = 0;
 	hw_mgr->ctx_data[ctx_id].fw_handle = 0;
@@ -829,6 +666,7 @@
 	mutex_destroy(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
 	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 	kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	return 0;
 }
@@ -861,40 +699,64 @@
 	struct cam_hw_intf *ipe0_dev_intf = NULL;
 	struct cam_hw_intf *ipe1_dev_intf = NULL;
 	struct cam_hw_intf *bps_dev_intf = NULL;
-	int rc = 0;
+	struct cam_icp_a5_set_irq_cb irq_cb;
+	struct cam_icp_a5_set_fw_buf_info fw_buf_info;
+	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	int i;
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	if (hw_mgr->fw_download ==  false) {
+		ICP_DBG("hw mgr is already closed\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return 0;
+	}
 
 	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
 	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
 	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
 
 	if ((!a5_dev_intf) || (!ipe0_dev_intf) || (!bps_dev_intf)) {
-		pr_err("dev intfs are wrong\n");
-		return rc;
+		pr_err("dev intfs are wrong, failed to close\n");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
 	}
+
+	irq_cb.icp_hw_mgr_cb = NULL;
+	irq_cb.data = NULL;
+	a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_SET_IRQ_CB,
+		&irq_cb, sizeof(irq_cb));
+
+	fw_buf_info.kva = 0;
+	fw_buf_info.iova = 0;
+	fw_buf_info.len = 0;
+	a5_dev_intf->hw_ops.process_cmd(
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_SET_FW_BUF,
+		&fw_buf_info,
+		sizeof(fw_buf_info));
+
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
+		ctx_data = &hw_mgr->ctx_data[i];
+		cam_icp_mgr_release_ctx(hw_mgr, i);
+	}
+
 	mutex_lock(&hw_mgr->hw_mgr_mutex);
-	rc = a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
-	if (rc < 0)
-		pr_err("a5 dev de-init failed\n");
-
-	rc = bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
-	if (rc < 0)
-		pr_err("bps dev de-init failed\n");
-
-	rc = ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
-	if (rc < 0)
-		pr_err("ipe0 dev de-init failed\n");
-
 	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
-	if (ipe1_dev_intf) {
-		rc = ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
-						NULL, 0);
-		if (rc < 0)
-			pr_err("ipe1 dev de-init failed\n");
-	}
+	if (ipe1_dev_intf)
+		ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
+			NULL, 0);
 
+	ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+	bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+	a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
+	cam_hfi_deinit();
 	cam_icp_free_hfi_mem();
 	hw_mgr->fw_download = false;
-	debugfs_remove_recursive(icp_hw_mgr.dentry);
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	return 0;
@@ -975,9 +837,9 @@
 	irq_cb.icp_hw_mgr_cb = cam_icp_hw_mgr_cb;
 	irq_cb.data = hw_mgr_priv;
 	rc = a5_dev_intf->hw_ops.process_cmd(
-				a5_dev_intf->hw_priv,
-				CAM_ICP_A5_SET_IRQ_CB,
-				&irq_cb, sizeof(irq_cb));
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_SET_IRQ_CB,
+		&irq_cb, sizeof(irq_cb));
 	if (rc < 0) {
 		pr_err("CAM_ICP_A5_SET_IRQ_CB failed\n");
 		rc = -EINVAL;
@@ -989,10 +851,10 @@
 	fw_buf_info.len = icp_hw_mgr.hfi_mem.fw_buf.len;
 
 	rc = a5_dev_intf->hw_ops.process_cmd(
-			a5_dev_intf->hw_priv,
-			CAM_ICP_A5_CMD_SET_FW_BUF,
-			&fw_buf_info,
-			sizeof(fw_buf_info));
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_SET_FW_BUF,
+		&fw_buf_info,
+		sizeof(fw_buf_info));
 	if (rc < 0) {
 		pr_err("CAM_ICP_A5_CMD_SET_FW_BUF failed\n");
 		goto set_irq_failed;
@@ -1001,9 +863,9 @@
 	cam_hfi_enable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 
 	rc = a5_dev_intf->hw_ops.process_cmd(
-			a5_dev_intf->hw_priv,
-			CAM_ICP_A5_CMD_FW_DOWNLOAD,
-			NULL, 0);
+		a5_dev_intf->hw_priv,
+		CAM_ICP_A5_CMD_FW_DOWNLOAD,
+		NULL, 0);
 	if (rc < 0) {
 		pr_err("FW download is failed\n");
 		goto set_irq_failed;
@@ -1083,14 +945,8 @@
 	}
 
 	hw_mgr->fw_download = true;
-
-	rc = cam_icp_stop_cpas(hw_mgr);
-	if (rc) {
-		pr_err("cpas stop failed\n");
-		goto set_irq_failed;
-	}
-
 	hw_mgr->ctxt_cnt = 0;
+	ICP_DBG("FW download done successfully\n");
 
 	return rc;
 
@@ -1443,20 +1299,11 @@
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		return -EINVAL;
 	}
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		return -EINVAL;
-	}
-
-	--hw_mgr->ctxt_cnt;
-	if (!hw_mgr->ctxt_cnt) {
-		ICP_DBG("stop cpas for last context\n");
-		cam_icp_stop_cpas(hw_mgr);
-	}
-	ICP_DBG("context count : %u\n", hw_mgr->ctxt_cnt);
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	ICP_DBG("fw handle %d\n", fw_handle);
 	return rc;
@@ -1662,13 +1509,6 @@
 
 	/* Fill ctx with acquire info */
 	ctx_data = &hw_mgr->ctx_data[ctx_id];
-
-	if (!hw_mgr->ctxt_cnt++) {
-		ICP_DBG("starting cpas\n");
-		cam_icp_start_cpas(hw_mgr);
-	}
-	ICP_DBG("context count : %u\n", hw_mgr->ctxt_cnt);
-
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	/* Fill ctx with acquire info */
@@ -1782,9 +1622,6 @@
 create_handle_failed:
 get_create_task_failed:
 cmd_cpu_buf_failed:
-	--hw_mgr->ctxt_cnt;
-	if (!hw_mgr->ctxt_cnt)
-		cam_icp_stop_cpas(hw_mgr);
 	cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
 	kfree(tmp_acquire);
 	return rc;
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c
index 15cb943..07f63d2 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.c
@@ -43,7 +43,7 @@
 		rc = cam_cpas_update_axi_vote(core_info->cpas_handle,
 			&cpas_vote->axi_vote);
 
-	if (rc < 0)
+	if (rc)
 		pr_err("cpas vote is failed: %d\n", rc);
 
 	return rc;
@@ -78,15 +78,19 @@
 
 	rc = cam_cpas_start(core_info->cpas_handle,
 		&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
-	if (rc < 0) {
+	if (rc) {
 		pr_err("cpass start failed: %d\n", rc);
 		return rc;
 	}
+	core_info->cpas_start = true;
 
 	rc = cam_ipe_enable_soc_resources(soc_info);
-	if (rc < 0) {
-		pr_err("soc enable is failed\n");
-		rc = cam_cpas_stop(core_info->cpas_handle);
+	if (rc) {
+		pr_err("soc enable is failed : %d\n", rc);
+		if (cam_cpas_stop(core_info->cpas_handle))
+			pr_err("cpas stop is failed\n");
+		else
+			core_info->cpas_start = false;
 	}
 
 	return rc;
@@ -113,12 +117,15 @@
 	}
 
 	rc = cam_ipe_disable_soc_resources(soc_info);
-	if (rc < 0)
-		pr_err("soc enable is failed\n");
+	if (rc)
+		pr_err("soc disable is failed : %d\n", rc);
 
-	rc = cam_cpas_stop(core_info->cpas_handle);
-	if (rc < 0)
-		pr_err("cpas stop is failed: %d\n", rc);
+	if (core_info->cpas_start) {
+		if (cam_cpas_stop(core_info->cpas_handle))
+			pr_err("cpas stop is failed\n");
+		else
+			core_info->cpas_start = false;
+	}
 
 	return rc;
 }
@@ -163,13 +170,19 @@
 		if (!cmd_args)
 			return -EINVAL;
 
-		rc = cam_cpas_start(core_info->cpas_handle,
-			&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+		if (!core_info->cpas_start) {
+			rc = cam_cpas_start(core_info->cpas_handle,
+				&cpas_vote->ahb_vote, &cpas_vote->axi_vote);
+			core_info->cpas_start = true;
+		}
 		break;
 	}
 
 	case CAM_ICP_IPE_CMD_CPAS_STOP:
-		cam_cpas_stop(core_info->cpas_handle);
+		if (core_info->cpas_start) {
+			cam_cpas_stop(core_info->cpas_handle);
+			core_info->cpas_start = false;
+		}
 		break;
 	default:
 		break;
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h
index 4818846..8f0e882 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/ipe_hw/ipe_core.h
@@ -26,6 +26,7 @@
 struct cam_ipe_device_core_info {
 	struct cam_ipe_device_hw_info *ipe_hw_info;
 	uint32_t cpas_handle;
+	bool cpas_start;
 };
 
 int cam_ipe_init_hw(void *device_priv,
diff --git a/drivers/media/platform/msm/dvb/Kconfig b/drivers/media/platform/msm/dvb/Kconfig
new file mode 100644
index 0000000..e205c81
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/Kconfig
@@ -0,0 +1,10 @@
+config DVB_MPQ
+	tristate "Qualcomm Technologies Inc Multimedia Processor DVB Adapter"
+	depends on ARCH_QCOM && DVB_CORE
+	default n
+
+	help
+	  Support for Qualcomm Technologies Inc MPQ based DVB adapter.
+	  Say Y or M if you own such a device and want to use it.
+
+source "drivers/media/platform/msm/dvb/demux/Kconfig"
diff --git a/drivers/media/platform/msm/dvb/Makefile b/drivers/media/platform/msm/dvb/Makefile
new file mode 100644
index 0000000..862ebca
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_DVB_MPQ)	    += adapter/
+obj-$(CONFIG_DVB_MPQ_DEMUX) += demux/
diff --git a/drivers/media/platform/msm/dvb/adapter/Makefile b/drivers/media/platform/msm/dvb/adapter/Makefile
new file mode 100644
index 0000000..662bf99
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/adapter/Makefile
@@ -0,0 +1,7 @@
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/platform/msm/dvb/include/
+ccflags-y += -Idrivers/media/platform/msm/dvb/demux/
+
+obj-$(CONFIG_DVB_MPQ) += mpq-adapter.o
+
+mpq-adapter-y := mpq_adapter.o mpq_stream_buffer.o
diff --git a/drivers/media/platform/msm/dvb/adapter/mpq_adapter.c b/drivers/media/platform/msm/dvb/adapter/mpq_adapter.c
new file mode 100644
index 0000000..1ccb98f
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/adapter/mpq_adapter.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include "mpq_adapter.h"
+#include "mpq_dvb_debug.h"
+
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* data-structure holding MPQ adapter information */
+static struct
+{
+	/* MPQ adapter registered to dvb-core */
+	struct dvb_adapter adapter;
+
+	/* mutex protect against the data-structure */
+	struct mutex mutex;
+
+	/* List of stream interfaces registered to the MPQ adapter */
+	struct {
+		/* pointer to the stream buffer using for data tunneling */
+		struct mpq_streambuffer *stream_buffer;
+
+		/* callback triggered when the stream interface is registered */
+		mpq_adapter_stream_if_callback callback;
+
+		/* parameter passed to the callback function */
+		void *user_param;
+	} interfaces[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES];
+} mpq_info;
+
+
+/**
+ * Initialize MPQ DVB adapter module.
+ *
+ * Return     error status
+ */
+static int __init mpq_adapter_init(void)
+{
+	int i;
+	int result;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	mutex_init(&mpq_info.mutex);
+
+	/* reset stream interfaces list */
+	for (i = 0; i < MPQ_ADAPTER_MAX_NUM_OF_INTERFACES; i++) {
+		mpq_info.interfaces[i].stream_buffer = NULL;
+		mpq_info.interfaces[i].callback = NULL;
+	}
+
+	/* regsiter a new dvb-adapter to dvb-core */
+	result = dvb_register_adapter(&mpq_info.adapter,
+				      "Qualcomm technologies, inc. DVB adapter",
+				      THIS_MODULE, NULL, adapter_nr);
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: dvb_register_adapter failed, errno %d\n",
+			__func__,
+			result);
+	}
+
+	return result;
+}
+
+
+/**
+ * Cleanup MPQ DVB adapter module.
+ */
+static void __exit mpq_adapter_exit(void)
+{
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	/* un-regsiter adapter from dvb-core */
+	dvb_unregister_adapter(&mpq_info.adapter);
+	mutex_destroy(&mpq_info.mutex);
+}
+
+struct dvb_adapter *mpq_adapter_get(void)
+{
+	return &mpq_info.adapter;
+}
+EXPORT_SYMBOL(mpq_adapter_get);
+
+
+int mpq_adapter_register_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		struct mpq_streambuffer *stream_buffer)
+{
+	int ret;
+
+	if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) {
+		ret = -EINVAL;
+		goto register_failed;
+	}
+
+	if (mutex_lock_interruptible(&mpq_info.mutex)) {
+		ret = -ERESTARTSYS;
+		goto register_failed;
+	}
+
+	if (mpq_info.interfaces[interface_id].stream_buffer != NULL) {
+		/* already registered interface */
+		ret = -EINVAL;
+		goto register_failed_unlock_mutex;
+	}
+
+	mpq_info.interfaces[interface_id].stream_buffer = stream_buffer;
+	mutex_unlock(&mpq_info.mutex);
+
+	/*
+	 * If callback is installed, trigger it to notify that
+	 * stream interface was registered.
+	 */
+	if (mpq_info.interfaces[interface_id].callback != NULL) {
+		mpq_info.interfaces[interface_id].callback(
+				interface_id,
+				mpq_info.interfaces[interface_id].user_param);
+	}
+
+	return 0;
+
+register_failed_unlock_mutex:
+	mutex_unlock(&mpq_info.mutex);
+register_failed:
+	return ret;
+}
+EXPORT_SYMBOL(mpq_adapter_register_stream_if);
+
+
+int mpq_adapter_unregister_stream_if(
+		enum mpq_adapter_stream_if interface_id)
+{
+	if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&mpq_info.mutex))
+		return -ERESTARTSYS;
+
+	/* clear the registered interface */
+	mpq_info.interfaces[interface_id].stream_buffer = NULL;
+
+	mutex_unlock(&mpq_info.mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_adapter_unregister_stream_if);
+
+
+int mpq_adapter_get_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		struct mpq_streambuffer **stream_buffer)
+{
+	if ((interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) ||
+		(stream_buffer == NULL))
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&mpq_info.mutex))
+		return -ERESTARTSYS;
+
+	*stream_buffer = mpq_info.interfaces[interface_id].stream_buffer;
+
+	mutex_unlock(&mpq_info.mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_adapter_get_stream_if);
+
+
+int mpq_adapter_notify_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		mpq_adapter_stream_if_callback callback,
+		void *user_param)
+{
+	if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&mpq_info.mutex))
+		return -ERESTARTSYS;
+
+	mpq_info.interfaces[interface_id].callback = callback;
+	mpq_info.interfaces[interface_id].user_param = user_param;
+
+	mutex_unlock(&mpq_info.mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_adapter_notify_stream_if);
+
+
+module_init(mpq_adapter_init);
+module_exit(mpq_adapter_exit);
+
+MODULE_DESCRIPTION("Qualcomm Technologies Inc. MPQ adapter");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c
new file mode 100644
index 0000000..4f84c58
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c
@@ -0,0 +1,827 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_stream_buffer.h"
+
+
+int mpq_streambuffer_init(
+		struct mpq_streambuffer *sbuff,
+		enum mpq_streambuffer_mode mode,
+		struct mpq_streambuffer_buffer_desc *data_buffers,
+		u32 data_buff_num,
+		void *packet_buff,
+		size_t packet_buff_size)
+{
+	if ((sbuff == NULL) || (data_buffers == NULL) ||
+		(packet_buff == NULL) || (data_buff_num == 0))
+		return -EINVAL;
+
+	if (data_buff_num > 1) {
+		if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
+			return -EINVAL;
+		/* Linear buffer group */
+		dvb_ringbuffer_init(
+			&sbuff->raw_data,
+			data_buffers,
+			data_buff_num *
+			sizeof(struct mpq_streambuffer_buffer_desc));
+	} else {
+		if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_RING)
+			return -EINVAL;
+		/* Single ring-buffer */
+		dvb_ringbuffer_init(&sbuff->raw_data,
+			data_buffers[0].base, data_buffers[0].size);
+	}
+	sbuff->mode = mode;
+	sbuff->buffers = data_buffers;
+	sbuff->pending_buffers_count = 0;
+	sbuff->buffers_num = data_buff_num;
+	sbuff->cb = NULL;
+	dvb_ringbuffer_init(&sbuff->packet_data, packet_buff, packet_buff_size);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_init);
+
+void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff)
+{
+	spin_lock(&sbuff->packet_data.lock);
+	spin_lock(&sbuff->raw_data.lock);
+	sbuff->packet_data.error = -ENODEV;
+	sbuff->raw_data.error = -ENODEV;
+	spin_unlock(&sbuff->raw_data.lock);
+	spin_unlock(&sbuff->packet_data.lock);
+
+	wake_up_all(&sbuff->raw_data.queue);
+	wake_up_all(&sbuff->packet_data.queue);
+}
+EXPORT_SYMBOL(mpq_streambuffer_terminate);
+
+ssize_t mpq_streambuffer_pkt_next(
+		struct mpq_streambuffer *sbuff,
+		ssize_t idx, size_t *pktlen)
+{
+	ssize_t packet_idx;
+
+	spin_lock(&sbuff->packet_data.lock);
+
+	/* buffer was released, return no packet available */
+	if (sbuff->packet_data.error == -ENODEV) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
+	packet_idx = dvb_ringbuffer_pkt_next(&sbuff->packet_data, idx, pktlen);
+	spin_unlock(&sbuff->packet_data.lock);
+
+	return packet_idx;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_next);
+
+
+ssize_t mpq_streambuffer_pkt_read(
+		struct mpq_streambuffer *sbuff,
+		size_t idx,
+		struct mpq_streambuffer_packet_header *packet,
+		u8 *user_data)
+{
+	size_t ret;
+	size_t read_len;
+
+	spin_lock(&sbuff->packet_data.lock);
+
+	/* buffer was released, return no packet available */
+	if (sbuff->packet_data.error == -ENODEV) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
+	/* read-out the packet header first */
+	ret = dvb_ringbuffer_pkt_read(
+				&sbuff->packet_data, idx, 0,
+				(u8 *)packet,
+				sizeof(struct mpq_streambuffer_packet_header));
+
+	/* verify length, at least packet header should exist */
+	if (ret != sizeof(struct mpq_streambuffer_packet_header)) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -EINVAL;
+	}
+
+	read_len = ret;
+
+	/* read-out private user-data if there are such */
+	if ((packet->user_data_len) && (user_data != NULL)) {
+		ret = dvb_ringbuffer_pkt_read(
+				&sbuff->packet_data,
+				idx,
+				sizeof(struct mpq_streambuffer_packet_header),
+				user_data,
+				packet->user_data_len);
+
+		if (ret < 0) {
+			spin_unlock(&sbuff->packet_data.lock);
+			return ret;
+		}
+
+		read_len += ret;
+	}
+
+	spin_unlock(&sbuff->packet_data.lock);
+
+	return read_len;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_read);
+
+
+int mpq_streambuffer_pkt_dispose(
+			struct mpq_streambuffer *sbuff,
+			size_t idx,
+			int dispose_data)
+{
+	int ret;
+	struct mpq_streambuffer_packet_header packet;
+
+	if (sbuff == NULL)
+		return -EINVAL;
+
+	spin_lock(&sbuff->packet_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->packet_data.error == -ENODEV) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
+	/* read-out the packet header first */
+	ret = dvb_ringbuffer_pkt_read(&sbuff->packet_data, idx,
+			0,
+			(u8 *)&packet,
+			sizeof(struct mpq_streambuffer_packet_header));
+
+	spin_unlock(&sbuff->packet_data.lock);
+
+	if (ret != sizeof(struct mpq_streambuffer_packet_header))
+		return -EINVAL;
+
+	if ((sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) ||
+		(dispose_data)) {
+		/* Advance the read pointer in the raw-data buffer first */
+		ret = mpq_streambuffer_data_read_dispose(sbuff,
+			packet.raw_data_len);
+		if (ret != 0)
+			return ret;
+	}
+
+	spin_lock(&sbuff->packet_data.lock);
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if ((sbuff->packet_data.error == -ENODEV) ||
+		(sbuff->raw_data.error == -ENODEV)) {
+		spin_unlock(&sbuff->raw_data.lock);
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
+	/* Move read pointer to the next linear buffer for subsequent reads */
+	if ((sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) &&
+		(packet.raw_data_len > 0)) {
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+
+		desc->write_ptr = 0;
+		desc->read_ptr = 0;
+
+		DVB_RINGBUFFER_SKIP(&sbuff->raw_data,
+				sizeof(struct mpq_streambuffer_buffer_desc));
+		sbuff->pending_buffers_count--;
+
+		wake_up_all(&sbuff->raw_data.queue);
+	}
+
+	/* Now clear the packet from the packet header */
+	dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx);
+
+	spin_unlock(&sbuff->raw_data.lock);
+	spin_unlock(&sbuff->packet_data.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_dispose);
+
+int mpq_streambuffer_pkt_write(
+			struct mpq_streambuffer *sbuff,
+			struct mpq_streambuffer_packet_header *packet,
+			u8 *user_data)
+{
+	ssize_t idx;
+	size_t len;
+
+	if ((sbuff == NULL) || (packet == NULL))
+		return -EINVAL;
+
+	spin_lock(&sbuff->packet_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->packet_data.error == -ENODEV) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
+	/* Make sure we can go to the next linear buffer */
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR &&
+		sbuff->pending_buffers_count == sbuff->buffers_num &&
+		packet->raw_data_len) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENOSPC;
+	}
+
+	len = sizeof(struct mpq_streambuffer_packet_header) +
+		packet->user_data_len;
+
+	/* Make sure enough space available for packet header */
+	if (dvb_ringbuffer_free(&sbuff->packet_data) <
+		(len + DVB_RINGBUFFER_PKTHDRSIZE)) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENOSPC;
+	}
+
+	/* Starting writing packet header */
+	idx = dvb_ringbuffer_pkt_start(&sbuff->packet_data, len);
+
+	/* Write non-user private data header */
+	dvb_ringbuffer_write(&sbuff->packet_data,
+		(u8 *)packet,
+		sizeof(struct mpq_streambuffer_packet_header));
+
+	/* Write user's own private data header */
+	dvb_ringbuffer_write(&sbuff->packet_data,
+		user_data,
+		packet->user_data_len);
+
+	dvb_ringbuffer_pkt_close(&sbuff->packet_data, idx);
+
+	/* Move write pointer to next linear buffer for subsequent writes */
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR &&
+		packet->raw_data_len) {
+		DVB_RINGBUFFER_PUSH(&sbuff->raw_data,
+				sizeof(struct mpq_streambuffer_buffer_desc));
+		sbuff->pending_buffers_count++;
+	}
+
+	spin_unlock(&sbuff->packet_data.lock);
+	wake_up_all(&sbuff->packet_data.queue);
+
+	return idx;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_write);
+
+ssize_t mpq_streambuffer_data_write(
+			struct mpq_streambuffer *sbuff,
+			const u8 *buf, size_t len)
+{
+	int res;
+
+	if ((sbuff == NULL) || (buf == NULL))
+		return -EINVAL;
+
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) {
+		if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) {
+			spin_unlock(&sbuff->raw_data.lock);
+			return -ENOSPC;
+		}
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (sbuff->raw_data.data == NULL) {
+			spin_unlock(&sbuff->raw_data.lock);
+			return -EPERM;
+		}
+		res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len);
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		/* Linear buffer group */
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pwrite];
+
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (desc->base == NULL) {
+			spin_unlock(&sbuff->raw_data.lock);
+			return -EPERM;
+		}
+
+		if ((sbuff->pending_buffers_count == sbuff->buffers_num) ||
+			((desc->size - desc->write_ptr) < len)) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: No space available! %d pending buffers out of %d total buffers. write_ptr=%d, size=%d\n",
+				__func__,
+				sbuff->pending_buffers_count,
+				sbuff->buffers_num,
+				desc->write_ptr,
+				desc->size);
+			spin_unlock(&sbuff->raw_data.lock);
+			return -ENOSPC;
+		}
+		memcpy(desc->base + desc->write_ptr, buf, len);
+		desc->write_ptr += len;
+		res = len;
+	}
+
+	spin_unlock(&sbuff->raw_data.lock);
+	return res;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_write);
+
+
+int mpq_streambuffer_data_write_deposit(
+				struct mpq_streambuffer *sbuff,
+				size_t len)
+{
+	if (sbuff == NULL)
+		return -EINVAL;
+
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) {
+		if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) {
+			spin_unlock(&sbuff->raw_data.lock);
+			return -ENOSPC;
+		}
+
+		DVB_RINGBUFFER_PUSH(&sbuff->raw_data, len);
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		/* Linear buffer group */
+		struct mpq_streambuffer_buffer_desc *desc =
+			(struct mpq_streambuffer_buffer_desc *)
+			&sbuff->raw_data.data[sbuff->raw_data.pwrite];
+
+		if ((sbuff->pending_buffers_count == sbuff->buffers_num) ||
+			 ((desc->size - desc->write_ptr) < len)) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: No space available!\n",
+				__func__);
+			spin_unlock(&sbuff->raw_data.lock);
+			return -ENOSPC;
+		}
+		desc->write_ptr += len;
+	}
+
+	spin_unlock(&sbuff->raw_data.lock);
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_write_deposit);
+
+
+ssize_t mpq_streambuffer_data_read(
+				struct mpq_streambuffer *sbuff,
+				u8 *buf, size_t len)
+{
+	ssize_t actual_len = 0;
+	u32 offset;
+
+	if ((sbuff == NULL) || (buf == NULL))
+		return -EINVAL;
+
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) {
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (sbuff->raw_data.data == NULL) {
+			spin_unlock(&sbuff->raw_data.lock);
+			return -EPERM;
+		}
+
+		offset = sbuff->raw_data.pread;
+		actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
+		if (actual_len < len)
+			len = actual_len;
+		if (len)
+			dvb_ringbuffer_read(&sbuff->raw_data, buf, len);
+
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		/* Linear buffer group */
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (desc->base == NULL) {
+			spin_unlock(&sbuff->raw_data.lock);
+			return -EPERM;
+		}
+
+		actual_len = (desc->write_ptr - desc->read_ptr);
+		if (actual_len < len)
+			len = actual_len;
+		memcpy(buf, desc->base + desc->read_ptr, len);
+		offset = desc->read_ptr;
+		desc->read_ptr += len;
+	}
+
+	spin_unlock(&sbuff->raw_data.lock);
+
+	if (sbuff->cb)
+		sbuff->cb(sbuff, offset, len, sbuff->cb_user_data);
+
+	return len;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_read);
+
+
+ssize_t mpq_streambuffer_data_read_user(
+		struct mpq_streambuffer *sbuff,
+		u8 __user *buf, size_t len)
+{
+	ssize_t actual_len = 0;
+	u32 offset;
+
+	if ((sbuff == NULL) || (buf == NULL))
+		return -EINVAL;
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV)
+		return -ENODEV;
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) {
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (sbuff->raw_data.data == NULL)
+			return -EPERM;
+
+		offset = sbuff->raw_data.pread;
+		actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
+		if (actual_len < len)
+			len = actual_len;
+		if (len)
+			dvb_ringbuffer_read_user(&sbuff->raw_data, buf, len);
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		/* Linear buffer group */
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (desc->base == NULL)
+			return -EPERM;
+
+		actual_len = (desc->write_ptr - desc->read_ptr);
+		if (actual_len < len)
+			len = actual_len;
+		if (copy_to_user(buf, desc->base + desc->read_ptr, len))
+			return -EFAULT;
+
+		offset = desc->read_ptr;
+		desc->read_ptr += len;
+	}
+
+	if (sbuff->cb)
+		sbuff->cb(sbuff, offset, len, sbuff->cb_user_data);
+
+	return len;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_read_user);
+
+int mpq_streambuffer_data_read_dispose(
+			struct mpq_streambuffer *sbuff,
+			size_t len)
+{
+	u32 offset;
+
+	if (sbuff == NULL)
+		return -EINVAL;
+
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) {
+		if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len)) {
+			spin_unlock(&sbuff->raw_data.lock);
+			return -EINVAL;
+		}
+
+		offset = sbuff->raw_data.pread;
+		DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len);
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+		offset = desc->read_ptr;
+
+		if ((desc->read_ptr + len) > desc->size)
+			desc->read_ptr = desc->size;
+		else
+			desc->read_ptr += len;
+	}
+
+	spin_unlock(&sbuff->raw_data.lock);
+
+	if (sbuff->cb)
+		sbuff->cb(sbuff, offset, len, sbuff->cb_user_data);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_read_dispose);
+
+
+int mpq_streambuffer_get_buffer_handle(
+	struct mpq_streambuffer *sbuff,
+	int read_buffer,
+	int *handle)
+{
+	struct mpq_streambuffer_buffer_desc *desc = NULL;
+
+	if ((sbuff == NULL) || (handle == NULL))
+		return -EINVAL;
+
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) {
+		*handle = sbuff->buffers[0].handle;
+	} else {
+		if (read_buffer)
+			desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+		else
+			desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pwrite];
+		*handle = desc->handle;
+	}
+
+	spin_unlock(&sbuff->raw_data.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_get_buffer_handle);
+
+
+int mpq_streambuffer_register_data_dispose(
+	struct mpq_streambuffer *sbuff,
+	mpq_streambuffer_dispose_cb cb_func,
+	void *user_data)
+{
+	if ((sbuff == NULL) || (cb_func == NULL))
+		return -EINVAL;
+
+	sbuff->cb = cb_func;
+	sbuff->cb_user_data = user_data;
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_register_data_dispose);
+
+
+ssize_t mpq_streambuffer_data_free(
+	struct mpq_streambuffer *sbuff)
+{
+	struct mpq_streambuffer_buffer_desc *desc;
+
+	if (sbuff == NULL)
+		return -EINVAL;
+
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return dvb_ringbuffer_free(&sbuff->raw_data);
+	}
+
+	if (sbuff->pending_buffers_count == sbuff->buffers_num) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return 0;
+	}
+
+	desc = (struct mpq_streambuffer_buffer_desc *)
+		&sbuff->raw_data.data[sbuff->raw_data.pwrite];
+
+	spin_unlock(&sbuff->raw_data.lock);
+
+	return desc->size - desc->write_ptr;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_free);
+
+
+ssize_t mpq_streambuffer_data_avail(
+	struct mpq_streambuffer *sbuff)
+{
+	struct mpq_streambuffer_buffer_desc *desc;
+
+	if (sbuff == NULL)
+		return -EINVAL;
+
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) {
+		ssize_t avail = dvb_ringbuffer_avail(&sbuff->raw_data);
+
+		spin_unlock(&sbuff->raw_data.lock);
+		return avail;
+	}
+
+	desc = (struct mpq_streambuffer_buffer_desc *)
+		&sbuff->raw_data.data[sbuff->raw_data.pread];
+
+	spin_unlock(&sbuff->raw_data.lock);
+
+	return desc->write_ptr - desc->read_ptr;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_avail);
+
+int mpq_streambuffer_get_data_rw_offset(
+	struct mpq_streambuffer *sbuff,
+	u32 *read_offset,
+	u32 *write_offset)
+{
+	if (sbuff == NULL)
+		return -EINVAL;
+
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) {
+		if (read_offset)
+			*read_offset = sbuff->raw_data.pread;
+		if (write_offset)
+			*write_offset = sbuff->raw_data.pwrite;
+	} else {
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		if (read_offset) {
+			desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+			*read_offset = desc->read_ptr;
+		}
+		if (write_offset) {
+			desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pwrite];
+			*write_offset = desc->write_ptr;
+		}
+	}
+
+	spin_unlock(&sbuff->raw_data.lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_get_data_rw_offset);
+
+ssize_t mpq_streambuffer_metadata_free(struct mpq_streambuffer *sbuff)
+{
+	ssize_t free;
+
+	if (sbuff == NULL)
+		return -EINVAL;
+
+	spin_lock(&sbuff->packet_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->packet_data.error == -ENODEV) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
+	free = dvb_ringbuffer_free(&sbuff->packet_data);
+
+	spin_unlock(&sbuff->packet_data.lock);
+
+	return free;
+}
+EXPORT_SYMBOL(mpq_streambuffer_metadata_free);
+
+int mpq_streambuffer_flush(struct mpq_streambuffer *sbuff)
+{
+	struct mpq_streambuffer_buffer_desc *desc;
+	size_t len;
+	int idx;
+	int ret = 0;
+
+	if (sbuff == NULL)
+		return -EINVAL;
+
+	spin_lock(&sbuff->packet_data.lock);
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* Check if buffer was released */
+	if (sbuff->packet_data.error == -ENODEV ||
+		sbuff->raw_data.error == -ENODEV) {
+		ret = -ENODEV;
+		goto end;
+	}
+
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
+		while (sbuff->pending_buffers_count) {
+			desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+			desc->write_ptr = 0;
+			desc->read_ptr = 0;
+			DVB_RINGBUFFER_SKIP(&sbuff->raw_data,
+				sizeof(struct mpq_streambuffer_buffer_desc));
+			sbuff->pending_buffers_count--;
+		}
+	else
+		dvb_ringbuffer_flush(&sbuff->raw_data);
+
+	/*
+	 * Dispose all packets (simply flushing is not enough since we want
+	 * the packets' status to move to disposed).
+	 */
+	do {
+		idx = dvb_ringbuffer_pkt_next(&sbuff->packet_data, -1, &len);
+		if (idx >= 0)
+			dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx);
+	} while (idx >= 0);
+
+end:
+	spin_unlock(&sbuff->raw_data.lock);
+	spin_unlock(&sbuff->packet_data.lock);
+	return ret;
+}
+EXPORT_SYMBOL(mpq_streambuffer_flush);
diff --git a/drivers/media/platform/msm/dvb/demux/Kconfig b/drivers/media/platform/msm/dvb/demux/Kconfig
new file mode 100644
index 0000000..b928212
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/demux/Kconfig
@@ -0,0 +1,47 @@
+menuconfig DVB_MPQ_DEMUX
+	tristate "DVB Demux Device"
+	depends on DVB_MPQ && ION && ION_MSM
+	default n
+
+	help
+	  Support for Qualcomm Technologies Inc based dvb demux device.
+	  Say Y if you own such a device and want to use it.
+	  The Demux device is used to stream playback either
+	  from TSIF interface or from DVR interface.
+
+config DVB_MPQ_NUM_DMX_DEVICES
+	int "Number of demux devices"
+	depends on DVB_MPQ_DEMUX
+	default 4
+	range 1 255
+
+	help
+	  Configure number of demux devices.
+	  Depends on your use-cases for maximum concurrent stream playback.
+
+config DVB_MPQ_MEDIA_BOX_DEMUX
+	bool "Media box demux support"
+	depends on DVB_MPQ_DEMUX
+	default n
+	help
+		Use this option if your HW is Qualcomm Technologies Inc
+		media box and demux support is required on that media box.
+		Currently this config is being used for demux video events
+		optimization.
+
+config DVB_MPQ_TSPP1
+	bool "TSPPv1 plugin"
+	depends on DVB_MPQ_DEMUX && TSPP
+	help
+		Use this option if your HW has
+		Transport Stream Packet Processor(TSPP) version1 support.
+		Demux may take adavantage of HW capabilities to perform
+		some tasks in HW instead of SW.
+
+config DVB_MPQ_SW
+	bool "Software plugin"
+	depends on DVB_MPQ_DEMUX && !DVB_MPQ_TSPP1
+	help
+		Use this option if your HW does not have any
+		TSPP hardware support. All  demux tasks will be
+		performed in SW.
diff --git a/drivers/media/platform/msm/dvb/demux/Makefile b/drivers/media/platform/msm/dvb/demux/Makefile
new file mode 100644
index 0000000..c08fa85
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/demux/Makefile
@@ -0,0 +1,14 @@
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/platform/msm/dvb/include/
+ccflags-y += -Idrivers/misc/
+
+obj-$(CONFIG_DVB_MPQ_DEMUX) += mpq-dmx-hw-plugin.o
+
+mpq-dmx-hw-plugin-y := mpq_dmx_plugin_common.o
+
+mpq-dmx-hw-plugin-$(CONFIG_QSEECOM) += mpq_sdmx.o
+
+mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP1) += mpq_dmx_plugin_tspp_v1.o
+
+mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_SW) += mpq_dmx_plugin_sw.o
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
new file mode 100644
index 0000000..f16c1ba
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -0,0 +1,6712 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/file.h>
+#include <linux/scatterlist.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+#include "mpq_sdmx.h"
+
+#define SDMX_MAJOR_VERSION_MATCH	(8)
+
+/* Length of mandatory fields that must exist in header of video PES */
+#define PES_MANDATORY_FIELDS_LEN			9
+
+/* Index of first byte in TS packet holding STC */
+#define STC_LOCATION_IDX			188
+
+#define MAX_PES_LENGTH	(SZ_64K)
+
+#define MAX_TS_PACKETS_FOR_SDMX_PROCESS	(500)
+
+/*
+ * PES header length field is 8 bits so PES header length after this field
+ * can be up to 256 bytes.
+ * Preceding fields of the PES header total to 9 bytes
+ * (including the PES header length field).
+ */
+#define MAX_PES_HEADER_LENGTH	(256 + PES_MANDATORY_FIELDS_LEN)
+
+/* TS packet with adaptation field only can take up the entire TSP */
+#define MAX_TSP_ADAPTATION_LENGTH (184)
+
+#define MAX_SDMX_METADATA_LENGTH	\
+	(TS_PACKET_HEADER_LENGTH +	\
+	MAX_TSP_ADAPTATION_LENGTH +	\
+	MAX_PES_HEADER_LENGTH)
+
+#define SDMX_METADATA_BUFFER_SIZE	(64*1024)
+#define SDMX_SECTION_BUFFER_SIZE	(64*1024)
+#define SDMX_PCR_BUFFER_SIZE		(64*1024)
+
+/* Number of demux devices, has default of linux configuration */
+static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+module_param(mpq_demux_device_num, int, 0444);
+
+/* ION heap IDs used for allocating video output buffer */
+static int video_secure_ion_heap = ION_CP_MM_HEAP_ID;
+module_param(video_secure_ion_heap, int, 0644);
+MODULE_PARM_DESC(video_secure_ion_heap, "ION heap for secure video buffer allocation");
+
+static int video_nonsecure_ion_heap = ION_IOMMU_HEAP_ID;
+module_param(video_nonsecure_ion_heap, int, 0644);
+MODULE_PARM_DESC(video_nonsecure_ion_heap, "ION heap for non-secure video buffer allocation");
+
+/* ION heap IDs used for allocating audio  output buffer */
+static int audio_nonsecure_ion_heap = ION_IOMMU_HEAP_ID;
+module_param(audio_nonsecure_ion_heap, int, 0644);
+MODULE_PARM_DESC(audio_nonsecure_ion_heap, "ION heap for non-secure audio buffer allocation");
+
+/* Value of TS packet scramble bits field for even key */
+static int mpq_sdmx_scramble_even = 0x2;
+module_param(mpq_sdmx_scramble_even, int, 0644);
+
+/* Value of TS packet scramble bits field for odd key */
+static int mpq_sdmx_scramble_odd = 0x3;
+module_param(mpq_sdmx_scramble_odd, int, 0644);
+
+/*
+ * Default action (discard or pass) taken when scramble bit is not one of the
+ * pass-through / odd / even values.
+ * When set packets will be discarded, otherwise passed through.
+ */
+static int mpq_sdmx_scramble_default_discard = 1;
+module_param(mpq_sdmx_scramble_default_discard, int, 0644);
+
+/* Max number of TS packets allowed as input for a single sdmx process */
+static int mpq_sdmx_proc_limit = MAX_TS_PACKETS_FOR_SDMX_PROCESS;
+module_param(mpq_sdmx_proc_limit, int, 0644);
+
+/* Debug flag for secure demux process */
+static int mpq_sdmx_debug;
+module_param(mpq_sdmx_debug, int, 0644);
+
+/*
+ * Indicates whether the demux should search for frame boundaries
+ * and notify on video packets on frame-basis or whether to provide
+ * only video PES packet payloads as-is.
+ */
+static int video_framing = 1;
+module_param(video_framing, int, 0644);
+
+/* TSIF operation mode: 1 = TSIF_MODE_1,  2 = TSIF_MODE_2, 3 = TSIF_LOOPBACK */
+static int tsif_mode = 2;
+module_param(tsif_mode, int, 0644);
+
+/* Inverse TSIF clock signal */
+static int clock_inv;
+module_param(clock_inv, int, 0644);
+
+/* TSIF Timestamp source: 0 = TSIF Clock Reference, 1 = LPASS time counter */
+enum tsif_tts_source {
+	TSIF_TTS_TCR = 0,       /* Time stamps from TCR counter */
+	TSIF_TTS_LPASS_TIMER    /* Time stamps from AV/Qtimer Timer  */
+};
+
+/* Store all mpq feeds corresponding to 4 TS programs in a Transport Stream */
+static struct mpq_feed *store_mpq_audio_feed[CONFIG_DVB_MPQ_NUM_DMX_DEVICES] = {
+	NULL, NULL, NULL, NULL};
+static struct mpq_feed *store_mpq_video_feed[CONFIG_DVB_MPQ_NUM_DMX_DEVICES] = {
+	NULL, NULL, NULL, NULL};
+static int non_predicted_video_frame;
+/* trigger video ES frame events on MPEG2 B frames and H264 non-IDR frames */
+#ifdef CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX
+static int video_b_frame_events = 1;
+#else
+static int video_b_frame_events;
+#endif
+
+/* Global data-structure for managing demux devices */
+static struct
+{
+	/* ION demux client used for memory allocation */
+	struct ion_client *ion_client;
+
+	/* demux devices array */
+	struct mpq_demux *devices;
+
+	/* Stream buffers objects used for tunneling to decoders */
+	struct mpq_streambuffer
+		decoder_buffers[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES];
+
+	/* Indicates whether secure demux TZ application is available */
+	int secure_demux_app_loaded;
+} mpq_dmx_info;
+
+
+int mpq_dmx_get_param_scramble_odd(void)
+{
+	return mpq_sdmx_scramble_odd;
+}
+
+int mpq_dmx_get_param_scramble_even(void)
+{
+	return mpq_sdmx_scramble_even;
+}
+
+int mpq_dmx_get_param_scramble_default_discard(void)
+{
+	return mpq_sdmx_scramble_default_discard;
+}
+
+int mpq_dmx_get_param_tsif_mode(void)
+{
+	return tsif_mode;
+}
+
+int mpq_dmx_get_param_clock_inv(void)
+{
+	return clock_inv;
+}
+
+struct mpq_streambuffer *consumer_video_streambuffer(int dmx_ts_pes_video)
+{
+	struct mpq_streambuffer *streambuffer = NULL;
+	struct mpq_video_feed_info *feed_data = NULL;
+
+	switch (dmx_ts_pes_video) {
+	case DMX_PES_VIDEO0:
+		if (store_mpq_video_feed[0] != NULL) {
+			feed_data = &store_mpq_video_feed[0]->video_info;
+			feed_data->stream_interface =
+				MPQ_ADAPTER_VIDEO0_STREAM_IF;
+		}
+		break;
+	case DMX_PES_VIDEO1:
+		if (store_mpq_video_feed[1] != NULL) {
+			feed_data = &store_mpq_video_feed[1]->video_info;
+			feed_data->stream_interface =
+				MPQ_ADAPTER_VIDEO1_STREAM_IF;
+		}
+		break;
+	case DMX_PES_VIDEO2:
+		if (store_mpq_video_feed[2] != NULL) {
+			feed_data = &store_mpq_video_feed[2]->video_info;
+			feed_data->stream_interface =
+				MPQ_ADAPTER_VIDEO2_STREAM_IF;
+		}
+		break;
+	case DMX_PES_VIDEO3:
+		if (store_mpq_video_feed[3] != NULL) {
+			feed_data = &store_mpq_video_feed[3]->video_info;
+			feed_data->stream_interface =
+				MPQ_ADAPTER_VIDEO3_STREAM_IF;
+		}
+		break;
+	}
+
+	if (feed_data != NULL)
+		mpq_adapter_get_stream_if(feed_data->stream_interface,
+					  &streambuffer);
+
+	return streambuffer;
+}
+EXPORT_SYMBOL(consumer_video_streambuffer);
+
+struct mpq_streambuffer *consumer_audio_streambuffer(int dmx_ts_pes_audio)
+{
+	struct mpq_streambuffer *streambuffer = NULL;
+	struct mpq_audio_feed_info *feed_data = NULL;
+
+	switch (dmx_ts_pes_audio) {
+	case DMX_PES_AUDIO0:
+		if (store_mpq_audio_feed[0] != NULL) {
+			feed_data = &store_mpq_audio_feed[0]->audio_info;
+			feed_data->stream_interface =
+				MPQ_ADAPTER_AUDIO0_STREAM_IF;
+		}
+		break;
+	case DMX_PES_AUDIO1:
+		if (store_mpq_audio_feed[1] != NULL) {
+			feed_data = &store_mpq_audio_feed[1]->audio_info;
+			feed_data->stream_interface =
+				MPQ_ADAPTER_AUDIO1_STREAM_IF;
+		}
+		break;
+	case DMX_PES_AUDIO2:
+		if (store_mpq_audio_feed[2] != NULL) {
+			feed_data = &store_mpq_audio_feed[2]->audio_info;
+			feed_data->stream_interface =
+				MPQ_ADAPTER_AUDIO2_STREAM_IF;
+		}
+		break;
+	case DMX_PES_AUDIO3:
+		if (store_mpq_audio_feed[3] != NULL) {
+			feed_data = &store_mpq_audio_feed[3]->audio_info;
+			feed_data->stream_interface =
+				MPQ_ADAPTER_AUDIO3_STREAM_IF;
+		}
+		break;
+	}
+
+	if (feed_data != NULL)
+		mpq_adapter_get_stream_if(feed_data->stream_interface,
+					  &streambuffer);
+
+	return streambuffer;
+}
+EXPORT_SYMBOL(consumer_audio_streambuffer);
+
+
+
+/* Check that PES header is valid and that it is a video PES */
+static int mpq_dmx_is_valid_video_pes(struct pes_packet_header *pes_header)
+{
+	/* start-code valid? */
+	if ((pes_header->packet_start_code_prefix_1 != 0) ||
+		(pes_header->packet_start_code_prefix_2 != 0) ||
+		(pes_header->packet_start_code_prefix_3 != 1))
+		return -EINVAL;
+
+	/* stream_id is video? */
+	if ((pes_header->stream_id & 0xF0) != 0xE0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mpq_dmx_is_valid_audio_pes(struct pes_packet_header *pes_header)
+{
+	/* start-code valid? */
+	if ((pes_header->packet_start_code_prefix_1 != 0) ||
+	    (pes_header->packet_start_code_prefix_2 != 0) ||
+	    (pes_header->packet_start_code_prefix_3 != 1))
+		return -EINVAL;
+
+	/* Note: AC3 stream ID = 0xBD */
+	if (pes_header->stream_id == 0xBD)
+		return 0;
+
+	/* stream_id is audio? */ /* 110x xxxx = Audio Stream IDs */
+	if ((pes_header->stream_id & 0xE0) != 0xC0)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* Check if a framing pattern is a video frame pattern or a header pattern */
+static inline int mpq_dmx_is_video_frame(
+				enum dmx_video_codec codec,
+				u64 pattern_type)
+{
+	switch (codec) {
+	case DMX_VIDEO_CODEC_MPEG2:
+		if (video_b_frame_events == 1)
+			if (pattern_type == DMX_IDX_MPEG_B_FRAME_START)
+				non_predicted_video_frame = 1;
+
+		if ((pattern_type == DMX_IDX_MPEG_I_FRAME_START) ||
+			(pattern_type == DMX_IDX_MPEG_P_FRAME_START) ||
+			(pattern_type == DMX_IDX_MPEG_B_FRAME_START))
+			return 1;
+		return 0;
+
+	case DMX_VIDEO_CODEC_H264:
+		if (video_b_frame_events == 1) {
+			if (pattern_type == DMX_IDX_H264_NON_IDR_BSLICE_START)
+				non_predicted_video_frame = 1;
+
+			if ((pattern_type == DMX_IDX_H264_IDR_ISLICE_START) ||
+			    (pattern_type ==
+				DMX_IDX_H264_NON_IDR_PSLICE_START) ||
+			    (pattern_type == DMX_IDX_H264_NON_IDR_BSLICE_START))
+				return 1;
+		} else {
+			if ((pattern_type == DMX_IDX_H264_IDR_START) ||
+			    (pattern_type == DMX_IDX_H264_NON_IDR_START))
+				return 1;
+		}
+		return 0;
+
+	case DMX_VIDEO_CODEC_VC1:
+		if (pattern_type == DMX_IDX_VC1_FRAME_START)
+			return 1;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ * mpq_dmx_get_pattern_params - Returns the required video
+ * patterns for framing operation based on video codec.
+ *
+ * @video_codec: the video codec.
+ * @patterns: a pointer to the pattern parameters, updated by this function.
+ * @patterns_num: number of patterns, updated by this function.
+ */
+static inline int mpq_dmx_get_pattern_params(
+	enum dmx_video_codec video_codec,
+	const struct dvb_dmx_video_patterns
+		 *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM],
+	int *patterns_num)
+{
+	switch (video_codec) {
+	case DMX_VIDEO_CODEC_MPEG2:
+		patterns[0] = dvb_dmx_get_pattern(DMX_IDX_MPEG_SEQ_HEADER);
+		patterns[1] = dvb_dmx_get_pattern(DMX_IDX_MPEG_GOP);
+		patterns[2] = dvb_dmx_get_pattern(DMX_IDX_MPEG_I_FRAME_START);
+		patterns[3] = dvb_dmx_get_pattern(DMX_IDX_MPEG_P_FRAME_START);
+		patterns[4] = dvb_dmx_get_pattern(DMX_IDX_MPEG_B_FRAME_START);
+		*patterns_num = 5;
+		break;
+
+	case DMX_VIDEO_CODEC_H264:
+		patterns[0] = dvb_dmx_get_pattern(DMX_IDX_H264_SPS);
+		patterns[1] = dvb_dmx_get_pattern(DMX_IDX_H264_PPS);
+		if (video_b_frame_events != 1) {
+			patterns[2] = dvb_dmx_get_pattern
+				(DMX_IDX_H264_IDR_START);
+			patterns[3] = dvb_dmx_get_pattern
+				(DMX_IDX_H264_NON_IDR_START);
+			patterns[4] = dvb_dmx_get_pattern(DMX_IDX_H264_SEI);
+			*patterns_num = 5;
+		} else {
+			patterns[2] = dvb_dmx_get_pattern
+				(DMX_IDX_H264_IDR_ISLICE_START);
+			patterns[3] = dvb_dmx_get_pattern
+				(DMX_IDX_H264_NON_IDR_PSLICE_START);
+			patterns[4] = dvb_dmx_get_pattern
+				(DMX_IDX_H264_NON_IDR_BSLICE_START);
+			patterns[5] = dvb_dmx_get_pattern(DMX_IDX_H264_SEI);
+			*patterns_num = 6;
+		}
+		break;
+
+	case DMX_VIDEO_CODEC_VC1:
+		patterns[0] = dvb_dmx_get_pattern(DMX_IDX_VC1_SEQ_HEADER);
+		patterns[1] = dvb_dmx_get_pattern(DMX_IDX_VC1_ENTRY_POINT);
+		patterns[2] = dvb_dmx_get_pattern(DMX_IDX_VC1_FRAME_START);
+		*patterns_num = 3;
+		break;
+
+	default:
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		*patterns_num = 0;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * mpq_dmx_update_decoder_stat -
+ * Update decoder output statistics in debug-fs.
+ *
+ * @mpq_feed: decoder feed object
+ */
+void mpq_dmx_update_decoder_stat(struct mpq_feed *mpq_feed)
+{
+	ktime_t curr_time;
+	u32 delta_time_ms;
+	struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+	enum mpq_adapter_stream_if idx;
+
+	if (!dvb_dmx_is_video_feed(mpq_feed->dvb_demux_feed) &&
+	    !dvb_dmx_is_audio_feed(mpq_feed->dvb_demux_feed))
+		return;
+
+	if (dvb_dmx_is_video_feed(mpq_feed->dvb_demux_feed) &&
+	    mpq_feed->video_info.stream_interface <=
+			MPQ_ADAPTER_VIDEO3_STREAM_IF)
+		idx = mpq_feed->video_info.stream_interface;
+	else if (dvb_dmx_is_audio_feed(mpq_feed->dvb_demux_feed) &&
+		mpq_feed->audio_info.stream_interface <=
+			MPQ_ADAPTER_AUDIO3_STREAM_IF)
+		idx = mpq_feed->audio_info.stream_interface;
+	else
+		return;
+
+	curr_time = ktime_get();
+	if (unlikely(!mpq_demux->decoder_stat[idx].out_count)) {
+		mpq_demux->decoder_stat[idx].out_last_time = curr_time;
+		mpq_demux->decoder_stat[idx].out_count++;
+		return;
+	}
+
+	/* calculate time-delta between frame */
+	delta_time_ms = mpq_dmx_calc_time_delta(curr_time,
+		mpq_demux->decoder_stat[idx].out_last_time);
+
+	mpq_demux->decoder_stat[idx].out_interval_sum += delta_time_ms;
+
+	mpq_demux->decoder_stat[idx].out_interval_average =
+	  mpq_demux->decoder_stat[idx].out_interval_sum /
+	  mpq_demux->decoder_stat[idx].out_count;
+
+	if (delta_time_ms > mpq_demux->decoder_stat[idx].out_interval_max)
+		mpq_demux->decoder_stat[idx].out_interval_max = delta_time_ms;
+
+	mpq_demux->decoder_stat[idx].out_last_time = curr_time;
+	mpq_demux->decoder_stat[idx].out_count++;
+}
+
+/*
+ * mpq_dmx_update_sdmx_stat -
+ * Update SDMX statistics in debug-fs.
+ *
+ * @mpq_demux: mpq_demux object
+ * @bytes_processed: number of bytes processed by sdmx
+ * @process_start_time: time before sdmx process was triggered
+ * @process_end_time: time after sdmx process finished
+ */
+static inline void mpq_dmx_update_sdmx_stat(struct mpq_demux *mpq_demux,
+		u32 bytes_processed, ktime_t process_start_time,
+		ktime_t process_end_time)
+{
+	u32 packets_num;
+	u32 process_time;
+
+	mpq_demux->sdmx_process_count++;
+	packets_num = bytes_processed / mpq_demux->demux.ts_packet_size;
+	mpq_demux->sdmx_process_packets_sum += packets_num;
+	mpq_demux->sdmx_process_packets_average =
+		mpq_demux->sdmx_process_packets_sum /
+		mpq_demux->sdmx_process_count;
+
+	process_time =
+		mpq_dmx_calc_time_delta(process_end_time, process_start_time);
+
+	mpq_demux->sdmx_process_time_sum += process_time;
+	mpq_demux->sdmx_process_time_average =
+		mpq_demux->sdmx_process_time_sum /
+		mpq_demux->sdmx_process_count;
+
+	if ((mpq_demux->sdmx_process_count == 1) ||
+		(packets_num < mpq_demux->sdmx_process_packets_min))
+		mpq_demux->sdmx_process_packets_min = packets_num;
+
+	if ((mpq_demux->sdmx_process_count == 1) ||
+		(process_time > mpq_demux->sdmx_process_time_max))
+		mpq_demux->sdmx_process_time_max = process_time;
+}
+
+static int mpq_sdmx_log_level_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t mpq_sdmx_log_level_read(struct file *fp,
+	char __user *user_buffer, size_t count, loff_t *position)
+{
+	char user_str[16];
+	struct mpq_demux *mpq_demux = fp->private_data;
+	int ret;
+
+	ret = scnprintf(user_str, 16, "%d", mpq_demux->sdmx_log_level);
+	ret = simple_read_from_buffer(user_buffer, count, position,
+		user_str, ret+1);
+
+	return ret;
+}
+
+static ssize_t mpq_sdmx_log_level_write(struct file *fp,
+	const char __user *user_buffer, size_t count, loff_t *position)
+{
+	char user_str[16];
+	int ret;
+	int ret_count;
+	int level;
+	struct mpq_demux *mpq_demux = fp->private_data;
+
+	if (count >= 16)
+		return -EINVAL;
+
+	ret_count = simple_write_to_buffer(user_str, 16, position, user_buffer,
+		count);
+	if (ret_count < 0)
+		return ret_count;
+
+	ret = kstrtoint(user_str, 0, &level);
+	if (ret)
+		return ret;
+
+	if (level < SDMX_LOG_NO_PRINT || level > SDMX_LOG_VERBOSE)
+		return -EINVAL;
+
+	mutex_lock(&mpq_demux->mutex);
+	mpq_demux->sdmx_log_level = level;
+	if (mpq_demux->sdmx_session_handle != SDMX_INVALID_SESSION_HANDLE) {
+		ret = sdmx_set_log_level(mpq_demux->sdmx_session_handle,
+			mpq_demux->sdmx_log_level);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: Could not set sdmx log level. ret = %d\n",
+				__func__, ret);
+			mutex_unlock(&mpq_demux->mutex);
+			return -EINVAL;
+		}
+	}
+
+	mutex_unlock(&mpq_demux->mutex);
+	return ret_count;
+}
+
+static const struct file_operations sdmx_debug_fops = {
+	.open = mpq_sdmx_log_level_open,
+	.read = mpq_sdmx_log_level_read,
+	.write = mpq_sdmx_log_level_write,
+	.owner = THIS_MODULE,
+};
+
+/* Extend dvb-demux debugfs with common plug-in entries */
+void mpq_dmx_init_debugfs_entries(struct mpq_demux *mpq_demux)
+{
+	int i;
+	char file_name[50];
+	struct dentry *debugfs_decoder_dir;
+
+	/*
+	 * Extend dvb-demux debugfs with HW statistics.
+	 * Note that destruction of debugfs directory is done
+	 * when dvb-demux is terminated.
+	 */
+	mpq_demux->hw_notification_count = 0;
+	mpq_demux->hw_notification_interval = 0;
+	mpq_demux->hw_notification_size = 0;
+	mpq_demux->hw_notification_min_size = 0xFFFFFFFF;
+
+	if (mpq_demux->demux.dmx.debugfs_demux_dir == NULL)
+		return;
+
+	debugfs_create_u32(
+		"hw_notification_interval",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->hw_notification_interval);
+
+	debugfs_create_u32(
+		"hw_notification_min_interval",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->hw_notification_min_interval);
+
+	debugfs_create_u32(
+		"hw_notification_count",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->hw_notification_count);
+
+	debugfs_create_u32(
+		"hw_notification_size",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->hw_notification_size);
+
+	debugfs_create_u32(
+		"hw_notification_min_size",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->hw_notification_min_size);
+
+	debugfs_decoder_dir = debugfs_create_dir("decoder",
+		mpq_demux->demux.dmx.debugfs_demux_dir);
+
+	for (i = 0;
+		 debugfs_decoder_dir &&
+		 (i < MPQ_ADAPTER_MAX_NUM_OF_INTERFACES);
+		 i++) {
+		snprintf(file_name, 50, "decoder%d_drop_count", i);
+		debugfs_create_u32(
+			file_name,
+			0444,
+			debugfs_decoder_dir,
+			&mpq_demux->decoder_stat[i].drop_count);
+
+		snprintf(file_name, 50, "decoder%d_out_count", i);
+		debugfs_create_u32(
+			file_name,
+			0444,
+			debugfs_decoder_dir,
+			&mpq_demux->decoder_stat[i].out_count);
+
+		snprintf(file_name, 50, "decoder%d_out_interval_sum", i);
+		debugfs_create_u32(
+			file_name,
+			0444,
+			debugfs_decoder_dir,
+			&mpq_demux->decoder_stat[i].out_interval_sum);
+
+		snprintf(file_name, 50, "decoder%d_out_interval_average", i);
+		debugfs_create_u32(
+			file_name,
+			0444,
+			debugfs_decoder_dir,
+			&mpq_demux->decoder_stat[i].out_interval_average);
+
+		snprintf(file_name, 50, "decoder%d_out_interval_max", i);
+		debugfs_create_u32(
+			file_name,
+			0444,
+			debugfs_decoder_dir,
+			&mpq_demux->decoder_stat[i].out_interval_max);
+
+		snprintf(file_name, 50, "decoder%d_ts_errors", i);
+		debugfs_create_u32(
+			file_name,
+			0444,
+			debugfs_decoder_dir,
+			&mpq_demux->decoder_stat[i].ts_errors);
+
+		snprintf(file_name, 50, "decoder%d_cc_errors", i);
+		debugfs_create_u32(
+			file_name,
+			0444,
+			debugfs_decoder_dir,
+			&mpq_demux->decoder_stat[i].cc_errors);
+	}
+
+	debugfs_create_u32(
+		"sdmx_process_count",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->sdmx_process_count);
+
+	debugfs_create_u32(
+		"sdmx_process_time_sum",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->sdmx_process_time_sum);
+
+	debugfs_create_u32(
+		"sdmx_process_time_average",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->sdmx_process_time_average);
+
+	debugfs_create_u32(
+		"sdmx_process_time_max",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->sdmx_process_time_max);
+
+	debugfs_create_u32(
+		"sdmx_process_packets_sum",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->sdmx_process_packets_sum);
+
+	debugfs_create_u32(
+		"sdmx_process_packets_average",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->sdmx_process_packets_average);
+
+	debugfs_create_u32(
+		"sdmx_process_packets_min",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		&mpq_demux->sdmx_process_packets_min);
+
+	debugfs_create_file("sdmx_log_level",
+		0664,
+		mpq_demux->demux.dmx.debugfs_demux_dir,
+		mpq_demux,
+		&sdmx_debug_fops);
+}
+
+/* Update dvb-demux debugfs with HW notification statistics */
+void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux)
+{
+	ktime_t curr_time;
+	u32 delta_time_ms;
+
+	curr_time = ktime_get();
+	if (likely(mpq_demux->hw_notification_count)) {
+		/* calculate time-delta between notifications */
+		delta_time_ms = mpq_dmx_calc_time_delta(curr_time,
+			mpq_demux->last_notification_time);
+
+		mpq_demux->hw_notification_interval = delta_time_ms;
+
+		if ((mpq_demux->hw_notification_count == 1) ||
+			(mpq_demux->hw_notification_interval &&
+			 mpq_demux->hw_notification_interval <
+				mpq_demux->hw_notification_min_interval))
+			mpq_demux->hw_notification_min_interval =
+				mpq_demux->hw_notification_interval;
+	}
+
+	mpq_demux->hw_notification_count++;
+	mpq_demux->last_notification_time = curr_time;
+}
+
+static void mpq_sdmx_check_app_loaded(void)
+{
+	int session;
+	u32 version;
+	int ret;
+
+	ret = sdmx_open_session(&session);
+	if (ret != SDMX_SUCCESS) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Could not initialize session with SDMX. ret = %d\n",
+			__func__, ret);
+		mpq_dmx_info.secure_demux_app_loaded = 0;
+		return;
+	}
+
+	/* Check proper sdmx major version */
+	ret = sdmx_get_version(session, &version);
+	if (ret != SDMX_SUCCESS) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Could not get sdmx version. ret = %d\n",
+			__func__, ret);
+	} else {
+		if ((version >> 8) != SDMX_MAJOR_VERSION_MATCH)
+			MPQ_DVB_ERR_PRINT(
+				"%s: sdmx major version does not match. expected=%d, actual=%d\n",
+				__func__, SDMX_MAJOR_VERSION_MATCH,
+				(version >> 8));
+		else
+			MPQ_DVB_DBG_PRINT(
+				"%s: sdmx major version is ok = %d\n",
+				__func__, SDMX_MAJOR_VERSION_MATCH);
+	}
+
+	mpq_dmx_info.secure_demux_app_loaded = 1;
+	sdmx_close_session(session);
+}
+
+int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func)
+{
+	int i;
+	int j;
+	int result;
+	struct mpq_demux *mpq_demux;
+	struct dvb_adapter *mpq_adapter;
+	struct mpq_feed *feed;
+
+	MPQ_DVB_DBG_PRINT("%s executed, device num %d\n",
+					  __func__,
+					  mpq_demux_device_num);
+
+	mpq_adapter = mpq_adapter_get();
+
+	if (mpq_adapter == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_adapter is not valid\n",
+			__func__);
+		result = -EPERM;
+		goto init_failed;
+	}
+
+	if (mpq_demux_device_num == 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_demux_device_num set to 0\n",
+			__func__);
+
+		result = -EPERM;
+		goto init_failed;
+	}
+
+	mpq_dmx_info.devices = NULL;
+	mpq_dmx_info.ion_client = NULL;
+
+	mpq_dmx_info.secure_demux_app_loaded = 0;
+
+	/* Allocate memory for all MPQ devices */
+	mpq_dmx_info.devices =
+		vzalloc(mpq_demux_device_num*sizeof(struct mpq_demux));
+
+	if (!mpq_dmx_info.devices) {
+		MPQ_DVB_ERR_PRINT(
+				"%s: failed to allocate devices memory\n",
+				__func__);
+
+		result = -ENOMEM;
+		goto init_failed;
+	}
+
+	/*
+	 * Create a new ION client used by demux to allocate memory
+	 * for decoder's buffers.
+	 */
+	mpq_dmx_info.ion_client =
+		msm_ion_client_create("demux_client");
+	if (IS_ERR_OR_NULL(mpq_dmx_info.ion_client)) {
+		MPQ_DVB_ERR_PRINT(
+				"%s: msm_ion_client_create\n",
+				__func__);
+
+		result = PTR_ERR(mpq_dmx_info.ion_client);
+		if (!result)
+			result = -ENOMEM;
+		mpq_dmx_info.ion_client = NULL;
+		goto init_failed_free_demux_devices;
+	}
+
+	/* Initialize and register all demux devices to the system */
+	for (i = 0; i < mpq_demux_device_num; i++) {
+		mpq_demux = mpq_dmx_info.devices+i;
+		mpq_demux->idx = i;
+
+		/* initialize demux source to memory by default */
+		mpq_demux->source = DMX_SOURCE_DVR0 + i;
+
+		/*
+		 * Give the plugin pointer to the ion client so
+		 * that it can allocate memory from ION if it requires so
+		 */
+		mpq_demux->ion_client = mpq_dmx_info.ion_client;
+
+		mutex_init(&mpq_demux->mutex);
+
+		mpq_demux->num_secure_feeds = 0;
+		mpq_demux->num_active_feeds = 0;
+		mpq_demux->sdmx_filter_count = 0;
+		mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
+		mpq_demux->sdmx_eos = 0;
+		mpq_demux->sdmx_log_level = SDMX_LOG_NO_PRINT;
+		mpq_demux->ts_packet_timestamp_source = 0;
+
+		if (mpq_demux->demux.feednum > MPQ_MAX_DMX_FILES) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: err - actual feednum (%d) larger than max, enlarge MPQ_MAX_DMX_FILES!\n",
+				__func__,
+				mpq_demux->demux.feednum);
+			result = -EINVAL;
+			goto init_failed_free_demux_devices;
+		}
+
+		/* Initialize private feed info */
+		for (j = 0; j < MPQ_MAX_DMX_FILES; j++) {
+			feed = &mpq_demux->feeds[j];
+			memset(feed, 0, sizeof(*feed));
+			feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE;
+			feed->mpq_demux = mpq_demux;
+			feed->session_id = 0;
+		}
+
+		/*
+		 * mpq_demux_plugin_hw_init should be implemented
+		 * by the specific plugin
+		 */
+		result = dmx_init_func(mpq_adapter, mpq_demux);
+		if (result < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: dmx_init_func (errno=%d)\n",
+				__func__,
+				result);
+
+			goto init_failed_free_demux_devices;
+		}
+
+		mpq_demux->is_initialized = 1;
+
+		/*
+		 * dvb-demux is now initialized,
+		 * update back-pointers of private feeds
+		 */
+		for (j = 0; j < MPQ_MAX_DMX_FILES; j++) {
+			feed = &mpq_demux->feeds[j];
+			feed->dvb_demux_feed = &mpq_demux->demux.feed[j];
+			mpq_demux->demux.feed[j].priv = feed;
+		}
+
+		/*
+		 * Add capability of receiving input from memory.
+		 * Every demux in our system may be connected to memory input,
+		 * or any live input.
+		 */
+		mpq_demux->fe_memory.source = DMX_MEMORY_FE;
+		result =
+			mpq_demux->demux.dmx.add_frontend(
+					&mpq_demux->demux.dmx,
+					&mpq_demux->fe_memory);
+
+		if (result < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: add_frontend (mem) failed (errno=%d)\n",
+				__func__,
+				result);
+
+			goto init_failed_free_demux_devices;
+		}
+	}
+
+	return 0;
+
+init_failed_free_demux_devices:
+	mpq_dmx_plugin_exit();
+init_failed:
+	return result;
+}
+
+void mpq_dmx_plugin_exit(void)
+{
+	int i;
+	struct mpq_demux *mpq_demux;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	if (mpq_dmx_info.ion_client != NULL) {
+		ion_client_destroy(mpq_dmx_info.ion_client);
+		mpq_dmx_info.ion_client = NULL;
+	}
+
+	if (mpq_dmx_info.devices != NULL) {
+		for (i = 0; i < mpq_demux_device_num; i++) {
+			mpq_demux = mpq_dmx_info.devices + i;
+
+			if (!mpq_demux->is_initialized)
+				continue;
+
+			if (mpq_demux->mpq_dmx_plugin_release)
+				mpq_demux->mpq_dmx_plugin_release(mpq_demux);
+
+			mpq_demux->demux.dmx.remove_frontend(
+						&mpq_demux->demux.dmx,
+						&mpq_demux->fe_memory);
+
+			if (mpq_dmx_info.secure_demux_app_loaded)
+				mpq_sdmx_close_session(mpq_demux);
+			mutex_destroy(&mpq_demux->mutex);
+			dvb_dmxdev_release(&mpq_demux->dmxdev);
+			dvb_dmx_release(&mpq_demux->demux);
+		}
+
+		vfree(mpq_dmx_info.devices);
+		mpq_dmx_info.devices = NULL;
+	}
+}
+
+int mpq_dmx_set_source(
+		struct dmx_demux *demux,
+		const dmx_source_t *src)
+{
+	int i;
+	int dvr_index;
+	int dmx_index;
+	struct dvb_demux *dvb_demux = demux->priv;
+	struct mpq_demux *mpq_demux;
+
+	if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL)) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	mpq_demux = dvb_demux->priv;
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * For dvr sources,
+	 * verify that this source is connected to the respective demux
+	 */
+	dmx_index = mpq_demux - mpq_dmx_info.devices;
+
+	if (*src >= DMX_SOURCE_DVR0) {
+		dvr_index = *src - DMX_SOURCE_DVR0;
+
+		if (dvr_index != dmx_index) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: can't connect demux%d to dvr%d\n",
+				__func__,
+				dmx_index,
+				dvr_index);
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * For front-end sources,
+	 * verify that this source is not already set to different demux
+	 */
+	for (i = 0; i < mpq_demux_device_num; i++) {
+		if ((&mpq_dmx_info.devices[i] != mpq_demux) &&
+			(mpq_dmx_info.devices[i].source == *src)) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: demux%d source can't be set,\n"
+				"demux%d occupies this source already\n",
+				__func__,
+				dmx_index,
+				i);
+			return -EBUSY;
+		}
+	}
+
+	mpq_demux->source = *src;
+	return 0;
+}
+
+/**
+ * Takes an ION allocated buffer's file descriptor and handles the details of
+ * mapping it into kernel memory and obtaining an ION handle for it.
+ * Internal helper function.
+ *
+ * @client: ION client
+ * @handle: ION file descriptor to map
+ * @priv_handle: returned ION handle. Must be freed when no longer needed
+ * @kernel_mem: returned kernel mapped pointer
+ *
+ * Note: mapping might not be possible in secured heaps/buffers, and so NULL
+ * might be returned in kernel_mem
+ *
+ * Return errors status
+ */
+static int mpq_map_buffer_to_kernel(
+	struct ion_client *client,
+	int handle,
+	struct ion_handle **priv_handle,
+	void **kernel_mem)
+{
+	struct ion_handle *ion_handle;
+	unsigned long ionflag = 0;
+	int ret;
+
+	if (client == NULL || priv_handle == NULL || kernel_mem == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	ion_handle = ion_import_dma_buf_fd(client, handle);
+	if (IS_ERR_OR_NULL(ion_handle)) {
+		ret = PTR_ERR(ion_handle);
+		MPQ_DVB_ERR_PRINT("%s: ion_import_dma_buf failed %d\n",
+			__func__, ret);
+		if (!ret)
+			ret = -ENOMEM;
+
+		goto map_buffer_failed;
+	}
+
+	ret = ion_handle_get_flags(client, ion_handle, &ionflag);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT("%s: ion_handle_get_flags failed %d\n",
+			__func__, ret);
+		goto map_buffer_failed_free_buff;
+	}
+
+	if (ionflag & ION_FLAG_SECURE) {
+		MPQ_DVB_DBG_PRINT("%s: secured buffer\n", __func__);
+		*kernel_mem = NULL;
+	} else {
+		size_t tmp;
+		*kernel_mem = ion_map_kernel(client, ion_handle);
+		if (IS_ERR_OR_NULL(*kernel_mem)) {
+			ret = PTR_ERR(*kernel_mem);
+			MPQ_DVB_ERR_PRINT("%s: ion_map_kernel failed, ret=%d\n",
+				__func__, ret);
+			if (!ret)
+				ret = -ENOMEM;
+			goto map_buffer_failed_free_buff;
+		}
+		ion_handle_get_size(client, ion_handle, &tmp);
+		MPQ_DVB_DBG_PRINT(
+			"%s: mapped to address 0x%p, size=%zu\n",
+			__func__, *kernel_mem, tmp);
+	}
+
+	*priv_handle = ion_handle;
+	return 0;
+
+map_buffer_failed_free_buff:
+	ion_free(client, ion_handle);
+map_buffer_failed:
+	return ret;
+}
+
+int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer,
+		void **priv_handle, void **kernel_mem)
+{
+	struct dvb_demux *dvb_demux = demux->priv;
+	struct mpq_demux *mpq_demux;
+
+	if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) ||
+		(priv_handle == NULL) || (kernel_mem == NULL)) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	mpq_demux = dvb_demux->priv;
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	return mpq_map_buffer_to_kernel(
+		mpq_demux->ion_client,
+		dmx_buffer->handle,
+		(struct ion_handle **)priv_handle, kernel_mem);
+}
+
+int mpq_dmx_unmap_buffer(struct dmx_demux *demux,
+		void *priv_handle)
+{
+	struct dvb_demux *dvb_demux = demux->priv;
+	struct ion_handle *ion_handle = priv_handle;
+	struct mpq_demux *mpq_demux;
+	unsigned long ionflag = 0;
+	int ret;
+
+	if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) ||
+		(priv_handle == NULL)) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	mpq_demux = dvb_demux->priv;
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = ion_handle_get_flags(mpq_demux->ion_client, ion_handle, &ionflag);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT("%s: ion_handle_get_flags failed %d\n",
+			__func__, ret);
+		return -EINVAL;
+	}
+
+	if (!(ionflag & ION_FLAG_SECURE))
+		ion_unmap_kernel(mpq_demux->ion_client, ion_handle);
+
+	ion_free(mpq_demux->ion_client, ion_handle);
+
+	return 0;
+}
+
+int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie)
+{
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	MPQ_DVB_DBG_PRINT("%s: cookie=%d\n", __func__, cookie);
+
+	if (cookie < 0) {
+		MPQ_DVB_ERR_PRINT("%s: invalid cookie parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	if (dvb_dmx_is_video_feed(feed)) {
+		struct mpq_video_feed_info *feed_data;
+		struct mpq_feed *mpq_feed;
+		struct mpq_streambuffer *stream_buffer;
+		int ret;
+
+		mutex_lock(&mpq_demux->mutex);
+		mpq_feed = feed->priv;
+		feed_data = &mpq_feed->video_info;
+
+		spin_lock(&feed_data->video_buffer_lock);
+		stream_buffer = feed_data->video_buffer;
+		if (stream_buffer == NULL) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: invalid feed, feed_data->video_buffer is NULL\n",
+				__func__);
+			spin_unlock(&feed_data->video_buffer_lock);
+			mutex_unlock(&mpq_demux->mutex);
+			return -EINVAL;
+		}
+
+		ret = mpq_streambuffer_pkt_dispose(stream_buffer, cookie, 1);
+		spin_unlock(&feed_data->video_buffer_lock);
+		mutex_unlock(&mpq_demux->mutex);
+
+		return ret;
+	} else if (dvb_dmx_is_audio_feed(feed)) {
+		struct mpq_audio_feed_info *feed_data;
+		struct mpq_feed *mpq_feed;
+		struct mpq_streambuffer *stream_buffer;
+		int ret;
+
+		mutex_lock(&mpq_demux->mutex);
+		mpq_feed = feed->priv;
+		feed_data = &mpq_feed->audio_info;
+
+		spin_lock(&feed_data->audio_buffer_lock);
+		stream_buffer = feed_data->audio_buffer;
+		if (stream_buffer == NULL) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: invalid feed, feed_data->audio_buffer is NULL\n",
+				__func__);
+			spin_unlock(&feed_data->audio_buffer_lock);
+			mutex_unlock(&mpq_demux->mutex);
+			return -EINVAL;
+		}
+
+		ret = mpq_streambuffer_pkt_dispose(stream_buffer, cookie, 1);
+		spin_unlock(&feed_data->audio_buffer_lock);
+		mutex_unlock(&mpq_demux->mutex);
+
+		return ret;
+	}
+	MPQ_DVB_ERR_PRINT("%s: Invalid feed type %d\n",
+			__func__, feed->pes_type);
+
+	return -EINVAL;
+}
+
+/**
+ * Handles the details of internal decoder buffer allocation via ION.
+ * Internal helper function.
+ * @feed_data: decoder feed object
+ * @dec_buffs: buffer information
+ * @client: ION client
+ *
+ * Return error status
+ */
+static int mpq_dmx_init_internal_buffers(
+	struct mpq_demux *mpq_demux,
+	struct mpq_video_feed_info *feed_data,
+	struct dmx_decoder_buffers *dec_buffs)
+{
+	struct ion_handle *temp_handle = NULL;
+	void *payload_buffer = NULL;
+	int actual_buffer_size = 0;
+	int ret = 0;
+
+	MPQ_DVB_DBG_PRINT("%s: Internal decoder buffer allocation\n", __func__);
+
+	actual_buffer_size = dec_buffs->buffers_size;
+	actual_buffer_size += (SZ_4K - 1);
+	actual_buffer_size &= ~(SZ_4K - 1);
+
+	temp_handle = ion_alloc(mpq_demux->ion_client,
+		actual_buffer_size, SZ_4K,
+		ION_HEAP(video_secure_ion_heap) |
+		ION_HEAP(video_nonsecure_ion_heap),
+		mpq_demux->decoder_alloc_flags);
+
+	if (IS_ERR_OR_NULL(temp_handle)) {
+		ret = PTR_ERR(temp_handle);
+		MPQ_DVB_ERR_PRINT("%s: FAILED to allocate payload buffer %d\n",
+			__func__, ret);
+		if (!ret)
+			ret = -ENOMEM;
+		goto end;
+	}
+
+	payload_buffer = ion_map_kernel(mpq_demux->ion_client, temp_handle);
+
+	if (IS_ERR_OR_NULL(payload_buffer)) {
+		ret = PTR_ERR(payload_buffer);
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to map payload buffer %d\n",
+			__func__, ret);
+		if (!ret)
+			ret = -ENOMEM;
+		goto init_failed_free_payload_buffer;
+	}
+
+	feed_data->buffer_desc.decoder_buffers_num = 1;
+	feed_data->buffer_desc.ion_handle[0] = temp_handle;
+	feed_data->buffer_desc.desc[0].base = payload_buffer;
+	feed_data->buffer_desc.desc[0].size = actual_buffer_size;
+	feed_data->buffer_desc.desc[0].read_ptr = 0;
+	feed_data->buffer_desc.desc[0].write_ptr = 0;
+	feed_data->buffer_desc.desc[0].handle =
+		ion_share_dma_buf_fd(mpq_demux->ion_client, temp_handle);
+
+	if (feed_data->buffer_desc.desc[0].handle < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to share payload buffer %d\n",
+			__func__, ret);
+		ret = -ENOMEM;
+		goto init_failed_unmap_payload_buffer;
+	}
+
+	feed_data->buffer_desc.shared_file = fget(
+		feed_data->buffer_desc.desc[0].handle);
+
+	return 0;
+
+init_failed_unmap_payload_buffer:
+	ion_unmap_kernel(mpq_demux->ion_client, temp_handle);
+	feed_data->buffer_desc.desc[0].base = NULL;
+init_failed_free_payload_buffer:
+	ion_free(mpq_demux->ion_client, temp_handle);
+	feed_data->buffer_desc.ion_handle[0] = NULL;
+	feed_data->buffer_desc.desc[0].size = 0;
+	feed_data->buffer_desc.decoder_buffers_num = 0;
+	feed_data->buffer_desc.shared_file = NULL;
+end:
+	return ret;
+
+}
+
+/**
+ * Handles the details of external decoder buffers allocated by user.
+ * Each buffer is mapped into kernel memory and an ION handle is obtained, and
+ * decoder feed object is updated with related information.
+ * Internal helper function.
+ * @feed_data: decoder feed object
+ * @dec_buffs: buffer information
+ * @client: ION client
+ *
+ * Return error status
+ */
+static int mpq_dmx_init_external_buffers(
+	struct mpq_video_feed_info *feed_data,
+	struct dmx_decoder_buffers *dec_buffs,
+	struct ion_client *client)
+{
+	struct ion_handle *temp_handle = NULL;
+	void *payload_buffer = NULL;
+	int actual_buffer_size = 0;
+	int ret = 0;
+	int i;
+
+	/*
+	 * Payload buffer was allocated externally (through ION).
+	 * Map the ion handles to kernel memory
+	 */
+	MPQ_DVB_DBG_PRINT("%s: External decoder buffer allocation\n", __func__);
+
+	actual_buffer_size = dec_buffs->buffers_size;
+	if (!dec_buffs->is_linear) {
+		MPQ_DVB_DBG_PRINT("%s: Ex. Ring-buffer\n", __func__);
+		feed_data->buffer_desc.decoder_buffers_num = 1;
+	} else {
+		MPQ_DVB_DBG_PRINT("%s: Ex. Linear\n", __func__);
+		feed_data->buffer_desc.decoder_buffers_num =
+			dec_buffs->buffers_num;
+	}
+
+	for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+		ret = mpq_map_buffer_to_kernel(
+			client,
+			dec_buffs->handles[i],
+			&temp_handle,
+			&payload_buffer);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: Failed mapping buffer %d\n",
+				__func__, i);
+			goto init_failed;
+		}
+		feed_data->buffer_desc.ion_handle[i] = temp_handle;
+		feed_data->buffer_desc.desc[i].base = payload_buffer;
+		feed_data->buffer_desc.desc[i].handle =
+			dec_buffs->handles[i];
+		feed_data->buffer_desc.desc[i].size =
+			dec_buffs->buffers_size;
+		feed_data->buffer_desc.desc[i].read_ptr = 0;
+		feed_data->buffer_desc.desc[i].write_ptr = 0;
+
+		MPQ_DVB_DBG_PRINT(
+			"%s: Buffer #%d: base=0x%p, handle=%d, size=%d\n",
+			__func__, i,
+			feed_data->buffer_desc.desc[i].base,
+			feed_data->buffer_desc.desc[i].handle,
+			feed_data->buffer_desc.desc[i].size);
+	}
+
+	return 0;
+
+init_failed:
+	for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+		if (feed_data->buffer_desc.ion_handle[i]) {
+			if (feed_data->buffer_desc.desc[i].base) {
+				ion_unmap_kernel(client,
+					feed_data->buffer_desc.ion_handle[i]);
+				feed_data->buffer_desc.desc[i].base = NULL;
+			}
+			ion_free(client, feed_data->buffer_desc.ion_handle[i]);
+			feed_data->buffer_desc.ion_handle[i] = NULL;
+			feed_data->buffer_desc.desc[i].size = 0;
+		}
+	}
+	return ret;
+}
+
+/**
+ * Handles the details of initializing the mpq_streambuffer object according
+ * to the user decoder buffer configuration: External/Internal buffers and
+ * ring/linear buffering mode.
+ * Internal helper function.
+ * @feed:  dvb demux feed object, contains the buffers configuration
+ * @feed_data: decoder feed object
+ * @stream_buffer: stream buffer object to initialize
+ *
+ * Return error status
+ */
+static int mpq_dmx_init_streambuffer(
+	struct mpq_feed *feed,
+	struct mpq_video_feed_info *feed_data,
+	struct mpq_streambuffer *stream_buffer)
+{
+	int ret;
+	void *packet_buffer = NULL;
+	struct mpq_demux *mpq_demux = feed->mpq_demux;
+	struct ion_client *client = mpq_demux->ion_client;
+	struct dmx_decoder_buffers *dec_buffs = NULL;
+	enum mpq_streambuffer_mode mode;
+
+	dec_buffs = feed->dvb_demux_feed->feed.ts.decoder_buffers;
+
+	/* Allocate packet buffer holding the meta-data */
+	packet_buffer = vmalloc(VIDEO_META_DATA_BUFFER_SIZE);
+
+	if (packet_buffer == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to allocate packets buffer\n",
+			__func__);
+
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	MPQ_DVB_DBG_PRINT("%s: dec_buffs: num=%d, size=%d, linear=%d\n",
+			__func__,
+			dec_buffs->buffers_num,
+			dec_buffs->buffers_size,
+			dec_buffs->is_linear);
+
+	if (dec_buffs->buffers_num == 0)
+		ret = mpq_dmx_init_internal_buffers(
+			mpq_demux, feed_data, dec_buffs);
+	else
+		ret = mpq_dmx_init_external_buffers(
+			feed_data, dec_buffs, client);
+
+	if (ret != 0)
+		goto init_failed_free_packet_buffer;
+
+	mode = dec_buffs->is_linear ? MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR :
+		MPQ_STREAMBUFFER_BUFFER_MODE_RING;
+	ret = mpq_streambuffer_init(
+			feed_data->video_buffer,
+			mode,
+			feed_data->buffer_desc.desc,
+			feed_data->buffer_desc.decoder_buffers_num,
+			packet_buffer,
+			VIDEO_META_DATA_BUFFER_SIZE);
+
+	if (ret != 0)
+		goto init_failed_free_packet_buffer;
+
+	goto end;
+
+
+init_failed_free_packet_buffer:
+	vfree(packet_buffer);
+end:
+	return ret;
+}
+
+static void mpq_dmx_release_streambuffer(
+	struct mpq_feed *feed,
+	struct mpq_video_feed_info *feed_data,
+	struct mpq_streambuffer *video_buffer,
+	struct ion_client *client)
+{
+	int buf_num = 0;
+	int i;
+	struct dmx_decoder_buffers *dec_buffs =
+		feed->dvb_demux_feed->feed.ts.decoder_buffers;
+
+	mpq_adapter_unregister_stream_if(feed_data->stream_interface);
+
+	mpq_streambuffer_terminate(video_buffer);
+
+	vfree(video_buffer->packet_data.data);
+
+	buf_num = feed_data->buffer_desc.decoder_buffers_num;
+
+	for (i = 0; i < buf_num; i++) {
+		if (feed_data->buffer_desc.ion_handle[i]) {
+			if (feed_data->buffer_desc.desc[i].base) {
+				ion_unmap_kernel(client,
+					feed_data->buffer_desc.ion_handle[i]);
+				feed_data->buffer_desc.desc[i].base = NULL;
+			}
+
+			/*
+			 * Un-share the buffer if kernel it the one that
+			 * shared it.
+			 */
+			if (!dec_buffs->buffers_num &&
+				feed_data->buffer_desc.shared_file) {
+				fput(feed_data->buffer_desc.shared_file);
+				feed_data->buffer_desc.shared_file = NULL;
+			}
+
+			ion_free(client, feed_data->buffer_desc.ion_handle[i]);
+			feed_data->buffer_desc.ion_handle[i] = NULL;
+			feed_data->buffer_desc.desc[i].size = 0;
+		}
+	}
+}
+
+int mpq_dmx_flush_stream_buffer(struct dvb_demux_feed *feed)
+{
+	struct mpq_feed *mpq_feed = feed->priv;
+	struct mpq_video_feed_info *feed_data = &mpq_feed->video_info;
+	struct mpq_streambuffer *sbuff;
+	int ret = 0;
+
+	if (!dvb_dmx_is_video_feed(feed)) {
+		MPQ_DVB_DBG_PRINT("%s: not a video feed, feed type=%d\n",
+			__func__, feed->pes_type);
+		return 0;
+	}
+
+	spin_lock(&feed_data->video_buffer_lock);
+
+	sbuff = feed_data->video_buffer;
+	if (sbuff == NULL) {
+		MPQ_DVB_DBG_PRINT("%s: feed_data->video_buffer is NULL\n",
+			__func__);
+		spin_unlock(&feed_data->video_buffer_lock);
+		return -ENODEV;
+	}
+
+	feed_data->pending_pattern_len = 0;
+
+	ret = mpq_streambuffer_flush(sbuff);
+	if (ret)
+		MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer_flush failed, ret=%d\n",
+			__func__, ret);
+
+	spin_unlock(&feed_data->video_buffer_lock);
+
+	return ret;
+}
+
+static int mpq_dmx_init_audio_internal_buffers(
+	struct mpq_demux *mpq_demux,
+	struct mpq_audio_feed_info *feed_data,
+	struct dmx_decoder_buffers *dec_buffs)
+{
+	struct ion_handle *temp_handle = NULL;
+	void *payload_buffer = NULL;
+	int actual_buffer_size = 0;
+	int ret = 0;
+
+	MPQ_DVB_DBG_PRINT("%s: Internal audio decoder buffer allocation\n",
+			  __func__);
+
+	actual_buffer_size = dec_buffs->buffers_size;
+	actual_buffer_size += (SZ_4K - 1);
+	actual_buffer_size &= ~(SZ_4K - 1);
+
+	temp_handle = ion_alloc(mpq_demux->ion_client,
+		actual_buffer_size, SZ_4K,
+		ION_HEAP(audio_nonsecure_ion_heap),
+		mpq_demux->decoder_alloc_flags);
+
+	if (IS_ERR_OR_NULL(temp_handle)) {
+		ret = PTR_ERR(temp_handle);
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to allocate audio payload buffer %d\n",
+			 __func__, ret);
+		if (!ret)
+			ret = -ENOMEM;
+		goto end;
+	}
+
+	payload_buffer = ion_map_kernel(mpq_demux->ion_client, temp_handle);
+
+	if (IS_ERR_OR_NULL(payload_buffer)) {
+		ret = PTR_ERR(payload_buffer);
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to map audio payload buffer %d\n",
+			__func__, ret);
+		if (!ret)
+			ret = -ENOMEM;
+		goto init_failed_free_payload_buffer;
+	}
+	feed_data->buffer_desc.decoder_buffers_num = 1;
+	feed_data->buffer_desc.ion_handle[0] = temp_handle;
+	feed_data->buffer_desc.desc[0].base = payload_buffer;
+	feed_data->buffer_desc.desc[0].size = actual_buffer_size;
+	feed_data->buffer_desc.desc[0].read_ptr = 0;
+	feed_data->buffer_desc.desc[0].write_ptr = 0;
+	feed_data->buffer_desc.desc[0].handle =
+		ion_share_dma_buf_fd(mpq_demux->ion_client, temp_handle);
+	if (feed_data->buffer_desc.desc[0].handle < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to share audio payload buffer %d\n",
+			__func__, ret);
+		ret = -ENOMEM;
+		goto init_failed_unmap_payload_buffer;
+	}
+
+	feed_data->buffer_desc.shared_file = fget(
+		feed_data->buffer_desc.desc[0].handle);
+
+	return 0;
+
+init_failed_unmap_payload_buffer:
+	ion_unmap_kernel(mpq_demux->ion_client, temp_handle);
+	feed_data->buffer_desc.desc[0].base = NULL;
+init_failed_free_payload_buffer:
+	ion_free(mpq_demux->ion_client, temp_handle);
+	feed_data->buffer_desc.ion_handle[0] = NULL;
+	feed_data->buffer_desc.desc[0].size = 0;
+	feed_data->buffer_desc.decoder_buffers_num = 0;
+	feed_data->buffer_desc.shared_file = NULL;
+end:
+	return ret;
+}
+
+static int mpq_dmx_init_audio_external_buffers(
+	struct mpq_audio_feed_info *feed_data,
+	struct dmx_decoder_buffers *dec_buffs,
+	struct ion_client *client)
+{
+	struct ion_handle *temp_handle = NULL;
+	void *payload_buffer = NULL;
+	int actual_buffer_size = 0;
+	int ret = 0;
+	int i;
+
+	/*
+	 * Payload buffer was allocated externally (through ION).
+	 * Map the ion handles to kernel memory
+	 */
+	MPQ_DVB_DBG_PRINT("%s: External audio decoder buffer allocation\n",
+				__func__);
+
+	actual_buffer_size = dec_buffs->buffers_size;
+	if (!dec_buffs->is_linear) {
+		MPQ_DVB_DBG_PRINT("%s: Ex. Ring-buffer\n", __func__);
+		feed_data->buffer_desc.decoder_buffers_num = 1;
+	} else {
+		MPQ_DVB_DBG_PRINT("%s: Ex. Linear\n", __func__);
+		feed_data->buffer_desc.decoder_buffers_num =
+			dec_buffs->buffers_num;
+	}
+
+	for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+		ret = mpq_map_buffer_to_kernel(
+			client,
+			dec_buffs->handles[i],
+			&temp_handle,
+			&payload_buffer);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: Failed mapping audio buffer %d\n",
+				__func__, i);
+			goto init_failed;
+		}
+		feed_data->buffer_desc.ion_handle[i] = temp_handle;
+		feed_data->buffer_desc.desc[i].base = payload_buffer;
+		feed_data->buffer_desc.desc[i].handle =
+			dec_buffs->handles[i];
+		feed_data->buffer_desc.desc[i].size =
+			dec_buffs->buffers_size;
+		feed_data->buffer_desc.desc[i].read_ptr = 0;
+		feed_data->buffer_desc.desc[i].write_ptr = 0;
+
+		MPQ_DVB_DBG_PRINT(
+			"%s: Audio Buffer #%d: base=0x%p, handle=%d, size=%d\n",
+			__func__, i,
+			feed_data->buffer_desc.desc[i].base,
+			feed_data->buffer_desc.desc[i].handle,
+			feed_data->buffer_desc.desc[i].size);
+	}
+
+	return 0;
+
+init_failed:
+	for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+		if (feed_data->buffer_desc.ion_handle[i]) {
+			if (feed_data->buffer_desc.desc[i].base) {
+				ion_unmap_kernel(client,
+					feed_data->buffer_desc.ion_handle[i]);
+				feed_data->buffer_desc.desc[i].base = NULL;
+			}
+			ion_free(client, feed_data->buffer_desc.ion_handle[i]);
+			feed_data->buffer_desc.ion_handle[i] = NULL;
+			feed_data->buffer_desc.desc[i].size = 0;
+		}
+	}
+	return ret;
+}
+static int mpq_dmx_init_audio_streambuffer(
+	struct mpq_feed *feed,
+	struct mpq_audio_feed_info *feed_data,
+	struct mpq_streambuffer *stream_buffer)
+{
+	int ret;
+	void *packet_buffer = NULL;
+	struct mpq_demux *mpq_demux = feed->mpq_demux;
+	struct ion_client *client = mpq_demux->ion_client;
+	struct dmx_decoder_buffers *dec_buffs = NULL;
+	enum mpq_streambuffer_mode mode;
+
+	dec_buffs = feed->dvb_demux_feed->feed.ts.decoder_buffers;
+
+	/* Allocate packet buffer holding the meta-data */
+	packet_buffer = vmalloc(AUDIO_META_DATA_BUFFER_SIZE);
+
+	if (packet_buffer == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to allocate packets buffer\n", __func__);
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	MPQ_DVB_DBG_PRINT("%s: dec_buffs: num=%d, size=%d, linear=%d\n",
+				__func__, dec_buffs->buffers_num,
+				dec_buffs->buffers_size,
+				dec_buffs->is_linear);
+
+	if (dec_buffs->buffers_num == 0)
+		ret = mpq_dmx_init_audio_internal_buffers(
+			mpq_demux, feed_data, dec_buffs);
+	else
+		ret = mpq_dmx_init_audio_external_buffers(
+			feed_data, dec_buffs, client);
+
+	if (ret != 0)
+		goto init_failed_free_packet_buffer;
+
+	mode = dec_buffs->is_linear ? MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR :
+		MPQ_STREAMBUFFER_BUFFER_MODE_RING;
+	ret = mpq_streambuffer_init(
+			feed_data->audio_buffer,
+			mode,
+			feed_data->buffer_desc.desc,
+			feed_data->buffer_desc.decoder_buffers_num,
+			packet_buffer,
+			AUDIO_META_DATA_BUFFER_SIZE);
+
+	if (ret != 0)
+		goto init_failed_free_packet_buffer;
+
+	goto end;
+
+
+init_failed_free_packet_buffer:
+	vfree(packet_buffer);
+end:
+	return ret;
+}
+
+static void mpq_dmx_release_audio_streambuffer(
+	struct mpq_feed *feed,
+	struct mpq_audio_feed_info *feed_data,
+	struct mpq_streambuffer *audio_buffer,
+	struct ion_client *client)
+{
+	int buf_num = 0;
+	int i;
+	struct dmx_decoder_buffers *dec_buffs =
+		feed->dvb_demux_feed->feed.ts.decoder_buffers;
+
+	mpq_adapter_unregister_stream_if(feed_data->stream_interface);
+
+	mpq_streambuffer_terminate(audio_buffer);
+
+	vfree(audio_buffer->packet_data.data);
+
+	buf_num = feed_data->buffer_desc.decoder_buffers_num;
+
+	for (i = 0; i < buf_num; i++) {
+		if (feed_data->buffer_desc.ion_handle[i]) {
+			if (feed_data->buffer_desc.desc[i].base) {
+				ion_unmap_kernel(client,
+					feed_data->buffer_desc.ion_handle[i]);
+				feed_data->buffer_desc.desc[i].base = NULL;
+			}
+
+			/*
+			 * Un-share the buffer if kernel is the one that
+			 * shared it.
+			 */
+			if (!dec_buffs->buffers_num &&
+				feed_data->buffer_desc.shared_file) {
+				fput(feed_data->buffer_desc.shared_file);
+				feed_data->buffer_desc.shared_file = NULL;
+			}
+
+			ion_free(client, feed_data->buffer_desc.ion_handle[i]);
+			feed_data->buffer_desc.ion_handle[i] = NULL;
+			feed_data->buffer_desc.desc[i].size = 0;
+		}
+	}
+}
+
+int mpq_dmx_flush_audio_stream_buffer(struct dvb_demux_feed *feed)
+{
+	struct mpq_feed *mpq_feed = feed->priv;
+	struct mpq_audio_feed_info *feed_data = &mpq_feed->audio_info;
+	struct mpq_streambuffer *sbuff;
+	int ret = 0;
+
+	if (!dvb_dmx_is_audio_feed(feed)) {
+		MPQ_DVB_DBG_PRINT("%s: not a audio feed, feed type=%d\n",
+			__func__, feed->pes_type);
+		return 0;
+	}
+
+	spin_lock(&feed_data->audio_buffer_lock);
+
+	sbuff = feed_data->audio_buffer;
+	if (sbuff == NULL) {
+		MPQ_DVB_DBG_PRINT("%s: feed_data->audio_buffer is NULL\n",
+			__func__);
+		spin_unlock(&feed_data->audio_buffer_lock);
+		return -ENODEV;
+	}
+
+	ret = mpq_streambuffer_flush(sbuff);
+	if (ret)
+		MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer_flush failed, ret=%d\n",
+			__func__, ret);
+
+	spin_unlock(&feed_data->audio_buffer_lock);
+
+	return ret;
+}
+
+static int mpq_dmx_flush_buffer(struct dmx_ts_feed *ts_feed, size_t length)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&demux->mutex))
+		return -ERESTARTSYS;
+
+	dvbdmx_ts_reset_pes_state(feed);
+
+	if (dvb_dmx_is_video_feed(feed)) {
+		MPQ_DVB_DBG_PRINT("%s: flushing video buffer\n", __func__);
+
+		ret = mpq_dmx_flush_stream_buffer(feed);
+	} else if (dvb_dmx_is_audio_feed(feed)) {
+		MPQ_DVB_DBG_PRINT("%s: flushing audio buffer\n", __func__);
+
+		ret = mpq_dmx_flush_audio_stream_buffer(feed);
+	}
+
+	mutex_unlock(&demux->mutex);
+	return ret;
+}
+
+/**
+ * mpq_dmx_init_video_feed - Initializes of video feed information
+ * used to pass data directly to decoder.
+ *
+ * @mpq_feed: The mpq feed object
+ *
+ * Return     error code.
+ */
+int mpq_dmx_init_video_feed(struct mpq_feed *mpq_feed)
+{
+	int ret;
+	struct mpq_video_feed_info *feed_data = &mpq_feed->video_info;
+	struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+	struct mpq_streambuffer *stream_buffer;
+
+	/* get and store framing information if required */
+	if (video_framing) {
+		mpq_dmx_get_pattern_params(
+			mpq_feed->dvb_demux_feed->video_codec,
+			feed_data->patterns, &feed_data->patterns_num);
+		if (!feed_data->patterns_num) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: FAILED to get framing pattern parameters\n",
+				__func__);
+
+			ret = -EINVAL;
+			goto init_failed_free_priv_data;
+		}
+	}
+
+	/* Register the new stream-buffer interface to MPQ adapter */
+	switch (mpq_feed->dvb_demux_feed->pes_type) {
+	case DMX_PES_VIDEO0:
+		store_mpq_video_feed[0] = mpq_feed;
+		feed_data->stream_interface =
+			MPQ_ADAPTER_VIDEO0_STREAM_IF;
+		break;
+
+	case DMX_PES_VIDEO1:
+		store_mpq_video_feed[1] = mpq_feed;
+		feed_data->stream_interface =
+			MPQ_ADAPTER_VIDEO1_STREAM_IF;
+		break;
+
+	case DMX_PES_VIDEO2:
+		store_mpq_video_feed[2] = mpq_feed;
+		feed_data->stream_interface =
+			MPQ_ADAPTER_VIDEO2_STREAM_IF;
+		break;
+
+	case DMX_PES_VIDEO3:
+		store_mpq_video_feed[3] = mpq_feed;
+		feed_data->stream_interface =
+			MPQ_ADAPTER_VIDEO3_STREAM_IF;
+		break;
+
+	default:
+		MPQ_DVB_ERR_PRINT(
+			"%s: Invalid pes type %d\n",
+			__func__,
+			mpq_feed->dvb_demux_feed->pes_type);
+		ret = -EINVAL;
+		goto init_failed_free_priv_data;
+	}
+
+	/* make sure not occupied already */
+	stream_buffer = NULL;
+	mpq_adapter_get_stream_if(
+			feed_data->stream_interface,
+			&stream_buffer);
+	if (stream_buffer != NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Video interface %d already occupied!\n",
+			__func__,
+			feed_data->stream_interface);
+		ret = -EBUSY;
+		goto init_failed_free_priv_data;
+	}
+
+	feed_data->video_buffer =
+		&mpq_dmx_info.decoder_buffers[feed_data->stream_interface];
+
+	ret = mpq_dmx_init_streambuffer(
+		mpq_feed, feed_data, feed_data->video_buffer);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_dmx_init_streambuffer failed, err = %d\n",
+			__func__, ret);
+		goto init_failed_free_priv_data;
+	}
+
+	ret = mpq_adapter_register_stream_if(
+			feed_data->stream_interface,
+			feed_data->video_buffer);
+
+	if (ret < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_adapter_register_stream_if failed, err = %d\n",
+			__func__, ret);
+		goto init_failed_free_stream_buffer;
+	}
+
+	spin_lock_init(&feed_data->video_buffer_lock);
+
+	feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN;
+	feed_data->pes_header_offset = 0;
+	mpq_feed->dvb_demux_feed->pusi_seen = 0;
+	mpq_feed->dvb_demux_feed->peslen = 0;
+	feed_data->fullness_wait_cancel = 0;
+	mpq_streambuffer_get_data_rw_offset(feed_data->video_buffer, NULL,
+		&feed_data->frame_offset);
+	feed_data->last_pattern_offset = 0;
+	feed_data->pending_pattern_len = 0;
+	feed_data->last_framing_match_type = 0;
+	feed_data->found_sequence_header_pattern = 0;
+	memset(&feed_data->prefix_size, 0,
+			sizeof(struct dvb_dmx_video_prefix_size_masks));
+	feed_data->first_prefix_size = 0;
+	feed_data->saved_pts_dts_info.pts_exist = 0;
+	feed_data->saved_pts_dts_info.dts_exist = 0;
+	feed_data->new_pts_dts_info.pts_exist = 0;
+	feed_data->new_pts_dts_info.dts_exist = 0;
+	feed_data->saved_info_used = 1;
+	feed_data->new_info_exists = 0;
+	feed_data->first_pts_dts_copy = 1;
+	feed_data->tei_errs = 0;
+	feed_data->last_continuity = -1;
+	feed_data->continuity_errs = 0;
+	feed_data->ts_packets_num = 0;
+	feed_data->ts_dropped_bytes = 0;
+
+	mpq_demux->decoder_stat[feed_data->stream_interface].drop_count = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].out_count = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].
+		out_interval_sum = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].
+		out_interval_max = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors = 0;
+
+	return 0;
+
+init_failed_free_stream_buffer:
+	mpq_dmx_release_streambuffer(mpq_feed, feed_data,
+		feed_data->video_buffer, mpq_demux->ion_client);
+	mpq_adapter_unregister_stream_if(feed_data->stream_interface);
+init_failed_free_priv_data:
+	feed_data->video_buffer = NULL;
+	return ret;
+}
+
+/* Register the new stream-buffer interface to MPQ adapter */
+int mpq_dmx_init_audio_feed(struct mpq_feed *mpq_feed)
+{
+	int ret;
+	struct mpq_audio_feed_info *feed_data = &mpq_feed->audio_info;
+	struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+	struct mpq_streambuffer *stream_buffer;
+
+	switch (mpq_feed->dvb_demux_feed->pes_type) {
+	case DMX_PES_AUDIO0:
+		store_mpq_audio_feed[0] = mpq_feed;
+		feed_data->stream_interface =
+			MPQ_ADAPTER_AUDIO0_STREAM_IF;
+		break;
+
+	case DMX_PES_AUDIO1:
+		store_mpq_audio_feed[1] = mpq_feed;
+		feed_data->stream_interface =
+			MPQ_ADAPTER_AUDIO1_STREAM_IF;
+		break;
+
+	case DMX_PES_AUDIO2:
+		store_mpq_audio_feed[2] = mpq_feed;
+		feed_data->stream_interface =
+			MPQ_ADAPTER_AUDIO2_STREAM_IF;
+		break;
+
+	case DMX_PES_AUDIO3:
+		store_mpq_audio_feed[3] = mpq_feed;
+		feed_data->stream_interface =
+			MPQ_ADAPTER_AUDIO3_STREAM_IF;
+		break;
+
+	default:
+		MPQ_DVB_ERR_PRINT(
+			"%s: Invalid pes type %d\n",
+			__func__,
+			mpq_feed->dvb_demux_feed->pes_type);
+		ret = -EINVAL;
+		goto init_failed_free_priv_data;
+	}
+
+	/* make sure not occupied already */
+	stream_buffer = NULL;
+	mpq_adapter_get_stream_if(
+			feed_data->stream_interface,
+			&stream_buffer);
+	if (stream_buffer != NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Audio interface %d already occupied!\n",
+			__func__, feed_data->stream_interface);
+		ret = -EBUSY;
+		goto init_failed_free_priv_data;
+	}
+
+	feed_data->audio_buffer =
+		&mpq_dmx_info.decoder_buffers[feed_data->stream_interface];
+
+	ret = mpq_dmx_init_audio_streambuffer(
+		mpq_feed, feed_data, feed_data->audio_buffer);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_dmx_init_streambuffer failed, err = %d\n",
+			__func__, ret);
+		goto init_failed_free_priv_data;
+	}
+
+	ret = mpq_adapter_register_stream_if(
+			feed_data->stream_interface,
+			feed_data->audio_buffer);
+
+	if (ret < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_adapter_register_stream_if failed, err = %d\n",
+			__func__, ret);
+		goto init_failed_free_stream_buffer;
+	}
+
+	spin_lock_init(&feed_data->audio_buffer_lock);
+
+	feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN;
+	feed_data->pes_header_offset = 0;
+	mpq_feed->dvb_demux_feed->pusi_seen = 0;
+	mpq_feed->dvb_demux_feed->peslen = 0;
+	feed_data->fullness_wait_cancel = 0;
+	mpq_streambuffer_get_data_rw_offset(feed_data->audio_buffer, NULL,
+		&feed_data->frame_offset);
+	feed_data->saved_pts_dts_info.pts_exist = 0;
+	feed_data->saved_pts_dts_info.dts_exist = 0;
+	feed_data->new_pts_dts_info.pts_exist = 0;
+	feed_data->new_pts_dts_info.dts_exist = 0;
+	feed_data->saved_info_used = 1;
+	feed_data->new_info_exists = 0;
+	feed_data->first_pts_dts_copy = 1;
+	feed_data->tei_errs = 0;
+	feed_data->last_continuity = -1;
+	feed_data->continuity_errs = 0;
+	feed_data->ts_packets_num = 0;
+	feed_data->ts_dropped_bytes = 0;
+
+	mpq_demux->decoder_stat[feed_data->stream_interface].drop_count = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].out_count = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].
+		out_interval_sum = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].
+		out_interval_max = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors = 0;
+	mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors = 0;
+
+	return 0;
+
+init_failed_free_stream_buffer:
+	mpq_dmx_release_audio_streambuffer(mpq_feed, feed_data,
+		feed_data->audio_buffer, mpq_demux->ion_client);
+	mpq_adapter_unregister_stream_if(feed_data->stream_interface);
+init_failed_free_priv_data:
+	feed_data->audio_buffer = NULL;
+	return ret;
+}
+
+/**
+ * mpq_dmx_terminate_video_feed - terminate video feed information
+ * that was previously initialized in mpq_dmx_init_video_feed
+ *
+ * @mpq_feed: The mpq feed used for the video TS packets
+ *
+ * Return     error code.
+ */
+int mpq_dmx_terminate_video_feed(struct mpq_feed *mpq_feed)
+{
+	struct mpq_streambuffer *video_buffer;
+	struct mpq_video_feed_info *feed_data;
+	struct mpq_demux *mpq_demux;
+
+	if (mpq_feed == NULL)
+		return -EINVAL;
+
+	mpq_demux = mpq_feed->mpq_demux;
+	feed_data = &mpq_feed->video_info;
+
+	spin_lock(&feed_data->video_buffer_lock);
+	video_buffer = feed_data->video_buffer;
+	feed_data->video_buffer = NULL;
+	wake_up_all(&video_buffer->raw_data.queue);
+	spin_unlock(&feed_data->video_buffer_lock);
+
+	mpq_dmx_release_streambuffer(mpq_feed, feed_data,
+		video_buffer, mpq_demux->ion_client);
+
+	return 0;
+}
+
+int mpq_dmx_terminate_audio_feed(struct mpq_feed *mpq_feed)
+{
+	struct mpq_streambuffer *audio_buffer;
+	struct mpq_audio_feed_info *feed_data;
+	struct mpq_demux *mpq_demux;
+
+	if (mpq_feed == NULL)
+		return -EINVAL;
+
+	mpq_demux = mpq_feed->mpq_demux;
+	feed_data = &mpq_feed->audio_info;
+
+	spin_lock(&feed_data->audio_buffer_lock);
+	audio_buffer = feed_data->audio_buffer;
+	feed_data->audio_buffer = NULL;
+	wake_up_all(&audio_buffer->raw_data.queue);
+	spin_unlock(&feed_data->audio_buffer_lock);
+
+	mpq_dmx_release_audio_streambuffer(mpq_feed, feed_data,
+		audio_buffer, mpq_demux->ion_client);
+
+	return 0;
+}
+
+struct dvb_demux_feed *mpq_dmx_peer_rec_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux_feed *tmp;
+	struct dvb_demux *dvb_demux = feed->demux;
+
+	list_for_each_entry(tmp, &dvb_demux->feed_list, list_head) {
+		if (tmp != feed && tmp->state == DMX_STATE_GO &&
+			tmp->feed.ts.buffer.ringbuff ==
+			feed->feed.ts.buffer.ringbuff) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: main feed pid=%d, secondary feed pid=%d\n",
+				__func__, tmp->pid, feed->pid);
+			return tmp;
+		}
+	}
+
+	return NULL;
+}
+
+static int mpq_sdmx_alloc_data_buf(struct mpq_feed *mpq_feed, size_t size)
+{
+	struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+	void *buf_base;
+	int ret;
+
+	mpq_feed->sdmx_buf_handle = ion_alloc(mpq_demux->ion_client,
+		size,
+		SZ_4K,
+		ION_HEAP(ION_QSECOM_HEAP_ID),
+		0);
+	if (IS_ERR_OR_NULL(mpq_feed->sdmx_buf_handle)) {
+		ret = PTR_ERR(mpq_feed->sdmx_buf_handle);
+		mpq_feed->sdmx_buf_handle = NULL;
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to allocate sdmx buffer %d\n",
+			__func__, ret);
+		if (!ret)
+			ret = -ENOMEM;
+		goto end;
+	}
+
+	buf_base = ion_map_kernel(mpq_demux->ion_client,
+		mpq_feed->sdmx_buf_handle);
+	if (IS_ERR_OR_NULL(buf_base)) {
+		ret = PTR_ERR(buf_base);
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to map sdmx buffer %d\n",
+			__func__, ret);
+		if (!ret)
+			ret = -ENOMEM;
+		goto failed_free_buf;
+	}
+
+	dvb_ringbuffer_init(&mpq_feed->sdmx_buf, buf_base, size);
+
+	return 0;
+
+failed_free_buf:
+	ion_free(mpq_demux->ion_client, mpq_feed->sdmx_buf_handle);
+	mpq_feed->sdmx_buf_handle = NULL;
+end:
+	return ret;
+}
+
+static int mpq_sdmx_free_data_buf(struct mpq_feed *mpq_feed)
+{
+	struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+
+	if (mpq_feed->sdmx_buf_handle) {
+		ion_unmap_kernel(mpq_demux->ion_client,
+			mpq_feed->sdmx_buf_handle);
+		mpq_feed->sdmx_buf.data = NULL;
+		ion_free(mpq_demux->ion_client,
+			mpq_feed->sdmx_buf_handle);
+		mpq_feed->sdmx_buf_handle = NULL;
+	}
+
+	return 0;
+}
+
+static int mpq_sdmx_init_metadata_buffer(struct mpq_demux *mpq_demux,
+	struct mpq_feed *feed, struct sdmx_buff_descr *metadata_buff_desc)
+{
+	void *metadata_buff_base;
+	ion_phys_addr_t temp;
+	int ret;
+	size_t size;
+
+	feed->metadata_buf_handle = ion_alloc(mpq_demux->ion_client,
+		SDMX_METADATA_BUFFER_SIZE,
+		SZ_4K,
+		ION_HEAP(ION_QSECOM_HEAP_ID),
+		0);
+	if (IS_ERR_OR_NULL(feed->metadata_buf_handle)) {
+		ret = PTR_ERR(feed->metadata_buf_handle);
+		feed->metadata_buf_handle = NULL;
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to allocate metadata buffer %d\n",
+			__func__, ret);
+		if (!ret)
+			ret = -ENOMEM;
+		goto end;
+	}
+
+	metadata_buff_base = ion_map_kernel(mpq_demux->ion_client,
+		feed->metadata_buf_handle);
+	if (IS_ERR_OR_NULL(metadata_buff_base)) {
+		ret = PTR_ERR(metadata_buff_base);
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to map metadata buffer %d\n",
+			__func__, ret);
+		if (!ret)
+			ret = -ENOMEM;
+		goto failed_free_metadata_buf;
+	}
+
+	ret = ion_phys(mpq_demux->ion_client,
+		feed->metadata_buf_handle,
+		&temp,
+		&size);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to get physical address %d\n",
+			__func__, ret);
+		goto failed_unmap_metadata_buf;
+	}
+	metadata_buff_desc->size = size;
+	metadata_buff_desc->base_addr = (u64)temp;
+
+	dvb_ringbuffer_init(&feed->metadata_buf, metadata_buff_base,
+		SDMX_METADATA_BUFFER_SIZE);
+
+	return 0;
+
+failed_unmap_metadata_buf:
+	ion_unmap_kernel(mpq_demux->ion_client, feed->metadata_buf_handle);
+failed_free_metadata_buf:
+	ion_free(mpq_demux->ion_client, feed->metadata_buf_handle);
+	feed->metadata_buf_handle = NULL;
+end:
+	return ret;
+}
+
+static int mpq_sdmx_terminate_metadata_buffer(struct mpq_feed *mpq_feed)
+{
+	struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+
+	if (mpq_feed->metadata_buf_handle) {
+		ion_unmap_kernel(mpq_demux->ion_client,
+			mpq_feed->metadata_buf_handle);
+		mpq_feed->metadata_buf.data = NULL;
+		ion_free(mpq_demux->ion_client,
+			mpq_feed->metadata_buf_handle);
+		mpq_feed->metadata_buf_handle = NULL;
+	}
+
+	return 0;
+}
+
+int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed)
+{
+	int ret = 0;
+	struct mpq_demux *mpq_demux;
+	struct mpq_feed *mpq_feed;
+	struct mpq_feed *main_rec_feed = NULL;
+	struct dvb_demux_feed *tmp;
+
+	if (feed == NULL)
+		return -EINVAL;
+
+	mpq_demux = feed->demux->priv;
+
+	mutex_lock(&mpq_demux->mutex);
+	mpq_feed = feed->priv;
+
+	if (mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE) {
+		if (mpq_feed->filter_type == SDMX_RAW_FILTER) {
+			tmp = mpq_dmx_peer_rec_feed(feed);
+			if (tmp)
+				main_rec_feed = tmp->priv;
+		}
+
+		if (main_rec_feed) {
+			/* This feed is part of a recording filter */
+			MPQ_DVB_DBG_PRINT(
+				"%s: Removing raw pid %d from filter %d\n",
+				__func__, feed->pid,
+				mpq_feed->sdmx_filter_handle);
+			ret = sdmx_remove_raw_pid(
+				mpq_demux->sdmx_session_handle,
+				mpq_feed->sdmx_filter_handle, feed->pid);
+			if (ret)
+				MPQ_DVB_ERR_PRINT(
+					"%s: SDMX_remove_raw_pid failed. ret = %d\n",
+					__func__, ret);
+
+			/* If this feed that we are removing was set as primary,
+			 * now other feeds should be set as primary
+			 */
+			if (!mpq_feed->secondary_feed)
+				main_rec_feed->secondary_feed = 0;
+		} else {
+			MPQ_DVB_DBG_PRINT("%s: Removing filter %d, pid %d\n",
+				__func__, mpq_feed->sdmx_filter_handle,
+				feed->pid);
+			ret = sdmx_remove_filter(mpq_demux->sdmx_session_handle,
+				mpq_feed->sdmx_filter_handle);
+			if (ret) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: SDMX_remove_filter failed. ret = %d\n",
+					__func__, ret);
+			}
+
+			mpq_demux->sdmx_filter_count--;
+			mpq_feed->sdmx_filter_handle =
+				SDMX_INVALID_FILTER_HANDLE;
+		}
+
+		mpq_sdmx_close_session(mpq_demux);
+		if (mpq_demux->num_secure_feeds > 0)
+			mpq_demux->num_secure_feeds--;
+		else
+			MPQ_DVB_DBG_PRINT("%s: Invalid secure feed count= %u\n",
+				 __func__, mpq_demux->num_secure_feeds);
+	}
+
+	if (dvb_dmx_is_video_feed(feed)) {
+		ret = mpq_dmx_terminate_video_feed(mpq_feed);
+		if (ret)
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_dmx_terminate_video_feed failed. ret = %d\n",
+				__func__, ret);
+	} else if (dvb_dmx_is_audio_feed(feed)) {
+		ret = mpq_dmx_terminate_audio_feed(mpq_feed);
+		if (ret)
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_dmx_terminate_audio_feed failed. ret = %d\n",
+				__func__, ret);
+	}
+
+	if (mpq_feed->sdmx_buf_handle) {
+		wake_up_all(&mpq_feed->sdmx_buf.queue);
+		mpq_sdmx_free_data_buf(mpq_feed);
+	}
+
+	mpq_sdmx_terminate_metadata_buffer(mpq_feed);
+	if (mpq_demux->num_active_feeds > 0)
+		mpq_demux->num_active_feeds--;
+	else
+		MPQ_DVB_DBG_PRINT("%s: Invalid num_active_feeds count = %u\n",
+				  __func__, mpq_demux->num_active_feeds);
+
+	mutex_unlock(&mpq_demux->mutex);
+
+	return ret;
+}
+
+int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
+{
+	struct mpq_feed *mpq_feed;
+
+	if (dvb_dmx_is_video_feed(feed)) {
+		struct mpq_video_feed_info *feed_data;
+
+		mpq_feed = feed->priv;
+		feed_data = &mpq_feed->video_info;
+		feed_data->fullness_wait_cancel = 0;
+
+		return 0;
+	} else if (dvb_dmx_is_audio_feed(feed)) {
+		struct mpq_audio_feed_info *feed_data;
+
+		mpq_feed = feed->priv;
+		feed_data = &mpq_feed->audio_info;
+		feed_data->fullness_wait_cancel = 0;
+
+		return 0;
+	}
+
+	MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n", __func__,
+			   feed->pes_type);
+
+	return -EINVAL;
+}
+
+/**
+ * Returns whether the free space of decoder's output
+ * buffer is larger than specific number of bytes.
+ *
+ * @sbuff: MPQ stream buffer used for decoder data.
+ * @required_space: number of required free bytes in the buffer
+ *
+ * Return 1 if required free bytes are available, 0 otherwise.
+ */
+static inline int mpq_dmx_check_video_decoder_fullness(
+	struct mpq_streambuffer *sbuff,
+	size_t required_space)
+{
+	ssize_t free = mpq_streambuffer_data_free(sbuff);
+	ssize_t free_meta = mpq_streambuffer_metadata_free(sbuff);
+
+	/* Verify meta-data buffer can contain at least 1 packet */
+	if (free_meta < VIDEO_META_DATA_PACKET_SIZE)
+		return 0;
+
+	/*
+	 * For linear buffers, verify there's enough space for this TSP
+	 * and an additional buffer is free, as framing might required one
+	 * more buffer to be available.
+	 */
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
+		return (free >= required_space &&
+			sbuff->pending_buffers_count < sbuff->buffers_num-1);
+	else
+		/* Ring buffer mode */
+		return (free >= required_space);
+}
+
+static inline int mpq_dmx_check_audio_decoder_fullness(
+	struct mpq_streambuffer *sbuff,
+	size_t required_space)
+{
+	ssize_t free = mpq_streambuffer_data_free(sbuff);
+	ssize_t free_meta = mpq_streambuffer_metadata_free(sbuff);
+
+	/* Verify meta-data buffer can contain at least 1 packet */
+	if (free_meta < AUDIO_META_DATA_PACKET_SIZE)
+		return 0;
+
+	/*
+	 * For linear buffers, verify there's enough space for this TSP
+	 * and an additional buffer is free, as framing might required one
+	 * more buffer to be available.
+	 */
+	if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
+		return (free >= required_space &&
+			sbuff->pending_buffers_count < sbuff->buffers_num-1);
+	else
+		return (free >= required_space); /* Ring buffer mode */
+}
+
+/**
+ * Checks whether decoder's output buffer has free space
+ * for specific number of bytes, if not, the function waits
+ * until the amount of free-space is available.
+ *
+ * @feed: decoder's feed object
+ * @required_space: number of required free bytes in the buffer
+ * @lock_feed: indicates whether mutex should be held before
+ * accessing the feed information. If the caller of this function
+ * already holds a mutex then this should be set to 0 and 1 otherwise.
+ *
+ * Return 0 if required space is available and error code
+ * in case waiting on buffer fullness was aborted.
+ */
+static int mpq_dmx_decoder_fullness_check(
+		struct dvb_demux_feed *feed,
+		size_t required_space,
+		int lock_feed)
+{
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+	struct mpq_streambuffer *sbuff = NULL;
+	struct mpq_video_feed_info *feed_data;
+	struct mpq_feed *mpq_feed;
+	int ret = 0;
+
+	if (!dvb_dmx_is_video_feed(feed)) {
+		MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n",
+			__func__,
+			feed->pes_type);
+		return -EINVAL;
+	}
+
+	if (lock_feed) {
+		mutex_lock(&mpq_demux->mutex);
+	} else if (!mutex_is_locked(&mpq_demux->mutex)) {
+		MPQ_DVB_ERR_PRINT(
+				"%s: Mutex should have been locked\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	mpq_feed = feed->priv;
+	feed_data = &mpq_feed->video_info;
+
+	sbuff = feed_data->video_buffer;
+	if (sbuff == NULL) {
+		if (lock_feed)
+			mutex_unlock(&mpq_demux->mutex);
+		MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer object is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if ((feed_data->video_buffer != NULL) &&
+		(!feed_data->fullness_wait_cancel) &&
+		(!mpq_dmx_check_video_decoder_fullness(sbuff,
+						       required_space))) {
+		DEFINE_WAIT(__wait);
+
+		for (;;) {
+			prepare_to_wait(&sbuff->raw_data.queue,
+				&__wait,
+				TASK_INTERRUPTIBLE);
+			if (!feed_data->video_buffer ||
+				feed_data->fullness_wait_cancel ||
+				mpq_dmx_check_video_decoder_fullness(sbuff,
+					required_space))
+				break;
+
+			if (!signal_pending(current)) {
+				mutex_unlock(&mpq_demux->mutex);
+				schedule();
+				mutex_lock(&mpq_demux->mutex);
+				continue;
+			}
+
+			ret = -ERESTARTSYS;
+			break;
+		}
+		finish_wait(&sbuff->raw_data.queue, &__wait);
+	}
+
+	if (ret < 0) {
+		if (lock_feed)
+			mutex_unlock(&mpq_demux->mutex);
+		return ret;
+	}
+
+	if ((feed_data->fullness_wait_cancel) ||
+		(feed_data->video_buffer == NULL)) {
+		if (lock_feed)
+			mutex_unlock(&mpq_demux->mutex);
+		return -EINVAL;
+	}
+
+	if (lock_feed)
+		mutex_unlock(&mpq_demux->mutex);
+	return 0;
+}
+
+static int mpq_dmx_audio_decoder_fullness_check(
+		struct dvb_demux_feed *feed,
+		size_t required_space,
+		int lock_feed)
+{
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+	struct mpq_streambuffer *sbuff = NULL;
+	struct mpq_audio_feed_info *feed_data;
+	struct mpq_feed *mpq_feed;
+	int ret = 0;
+
+	if (!dvb_dmx_is_audio_feed(feed)) {
+		MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n",
+			__func__,
+			feed->pes_type);
+		return -EINVAL;
+	}
+
+	if (lock_feed) {
+		mutex_lock(&mpq_demux->mutex);
+	} else if (!mutex_is_locked(&mpq_demux->mutex)) {
+		MPQ_DVB_ERR_PRINT(
+				"%s: Mutex should have been locked\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	mpq_feed = feed->priv;
+	feed_data = &mpq_feed->audio_info;
+
+	sbuff = feed_data->audio_buffer;
+	if (sbuff == NULL) {
+		if (lock_feed)
+			mutex_unlock(&mpq_demux->mutex);
+		MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer object is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if ((feed_data->audio_buffer != NULL) &&
+		(!feed_data->fullness_wait_cancel) &&
+		(!mpq_dmx_check_audio_decoder_fullness(sbuff,
+						       required_space))) {
+		DEFINE_WAIT(__wait);
+
+		for (;;) {
+			prepare_to_wait(&sbuff->raw_data.queue,
+					&__wait, TASK_INTERRUPTIBLE);
+			if (!feed_data->audio_buffer ||
+				feed_data->fullness_wait_cancel ||
+				mpq_dmx_check_audio_decoder_fullness(sbuff,
+					required_space))
+				break;
+
+			if (!signal_pending(current)) {
+				mutex_unlock(&mpq_demux->mutex);
+				schedule();
+				mutex_lock(&mpq_demux->mutex);
+				continue;
+			}
+
+			ret = -ERESTARTSYS;
+			break;
+		}
+		finish_wait(&sbuff->raw_data.queue, &__wait);
+	}
+
+	if (ret < 0) {
+		if (lock_feed)
+			mutex_unlock(&mpq_demux->mutex);
+		return ret;
+	}
+
+	if ((feed_data->fullness_wait_cancel) ||
+		(feed_data->audio_buffer == NULL)) {
+		if (lock_feed)
+			mutex_unlock(&mpq_demux->mutex);
+		return -EINVAL;
+	}
+
+	if (lock_feed)
+		mutex_unlock(&mpq_demux->mutex);
+	return 0;
+}
+
+int mpq_dmx_decoder_fullness_wait(
+		struct dvb_demux_feed *feed,
+		size_t required_space)
+{
+	if (dvb_dmx_is_video_feed(feed))
+		return mpq_dmx_decoder_fullness_check(feed, required_space, 1);
+	else if (dvb_dmx_is_audio_feed(feed))
+		return mpq_dmx_audio_decoder_fullness_check(feed,
+							    required_space, 1);
+
+	return 0;
+}
+
+int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
+{
+	if (dvb_dmx_is_video_feed(feed)) {
+		struct mpq_feed *mpq_feed;
+		struct mpq_video_feed_info *feed_data;
+		struct dvb_ringbuffer *video_buff;
+
+		mpq_feed = feed->priv;
+		feed_data = &mpq_feed->video_info;
+
+		feed_data->fullness_wait_cancel = 1;
+
+		spin_lock(&feed_data->video_buffer_lock);
+		if (feed_data->video_buffer == NULL) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: video_buffer released\n", __func__);
+			spin_unlock(&feed_data->video_buffer_lock);
+			return 0;
+		}
+
+		video_buff = &feed_data->video_buffer->raw_data;
+		wake_up_all(&video_buff->queue);
+		spin_unlock(&feed_data->video_buffer_lock);
+
+		return 0;
+	} else if (dvb_dmx_is_audio_feed(feed)) {
+		struct mpq_feed *mpq_feed;
+		struct mpq_audio_feed_info *feed_data;
+		struct dvb_ringbuffer *audio_buff;
+
+		mpq_feed = feed->priv;
+		feed_data = &mpq_feed->audio_info;
+
+		feed_data->fullness_wait_cancel = 1;
+
+		spin_lock(&feed_data->audio_buffer_lock);
+		if (feed_data->audio_buffer == NULL) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: audio_buffer released\n", __func__);
+			spin_unlock(&feed_data->audio_buffer_lock);
+			return 0;
+		}
+
+		audio_buff = &feed_data->audio_buffer->raw_data;
+		wake_up_all(&audio_buff->queue);
+		spin_unlock(&feed_data->audio_buffer_lock);
+
+		return 0;
+	}
+
+	MPQ_DVB_ERR_PRINT(
+			"%s: Invalid feed type %d\n", __func__, feed->pes_type);
+
+	return -EINVAL;
+}
+
+int mpq_dmx_parse_mandatory_pes_header(
+				struct dvb_demux_feed *feed,
+				struct mpq_video_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				const u8 *buf,
+				u32 *ts_payload_offset,
+				int *bytes_avail)
+{
+	int left_size, copy_len;
+
+	if (feed_data->pes_header_offset < PES_MANDATORY_FIELDS_LEN) {
+		left_size =
+			PES_MANDATORY_FIELDS_LEN -
+			feed_data->pes_header_offset;
+
+		copy_len = (left_size > *bytes_avail) ?
+					*bytes_avail :
+					left_size;
+
+		memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+				(buf + *ts_payload_offset),
+				copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+
+		if (left_size > *bytes_avail)
+			return -EINVAL;
+
+		/* else - we have beginning of PES header */
+		*bytes_avail -= left_size;
+		*ts_payload_offset += left_size;
+
+		/* Make sure the PES packet is valid */
+		if (mpq_dmx_is_valid_video_pes(pes_header) < 0) {
+			/*
+			 * Since the new PES header parsing
+			 * failed, reset pusi_seen to drop all
+			 * data until next PUSI
+			 */
+			feed->pusi_seen = 0;
+			feed_data->pes_header_offset = 0;
+
+			MPQ_DVB_ERR_PRINT(
+				"%s: invalid packet\n",
+				__func__);
+
+			return -EINVAL;
+		}
+
+		feed_data->pes_header_left_bytes =
+			pes_header->pes_header_data_length;
+	}
+
+	return 0;
+}
+
+int mpq_dmx_parse_mandatory_audio_pes_header(
+				struct dvb_demux_feed *feed,
+				struct mpq_audio_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				const u8 *buf,
+				u32 *ts_payload_offset,
+				int *bytes_avail)
+{
+	int left_size, copy_len;
+
+	if (feed_data->pes_header_offset < PES_MANDATORY_FIELDS_LEN) {
+		left_size =
+			PES_MANDATORY_FIELDS_LEN -
+			feed_data->pes_header_offset;
+
+		copy_len = (left_size > *bytes_avail) ?
+					*bytes_avail :
+					left_size;
+
+		memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+				(buf + *ts_payload_offset),
+				copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+
+		if (left_size > *bytes_avail)
+			return -EINVAL;
+
+		/* else - we have beginning of PES header */
+		*bytes_avail -= left_size;
+		*ts_payload_offset += left_size;
+
+		/* Make sure the PES packet is valid */
+		if (mpq_dmx_is_valid_audio_pes(pes_header) < 0) {
+			/*
+			 * Since the new PES header parsing
+			 * failed, reset pusi_seen to drop all
+			 * data until next PUSI
+			 */
+			feed->pusi_seen = 0;
+			feed_data->pes_header_offset = 0;
+
+			MPQ_DVB_ERR_PRINT(
+				"%s: invalid packet\n",
+				__func__);
+
+			return -EINVAL;
+		}
+
+		feed_data->pes_header_left_bytes =
+			pes_header->pes_header_data_length;
+	}
+
+	return 0;
+}
+
+static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data,
+				struct pes_packet_header *pes_header)
+{
+	struct dmx_pts_dts_info *info = &(feed_data->new_pts_dts_info);
+
+	/* Get PTS/DTS information from PES header */
+
+	if ((pes_header->pts_dts_flag == 2) ||
+		(pes_header->pts_dts_flag == 3)) {
+		info->pts_exist = 1;
+
+		info->pts =
+			((u64)pes_header->pts_1 << 30) |
+			((u64)pes_header->pts_2 << 22) |
+			((u64)pes_header->pts_3 << 15) |
+			((u64)pes_header->pts_4 << 7) |
+			(u64)pes_header->pts_5;
+	} else {
+		info->pts_exist = 0;
+		info->pts = 0;
+	}
+
+	if (pes_header->pts_dts_flag == 3) {
+		info->dts_exist = 1;
+
+		info->dts =
+			((u64)pes_header->dts_1 << 30) |
+			((u64)pes_header->dts_2 << 22) |
+			((u64)pes_header->dts_3 << 15) |
+			((u64)pes_header->dts_4 << 7) |
+			(u64)pes_header->dts_5;
+	} else {
+		info->dts_exist = 0;
+		info->dts = 0;
+	}
+
+	feed_data->new_info_exists = 1;
+}
+
+static inline void mpq_dmx_get_audio_pts_dts(
+				struct mpq_audio_feed_info *feed_data,
+				struct pes_packet_header *pes_header)
+{
+	struct dmx_pts_dts_info *info = &(feed_data->new_pts_dts_info);
+
+	/* Get PTS/DTS information from PES header */
+
+	if ((pes_header->pts_dts_flag == 2) ||
+		(pes_header->pts_dts_flag == 3)) {
+		info->pts_exist = 1;
+
+		info->pts =
+			((u64)pes_header->pts_1 << 30) |
+			((u64)pes_header->pts_2 << 22) |
+			((u64)pes_header->pts_3 << 15) |
+			((u64)pes_header->pts_4 << 7) |
+			(u64)pes_header->pts_5;
+	} else {
+		info->pts_exist = 0;
+		info->pts = 0;
+	}
+
+	if (pes_header->pts_dts_flag == 3) {
+		info->dts_exist = 1;
+
+		info->dts =
+			((u64)pes_header->dts_1 << 30) |
+			((u64)pes_header->dts_2 << 22) |
+			((u64)pes_header->dts_3 << 15) |
+			((u64)pes_header->dts_4 << 7) |
+			(u64)pes_header->dts_5;
+	} else {
+		info->dts_exist = 0;
+		info->dts = 0;
+	}
+
+	feed_data->new_info_exists = 1;
+}
+
+int mpq_dmx_parse_remaining_pes_header(
+				struct dvb_demux_feed *feed,
+				struct mpq_video_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				const u8 *buf,
+				u32 *ts_payload_offset,
+				int *bytes_avail)
+{
+	int left_size, copy_len;
+
+	/* Remaining header bytes that need to be processed? */
+	if (!feed_data->pes_header_left_bytes)
+		return 0;
+
+	/* Did we capture the PTS value (if exists)? */
+	if ((*bytes_avail != 0) &&
+		(feed_data->pes_header_offset <
+		 (PES_MANDATORY_FIELDS_LEN+5)) &&
+		((pes_header->pts_dts_flag == 2) ||
+		 (pes_header->pts_dts_flag == 3))) {
+
+		/* 5 more bytes should be there */
+		left_size =
+			PES_MANDATORY_FIELDS_LEN + 5 -
+			feed_data->pes_header_offset;
+
+		copy_len = (left_size > *bytes_avail) ?
+					*bytes_avail :
+					left_size;
+
+		memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+			(buf + *ts_payload_offset),
+			copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+		feed_data->pes_header_left_bytes -= copy_len;
+
+		if (left_size > *bytes_avail)
+			return -EINVAL;
+
+		/* else - we have the PTS */
+		*bytes_avail -= copy_len;
+		*ts_payload_offset += copy_len;
+	}
+
+	/* Did we capture the DTS value (if exist)? */
+	if ((*bytes_avail != 0) &&
+		(feed_data->pes_header_offset <
+		 (PES_MANDATORY_FIELDS_LEN+10)) &&
+		(pes_header->pts_dts_flag == 3)) {
+
+		/* 5 more bytes should be there */
+		left_size =
+			PES_MANDATORY_FIELDS_LEN + 10 -
+			feed_data->pes_header_offset;
+
+		copy_len = (left_size > *bytes_avail) ?
+					*bytes_avail :
+					left_size;
+
+		memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+			(buf + *ts_payload_offset),
+			copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+		feed_data->pes_header_left_bytes -= copy_len;
+
+		if (left_size > *bytes_avail)
+			return -EINVAL;
+
+		/* else - we have the DTS */
+		*bytes_avail -= copy_len;
+		*ts_payload_offset += copy_len;
+	}
+
+	/* Any more header bytes?! */
+	if (feed_data->pes_header_left_bytes >= *bytes_avail) {
+		feed_data->pes_header_left_bytes -= *bytes_avail;
+		return -EINVAL;
+	}
+
+	/* get PTS/DTS information from PES header to be written later */
+	mpq_dmx_get_pts_dts(feed_data, pes_header);
+
+	/* Got PES header, process payload */
+	*bytes_avail -= feed_data->pes_header_left_bytes;
+	*ts_payload_offset += feed_data->pes_header_left_bytes;
+	feed_data->pes_header_left_bytes = 0;
+
+	return 0;
+}
+
+int mpq_dmx_parse_remaining_audio_pes_header(
+				struct dvb_demux_feed *feed,
+				struct mpq_audio_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				const u8 *buf,
+				u32 *ts_payload_offset,
+				int *bytes_avail)
+{
+	int left_size, copy_len;
+
+	/* Remaining header bytes that need to be processed? */
+	if (!feed_data->pes_header_left_bytes)
+		return 0;
+
+	/* Did we capture the PTS value (if exists)? */
+	if ((*bytes_avail != 0) &&
+		(feed_data->pes_header_offset <
+		 (PES_MANDATORY_FIELDS_LEN+5)) &&
+		((pes_header->pts_dts_flag == 2) ||
+		 (pes_header->pts_dts_flag == 3))) {
+
+		/* 5 more bytes should be there */
+		left_size =
+			PES_MANDATORY_FIELDS_LEN + 5 -
+			feed_data->pes_header_offset;
+
+		copy_len =
+			(left_size > *bytes_avail) ? *bytes_avail : left_size;
+
+		memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+			(buf + *ts_payload_offset), copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+		feed_data->pes_header_left_bytes -= copy_len;
+
+		if (left_size > *bytes_avail)
+			return -EINVAL;
+
+		/* else - we have the PTS */
+		*bytes_avail -= copy_len;
+		*ts_payload_offset += copy_len;
+	}
+
+	/* Did we capture the DTS value (if exist)? */
+	if ((*bytes_avail != 0) &&
+		(feed_data->pes_header_offset <
+		 (PES_MANDATORY_FIELDS_LEN+10)) &&
+		(pes_header->pts_dts_flag == 3)) {
+
+		/* 5 more bytes should be there */
+		left_size =
+			PES_MANDATORY_FIELDS_LEN + 10 -
+			feed_data->pes_header_offset;
+
+		copy_len = (left_size > *bytes_avail) ?
+					*bytes_avail :
+					left_size;
+
+		memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+			(buf + *ts_payload_offset),
+			copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+		feed_data->pes_header_left_bytes -= copy_len;
+
+		if (left_size > *bytes_avail)
+			return -EINVAL;
+
+		/* else - we have the DTS */
+		*bytes_avail -= copy_len;
+		*ts_payload_offset += copy_len;
+	}
+
+	/* Any more header bytes?! */
+	if (feed_data->pes_header_left_bytes >= *bytes_avail) {
+		feed_data->pes_header_left_bytes -= *bytes_avail;
+		return -EINVAL;
+	}
+
+	/* get PTS/DTS information from PES header to be written later */
+	mpq_dmx_get_audio_pts_dts(feed_data, pes_header);
+
+	/* Got PES header, process payload */
+	*bytes_avail -= feed_data->pes_header_left_bytes;
+	*ts_payload_offset += feed_data->pes_header_left_bytes;
+	feed_data->pes_header_left_bytes = 0;
+
+	return 0;
+}
+
+static void mpq_dmx_check_continuity(struct mpq_video_feed_info *feed_data,
+					int current_continuity,
+					int discontinuity_indicator)
+{
+	const int max_continuity = 0x0F; /* 4 bits in the TS packet header */
+
+	/* sanity check */
+	if (unlikely((current_continuity < 0) ||
+			(current_continuity > max_continuity))) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: received invalid continuity counter value %d\n",
+					__func__, current_continuity);
+		return;
+	}
+
+	/* reset last continuity */
+	if ((feed_data->last_continuity == -1) ||
+		(discontinuity_indicator)) {
+		feed_data->last_continuity = current_continuity;
+		return;
+	}
+
+	/* check for continuity errors */
+	if (current_continuity !=
+			((feed_data->last_continuity + 1) & max_continuity))
+		feed_data->continuity_errs++;
+
+	/* save for next time */
+	feed_data->last_continuity = current_continuity;
+}
+
+static void mpq_dmx_check_audio_continuity(
+					struct mpq_audio_feed_info *feed_data,
+					int current_continuity,
+					int discontinuity_indicator)
+{
+	const int max_continuity = 0x0F; /* 4 bits in the TS packet header */
+
+	/* sanity check */
+	if (unlikely((current_continuity < 0) ||
+			(current_continuity > max_continuity))) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: received invalid continuity counter value %d\n",
+					__func__, current_continuity);
+		return;
+	}
+
+	/* reset last continuity */
+	if ((feed_data->last_continuity == -1) || (discontinuity_indicator)) {
+		feed_data->last_continuity = current_continuity;
+		return;
+	}
+
+	/* check for continuity errors */
+	if (current_continuity !=
+			((feed_data->last_continuity + 1) & max_continuity))
+		feed_data->continuity_errs++;
+
+	/* save for next time */
+	feed_data->last_continuity = current_continuity;
+}
+
+static inline void mpq_dmx_prepare_es_event_data(
+			struct mpq_streambuffer_packet_header *packet,
+			struct mpq_adapter_video_meta_data *meta_data,
+			struct mpq_video_feed_info *feed_data,
+			struct mpq_streambuffer *stream_buffer,
+			struct dmx_data_ready *data,
+			int cookie)
+{
+	struct dmx_pts_dts_info *pts_dts;
+
+	if (meta_data->packet_type == DMX_PES_PACKET) {
+		pts_dts = &meta_data->info.pes.pts_dts_info;
+		data->buf.stc = meta_data->info.pes.stc;
+	} else {
+		pts_dts = &meta_data->info.framing.pts_dts_info;
+		data->buf.stc = meta_data->info.framing.stc;
+	}
+
+	pts_dts = meta_data->packet_type == DMX_PES_PACKET ?
+		&meta_data->info.pes.pts_dts_info :
+		&meta_data->info.framing.pts_dts_info;
+
+	data->data_length = 0;
+	data->buf.handle = packet->raw_data_handle;
+	data->buf.cookie = cookie;
+	data->buf.offset = packet->raw_data_offset;
+	data->buf.len = packet->raw_data_len;
+	data->buf.pts_exists = pts_dts->pts_exist;
+	data->buf.pts = pts_dts->pts;
+	data->buf.dts_exists = pts_dts->dts_exist;
+	data->buf.dts = pts_dts->dts;
+	data->buf.tei_counter = feed_data->tei_errs;
+	data->buf.cont_err_counter = feed_data->continuity_errs;
+	data->buf.ts_packets_num = feed_data->ts_packets_num;
+	data->buf.ts_dropped_bytes = feed_data->ts_dropped_bytes;
+	data->status = DMX_OK_DECODER_BUF;
+
+	MPQ_DVB_DBG_PRINT("%s: cookie=%d\n", __func__, data->buf.cookie);
+
+	/* reset counters */
+	feed_data->ts_packets_num = 0;
+	feed_data->ts_dropped_bytes = 0;
+	feed_data->tei_errs = 0;
+	feed_data->continuity_errs = 0;
+}
+
+static inline void mpq_dmx_prepare_audio_es_event_data(
+			struct mpq_streambuffer_packet_header *packet,
+			struct mpq_adapter_audio_meta_data *meta_data,
+			struct mpq_audio_feed_info *feed_data,
+			struct mpq_streambuffer *stream_buffer,
+			struct dmx_data_ready *data,
+			int cookie)
+{
+	struct dmx_pts_dts_info *pts_dts;
+
+	pts_dts = &meta_data->info.pes.pts_dts_info;
+	data->buf.stc = meta_data->info.pes.stc;
+
+	data->data_length = 0;
+	data->buf.handle = packet->raw_data_handle;
+	data->buf.cookie = cookie;
+	data->buf.offset = packet->raw_data_offset;
+	data->buf.len = packet->raw_data_len;
+	data->buf.pts_exists = pts_dts->pts_exist;
+	data->buf.pts = pts_dts->pts;
+	data->buf.dts_exists = pts_dts->dts_exist;
+	data->buf.dts = pts_dts->dts;
+	data->buf.tei_counter = feed_data->tei_errs;
+	data->buf.cont_err_counter = feed_data->continuity_errs;
+	data->buf.ts_packets_num = feed_data->ts_packets_num;
+	data->buf.ts_dropped_bytes = feed_data->ts_dropped_bytes;
+	data->status = DMX_OK_DECODER_BUF;
+
+	MPQ_DVB_DBG_PRINT("%s: cookie=%d\n", __func__, data->buf.cookie);
+
+	/* reset counters */
+	feed_data->ts_packets_num = 0;
+	feed_data->ts_dropped_bytes = 0;
+	feed_data->tei_errs = 0;
+	feed_data->continuity_errs = 0;
+}
+
+static int mpq_sdmx_dvr_buffer_desc(struct mpq_demux *mpq_demux,
+	struct sdmx_buff_descr *buf_desc)
+{
+	struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *)
+				mpq_demux->demux.dmx.dvr_input.ringbuff;
+	struct ion_handle *ion_handle =
+		mpq_demux->demux.dmx.dvr_input.priv_handle;
+	ion_phys_addr_t phys_addr;
+	size_t len;
+	int ret;
+
+	ret = ion_phys(mpq_demux->ion_client, ion_handle, &phys_addr, &len);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Failed to obtain physical address of input buffer. ret = %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	buf_desc->base_addr = (u64)phys_addr;
+	buf_desc->size = rbuf->size;
+
+	return 0;
+}
+
+static inline int mpq_dmx_notify_overflow(struct dvb_demux_feed *feed)
+{
+	struct dmx_data_ready data;
+
+	data.data_length = 0;
+	data.status = DMX_OVERRUN_ERROR;
+	return feed->data_ready_cb.ts(&feed->feed.ts, &data);
+}
+
+/**
+ * mpq_dmx_decoder_frame_closure - Helper function to handle closing current
+ * pending frame upon reaching EOS.
+ *
+ * @mpq_demux - mpq demux instance
+ * @mpq_feed - mpq feed object
+ */
+static void mpq_dmx_decoder_frame_closure(struct mpq_demux *mpq_demux,
+		struct mpq_feed *mpq_feed)
+{
+	struct mpq_streambuffer_packet_header packet;
+	struct mpq_streambuffer *stream_buffer;
+	struct mpq_adapter_video_meta_data meta_data;
+	struct mpq_video_feed_info *feed_data;
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct dmx_data_ready data;
+	int cookie;
+
+	feed_data = &mpq_feed->video_info;
+
+	/*
+	 * spin-lock is taken to protect against manipulation of video
+	 * output buffer by the API (terminate video feed, re-use of video
+	 * buffers).
+	 */
+	spin_lock(&feed_data->video_buffer_lock);
+	stream_buffer = feed_data->video_buffer;
+
+	if (stream_buffer == NULL) {
+		MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__);
+		spin_unlock(&feed_data->video_buffer_lock);
+		return;
+	}
+
+	/* Report last pattern found */
+	if ((feed_data->pending_pattern_len) &&
+		mpq_dmx_is_video_frame(feed->video_codec,
+			feed_data->last_framing_match_type)) {
+		meta_data.packet_type = DMX_FRAMING_INFO_PACKET;
+		mpq_dmx_write_pts_dts(feed_data,
+			&(meta_data.info.framing.pts_dts_info));
+		mpq_dmx_save_pts_dts(feed_data);
+		packet.user_data_len =
+			sizeof(struct mpq_adapter_video_meta_data);
+		packet.raw_data_len = feed_data->pending_pattern_len;
+		packet.raw_data_offset = feed_data->frame_offset;
+		meta_data.info.framing.pattern_type =
+			feed_data->last_framing_match_type;
+		meta_data.info.framing.stc = feed_data->last_framing_match_stc;
+		meta_data.info.framing.continuity_error_counter =
+			feed_data->continuity_errs;
+		meta_data.info.framing.transport_error_indicator_counter =
+			feed_data->tei_errs;
+		meta_data.info.framing.ts_dropped_bytes =
+			feed_data->ts_dropped_bytes;
+		meta_data.info.framing.ts_packets_num =
+			feed_data->ts_packets_num;
+
+		mpq_streambuffer_get_buffer_handle(stream_buffer,
+			0, /* current write buffer handle */
+			&packet.raw_data_handle);
+
+		mpq_dmx_update_decoder_stat(mpq_feed);
+
+		/* Writing meta-data that includes the framing information */
+		cookie = mpq_streambuffer_pkt_write(stream_buffer, &packet,
+			(u8 *)&meta_data);
+		if (cookie >= 0) {
+			mpq_dmx_prepare_es_event_data(&packet, &meta_data,
+				feed_data, stream_buffer, &data, cookie);
+			feed->data_ready_cb.ts(&feed->feed.ts, &data);
+		} else {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_streambuffer_pkt_write failed, ret=%d\n",
+				__func__, cookie);
+		}
+	}
+
+	spin_unlock(&feed_data->video_buffer_lock);
+}
+
+/**
+ * mpq_dmx_decoder_pes_closure - Helper function to handle closing current PES
+ * upon reaching EOS.
+ *
+ * @mpq_demux - mpq demux instance
+ * @mpq_feed - mpq feed object
+ */
+static void mpq_dmx_decoder_pes_closure(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed)
+{
+	struct mpq_streambuffer_packet_header packet;
+	struct mpq_streambuffer *stream_buffer;
+	struct mpq_adapter_video_meta_data meta_data;
+	struct mpq_video_feed_info *feed_data;
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct dmx_data_ready data;
+	int cookie;
+
+	feed_data = &mpq_feed->video_info;
+
+	/*
+	 * spin-lock is taken to protect against manipulation of video
+	 * output buffer by the API (terminate video feed, re-use of video
+	 * buffers).
+	 */
+	spin_lock(&feed_data->video_buffer_lock);
+	stream_buffer = feed_data->video_buffer;
+
+	if (stream_buffer == NULL) {
+		MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__);
+		spin_unlock(&feed_data->video_buffer_lock);
+		return;
+	}
+
+	/*
+	 * Close previous PES.
+	 * Push new packet to the meta-data buffer.
+	 */
+	if ((feed->pusi_seen) && (feed_data->pes_header_left_bytes == 0)) {
+		packet.raw_data_len = feed->peslen;
+		mpq_streambuffer_get_buffer_handle(stream_buffer,
+			0, /* current write buffer handle */
+			&packet.raw_data_handle);
+		packet.raw_data_offset = feed_data->frame_offset;
+		packet.user_data_len =
+			sizeof(struct mpq_adapter_video_meta_data);
+
+		mpq_dmx_write_pts_dts(feed_data,
+			&(meta_data.info.pes.pts_dts_info));
+
+		meta_data.packet_type = DMX_PES_PACKET;
+		meta_data.info.pes.stc = feed_data->prev_stc;
+
+		mpq_dmx_update_decoder_stat(mpq_feed);
+
+		cookie = mpq_streambuffer_pkt_write(stream_buffer, &packet,
+			(u8 *)&meta_data);
+		if (cookie >= 0) {
+			/* Save write offset where new PES will begin */
+			mpq_streambuffer_get_data_rw_offset(stream_buffer, NULL,
+				&feed_data->frame_offset);
+			mpq_dmx_prepare_es_event_data(&packet, &meta_data,
+				feed_data, stream_buffer, &data, cookie);
+			feed->data_ready_cb.ts(&feed->feed.ts, &data);
+		} else {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_streambuffer_pkt_write failed, ret=%d\n",
+				__func__, cookie);
+		}
+	}
+	/* Reset PES info */
+	feed->peslen = 0;
+	feed_data->pes_header_offset = 0;
+	feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN;
+
+	spin_unlock(&feed_data->video_buffer_lock);
+}
+
+/*
+ * in audio handling although ES frames are send to decoder, close the
+ * pes packet
+ */
+static void mpq_dmx_decoder_audio_pes_closure(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed)
+{
+	struct mpq_streambuffer_packet_header packet;
+	struct mpq_streambuffer *stream_buffer;
+	struct mpq_adapter_audio_meta_data meta_data;
+	struct mpq_audio_feed_info *feed_data;
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct dmx_data_ready data;
+	int cookie;
+
+	feed_data = &mpq_feed->audio_info;
+
+	/*
+	 * spin-lock is taken to protect against manipulation of audio
+	 * output buffer by the API (terminate audio feed, re-use of audio
+	 * buffers).
+	 */
+	spin_lock(&feed_data->audio_buffer_lock);
+	stream_buffer = feed_data->audio_buffer;
+
+	if (stream_buffer == NULL) {
+		MPQ_DVB_DBG_PRINT("%s: audio_buffer released\n", __func__);
+		spin_unlock(&feed_data->audio_buffer_lock);
+		return;
+	}
+
+	/*
+	 * Close previous PES.
+	 * Push new packet to the meta-data buffer.
+	 */
+	if ((feed->pusi_seen) && (feed_data->pes_header_left_bytes == 0)) {
+		packet.raw_data_len = feed->peslen;
+		mpq_streambuffer_get_buffer_handle(stream_buffer,
+			0, /* current write buffer handle */
+			&packet.raw_data_handle);
+		packet.raw_data_offset = feed_data->frame_offset;
+		packet.user_data_len =
+			sizeof(struct mpq_adapter_audio_meta_data);
+
+		mpq_dmx_write_audio_pts_dts(feed_data,
+			&(meta_data.info.pes.pts_dts_info));
+
+		meta_data.packet_type = DMX_PES_PACKET;
+		meta_data.info.pes.stc = feed_data->prev_stc;
+
+		mpq_dmx_update_decoder_stat(mpq_feed);
+
+		cookie = mpq_streambuffer_pkt_write(stream_buffer, &packet,
+			(u8 *)&meta_data);
+		if (cookie >= 0) {
+			/* Save write offset where new PES will begin */
+			mpq_streambuffer_get_data_rw_offset(stream_buffer, NULL,
+				&feed_data->frame_offset);
+			mpq_dmx_prepare_audio_es_event_data(&packet, &meta_data,
+				feed_data, stream_buffer, &data, cookie);
+			feed->data_ready_cb.ts(&feed->feed.ts, &data);
+		} else {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_sb_pkt_write failed, ret=%d\n",
+				__func__, cookie);
+		}
+	}
+	/* Reset PES info */
+	feed->peslen = 0;
+	feed_data->pes_header_offset = 0;
+	feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN;
+
+	spin_unlock(&feed_data->audio_buffer_lock);
+}
+
+static int mpq_dmx_process_video_packet_framing(
+			struct dvb_demux_feed *feed,
+			const u8 *buf,
+			u64 curr_stc)
+{
+	int bytes_avail;
+	u32 ts_payload_offset;
+	struct mpq_video_feed_info *feed_data;
+	const struct ts_packet_header *ts_header;
+	struct mpq_streambuffer *stream_buffer;
+	struct pes_packet_header *pes_header;
+	struct mpq_demux *mpq_demux;
+	struct mpq_feed *mpq_feed;
+
+	struct dvb_dmx_video_patterns_results framing_res;
+	struct mpq_streambuffer_packet_header packet;
+	struct mpq_adapter_video_meta_data meta_data;
+	int bytes_written = 0;
+	int bytes_to_write = 0;
+	int found_patterns = 0;
+	int first_pattern = 0;
+	int i;
+	int is_video_frame = 0;
+	int pending_data_len = 0;
+	int ret = 0;
+	int discontinuity_indicator = 0;
+	struct dmx_data_ready data;
+
+	mpq_demux = feed->demux->priv;
+
+	mpq_feed = feed->priv;
+	feed_data = &mpq_feed->video_info;
+
+	/*
+	 * spin-lock is taken to protect against manipulation of video
+	 * output buffer by the API (terminate video feed, re-use of video
+	 * buffers). Mutex on the video-feed cannot be held here
+	 * since SW demux holds a spin-lock while calling write_to_decoder
+	 */
+	spin_lock(&feed_data->video_buffer_lock);
+	stream_buffer = feed_data->video_buffer;
+
+	if (stream_buffer == NULL) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: video_buffer released\n",
+			__func__);
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	ts_header = (const struct ts_packet_header *)buf;
+
+	pes_header = &feed_data->pes_header;
+
+	/* Make sure this TS packet has a payload and not scrambled */
+	if ((ts_header->sync_byte != 0x47) ||
+		(ts_header->adaptation_field_control == 0) ||
+		(ts_header->adaptation_field_control == 2) ||
+		(ts_header->transport_scrambling_control)) {
+		/* continue to next packet */
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	if (ts_header->payload_unit_start_indicator) { /* PUSI? */
+		if (feed->pusi_seen) { /* Did we see PUSI before? */
+			/*
+			 * Double check that we are not in middle of
+			 * previous PES header parsing.
+			 */
+			if (feed_data->pes_header_left_bytes != 0)
+				MPQ_DVB_ERR_PRINT(
+					"%s: received PUSI while handling PES header of previous PES\n",
+					__func__);
+
+			feed->peslen = 0;
+			feed_data->pes_header_offset = 0;
+			feed_data->pes_header_left_bytes =
+				PES_MANDATORY_FIELDS_LEN;
+		} else {
+			feed->pusi_seen = 1;
+		}
+	}
+
+	/*
+	 * Parse PES data only if PUSI was encountered,
+	 * otherwise the data is dropped
+	 */
+	if (!feed->pusi_seen) {
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0; /* drop and wait for next packets */
+	}
+
+	ts_payload_offset = sizeof(struct ts_packet_header);
+
+	/*
+	 * Skip adaptation field if exists.
+	 * Save discontinuity indicator if exists.
+	 */
+	if (ts_header->adaptation_field_control == 3) {
+		const struct ts_adaptation_field *adaptation_field =
+			(const struct ts_adaptation_field *)(buf +
+				ts_payload_offset);
+
+		discontinuity_indicator =
+			adaptation_field->discontinuity_indicator;
+		ts_payload_offset += buf[ts_payload_offset] + 1;
+	}
+
+	bytes_avail = TS_PACKET_SIZE - ts_payload_offset;
+
+	/* Get the mandatory fields of the video PES header */
+	if (mpq_dmx_parse_mandatory_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	if (mpq_dmx_parse_remaining_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	/*
+	 * If we reached here,
+	 * then we are now at the PES payload data
+	 */
+	if (bytes_avail == 0) {
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	/*
+	 * the decoder requires demux to do framing,
+	 * so search for the patterns now.
+	 */
+	found_patterns = dvb_dmx_video_pattern_search(
+				feed_data->patterns,
+				feed_data->patterns_num,
+				(buf + ts_payload_offset),
+				bytes_avail,
+				&feed_data->prefix_size,
+				&framing_res);
+
+	if (!feed_data->found_sequence_header_pattern) {
+		for (i = 0; i < found_patterns; i++) {
+			if ((framing_res.info[i].type ==
+				DMX_IDX_MPEG_SEQ_HEADER) ||
+			    (framing_res.info[i].type ==
+				DMX_IDX_H264_SPS) ||
+				(framing_res.info[i].type ==
+				DMX_IDX_VC1_SEQ_HEADER)) {
+
+				MPQ_DVB_DBG_PRINT(
+					"%s: Found Sequence Pattern, buf %p, i = %d, offset = %d, type = %lld\n",
+					__func__, buf, i,
+					framing_res.info[i].offset,
+					framing_res.info[i].type);
+
+				first_pattern = i;
+				feed_data->found_sequence_header_pattern = 1;
+				ts_payload_offset +=
+					framing_res.info[i].offset;
+				bytes_avail -= framing_res.info[i].offset;
+
+				if (framing_res.info[i].used_prefix_size) {
+					feed_data->first_prefix_size =
+						framing_res.info[i].
+							used_prefix_size;
+				}
+				break;
+			}
+		}
+	}
+
+	/*
+	 * If decoder requires demux to do framing,
+	 * pass data to decoder only after sequence header
+	 * or equivalent is found. Otherwise the data is dropped.
+	 */
+	if (!feed_data->found_sequence_header_pattern) {
+		feed_data->prev_stc = curr_stc;
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	/* Update error counters based on TS header */
+	feed_data->ts_packets_num++;
+	feed_data->tei_errs += ts_header->transport_error_indicator;
+	mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors +=
+		ts_header->transport_error_indicator;
+	mpq_dmx_check_continuity(feed_data,
+				ts_header->continuity_counter,
+				discontinuity_indicator);
+	mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors +=
+		feed_data->continuity_errs;
+
+	/* Need to back-up the PTS information of the very first frame */
+	if (feed_data->first_pts_dts_copy) {
+		for (i = first_pattern; i < found_patterns; i++) {
+			is_video_frame = mpq_dmx_is_video_frame(
+					feed->video_codec,
+					framing_res.info[i].type);
+
+			if (is_video_frame == 1) {
+				mpq_dmx_save_pts_dts(feed_data);
+				feed_data->first_pts_dts_copy = 0;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * write prefix used to find first Sequence pattern, if needed.
+	 * feed_data->patterns[0]->pattern always contains the sequence
+	 * header pattern.
+	 */
+	if (feed_data->first_prefix_size) {
+		ret = mpq_streambuffer_data_write(stream_buffer,
+			feed_data->patterns[0]->pattern,
+			feed_data->first_prefix_size);
+		if (ret < 0) {
+			mpq_demux->decoder_stat
+				[feed_data->stream_interface].drop_count +=
+				feed_data->first_prefix_size;
+			feed_data->ts_dropped_bytes +=
+				feed_data->first_prefix_size;
+			MPQ_DVB_DBG_PRINT("%s: could not write prefix\n",
+				__func__);
+			if (ret == -ENOSPC)
+				mpq_dmx_notify_overflow(feed);
+		} else {
+			MPQ_DVB_DBG_PRINT(
+				"%s: Writing pattern prefix of size %d\n",
+				__func__, feed_data->first_prefix_size);
+			/*
+			 * update the length of the data we report
+			 * to include the size of the prefix that was used.
+			 */
+			feed_data->pending_pattern_len +=
+				feed_data->first_prefix_size;
+		}
+	}
+
+	feed->peslen += bytes_avail;
+	pending_data_len += bytes_avail;
+
+	meta_data.packet_type = DMX_FRAMING_INFO_PACKET;
+	packet.user_data_len = sizeof(struct mpq_adapter_video_meta_data);
+
+	/*
+	 * Go over all the patterns that were found in this packet.
+	 * For each pattern found, write the relevant data to the data
+	 * buffer, then write the respective meta-data.
+	 * Each pattern can only be reported when the next pattern is found
+	 * (in order to know the data length).
+	 * There are three possible cases for each pattern:
+	 * 1. This is the very first pattern we found in any TS packet in this
+	 *    feed.
+	 * 2. This is the first pattern found in this TS packet, but we've
+	 *    already found patterns in previous packets.
+	 * 3. This is not the first pattern in this packet, i.e., we've
+	 *    already found patterns in this TS packet.
+	 */
+	for (i = first_pattern; i < found_patterns; i++) {
+		if (i == first_pattern) {
+			/*
+			 * The way to identify the very first pattern:
+			 * 1. It's the first pattern found in this packet.
+			 * 2. The pending_pattern_len, which indicates the
+			 *    data length of the previous pattern that has
+			 *    not yet been reported, is usually 0. However,
+			 *    it may be larger than 0 if a prefix was used
+			 *    to find this pattern (i.e., the pattern was
+			 *    split over two TS packets). In that case,
+			 *    pending_pattern_len equals first_prefix_size.
+			 *    first_prefix_size is set to 0 later in this
+			 *    function.
+			 */
+			if (feed_data->first_prefix_size ==
+				feed_data->pending_pattern_len) {
+				/*
+				 * This is the very first pattern, so no
+				 * previous pending frame data exists.
+				 * Update frame info and skip to the
+				 * next frame.
+				 */
+				feed_data->last_framing_match_type =
+					framing_res.info[i].type;
+				feed_data->last_pattern_offset =
+					framing_res.info[i].offset;
+				if (framing_res.info[i].used_prefix_size)
+					feed_data->last_framing_match_stc =
+						feed_data->prev_stc;
+				else
+					feed_data->last_framing_match_stc =
+						curr_stc;
+				continue;
+			}
+			/*
+			 * This is the first pattern in this
+			 * packet and previous frame from
+			 * previous packet is pending for report
+			 */
+			bytes_to_write = framing_res.info[i].offset;
+		} else {
+			/* Previous pending frame is in the same packet */
+			bytes_to_write =
+				framing_res.info[i].offset -
+				feed_data->last_pattern_offset;
+		}
+
+		ret = mpq_streambuffer_data_write(
+			stream_buffer,
+			(buf + ts_payload_offset + bytes_written),
+			bytes_to_write);
+		if (ret < 0) {
+			mpq_demux->decoder_stat
+				[feed_data->stream_interface].drop_count +=
+				bytes_to_write;
+			feed_data->ts_dropped_bytes += bytes_to_write;
+			MPQ_DVB_DBG_PRINT(
+				"%s: Couldn't write %d bytes to data buffer, ret=%d\n",
+				__func__, bytes_to_write, ret);
+			if (ret == -ENOSPC)
+				mpq_dmx_notify_overflow(feed);
+		} else {
+			bytes_written += bytes_to_write;
+			pending_data_len -= bytes_to_write;
+			feed_data->pending_pattern_len += bytes_to_write;
+		}
+		non_predicted_video_frame = 0;
+
+		is_video_frame = mpq_dmx_is_video_frame(
+				feed->video_codec,
+				feed_data->last_framing_match_type);
+		if (is_video_frame == 1) {
+			mpq_dmx_write_pts_dts(feed_data,
+				&(meta_data.info.framing.pts_dts_info));
+			mpq_dmx_save_pts_dts(feed_data);
+
+			packet.raw_data_len = feed_data->pending_pattern_len -
+				framing_res.info[i].used_prefix_size;
+			packet.raw_data_offset = feed_data->frame_offset;
+			meta_data.info.framing.pattern_type =
+				feed_data->last_framing_match_type;
+			meta_data.info.framing.stc =
+				feed_data->last_framing_match_stc;
+			meta_data.info.framing.continuity_error_counter =
+				feed_data->continuity_errs;
+			meta_data.info.framing.
+				transport_error_indicator_counter =
+				 feed_data->tei_errs;
+			meta_data.info.framing.ts_dropped_bytes =
+				feed_data->ts_dropped_bytes;
+			meta_data.info.framing.ts_packets_num =
+				feed_data->ts_packets_num;
+
+			mpq_streambuffer_get_buffer_handle(
+				stream_buffer,
+				0,	/* current write buffer handle */
+				&packet.raw_data_handle);
+
+			mpq_dmx_update_decoder_stat(mpq_feed);
+
+			if (video_b_frame_events == 1) {
+				if (non_predicted_video_frame == 0) {
+					struct dmx_pts_dts_info *pts_dts;
+
+					pts_dts =
+					&meta_data.info.framing.pts_dts_info;
+					pts_dts->pts_exist = 0;
+					pts_dts->pts = 0;
+					pts_dts->dts_exist = 0;
+					pts_dts->dts = 0;
+				}
+			}
+			/*
+			 * Write meta-data that includes the framing information
+			 */
+			ret = mpq_streambuffer_pkt_write(stream_buffer, &packet,
+				(u8 *)&meta_data);
+			if (ret < 0) {
+				MPQ_DVB_ERR_PRINT
+					("%s: mpq_sb_pkt_write failed ret=%d\n",
+					 __func__, ret);
+				if (ret == -ENOSPC)
+					mpq_dmx_notify_overflow(feed);
+			} else {
+				mpq_dmx_prepare_es_event_data(
+					&packet, &meta_data, feed_data,
+					stream_buffer, &data, ret);
+
+				/* Trigger ES Data Event for VPTS */
+				feed->data_ready_cb.ts(&feed->feed.ts, &data);
+
+				if (feed_data->video_buffer->mode ==
+					MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
+					feed_data->frame_offset = 0;
+				else
+					mpq_streambuffer_get_data_rw_offset(
+						feed_data->video_buffer,
+						NULL,
+						&feed_data->frame_offset);
+			}
+
+			/*
+			 * In linear buffers, after writing the packet
+			 * we switched over to a new linear buffer for the new
+			 * frame. In that case, we should re-write the prefix
+			 * of the existing frame if any exists.
+			 */
+			if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR ==
+				 feed_data->video_buffer->mode) &&
+				framing_res.info[i].used_prefix_size) {
+				ret = mpq_streambuffer_data_write(stream_buffer,
+					feed_data->prev_pattern +
+					 DVB_DMX_MAX_PATTERN_LEN -
+					 framing_res.info[i].used_prefix_size,
+					framing_res.info[i].used_prefix_size);
+
+				if (ret < 0) {
+					feed_data->pending_pattern_len = 0;
+					mpq_demux->decoder_stat
+						[feed_data->stream_interface].
+						drop_count += bytes_avail;
+					feed_data->ts_dropped_bytes +=
+					 framing_res.info[i].used_prefix_size;
+					if (ret == -ENOSPC)
+						mpq_dmx_notify_overflow(feed);
+				} else {
+					feed_data->pending_pattern_len =
+					 framing_res.info[i].used_prefix_size;
+				}
+			} else {
+				s32 offset = (s32)feed_data->frame_offset;
+				u32 buff_size =
+				 feed_data->video_buffer->buffers[0].size;
+
+				offset -= framing_res.info[i].used_prefix_size;
+				offset += (offset < 0) ? buff_size : 0;
+				feed_data->pending_pattern_len =
+					framing_res.info[i].used_prefix_size;
+
+				if (MPQ_STREAMBUFFER_BUFFER_MODE_RING ==
+					feed_data->video_buffer->mode) {
+					feed_data->frame_offset = (u32)offset;
+				}
+			}
+		}
+
+		/* save the last match for next time */
+		feed_data->last_framing_match_type =
+			framing_res.info[i].type;
+		feed_data->last_pattern_offset =
+			framing_res.info[i].offset;
+		if (framing_res.info[i].used_prefix_size)
+			feed_data->last_framing_match_stc = feed_data->prev_stc;
+		else
+			feed_data->last_framing_match_stc = curr_stc;
+	}
+
+	feed_data->prev_stc = curr_stc;
+	feed_data->first_prefix_size = 0;
+
+	/*
+	 * Save the trailing of the TS packet as we might have a pattern
+	 * split that we need to re-use when closing the next
+	 * video linear buffer.
+	 */
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR ==
+		feed_data->video_buffer->mode)
+		memcpy(feed_data->prev_pattern,
+			buf + TS_PACKET_SIZE - DVB_DMX_MAX_PATTERN_LEN,
+			DVB_DMX_MAX_PATTERN_LEN);
+
+	if (pending_data_len) {
+		ret = mpq_streambuffer_data_write(
+			stream_buffer,
+			(buf + ts_payload_offset + bytes_written),
+			pending_data_len);
+
+		if (ret < 0) {
+			mpq_demux->decoder_stat
+				[feed_data->stream_interface].drop_count +=
+				pending_data_len;
+			feed_data->ts_dropped_bytes += pending_data_len;
+			MPQ_DVB_DBG_PRINT(
+				"%s: Couldn't write %d pending bytes to data buffer, ret=%d\n",
+				__func__, pending_data_len, ret);
+			if (ret == -ENOSPC)
+				mpq_dmx_notify_overflow(feed);
+		} else {
+			feed_data->pending_pattern_len += pending_data_len;
+		}
+	}
+
+	spin_unlock(&feed_data->video_buffer_lock);
+	return 0;
+}
+
+static int mpq_dmx_process_video_packet_no_framing(
+			struct dvb_demux_feed *feed,
+			const u8 *buf,
+			u64 curr_stc)
+{
+	int bytes_avail;
+	u32 ts_payload_offset;
+	struct mpq_video_feed_info *feed_data;
+	const struct ts_packet_header *ts_header;
+	struct mpq_streambuffer *stream_buffer;
+	struct pes_packet_header *pes_header;
+	struct mpq_demux *mpq_demux;
+	struct mpq_feed *mpq_feed;
+	int discontinuity_indicator = 0;
+	struct dmx_data_ready data;
+	int cookie;
+	int ret;
+
+	mpq_demux = feed->demux->priv;
+	mpq_feed = feed->priv;
+	feed_data = &mpq_feed->video_info;
+
+	/*
+	 * spin-lock is taken to protect against manipulation of video
+	 * output buffer by the API (terminate video feed, re-use of video
+	 * buffers). Mutex on the video-feed cannot be held here
+	 * since SW demux holds a spin-lock while calling write_to_decoder
+	 */
+	spin_lock(&feed_data->video_buffer_lock);
+	stream_buffer = feed_data->video_buffer;
+	if (stream_buffer == NULL) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: video_buffer released\n",
+			__func__);
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	ts_header = (const struct ts_packet_header *)buf;
+
+	pes_header = &feed_data->pes_header;
+
+	/* Make sure this TS packet has a payload and not scrambled */
+	if ((ts_header->sync_byte != 0x47) ||
+		(ts_header->adaptation_field_control == 0) ||
+		(ts_header->adaptation_field_control == 2) ||
+		(ts_header->transport_scrambling_control)) {
+		/* continue to next packet */
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	if (ts_header->payload_unit_start_indicator) { /* PUSI? */
+		if (feed->pusi_seen) { /* Did we see PUSI before? */
+			struct mpq_streambuffer_packet_header packet;
+			struct mpq_adapter_video_meta_data meta_data;
+
+			/*
+			 * Close previous PES.
+			 * Push new packet to the meta-data buffer.
+			 * Double check that we are not in middle of
+			 * previous PES header parsing.
+			 */
+
+			if (feed_data->pes_header_left_bytes == 0) {
+				packet.raw_data_len = feed->peslen;
+				mpq_streambuffer_get_buffer_handle(
+					stream_buffer,
+					0, /* current write buffer handle */
+					&packet.raw_data_handle);
+				packet.raw_data_offset =
+					feed_data->frame_offset;
+				packet.user_data_len =
+					sizeof(struct
+						mpq_adapter_video_meta_data);
+
+				mpq_dmx_write_pts_dts(feed_data,
+					&(meta_data.info.pes.pts_dts_info));
+
+				/* Mark that we detected start of new PES */
+				feed_data->first_pts_dts_copy = 1;
+
+				meta_data.packet_type = DMX_PES_PACKET;
+				meta_data.info.pes.stc = feed_data->prev_stc;
+
+				mpq_dmx_update_decoder_stat(mpq_feed);
+
+				cookie = mpq_streambuffer_pkt_write(
+					stream_buffer, &packet,
+					(u8 *)&meta_data);
+				if (cookie < 0) {
+					MPQ_DVB_ERR_PRINT
+						("%s: write failed, ret=%d\n",
+						__func__, cookie);
+				} else {
+					/*
+					 * Save write offset where new PES
+					 * will begin
+					 */
+					mpq_streambuffer_get_data_rw_offset(
+						stream_buffer,
+						NULL,
+						&feed_data->frame_offset);
+
+					mpq_dmx_prepare_es_event_data(
+						&packet, &meta_data,
+						feed_data,
+						stream_buffer, &data, cookie);
+
+					feed->data_ready_cb.ts(&feed->feed.ts,
+						&data);
+				}
+			} else {
+				MPQ_DVB_ERR_PRINT(
+					"%s: received PUSI while handling PES header of previous PES\n",
+					__func__);
+			}
+
+			/* Reset PES info */
+			feed->peslen = 0;
+			feed_data->pes_header_offset = 0;
+			feed_data->pes_header_left_bytes =
+				PES_MANDATORY_FIELDS_LEN;
+		} else {
+			feed->pusi_seen = 1;
+		}
+
+		feed_data->prev_stc = curr_stc;
+	}
+
+	/*
+	 * Parse PES data only if PUSI was encountered,
+	 * otherwise the data is dropped
+	 */
+	if (!feed->pusi_seen) {
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0; /* drop and wait for next packets */
+	}
+
+	ts_payload_offset = sizeof(struct ts_packet_header);
+
+	/*
+	 * Skip adaptation field if exists.
+	 * Save discontinuity indicator if exists.
+	 */
+	if (ts_header->adaptation_field_control == 3) {
+		const struct ts_adaptation_field *adaptation_field =
+			(const struct ts_adaptation_field *)(buf +
+				ts_payload_offset);
+
+		discontinuity_indicator =
+			adaptation_field->discontinuity_indicator;
+		ts_payload_offset += buf[ts_payload_offset] + 1;
+	}
+
+	bytes_avail = TS_PACKET_SIZE - ts_payload_offset;
+
+	/* Get the mandatory fields of the video PES header */
+	if (mpq_dmx_parse_mandatory_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	if (mpq_dmx_parse_remaining_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	/*
+	 * If we reached here,
+	 * then we are now at the PES payload data
+	 */
+	if (bytes_avail == 0) {
+		spin_unlock(&feed_data->video_buffer_lock);
+		return 0;
+	}
+
+	/*
+	 * Need to back-up the PTS information
+	 * of the start of new PES
+	 */
+	if (feed_data->first_pts_dts_copy) {
+		mpq_dmx_save_pts_dts(feed_data);
+		feed_data->first_pts_dts_copy = 0;
+	}
+
+	/* Update error counters based on TS header */
+	feed_data->ts_packets_num++;
+	feed_data->tei_errs += ts_header->transport_error_indicator;
+	mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors +=
+		ts_header->transport_error_indicator;
+	mpq_dmx_check_continuity(feed_data,
+				ts_header->continuity_counter,
+				discontinuity_indicator);
+	mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors +=
+		feed_data->continuity_errs;
+
+	ret = mpq_streambuffer_data_write(stream_buffer, buf+ts_payload_offset,
+		bytes_avail);
+	if (ret < 0) {
+		mpq_demux->decoder_stat
+			[feed_data->stream_interface].drop_count += bytes_avail;
+		feed_data->ts_dropped_bytes += bytes_avail;
+		if (ret == -ENOSPC)
+			mpq_dmx_notify_overflow(feed);
+	} else {
+		feed->peslen += bytes_avail;
+	}
+
+	spin_unlock(&feed_data->video_buffer_lock);
+
+	return 0;
+}
+
+/*
+ * parse PES headers and send down ES packets to decoder
+ * Trigger a new ES Data Event with APTS and QTimer in 1st PES
+ */
+static int mpq_dmx_process_audio_packet_no_framing(
+			struct dvb_demux_feed *feed,
+			const u8 *buf,
+			u64 curr_stc)
+{
+	int bytes_avail;
+	u32 ts_payload_offset;
+	struct mpq_audio_feed_info *feed_data;
+	const struct ts_packet_header *ts_header;
+	struct mpq_streambuffer *stream_buffer;
+	struct pes_packet_header *pes_header;
+	struct mpq_demux *mpq_demux;
+	struct mpq_feed *mpq_feed;
+	int discontinuity_indicator = 0;
+	struct dmx_data_ready data;
+	int cookie;
+	int ret;
+
+	mpq_demux = feed->demux->priv;
+	mpq_feed = feed->priv;
+	feed_data = &mpq_feed->audio_info;
+
+	/*
+	 * spin-lock is taken to protect against manipulation of audio
+	 * output buffer by the API (terminate audio feed, re-use of audio
+	 * buffers). Mutex on the audio-feed cannot be held here
+	 * since SW demux holds a spin-lock while calling write_to_decoder
+	 */
+	spin_lock(&feed_data->audio_buffer_lock);
+	stream_buffer = feed_data->audio_buffer;
+	if (stream_buffer == NULL) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: audio_buffer released\n",
+			__func__);
+		spin_unlock(&feed_data->audio_buffer_lock);
+		return 0;
+	}
+
+	ts_header = (const struct ts_packet_header *)buf;
+
+	pes_header = &feed_data->pes_header;
+
+	/* Make sure this TS packet has a payload and not scrambled */
+	if ((ts_header->sync_byte != 0x47) ||
+		(ts_header->adaptation_field_control == 0) ||
+		(ts_header->adaptation_field_control == 2) ||
+		(ts_header->transport_scrambling_control)) {
+		/* continue to next packet */
+		spin_unlock(&feed_data->audio_buffer_lock);
+		return 0;
+	}
+
+	if (ts_header->payload_unit_start_indicator) { /* PUSI? */
+		if (feed->pusi_seen) { /* Did we see PUSI before? */
+			struct mpq_streambuffer_packet_header packet;
+			struct mpq_adapter_audio_meta_data meta_data;
+
+			/*
+			 * Close previous PES.
+			 * Push new packet to the meta-data buffer.
+			 * Double check that we are not in middle of
+			 * previous PES header parsing.
+			 */
+
+			if (feed_data->pes_header_left_bytes == 0) {
+				packet.raw_data_len = feed->peslen;
+				mpq_streambuffer_get_buffer_handle(
+					stream_buffer,
+					0, /* current write buffer handle */
+					&packet.raw_data_handle);
+				packet.raw_data_offset =
+					feed_data->frame_offset;
+				packet.user_data_len =
+					sizeof(struct
+						mpq_adapter_audio_meta_data);
+
+				mpq_dmx_write_audio_pts_dts(feed_data,
+					&(meta_data.info.pes.pts_dts_info));
+
+				/* Mark that we detected start of new PES */
+				feed_data->first_pts_dts_copy = 1;
+
+				meta_data.packet_type = DMX_PES_PACKET;
+				meta_data.info.pes.stc = feed_data->prev_stc;
+
+				mpq_dmx_update_decoder_stat(mpq_feed);
+
+				/* actual writing of stream audio headers */
+				cookie = mpq_streambuffer_pkt_write(
+					stream_buffer, &packet,
+					(u8 *)&meta_data);
+				if (cookie < 0) {
+					MPQ_DVB_ERR_PRINT
+						("%s: write failed, ret=%d\n",
+						 __func__, cookie);
+				} else {
+					/*
+					 * Save write offset where new PES
+					 * will begin
+					 */
+					mpq_streambuffer_get_data_rw_offset(
+						stream_buffer,
+						NULL,
+						&feed_data->frame_offset);
+
+					mpq_dmx_prepare_audio_es_event_data(
+						&packet, &meta_data,
+						feed_data,
+						stream_buffer, &data, cookie);
+
+					/*
+					 * Trigger ES data event for APTS
+					 * and AFRAME
+					 */
+					feed->data_ready_cb.ts(&feed->feed.ts,
+							       &data);
+				}
+			} else {
+				MPQ_DVB_ERR_PRINT(
+					"%s: received PUSI while handling PES header of previous PES\n",
+					 __func__);
+			}
+
+			/* Reset PES info */
+			feed->peslen = 0;
+			feed_data->pes_header_offset = 0;
+			feed_data->pes_header_left_bytes =
+				PES_MANDATORY_FIELDS_LEN;
+		} else {
+			feed->pusi_seen = 1;
+		}
+
+		feed_data->prev_stc = curr_stc;
+	}
+
+	/*
+	 * Parse PES data only if PUSI was encountered,
+	 * otherwise the data is dropped
+	 */
+	if (!feed->pusi_seen) {
+		spin_unlock(&feed_data->audio_buffer_lock);
+		return 0; /* drop and wait for next packets */
+	}
+
+	ts_payload_offset = sizeof(struct ts_packet_header);
+
+	/*
+	 * Skip adaptation field if exists.
+	 * Save discontinuity indicator if exists.
+	 */
+	if (ts_header->adaptation_field_control == 3) {
+		const struct ts_adaptation_field *adaptation_field =
+			(const struct ts_adaptation_field *)(buf +
+				ts_payload_offset);
+
+		discontinuity_indicator =
+			adaptation_field->discontinuity_indicator;
+		ts_payload_offset += buf[ts_payload_offset] + 1;
+	}
+
+	bytes_avail = TS_PACKET_SIZE - ts_payload_offset;
+
+	/* The audio decoder requires ES packets ! */
+
+	/* Get the mandatory fields of the audio PES header */
+	if (mpq_dmx_parse_mandatory_audio_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&feed_data->audio_buffer_lock);
+		return 0;
+	}
+
+	if (mpq_dmx_parse_remaining_audio_pes_header(feed, feed_data,
+						pes_header, buf,
+						&ts_payload_offset,
+						&bytes_avail)) {
+		spin_unlock(&feed_data->audio_buffer_lock);
+		return 0;
+	}
+
+	/*
+	 * If we reached here,
+	 * then we are now at the PES payload data
+	 */
+	if (bytes_avail == 0) {
+		spin_unlock(&feed_data->audio_buffer_lock);
+		return 0;
+	}
+
+	/*
+	 * Need to back-up the PTS information
+	 * of the start of new PES
+	 */
+	if (feed_data->first_pts_dts_copy) {
+		mpq_dmx_save_audio_pts_dts(feed_data);
+		feed_data->first_pts_dts_copy = 0;
+	}
+
+	/* Update error counters based on TS header */
+	feed_data->ts_packets_num++;
+	feed_data->tei_errs += ts_header->transport_error_indicator;
+	mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors +=
+		ts_header->transport_error_indicator;
+	mpq_dmx_check_audio_continuity(feed_data,
+				ts_header->continuity_counter,
+				discontinuity_indicator);
+	mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors +=
+		feed_data->continuity_errs;
+
+	/* actual writing of audio data for a stream */
+	ret = mpq_streambuffer_data_write(stream_buffer, buf+ts_payload_offset,
+		bytes_avail);
+	if (ret < 0) {
+		mpq_demux->decoder_stat
+			[feed_data->stream_interface].drop_count += bytes_avail;
+		feed_data->ts_dropped_bytes += bytes_avail;
+		if (ret == -ENOSPC)
+			mpq_dmx_notify_overflow(feed);
+	} else {
+		feed->peslen += bytes_avail;
+	}
+
+	spin_unlock(&feed_data->audio_buffer_lock);
+
+	return 0;
+}
+
+/* function ptr used in several places, handle differently */
+int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed,
+		struct dmx_buffer_status *dmx_buffer_status)
+{
+
+	if (dvb_dmx_is_video_feed(feed)) {
+		struct mpq_demux *mpq_demux = feed->demux->priv;
+		struct mpq_video_feed_info *feed_data;
+		struct mpq_streambuffer *video_buff;
+		struct mpq_feed *mpq_feed;
+
+		mutex_lock(&mpq_demux->mutex);
+
+		mpq_feed = feed->priv;
+		feed_data = &mpq_feed->video_info;
+		video_buff = feed_data->video_buffer;
+		if (!video_buff) {
+			mutex_unlock(&mpq_demux->mutex);
+			return -EINVAL;
+		}
+
+		dmx_buffer_status->error = video_buff->raw_data.error;
+
+		if (video_buff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) {
+			dmx_buffer_status->fullness =
+				video_buff->buffers[0].size *
+				video_buff->pending_buffers_count;
+			dmx_buffer_status->free_bytes =
+				video_buff->buffers[0].size *
+				(video_buff->buffers_num -
+				 video_buff->pending_buffers_count);
+			dmx_buffer_status->size =
+				video_buff->buffers[0].size *
+				video_buff->buffers_num;
+		} else {
+			dmx_buffer_status->fullness =
+				mpq_streambuffer_data_avail(video_buff);
+			dmx_buffer_status->free_bytes =
+				mpq_streambuffer_data_free(video_buff);
+			dmx_buffer_status->size = video_buff->buffers[0].size;
+		}
+
+		mpq_streambuffer_get_data_rw_offset(
+					video_buff,
+					&dmx_buffer_status->read_offset,
+					&dmx_buffer_status->write_offset);
+
+		mutex_unlock(&mpq_demux->mutex);
+
+	} else if (dvb_dmx_is_audio_feed(feed)) {
+		struct mpq_demux *mpq_demux = feed->demux->priv;
+		struct mpq_audio_feed_info *feed_data;
+		struct mpq_streambuffer *audio_buff;
+		struct mpq_feed *mpq_feed;
+
+		mutex_lock(&mpq_demux->mutex);
+
+		mpq_feed = feed->priv;
+		feed_data = &mpq_feed->audio_info;
+		audio_buff = feed_data->audio_buffer;
+		if (!audio_buff) {
+			mutex_unlock(&mpq_demux->mutex);
+			return -EINVAL;
+		}
+
+		dmx_buffer_status->error = audio_buff->raw_data.error;
+
+		if (audio_buff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) {
+			dmx_buffer_status->fullness =
+				audio_buff->buffers[0].size *
+				audio_buff->pending_buffers_count;
+			dmx_buffer_status->free_bytes =
+				audio_buff->buffers[0].size *
+				(audio_buff->buffers_num -
+				 audio_buff->pending_buffers_count);
+			dmx_buffer_status->size =
+				audio_buff->buffers[0].size *
+				audio_buff->buffers_num;
+		} else {
+			dmx_buffer_status->fullness =
+				mpq_streambuffer_data_avail(audio_buff);
+			dmx_buffer_status->free_bytes =
+				mpq_streambuffer_data_free(audio_buff);
+			dmx_buffer_status->size = audio_buff->buffers[0].size;
+		}
+
+		mpq_streambuffer_get_data_rw_offset(
+					audio_buff,
+					&dmx_buffer_status->read_offset,
+					&dmx_buffer_status->write_offset);
+
+		mutex_unlock(&mpq_demux->mutex);
+	} else {
+		MPQ_DVB_ERR_PRINT("%s: Invalid feed type %d\n",
+				   __func__, feed->pes_type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int mpq_dmx_process_video_packet(
+			struct dvb_demux_feed *feed,
+			const u8 *buf)
+{
+	u64 curr_stc;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	if ((mpq_demux->source >= DMX_SOURCE_DVR0) &&
+		(mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
+		curr_stc = 0;
+	} else {
+		if (mpq_demux->ts_packet_timestamp_source !=
+		    TSIF_TTS_LPASS_TIMER) {
+			curr_stc = buf[STC_LOCATION_IDX + 2] << 16;
+			curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
+			curr_stc += buf[STC_LOCATION_IDX];
+			curr_stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+		} else {
+			curr_stc = buf[STC_LOCATION_IDX + 3] << 24;
+			curr_stc += buf[STC_LOCATION_IDX + 2] << 16;
+			curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
+			curr_stc += buf[STC_LOCATION_IDX];
+		}
+	}
+
+	if (!video_framing)
+		return mpq_dmx_process_video_packet_no_framing(feed, buf,
+				curr_stc);
+	else
+		return mpq_dmx_process_video_packet_framing(feed, buf,
+				curr_stc);
+}
+
+int mpq_dmx_process_audio_packet(
+			struct dvb_demux_feed *feed,
+			const u8 *buf)
+{
+	u64 curr_stc;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	if ((mpq_demux->source >= DMX_SOURCE_DVR0) &&
+		(mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
+		curr_stc = 0;
+	} else {
+		if (mpq_demux->ts_packet_timestamp_source !=
+		    TSIF_TTS_LPASS_TIMER) {
+			curr_stc = buf[STC_LOCATION_IDX + 2] << 16;
+			curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
+			curr_stc += buf[STC_LOCATION_IDX];
+			curr_stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+		} else {
+			curr_stc = buf[STC_LOCATION_IDX + 3] << 24;
+			curr_stc += buf[STC_LOCATION_IDX + 2] << 16;
+			curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
+			curr_stc += buf[STC_LOCATION_IDX];
+		}
+	}
+
+	return mpq_dmx_process_audio_packet_no_framing(feed, buf, curr_stc);
+}
+
+int mpq_dmx_extract_pcr_and_dci(const u8 *buf, u64 *pcr, int *dci)
+{
+	const struct ts_packet_header *ts_header;
+	const struct ts_adaptation_field *adaptation_field;
+
+	if (buf == NULL || pcr == NULL || dci == NULL)
+		return 0;
+
+	ts_header = (const struct ts_packet_header *)buf;
+
+	/* Make sure this TS packet has a adaptation field */
+	if ((ts_header->sync_byte != 0x47) ||
+		(ts_header->adaptation_field_control == 0) ||
+		(ts_header->adaptation_field_control == 1) ||
+		ts_header->transport_error_indicator)
+		return 0;
+
+	adaptation_field = (const struct ts_adaptation_field *)
+			(buf + sizeof(struct ts_packet_header));
+
+	if ((!adaptation_field->adaptation_field_length) ||
+		(!adaptation_field->PCR_flag))
+		return 0; /* 0 adaptation field or no PCR */
+
+	*pcr = ((u64)adaptation_field->program_clock_reference_base_1) << 25;
+	*pcr += ((u64)adaptation_field->program_clock_reference_base_2) << 17;
+	*pcr += ((u64)adaptation_field->program_clock_reference_base_3) << 9;
+	*pcr += ((u64)adaptation_field->program_clock_reference_base_4) << 1;
+	*pcr += adaptation_field->program_clock_reference_base_5;
+	*pcr *= 300;
+	*pcr += (((u64)adaptation_field->program_clock_reference_ext_1) << 8) +
+		adaptation_field->program_clock_reference_ext_2;
+
+	*dci = adaptation_field->discontinuity_indicator;
+
+	return 1;
+}
+
+int mpq_dmx_process_pcr_packet(
+			struct dvb_demux_feed *feed,
+			const u8 *buf)
+{
+	u64 stc;
+	struct dmx_data_ready data;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	if (mpq_dmx_extract_pcr_and_dci(buf, &data.pcr.pcr,
+		&data.pcr.disc_indicator_set) == 0)
+		return 0;
+
+	/*
+	 * When we play from front-end, we configure HW
+	 * to output the extra timestamp, if we are playing
+	 * from DVR, we don't have a timestamp if the packet
+	 * format is not 192-tail.
+	 */
+	if ((mpq_demux->source >= DMX_SOURCE_DVR0) &&
+		(mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
+		stc = 0;
+	} else {
+		if (mpq_demux->ts_packet_timestamp_source !=
+		    TSIF_TTS_LPASS_TIMER) {
+			stc = buf[STC_LOCATION_IDX + 2] << 16;
+			stc += buf[STC_LOCATION_IDX + 1] << 8;
+			stc += buf[STC_LOCATION_IDX];
+			stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+		} else {
+			stc = buf[STC_LOCATION_IDX + 3] << 24;
+			stc += buf[STC_LOCATION_IDX + 2] << 16;
+			stc += buf[STC_LOCATION_IDX + 1] << 8;
+			stc += buf[STC_LOCATION_IDX];
+		}
+	}
+
+	data.data_length = 0;
+	data.pcr.stc = stc;
+	data.status = DMX_OK_PCR;
+	feed->data_ready_cb.ts(&feed->feed.ts, &data);
+
+	return 0;
+}
+
+int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed, int feed_type)
+{
+	if (feed_type == 1) { /* video feed */
+		struct mpq_video_feed_info *feed_data = &mpq_feed->video_info;
+		struct mpq_streambuffer *stream_buffer;
+		struct mpq_streambuffer_packet_header oob_packet;
+		struct mpq_adapter_video_meta_data oob_meta_data;
+		int ret;
+
+		spin_lock(&feed_data->video_buffer_lock);
+		stream_buffer = feed_data->video_buffer;
+
+		if (stream_buffer == NULL) {
+			MPQ_DVB_DBG_PRINT("%s: video_buffer released\n",
+					  __func__);
+			spin_unlock(&feed_data->video_buffer_lock);
+			return 0;
+		}
+
+		memset(&oob_packet, 0, sizeof(oob_packet));
+		oob_packet.user_data_len = sizeof(oob_meta_data);
+		oob_meta_data.packet_type = DMX_EOS_PACKET;
+
+		ret = mpq_streambuffer_pkt_write(stream_buffer, &oob_packet,
+						 (u8 *)&oob_meta_data);
+
+		spin_unlock(&feed_data->video_buffer_lock);
+		return (ret < 0) ? ret : 0;
+
+	} else if (feed_type == 2) { /* audio feed */
+		struct mpq_audio_feed_info *feed_data = &mpq_feed->audio_info;
+		struct mpq_streambuffer *stream_buffer;
+		struct mpq_streambuffer_packet_header oob_packet;
+		struct mpq_adapter_audio_meta_data oob_meta_data;
+		int ret;
+
+		spin_lock(&feed_data->audio_buffer_lock);
+		stream_buffer = feed_data->audio_buffer;
+
+		if (stream_buffer == NULL) {
+			MPQ_DVB_DBG_PRINT("%s: audio_buffer released\n",
+					  __func__);
+			spin_unlock(&feed_data->audio_buffer_lock);
+			return 0;
+		}
+
+		memset(&oob_packet, 0, sizeof(oob_packet));
+		oob_packet.user_data_len = sizeof(oob_meta_data);
+		oob_meta_data.packet_type = DMX_EOS_PACKET;
+
+		ret = mpq_streambuffer_pkt_write(stream_buffer, &oob_packet,
+						 (u8 *)&oob_meta_data);
+
+		spin_unlock(&feed_data->audio_buffer_lock);
+		return (ret < 0) ? ret : 0;
+	}
+
+	return 0;
+}
+
+void mpq_dmx_convert_tts(struct dvb_demux_feed *feed,
+			const u8 timestamp[TIMESTAMP_LEN],
+			u64 *timestampIn27Mhz)
+{
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	if (unlikely(!timestampIn27Mhz))
+		return;
+
+	if (mpq_demux->ts_packet_timestamp_source != TSIF_TTS_LPASS_TIMER) {
+		*timestampIn27Mhz = timestamp[2] << 16;
+		*timestampIn27Mhz += timestamp[1] << 8;
+		*timestampIn27Mhz += timestamp[0];
+		*timestampIn27Mhz *= 256; /* convert from 105.47 KHZ to 27MHz */
+	} else {
+		*timestampIn27Mhz = timestamp[3] << 24;
+		*timestampIn27Mhz += timestamp[2] << 16;
+		*timestampIn27Mhz += timestamp[1] << 8;
+		*timestampIn27Mhz += timestamp[0];
+	}
+}
+
+int mpq_sdmx_open_session(struct mpq_demux *mpq_demux)
+{
+	enum sdmx_status ret = SDMX_SUCCESS;
+	enum sdmx_proc_mode proc_mode;
+	enum sdmx_pkt_format pkt_format;
+
+	MPQ_DVB_DBG_PRINT("%s: ref_count %d\n",
+		__func__, mpq_demux->sdmx_session_ref_count);
+
+	if (mpq_demux->sdmx_session_ref_count) {
+		/* session is already open */
+		mpq_demux->sdmx_session_ref_count++;
+		return ret;
+	}
+
+	proc_mode = (mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) ?
+		SDMX_PUSH_MODE : SDMX_PULL_MODE;
+	MPQ_DVB_DBG_PRINT(
+		"%s: Proc mode = %s\n",
+		__func__, SDMX_PUSH_MODE == proc_mode ? "Push" : "Pull");
+
+	if (mpq_demux->source < DMX_SOURCE_DVR0) {
+		pkt_format = SDMX_192_BYTE_PKT;
+	} else if (mpq_demux->demux.tsp_format == DMX_TSP_FORMAT_188) {
+		pkt_format = SDMX_188_BYTE_PKT;
+	} else if (mpq_demux->demux.tsp_format == DMX_TSP_FORMAT_192_TAIL) {
+		pkt_format = SDMX_192_BYTE_PKT;
+	} else {
+		MPQ_DVB_ERR_PRINT("%s: invalid tsp format\n", __func__);
+		return -EINVAL;
+	}
+
+	MPQ_DVB_DBG_PRINT("%s: (%s) source, packet format: %d\n",
+		 __func__,
+		 (mpq_demux->source < DMX_SOURCE_DVR0) ?
+		 "frontend" : "DVR", pkt_format);
+
+	/* open session and set configuration */
+	ret = sdmx_open_session(&mpq_demux->sdmx_session_handle);
+	if (ret != SDMX_SUCCESS) {
+		MPQ_DVB_ERR_PRINT("%s: Could not open session. ret=%d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	MPQ_DVB_DBG_PRINT("%s: new session_handle = %d\n",
+		__func__, mpq_demux->sdmx_session_handle);
+
+	ret = sdmx_set_session_cfg(mpq_demux->sdmx_session_handle,
+		proc_mode,
+		SDMX_PKT_ENC_MODE,
+		pkt_format,
+		mpq_sdmx_scramble_odd,
+		mpq_sdmx_scramble_even);
+	if (ret != SDMX_SUCCESS) {
+		MPQ_DVB_ERR_PRINT("%s: Could not set session config. ret=%d\n",
+			__func__, ret);
+		sdmx_close_session(mpq_demux->sdmx_session_handle);
+		mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
+		return -EINVAL;
+	}
+
+	ret = sdmx_set_log_level(mpq_demux->sdmx_session_handle,
+		mpq_demux->sdmx_log_level);
+	if (ret != SDMX_SUCCESS) {
+		MPQ_DVB_ERR_PRINT("%s: Could not set log level. ret=%d\n",
+				__func__, ret);
+		/* Don't fail open session if just log level setting failed */
+		ret = 0;
+	}
+
+	mpq_demux->sdmx_process_count = 0;
+	mpq_demux->sdmx_process_time_sum = 0;
+	mpq_demux->sdmx_process_time_average = 0;
+	mpq_demux->sdmx_process_time_max = 0;
+	mpq_demux->sdmx_process_packets_sum = 0;
+	mpq_demux->sdmx_process_packets_average = 0;
+	mpq_demux->sdmx_process_packets_min = 0;
+
+	mpq_demux->sdmx_session_ref_count++;
+	return ret;
+}
+
+int mpq_sdmx_close_session(struct mpq_demux *mpq_demux)
+{
+	int ret = 0;
+	enum sdmx_status status;
+
+	MPQ_DVB_DBG_PRINT("%s: session_handle = %d, ref_count %d\n",
+			__func__,
+			mpq_demux->sdmx_session_handle,
+			mpq_demux->sdmx_session_ref_count);
+
+	if (!mpq_demux->sdmx_session_ref_count)
+		return -EINVAL;
+
+	if (mpq_demux->sdmx_session_ref_count == 1) {
+		status = sdmx_close_session(mpq_demux->sdmx_session_handle);
+		if (status != SDMX_SUCCESS) {
+			MPQ_DVB_ERR_PRINT("%s: sdmx_close_session failed %d\n",
+				__func__, status);
+		}
+		mpq_demux->sdmx_eos = 0;
+		mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
+	}
+
+	mpq_demux->sdmx_session_ref_count--;
+
+	return ret;
+}
+
+static int mpq_sdmx_get_buffer_chunks(struct mpq_demux *mpq_demux,
+	struct ion_handle *buff_handle,
+	u32 actual_buff_size,
+	struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS])
+{
+	int i;
+	struct sg_table *sg_ptr;
+	struct scatterlist *sg;
+	u32 chunk_size;
+	int ret;
+
+	memset(buff_chunks, 0,
+		sizeof(struct sdmx_buff_descr) * SDMX_MAX_PHYSICAL_CHUNKS);
+
+	sg_ptr = ion_sg_table(mpq_demux->ion_client, buff_handle);
+	if (IS_ERR_OR_NULL(sg_ptr)) {
+		ret = PTR_ERR(sg_ptr);
+		MPQ_DVB_ERR_PRINT("%s: ion_sg_table failed, ret=%d\n",
+			__func__, ret);
+		if (!ret)
+			ret = -EINVAL;
+		return ret;
+	}
+
+	if (sg_ptr->nents == 0) {
+		MPQ_DVB_ERR_PRINT("%s: num of scattered entries is 0\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (sg_ptr->nents > SDMX_MAX_PHYSICAL_CHUNKS) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: num of scattered entries %d greater than max supported %d\n",
+			__func__, sg_ptr->nents, SDMX_MAX_PHYSICAL_CHUNKS);
+		return -EINVAL;
+	}
+
+	sg = sg_ptr->sgl;
+	for (i = 0; i < sg_ptr->nents; i++) {
+		buff_chunks[i].base_addr = (u64)sg_dma_address(sg);
+
+		if (sg->length > actual_buff_size)
+			chunk_size = actual_buff_size;
+		else
+			chunk_size = sg->length;
+
+		buff_chunks[i].size = chunk_size;
+		sg = sg_next(sg);
+		actual_buff_size -= chunk_size;
+	}
+
+	return 0;
+}
+
+static int mpq_sdmx_init_data_buffer(struct mpq_demux *mpq_demux,
+	struct mpq_feed *feed, u32 *num_buffers,
+	struct sdmx_data_buff_descr buf_desc[DMX_MAX_DECODER_BUFFER_NUM],
+	enum sdmx_buf_mode *buf_mode)
+{
+	struct dvb_demux_feed *dvbdmx_feed = feed->dvb_demux_feed;
+	struct dvb_ringbuffer *buffer;
+	struct mpq_video_feed_info *feed_data = &feed->video_info;
+	struct ion_handle *sdmx_buff;
+	int ret;
+	int i;
+
+	*buf_mode = SDMX_RING_BUF;
+
+	if (dvb_dmx_is_video_feed(feed->dvb_demux_feed)) {
+		if (feed_data->buffer_desc.decoder_buffers_num > 1)
+			*buf_mode = SDMX_LINEAR_GROUP_BUF;
+		*num_buffers = feed_data->buffer_desc.decoder_buffers_num;
+
+		for (i = 0; i < *num_buffers; i++) {
+			buf_desc[i].length =
+				feed_data->buffer_desc.desc[i].size;
+
+			ret = mpq_sdmx_get_buffer_chunks(mpq_demux,
+					feed_data->buffer_desc.ion_handle[i],
+					buf_desc[i].length,
+					buf_desc[i].buff_chunks);
+			if (ret) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: mpq_sdmx_get_buffer_chunks failed\n",
+					__func__);
+				return ret;
+			}
+		}
+
+		return 0;
+	}
+
+	*num_buffers = 1;
+	if (dvb_dmx_is_sec_feed(dvbdmx_feed) ||
+		dvb_dmx_is_pcr_feed(dvbdmx_feed)) {
+		buffer = &feed->sdmx_buf;
+		sdmx_buff = feed->sdmx_buf_handle;
+	} else {
+		buffer = (struct dvb_ringbuffer *)
+			dvbdmx_feed->feed.ts.buffer.ringbuff;
+		sdmx_buff = dvbdmx_feed->feed.ts.buffer.priv_handle;
+	}
+
+	if (sdmx_buff == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Invalid buffer allocation\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	buf_desc[0].length = buffer->size;
+	ret = mpq_sdmx_get_buffer_chunks(mpq_demux, sdmx_buff,
+		buf_desc[0].length,
+		buf_desc[0].buff_chunks);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_sdmx_get_buffer_chunks failed\n",
+			__func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mpq_sdmx_filter_setup(struct mpq_demux *mpq_demux,
+	struct dvb_demux_feed *dvbdmx_feed)
+{
+	int ret = 0;
+	struct mpq_feed *feed;
+	struct mpq_feed *main_rec_feed = NULL;
+	struct dvb_demux_feed *tmp;
+	struct sdmx_buff_descr metadata_buff_desc;
+	struct sdmx_data_buff_descr *data_buff_desc = NULL;
+	u32 data_buf_num = DMX_MAX_DECODER_BUFFER_NUM;
+	enum sdmx_buf_mode buf_mode;
+	enum sdmx_raw_out_format ts_out_format = SDMX_188_OUTPUT;
+	u32 filter_flags = 0;
+
+	feed = dvbdmx_feed->priv;
+
+	if (dvb_dmx_is_sec_feed(dvbdmx_feed)) {
+		feed->filter_type = SDMX_SECTION_FILTER;
+		if (dvbdmx_feed->feed.sec.check_crc)
+			filter_flags |= SDMX_FILTER_FLAG_VERIFY_SECTION_CRC;
+		MPQ_DVB_DBG_PRINT("%s: SDMX_SECTION_FILTER\n", __func__);
+	} else if (dvb_dmx_is_pcr_feed(dvbdmx_feed)) {
+		feed->filter_type = SDMX_PCR_FILTER;
+		MPQ_DVB_DBG_PRINT("%s: SDMX_PCR_FILTER\n", __func__);
+	} else if (dvb_dmx_is_video_feed(dvbdmx_feed)) {
+		feed->filter_type = SDMX_SEPARATED_PES_FILTER;
+		MPQ_DVB_DBG_PRINT("%s: SDMX_SEPARATED_PES_FILTER\n", __func__);
+	} else if (dvb_dmx_is_rec_feed(dvbdmx_feed)) {
+		feed->filter_type = SDMX_RAW_FILTER;
+		switch (dvbdmx_feed->tsp_out_format) {
+		case (DMX_TSP_FORMAT_188):
+			ts_out_format = SDMX_188_OUTPUT;
+			break;
+		case (DMX_TSP_FORMAT_192_HEAD):
+			ts_out_format = SDMX_192_HEAD_OUTPUT;
+			break;
+		case (DMX_TSP_FORMAT_192_TAIL):
+			ts_out_format = SDMX_192_TAIL_OUTPUT;
+			break;
+		default:
+			MPQ_DVB_ERR_PRINT(
+				"%s: Unsupported TS output format %d\n",
+				__func__, dvbdmx_feed->tsp_out_format);
+			return -EINVAL;
+		}
+		MPQ_DVB_DBG_PRINT("%s: SDMX_RAW_FILTER\n", __func__);
+	} else {
+		feed->filter_type = SDMX_PES_FILTER;
+		MPQ_DVB_DBG_PRINT("%s: SDMX_PES_FILTER\n", __func__);
+	}
+
+	data_buff_desc = vmalloc(
+			sizeof(*data_buff_desc)*DMX_MAX_DECODER_BUFFER_NUM);
+	if (!data_buff_desc) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: failed to allocate memory for data buffer\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Recording feed sdmx filter handle lookup:
+	 * In case this is a recording filter with multiple feeds,
+	 * this feed is either the first feed of a new recording filter,
+	 * or it is another feed of an existing filter for which a filter was
+	 * already opened with sdmx. In such case, we need to look up in the
+	 * feed pool for a allocated feed with same output buffer (meaning they
+	 * belong to the same filter) and to use the already allocated sdmx
+	 * filter handle.
+	 */
+	if (feed->filter_type == SDMX_RAW_FILTER) {
+		tmp = mpq_dmx_peer_rec_feed(dvbdmx_feed);
+		if (tmp)
+			main_rec_feed = tmp->priv;
+	}
+
+	/*
+	 * If this PID is not part of existing recording filter,
+	 * configure a new filter to SDMX.
+	 */
+	if (!main_rec_feed) {
+		feed->secondary_feed = 0;
+
+		MPQ_DVB_DBG_PRINT(
+			"%s: Adding new sdmx filter, pid %d, flags=0x%X, ts_out_format=%d\n",
+			__func__, dvbdmx_feed->pid, filter_flags,
+			ts_out_format);
+
+		/* Meta-data initialization,
+		 * Recording filters do no need meta-data buffers.
+		 */
+		if (dvb_dmx_is_rec_feed(dvbdmx_feed)) {
+			metadata_buff_desc.base_addr = 0;
+			metadata_buff_desc.size = 0;
+		} else {
+			ret = mpq_sdmx_init_metadata_buffer(mpq_demux, feed,
+				&metadata_buff_desc);
+			if (ret) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: Failed to initialize metadata buffer. ret=%d\n",
+					__func__, ret);
+				goto sdmx_filter_setup_failed;
+			}
+		}
+
+		ret = mpq_sdmx_init_data_buffer(mpq_demux, feed, &data_buf_num,
+			data_buff_desc, &buf_mode);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: Failed to initialize data buffer. ret=%d\n",
+				__func__, ret);
+			mpq_sdmx_terminate_metadata_buffer(feed);
+			goto sdmx_filter_setup_failed;
+		}
+		ret = sdmx_add_filter(mpq_demux->sdmx_session_handle,
+			dvbdmx_feed->pid,
+			feed->filter_type,
+			&metadata_buff_desc,
+			buf_mode,
+			data_buf_num,
+			data_buff_desc,
+			&feed->sdmx_filter_handle,
+			ts_out_format,
+			filter_flags);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: SDMX_add_filter failed. ret = %d\n",
+				__func__, ret);
+			ret = -ENODEV;
+			mpq_sdmx_terminate_metadata_buffer(feed);
+			goto sdmx_filter_setup_failed;
+		}
+
+		MPQ_DVB_DBG_PRINT(
+			"%s: feed=0x%p, filter pid=%d, handle=%d, data buffer(s)=%d, size=%d\n",
+			__func__, feed, dvbdmx_feed->pid,
+			feed->sdmx_filter_handle,
+			data_buf_num, data_buff_desc[0].length);
+
+		mpq_demux->sdmx_filter_count++;
+	} else {
+		MPQ_DVB_DBG_PRINT(
+			"%s: Adding RAW pid to sdmx, pid %d\n",
+			__func__, dvbdmx_feed->pid);
+
+		feed->secondary_feed = 1;
+		feed->sdmx_filter_handle = main_rec_feed->sdmx_filter_handle;
+		ret = sdmx_add_raw_pid(mpq_demux->sdmx_session_handle,
+			feed->sdmx_filter_handle, dvbdmx_feed->pid);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: FAILED to add raw pid, ret=%d\n",
+				__func__, ret);
+			ret = -ENODEV;
+			goto sdmx_filter_setup_failed;
+		}
+	}
+
+	/*
+	 * If pid has a key ladder id associated, we need to
+	 * set it to SDMX.
+	 */
+	if (dvbdmx_feed->secure_mode.is_secured &&
+		dvbdmx_feed->cipher_ops.operations_count) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: set key-ladder %d to PID %d\n",
+			__func__,
+			dvbdmx_feed->cipher_ops.operations[0].key_ladder_id,
+			dvbdmx_feed->cipher_ops.pid);
+
+		ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle,
+			dvbdmx_feed->cipher_ops.pid,
+			dvbdmx_feed->cipher_ops.operations[0].key_ladder_id);
+
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: FAILED to set key ladder, ret=%d\n",
+				__func__, ret);
+		}
+	}
+
+	vfree(data_buff_desc);
+	return 0;
+
+sdmx_filter_setup_failed:
+	vfree(data_buff_desc);
+	return ret;
+}
+
+/**
+ * mpq_sdmx_init_feed - initialize secure demux related elements of mpq feed
+ *
+ * @mpq_demux: mpq_demux object
+ * @mpq_feed: mpq_feed object
+ *
+ * Note: the function assumes mpq_demux->mutex locking is done by caller.
+ */
+static int mpq_sdmx_init_feed(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed)
+{
+	int ret;
+
+	ret = mpq_sdmx_open_session(mpq_demux);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_sdmx_open_session failed, ret=%d\n",
+			__func__, ret);
+
+		ret = -ENODEV;
+		goto init_sdmx_feed_failed;
+	}
+
+	/* PCR and sections have internal buffer for SDMX */
+	if (dvb_dmx_is_pcr_feed(mpq_feed->dvb_demux_feed))
+		ret = mpq_sdmx_alloc_data_buf(mpq_feed, SDMX_PCR_BUFFER_SIZE);
+	else if (dvb_dmx_is_sec_feed(mpq_feed->dvb_demux_feed))
+		ret = mpq_sdmx_alloc_data_buf(mpq_feed,
+			SDMX_SECTION_BUFFER_SIZE);
+	else
+		ret = 0;
+
+	if (ret) {
+		MPQ_DVB_ERR_PRINT("%s: init buffer failed, ret=%d\n",
+			__func__, ret);
+		goto init_sdmx_feed_failed_free_sdmx;
+	}
+
+	ret = mpq_sdmx_filter_setup(mpq_demux, mpq_feed->dvb_demux_feed);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_sdmx_filter_setup failed, ret=%d\n",
+			__func__, ret);
+		goto init_sdmx_feed_failed_free_data_buff;
+	}
+
+	mpq_demux->num_secure_feeds++;
+	return 0;
+
+init_sdmx_feed_failed_free_data_buff:
+	mpq_sdmx_free_data_buf(mpq_feed);
+init_sdmx_feed_failed_free_sdmx:
+	mpq_sdmx_close_session(mpq_demux);
+init_sdmx_feed_failed:
+	return ret;
+}
+
+int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed)
+{
+	int ret = 0;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+	struct mpq_feed *mpq_feed = feed->priv;
+
+	if (mutex_lock_interruptible(&mpq_demux->mutex))
+		return -ERESTARTSYS;
+
+	mpq_feed->sdmx_buf_handle = NULL;
+	mpq_feed->metadata_buf_handle = NULL;
+	mpq_feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE;
+
+	if (feed->type != DMX_TYPE_SEC)
+		feed->feed.ts.flush_buffer = mpq_dmx_flush_buffer;
+
+	if (dvb_dmx_is_video_feed(feed)) {
+		ret = mpq_dmx_init_video_feed(mpq_feed);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_dmx_init_video_feed failed, ret=%d\n",
+				__func__, ret);
+			goto init_mpq_feed_end;
+		}
+	}
+
+	if (dvb_dmx_is_audio_feed(feed)) {
+		ret = mpq_dmx_init_audio_feed(mpq_feed);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_dmx_init_audio_feed failed, ret=%d\n",
+				__func__, ret);
+			goto init_mpq_feed_end;
+		}
+	}
+
+	/*
+	 * sdmx is not relevant for recording filters, which always use
+	 * regular filters (non-sdmx)
+	 */
+	if (!mpq_sdmx_is_loaded() || !feed->secure_mode.is_secured ||
+		dvb_dmx_is_rec_feed(feed)) {
+		if (!mpq_sdmx_is_loaded())
+			mpq_demux->sdmx_session_handle =
+				SDMX_INVALID_SESSION_HANDLE;
+		goto init_mpq_feed_end;
+	}
+
+	 /* Initialization of secure demux filters (PES/PCR/Video/Section) */
+	ret = mpq_sdmx_init_feed(mpq_demux, mpq_feed);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_sdmx_init_feed failed, ret=%d\n",
+			__func__, ret);
+		if (dvb_dmx_is_video_feed(feed))
+			mpq_dmx_terminate_video_feed(mpq_feed);
+		else if (dvb_dmx_is_audio_feed(feed))
+			mpq_dmx_terminate_audio_feed(mpq_feed);
+	}
+
+init_mpq_feed_end:
+	if (!ret) {
+		mpq_demux->num_active_feeds++;
+		mpq_feed->session_id++;
+	}
+	mutex_unlock(&mpq_demux->mutex);
+	return ret;
+}
+
+/**
+ * Note: Called only when filter is in "GO" state - after feed has been started.
+ */
+int mpq_dmx_set_cipher_ops(struct dvb_demux_feed *feed,
+		struct dmx_cipher_operations *cipher_ops)
+{
+	struct mpq_feed *mpq_feed;
+	struct mpq_demux *mpq_demux;
+	int ret = 0;
+
+	if (!feed || !feed->priv || !cipher_ops) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid parameters\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	MPQ_DVB_DBG_PRINT("%s(%d, %d, %d)\n",
+		__func__, cipher_ops->pid,
+		cipher_ops->operations_count,
+		cipher_ops->operations[0].key_ladder_id);
+
+	if ((cipher_ops->operations_count > 1) ||
+		(cipher_ops->operations_count &&
+		 cipher_ops->operations[0].encrypt)) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Invalid cipher operations, count=%d, encrypt=%d\n",
+			__func__, cipher_ops->operations_count,
+			cipher_ops->operations[0].encrypt);
+		return -EINVAL;
+	}
+
+	if (!feed->secure_mode.is_secured) {
+		/*
+		 * Filter is not configured as secured, setting cipher
+		 * operations is not allowed.
+		 */
+		MPQ_DVB_ERR_PRINT(
+			"%s: Cannot set cipher operations to non-secure filter\n",
+			__func__);
+		return -EPERM;
+	}
+
+	mpq_feed = feed->priv;
+	mpq_demux = mpq_feed->mpq_demux;
+
+	mutex_lock(&mpq_demux->mutex);
+
+	/*
+	 * Feed is running in secure mode, this secure mode request is to
+	 * update the key ladder id
+	 */
+	if ((mpq_demux->sdmx_session_handle != SDMX_INVALID_SESSION_HANDLE) &&
+		cipher_ops->operations_count) {
+		ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle,
+			cipher_ops->pid,
+			cipher_ops->operations[0].key_ladder_id);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: FAILED to set key ladder, ret=%d\n",
+				__func__, ret);
+			ret = -ENODEV;
+		}
+	}
+
+	mutex_unlock(&mpq_demux->mutex);
+
+	return ret;
+}
+
+static int mpq_sdmx_invalidate_buffer(struct mpq_feed *mpq_feed)
+{
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct mpq_video_feed_info *feed_data;
+	struct dvb_ringbuffer *buffer;
+	struct ion_handle *ion_handle;
+	int ret = 0;
+	int i;
+
+	if (!dvb_dmx_is_video_feed(feed)) {
+		if (dvb_dmx_is_sec_feed(feed) ||
+			dvb_dmx_is_pcr_feed(feed)) {
+			buffer = (struct dvb_ringbuffer *)
+				&mpq_feed->sdmx_buf;
+			ion_handle = mpq_feed->sdmx_buf_handle;
+		} else {
+			buffer = (struct dvb_ringbuffer *)
+				feed->feed.ts.buffer.ringbuff;
+			ion_handle = feed->feed.ts.buffer.priv_handle;
+		}
+
+		ret = msm_ion_do_cache_op(mpq_feed->mpq_demux->ion_client,
+			ion_handle, buffer->data,
+			buffer->size, ION_IOC_INV_CACHES);
+		if (ret)
+			MPQ_DVB_ERR_PRINT(
+				"%s: msm_ion_do_cache_op failed, ret = %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	/* Video buffers */
+	feed_data = &mpq_feed->video_info;
+	for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+		if (feed_data->buffer_desc.desc[i].base) {
+			/* Non-secured buffer */
+			ret = msm_ion_do_cache_op(
+				mpq_feed->mpq_demux->ion_client,
+				feed_data->buffer_desc.ion_handle[i],
+				feed_data->buffer_desc.desc[i].base,
+				feed_data->buffer_desc.desc[i].size,
+				ION_IOC_INV_CACHES);
+			if (ret)
+				MPQ_DVB_ERR_PRINT(
+					"%s: msm_ion_do_cache_op failed, ret = %d\n",
+					__func__, ret);
+		}
+	}
+
+	return ret;
+}
+
+static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux,
+	struct sdmx_filter_status *filter_sts,
+	struct mpq_feed *mpq_feed)
+{
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct mpq_video_feed_info *feed_data;
+	struct mpq_streambuffer *sbuff;
+
+	filter_sts->filter_handle = mpq_feed->sdmx_filter_handle;
+	filter_sts->metadata_fill_count =
+		dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+	filter_sts->metadata_write_offset = mpq_feed->metadata_buf.pwrite;
+	filter_sts->error_indicators = 0;
+	filter_sts->status_indicators = 0;
+
+	MPQ_DVB_DBG_PRINT(
+		"%s: Filter meta-data buffer status: fill count = %d, write_offset = %d\n",
+		__func__, filter_sts->metadata_fill_count,
+		filter_sts->metadata_write_offset);
+
+	if (!dvb_dmx_is_video_feed(feed)) {
+		struct dvb_ringbuffer *buffer;
+
+		if (dvb_dmx_is_sec_feed(feed) ||
+			dvb_dmx_is_pcr_feed(feed)) {
+			buffer = (struct dvb_ringbuffer *)
+				&mpq_feed->sdmx_buf;
+		} else {
+			buffer = (struct dvb_ringbuffer *)
+				feed->feed.ts.buffer.ringbuff;
+		}
+
+		filter_sts->data_fill_count = dvb_ringbuffer_avail(buffer);
+		filter_sts->data_write_offset = buffer->pwrite;
+
+		MPQ_DVB_DBG_PRINT(
+			"%s: Filter buffers status: fill count = %d, write_offset = %d\n",
+			__func__, filter_sts->data_fill_count,
+			filter_sts->data_write_offset);
+
+		return;
+	}
+
+	/* Video feed - decoder buffers */
+	feed_data = &mpq_feed->video_info;
+
+	spin_lock(&mpq_feed->video_info.video_buffer_lock);
+	sbuff = feed_data->video_buffer;
+	if (sbuff == NULL) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: video_buffer released\n",
+			__func__);
+		spin_unlock(&feed_data->video_buffer_lock);
+		return;
+	}
+
+	if (feed_data->buffer_desc.decoder_buffers_num > 1) {
+		/* linear mode */
+		filter_sts->data_fill_count = sbuff->pending_buffers_count;
+		filter_sts->data_write_offset =
+			sbuff->raw_data.pwrite /
+			sizeof(struct mpq_streambuffer_buffer_desc);
+	} else {
+		/* ring buffer mode */
+		filter_sts->data_fill_count =
+			mpq_streambuffer_data_avail(sbuff);
+		mpq_streambuffer_get_data_rw_offset(sbuff, NULL,
+			&filter_sts->data_write_offset);
+
+	}
+
+	spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+
+	MPQ_DVB_DBG_PRINT(
+		"%s: Decoder buffers filter status: fill count = %d, write_offset = %d\n",
+		__func__, filter_sts->data_fill_count,
+		filter_sts->data_write_offset);
+}
+
+static int mpq_sdmx_section_filtering(struct mpq_feed *mpq_feed,
+	struct dvb_demux_filter *f,
+	struct sdmx_metadata_header *header)
+{
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	int ret;
+	u8 neq = 0;
+	u8 xor;
+	u8 tmp;
+	int i;
+
+	if (!mutex_is_locked(&mpq_feed->mpq_demux->mutex)) {
+		MPQ_DVB_ERR_PRINT(
+				"%s: Mutex should have been locked\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+		tmp = DVB_RINGBUFFER_PEEK(&mpq_feed->sdmx_buf, i);
+		xor = f->filter.filter_value[i] ^ tmp;
+
+		if (f->maskandmode[i] & xor)
+			return 0;
+
+		neq |= f->maskandnotmode[i] & xor;
+	}
+
+	if (f->doneq && !neq)
+		return 0;
+
+	if (feed->demux->playback_mode == DMX_PB_MODE_PULL) {
+		mutex_unlock(&mpq_feed->mpq_demux->mutex);
+
+		ret = feed->demux->buffer_ctrl.sec(&f->filter,
+					header->payload_length, 1);
+
+		mutex_lock(&mpq_feed->mpq_demux->mutex);
+
+		if (ret) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: buffer_ctrl.sec aborted\n",
+				__func__);
+			return ret;
+		}
+
+		if (mpq_feed->sdmx_filter_handle ==
+			SDMX_INVALID_FILTER_HANDLE) {
+			MPQ_DVB_DBG_PRINT("%s: filter was stopped\n",
+				__func__);
+			return -ENODEV;
+		}
+	}
+
+	if (mpq_feed->sdmx_buf.pread + header->payload_length <
+		mpq_feed->sdmx_buf.size) {
+		feed->cb.sec(&mpq_feed->sdmx_buf.data[mpq_feed->sdmx_buf.pread],
+			header->payload_length,
+			NULL, 0, &f->filter);
+	} else {
+		int split = mpq_feed->sdmx_buf.size - mpq_feed->sdmx_buf.pread;
+
+		feed->cb.sec(&mpq_feed->sdmx_buf.data[mpq_feed->sdmx_buf.pread],
+			split,
+			&mpq_feed->sdmx_buf.data[0],
+			header->payload_length - split,
+			&f->filter);
+	}
+
+	return 0;
+}
+
+static int mpq_sdmx_check_ts_stall(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed,
+	struct sdmx_filter_status *sts,
+	size_t req,
+	int events_only)
+{
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	int ret;
+
+	if (!mutex_is_locked(&mpq_feed->mpq_demux->mutex)) {
+		MPQ_DVB_ERR_PRINT(
+				"%s: Mutex should have been locked\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * For PULL mode need to verify there is enough space for the dmxdev
+	 * event. Also, if data buffer is full we want to stall until some
+	 * data is removed from it to prevent calling the sdmx when it cannot
+	 * output data to the still full buffer.
+	 */
+	if (mpq_demux->demux.playback_mode == DMX_PB_MODE_PULL) {
+		MPQ_DVB_DBG_PRINT("%s: Stalling for events and %zu bytes\n",
+			__func__, req);
+
+		mutex_unlock(&mpq_demux->mutex);
+
+		ret = mpq_demux->demux.buffer_ctrl.ts(&feed->feed.ts, req, 1);
+		MPQ_DVB_DBG_PRINT("%s: stall result = %d\n",
+			__func__, ret);
+
+		mutex_lock(&mpq_demux->mutex);
+
+		if (mpq_feed->sdmx_filter_handle ==
+			SDMX_INVALID_FILTER_HANDLE) {
+			MPQ_DVB_DBG_PRINT("%s: filter was stopped\n",
+					__func__);
+			return -ENODEV;
+		}
+
+		return ret;
+	}
+
+	return 0;
+}
+
+/* Handle filter results for filters with no extra meta-data */
+static void mpq_sdmx_pes_filter_results(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed,
+	struct sdmx_filter_status *sts)
+{
+	int ret;
+	struct sdmx_metadata_header header;
+	struct sdmx_pes_counters counters;
+	struct dmx_data_ready data_event;
+	struct dmx_data_ready pes_event;
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct dvb_ringbuffer *buf = (struct dvb_ringbuffer *)
+		feed->feed.ts.buffer.ringbuff;
+	ssize_t bytes_avail;
+
+	if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+		goto pes_filter_check_overflow;
+
+	MPQ_DVB_DBG_PRINT(
+		"%s: Meta: fill=%u, write=%u. Data: fill=%u, write=%u\n",
+		__func__, sts->metadata_fill_count, sts->metadata_write_offset,
+		sts->data_fill_count, sts->data_write_offset);
+
+	mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset;
+
+	if ((sts->metadata_fill_count == 0) &&
+		(sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) {
+		ssize_t free = dvb_ringbuffer_free(buf);
+
+		ret = 0;
+		if ((free + SZ_2K) < MAX_PES_LENGTH)
+			ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts,
+				free + SZ_2K, 0);
+		else
+			MPQ_DVB_ERR_PRINT(
+				"%s: Cannot stall when free space bigger than max PES size\n",
+				__func__);
+		if (ret) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: mpq_sdmx_check_ts_stall aborted\n",
+				__func__);
+			return;
+		}
+	}
+
+	while (sts->metadata_fill_count) {
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if (bytes_avail < (sizeof(header) + sizeof(counters))) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: metadata_fill_count is %d less than required %zu bytes\n",
+				__func__,
+				sts->metadata_fill_count,
+				sizeof(header) + sizeof(counters));
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
+			break;
+		}
+
+		dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&header,
+			sizeof(header));
+		MPQ_DVB_DBG_PRINT(
+			"%s: metadata header: start=%u, length=%u\n",
+			__func__, header.payload_start, header.payload_length);
+		sts->metadata_fill_count -= sizeof(header);
+
+		dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&counters,
+			sizeof(counters));
+		sts->metadata_fill_count -= sizeof(counters);
+
+		/* Notify new data in buffer */
+		data_event.status = DMX_OK;
+		data_event.data_length = header.payload_length;
+		ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts,
+			data_event.data_length, 0);
+		if (ret) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: mpq_sdmx_check_ts_stall aborted\n",
+				__func__);
+			return;
+		}
+
+		feed->data_ready_cb.ts(&feed->feed.ts, &data_event);
+
+		/* Notify new complete PES */
+		pes_event.status = DMX_OK_PES_END;
+		pes_event.pes_end.actual_length = header.payload_length;
+		pes_event.pes_end.start_gap = 0;
+		pes_event.data_length = 0;
+
+		/* Parse error indicators */
+		if (sts->error_indicators & SDMX_FILTER_ERR_INVALID_PES_LEN)
+			pes_event.pes_end.pes_length_mismatch = 1;
+		else
+			pes_event.pes_end.pes_length_mismatch = 0;
+
+		pes_event.pes_end.disc_indicator_set = 0;
+
+		pes_event.pes_end.stc = 0;
+		pes_event.pes_end.tei_counter = counters.transport_err_count;
+		pes_event.pes_end.cont_err_counter =
+			counters.continuity_err_count;
+		pes_event.pes_end.ts_packets_num =
+			counters.pes_ts_count;
+
+		ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, 0, 1);
+		if (ret) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: mpq_sdmx_check_ts_stall aborted\n",
+				__func__);
+			return;
+		}
+		feed->data_ready_cb.ts(&feed->feed.ts, &pes_event);
+	}
+
+pes_filter_check_overflow:
+	if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) &&
+		(sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) {
+		MPQ_DVB_ERR_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__);
+		mpq_dmx_notify_overflow(feed);
+	}
+
+	if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) {
+		data_event.data_length = 0;
+		data_event.status = DMX_OK_EOS;
+		feed->data_ready_cb.ts(&feed->feed.ts, &data_event);
+	}
+}
+
+static void mpq_sdmx_section_filter_results(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed,
+	struct sdmx_filter_status *sts)
+{
+	struct sdmx_metadata_header header;
+	struct dmx_data_ready event;
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct dvb_demux_filter *f;
+	struct dmx_section_feed *sec = &feed->feed.sec;
+	ssize_t bytes_avail;
+
+	/* Parse error indicators */
+	if (sts->error_indicators & SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL) {
+		MPQ_DVB_DBG_PRINT("%s: Notify CRC err event\n", __func__);
+		event.status = DMX_CRC_ERROR;
+		event.data_length = 0;
+		dvb_dmx_notify_section_event(feed, &event, 1);
+	}
+
+	if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)
+		MPQ_DVB_ERR_PRINT("%s: internal section buffer overflowed!\n",
+			__func__);
+
+	if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+		goto section_filter_check_eos;
+
+	mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset;
+	mpq_feed->sdmx_buf.pwrite = sts->data_write_offset;
+
+	while (sts->metadata_fill_count) {
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if (bytes_avail < sizeof(header)) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: metadata_fill_count is %d less than required %zu bytes\n",
+				__func__,
+				sts->metadata_fill_count,
+				sizeof(header));
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
+			break;
+		}
+
+		dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header,
+			sizeof(header));
+		sts->metadata_fill_count -= sizeof(header);
+		MPQ_DVB_DBG_PRINT(
+			"%s: metadata header: start=%u, length=%u\n",
+			__func__, header.payload_start, header.payload_length);
+
+		f = feed->filter;
+		do {
+			if (mpq_sdmx_section_filtering(mpq_feed, f, &header))
+				return;
+		} while ((f = f->next) && sec->is_filtering);
+
+		DVB_RINGBUFFER_SKIP(&mpq_feed->sdmx_buf, header.payload_length);
+	}
+
+section_filter_check_eos:
+	if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) {
+		event.data_length = 0;
+		event.status = DMX_OK_EOS;
+		dvb_dmx_notify_section_event(feed, &event, 1);
+	}
+}
+
+static void mpq_sdmx_decoder_filter_results(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed,
+	struct sdmx_filter_status *sts)
+{
+	struct sdmx_metadata_header header;
+	struct sdmx_pes_counters counters;
+	int pes_header_offset;
+	struct ts_packet_header *ts_header;
+	struct ts_adaptation_field *ts_adapt;
+	struct pes_packet_header *pes_header;
+	u8 metadata_buf[MAX_SDMX_METADATA_LENGTH];
+	struct mpq_streambuffer *sbuf;
+	int ret;
+	struct dmx_data_ready data_event;
+	struct dmx_data_ready data;
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	ssize_t bytes_avail;
+
+	if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+		goto decoder_filter_check_flags;
+
+	/* Update meta data buffer write pointer */
+	mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset;
+
+	if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PULL) &&
+		(sts->error_indicators & SDMX_FILTER_ERR_D_LIN_BUFS_FULL)) {
+		MPQ_DVB_DBG_PRINT("%s: Decoder stall...\n", __func__);
+
+		ret = mpq_dmx_decoder_fullness_check(
+			mpq_feed->dvb_demux_feed, 0, 0);
+		if (ret) {
+			/* we reach here if demuxing was aborted */
+			MPQ_DVB_DBG_PRINT(
+				"%s: mpq_dmx_decoder_fullness_check aborted\n",
+				__func__);
+			return;
+		}
+	}
+
+	while (sts->metadata_fill_count) {
+		struct mpq_streambuffer_packet_header packet;
+		struct mpq_adapter_video_meta_data meta_data;
+
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if (bytes_avail < (sizeof(header) + sizeof(counters))) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: metadata_fill_count is %d less than required %zu bytes\n",
+				__func__,
+				sts->metadata_fill_count,
+				sizeof(header) + sizeof(counters));
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
+			break;
+		}
+
+		/* Read metadata header */
+		dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&header,
+			sizeof(header));
+		sts->metadata_fill_count -= sizeof(header);
+		MPQ_DVB_DBG_PRINT(
+			"%s: metadata header: start=%u, length=%u, metadata=%u\n",
+			__func__, header.payload_start, header.payload_length,
+			header.metadata_length);
+
+		/* Read metadata - PES counters */
+		dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&counters,
+					sizeof(counters));
+		sts->metadata_fill_count -= sizeof(counters);
+
+		/* Read metadata - TS & PES headers */
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if ((header.metadata_length < MAX_SDMX_METADATA_LENGTH) &&
+			(header.metadata_length >= sizeof(counters)) &&
+			(bytes_avail >=
+			 (header.metadata_length - sizeof(counters)))) {
+			dvb_ringbuffer_read(&mpq_feed->metadata_buf,
+				metadata_buf,
+				header.metadata_length - sizeof(counters));
+		} else {
+			MPQ_DVB_ERR_PRINT(
+				"%s: meta-data size %d larger than available meta-data %zd or max allowed %d\n",
+				__func__, header.metadata_length,
+				bytes_avail,
+				MAX_SDMX_METADATA_LENGTH);
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
+			break;
+		}
+
+		sts->metadata_fill_count -=
+			(header.metadata_length - sizeof(counters));
+
+		ts_header = (struct ts_packet_header *)&metadata_buf[0];
+		if (ts_header->adaptation_field_control == 1) {
+			ts_adapt = NULL;
+			pes_header_offset = sizeof(*ts_header);
+		} else {
+			ts_adapt = (struct ts_adaptation_field *)
+				&metadata_buf[sizeof(*ts_header)];
+			pes_header_offset = sizeof(*ts_header) + 1 +
+				ts_adapt->adaptation_field_length;
+		}
+		pes_header = (struct pes_packet_header *)
+			&metadata_buf[pes_header_offset];
+		meta_data.packet_type = DMX_PES_PACKET;
+		/* TODO - set to real STC when SDMX supports it */
+		meta_data.info.pes.stc = 0;
+
+		if (pes_header->pts_dts_flag & 0x2) {
+			meta_data.info.pes.pts_dts_info.pts_exist = 1;
+			meta_data.info.pes.pts_dts_info.pts =
+				((u64)pes_header->pts_1 << 30) |
+				((u64)pes_header->pts_2 << 22) |
+				((u64)pes_header->pts_3 << 15) |
+				((u64)pes_header->pts_4 << 7) |
+				(u64)pes_header->pts_5;
+		} else {
+			meta_data.info.pes.pts_dts_info.pts_exist = 0;
+		}
+
+		if (pes_header->pts_dts_flag & 0x1) {
+			meta_data.info.pes.pts_dts_info.dts_exist = 1;
+			meta_data.info.pes.pts_dts_info.dts =
+				((u64)pes_header->dts_1 << 30) |
+				((u64)pes_header->dts_2 << 22) |
+				((u64)pes_header->dts_3 << 15) |
+				((u64)pes_header->dts_4 << 7) |
+				(u64)pes_header->dts_5;
+		} else {
+			meta_data.info.pes.pts_dts_info.dts_exist = 0;
+		}
+
+		spin_lock(&mpq_feed->video_info.video_buffer_lock);
+
+		mpq_feed->video_info.tei_errs =
+			counters.transport_err_count;
+		mpq_feed->video_info.continuity_errs =
+			counters.continuity_err_count;
+		mpq_feed->video_info.ts_packets_num =
+			counters.pes_ts_count;
+		mpq_feed->video_info.ts_dropped_bytes =
+			counters.drop_count *
+			mpq_demux->demux.ts_packet_size;
+
+		sbuf = mpq_feed->video_info.video_buffer;
+		if (sbuf == NULL) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: video_buffer released\n",
+				__func__);
+			spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+			return;
+		}
+
+		if (!header.payload_length) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: warnning - video frame with 0 length, dropping\n",
+				__func__);
+			spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+			continue;
+		}
+
+		packet.raw_data_len = header.payload_length;
+		packet.user_data_len = sizeof(meta_data);
+		mpq_streambuffer_get_buffer_handle(sbuf, 0,
+			&packet.raw_data_handle);
+		mpq_streambuffer_get_data_rw_offset(sbuf,
+			NULL, &packet.raw_data_offset);
+		ret = mpq_streambuffer_data_write_deposit(sbuf,
+			header.payload_length);
+		if (ret) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_streambuffer_data_write_deposit failed. ret=%d\n",
+				__func__, ret);
+		}
+		mpq_dmx_update_decoder_stat(mpq_feed);
+		ret = mpq_streambuffer_pkt_write(sbuf, &packet,
+			(u8 *)&meta_data);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_streambuffer_pkt_write failed, ret=%d\n",
+				__func__, ret);
+		} else {
+			mpq_dmx_prepare_es_event_data(
+				&packet, &meta_data, &mpq_feed->video_info,
+				sbuf, &data, ret);
+			MPQ_DVB_DBG_PRINT("%s: Notify ES Event\n", __func__);
+			feed->data_ready_cb.ts(&feed->feed.ts, &data);
+		}
+
+		spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+	}
+
+decoder_filter_check_flags:
+	if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) &&
+		(sts->error_indicators & SDMX_FILTER_ERR_D_LIN_BUFS_FULL)) {
+		MPQ_DVB_ERR_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__);
+		mpq_dmx_notify_overflow(mpq_feed->dvb_demux_feed);
+	}
+
+	if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) {
+		/* Notify decoder via the stream buffer */
+		ret = mpq_dmx_decoder_eos_cmd(mpq_feed, 1);
+		if (ret)
+			MPQ_DVB_ERR_PRINT(
+				"%s: Failed to notify decoder on EOS, ret=%d\n",
+				__func__, ret);
+
+		/* Notify user filter */
+		data_event.data_length = 0;
+		data_event.status = DMX_OK_EOS;
+		mpq_feed->dvb_demux_feed->data_ready_cb.ts(
+			&mpq_feed->dvb_demux_feed->feed.ts, &data_event);
+	}
+}
+
+static void mpq_sdmx_pcr_filter_results(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed,
+	struct sdmx_filter_status *sts)
+{
+	int ret;
+	struct sdmx_metadata_header header;
+	struct dmx_data_ready data;
+	struct dvb_ringbuffer *rbuff = &mpq_feed->sdmx_buf;
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	u8 buf[TS_PACKET_HEADER_LENGTH + MAX_TSP_ADAPTATION_LENGTH +
+	       TIMESTAMP_LEN];
+	size_t stc_len = 0;
+	ssize_t bytes_avail;
+
+	if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)
+		MPQ_DVB_ERR_PRINT("%s: internal PCR buffer overflowed!\n",
+			__func__);
+
+	if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+		goto pcr_filter_check_eos;
+
+	if (mpq_demux->demux.tsp_format == DMX_TSP_FORMAT_192_TAIL)
+		stc_len = 4;
+
+	mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset;
+	rbuff->pwrite = sts->data_write_offset;
+
+	while (sts->metadata_fill_count) {
+		bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf);
+		if (bytes_avail < sizeof(header)) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: metadata_fill_count is %d less than required %zu bytes\n",
+				__func__,
+				sts->metadata_fill_count,
+				sizeof(header));
+
+			/* clean-up remaining bytes to try to recover */
+			DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf,
+				bytes_avail);
+			sts->metadata_fill_count = 0;
+			break;
+		}
+
+		dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header,
+			sizeof(header));
+		MPQ_DVB_DBG_PRINT(
+			"%s: metadata header: start=%u, length=%u\n",
+			__func__, header.payload_start, header.payload_length);
+		sts->metadata_fill_count -= sizeof(header);
+
+		dvb_ringbuffer_read(rbuff, buf, header.payload_length);
+
+		if (mpq_dmx_extract_pcr_and_dci(buf, &data.pcr.pcr,
+			&data.pcr.disc_indicator_set)) {
+
+			if (stc_len) {
+				data.pcr.stc =
+					buf[header.payload_length-2] << 16;
+				data.pcr.stc +=
+					buf[header.payload_length-3] << 8;
+				data.pcr.stc += buf[header.payload_length-4];
+				 /* convert from 105.47 KHZ to 27MHz */
+				data.pcr.stc *= 256;
+			} else {
+				data.pcr.stc = 0;
+			}
+
+			data.data_length = 0;
+			data.status = DMX_OK_PCR;
+			ret = mpq_sdmx_check_ts_stall(
+				mpq_demux, mpq_feed, sts, 0, 1);
+			if (ret) {
+				MPQ_DVB_DBG_PRINT(
+					"%s: mpq_sdmx_check_ts_stall aborted\n",
+					__func__);
+				return;
+			}
+			feed->data_ready_cb.ts(&feed->feed.ts, &data);
+		}
+	}
+
+pcr_filter_check_eos:
+	if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) {
+		data.data_length = 0;
+		data.status = DMX_OK_EOS;
+		feed->data_ready_cb.ts(&feed->feed.ts, &data);
+	}
+}
+
+static void mpq_sdmx_raw_filter_results(struct mpq_demux *mpq_demux,
+	struct mpq_feed *mpq_feed,
+	struct sdmx_filter_status *sts)
+{
+	int ret;
+	ssize_t new_data;
+	struct dmx_data_ready data_event;
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct dvb_ringbuffer *buf = (struct dvb_ringbuffer *)
+					feed->feed.ts.buffer.ringbuff;
+
+	if ((!sts->metadata_fill_count) && (!sts->data_fill_count))
+		goto raw_filter_check_flags;
+
+	new_data = sts->data_write_offset -
+		buf->pwrite;
+	if (new_data < 0)
+		new_data += buf->size;
+
+	ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts,
+		new_data + feed->demux->ts_packet_size, 0);
+	if (ret) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: mpq_sdmx_check_ts_stall aborted\n",
+			__func__);
+		return;
+	}
+
+	data_event.status = DMX_OK;
+	data_event.data_length = new_data;
+	feed->data_ready_cb.ts(&feed->feed.ts, &data_event);
+	MPQ_DVB_DBG_PRINT("%s: Callback DMX_OK, size=%d\n",
+		__func__, data_event.data_length);
+
+raw_filter_check_flags:
+	if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) &&
+		(sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) {
+		MPQ_DVB_DBG_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__);
+		mpq_dmx_notify_overflow(feed);
+	}
+
+	if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) {
+		data_event.data_length = 0;
+		data_event.status = DMX_OK_EOS;
+		feed->data_ready_cb.ts(&feed->feed.ts, &data_event);
+	}
+
+}
+
+static void mpq_sdmx_process_results(struct mpq_demux *mpq_demux)
+{
+	int i;
+	int sdmx_filters;
+	struct sdmx_filter_status *sts;
+	struct mpq_feed *mpq_feed;
+	u8 mpq_feed_idx;
+
+	sdmx_filters = mpq_demux->sdmx_filter_count;
+	for (i = 0; i < sdmx_filters; i++) {
+		sts = &mpq_demux->sdmx_filters_state.status[i];
+		MPQ_DVB_DBG_PRINT(
+			"%s: Filter: handle=%d, status=0x%x, errors=0x%x\n",
+			__func__, sts->filter_handle, sts->status_indicators,
+			sts->error_indicators);
+		MPQ_DVB_DBG_PRINT("%s: Metadata fill count=%d (write=%d)\n",
+			__func__, sts->metadata_fill_count,
+			sts->metadata_write_offset);
+		MPQ_DVB_DBG_PRINT("%s: Data fill count=%d (write=%d)\n",
+			__func__, sts->data_fill_count, sts->data_write_offset);
+
+		mpq_feed_idx = mpq_demux->sdmx_filters_state.mpq_feed_idx[i];
+		mpq_feed = &mpq_demux->feeds[mpq_feed_idx];
+		if ((mpq_feed->dvb_demux_feed->state != DMX_STATE_GO) ||
+			(sts->filter_handle != mpq_feed->sdmx_filter_handle) ||
+			mpq_feed->secondary_feed ||
+			(mpq_demux->sdmx_filters_state.session_id[i] !=
+			 mpq_feed->session_id))
+			continue;
+
+		/* Invalidate output buffer before processing the results */
+		mpq_sdmx_invalidate_buffer(mpq_feed);
+
+		if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL)
+			MPQ_DVB_ERR_PRINT(
+				"%s: meta-data buff for pid %d overflowed!\n",
+				__func__, mpq_feed->dvb_demux_feed->pid);
+
+		switch (mpq_feed->filter_type) {
+		case SDMX_PCR_FILTER:
+			mpq_sdmx_pcr_filter_results(mpq_demux, mpq_feed, sts);
+			break;
+		case SDMX_PES_FILTER:
+			mpq_sdmx_pes_filter_results(mpq_demux, mpq_feed,
+				sts);
+			break;
+		case SDMX_SEPARATED_PES_FILTER:
+			mpq_sdmx_decoder_filter_results(mpq_demux, mpq_feed,
+				sts);
+			break;
+		case SDMX_SECTION_FILTER:
+			mpq_sdmx_section_filter_results(mpq_demux, mpq_feed,
+				sts);
+			break;
+		case SDMX_RAW_FILTER:
+			mpq_sdmx_raw_filter_results(mpq_demux, mpq_feed, sts);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static int mpq_sdmx_process_buffer(struct mpq_demux *mpq_demux,
+	struct sdmx_buff_descr *input,
+	u32 fill_count,
+	u32 read_offset)
+{
+	struct sdmx_filter_status *sts;
+	struct mpq_feed *mpq_feed;
+	u8 flags = 0;
+	u32 errors;
+	u32 status;
+	u32 prev_read_offset;
+	u32 prev_fill_count;
+	enum sdmx_status sdmx_res;
+	int i;
+	int filter_index = 0;
+	int bytes_read;
+	ktime_t process_start_time;
+	ktime_t process_end_time;
+
+	mutex_lock(&mpq_demux->mutex);
+
+	/*
+	 * All active filters may get totally closed and therefore
+	 * sdmx session may get terminated, in such case nothing to process
+	 */
+	if (mpq_demux->sdmx_session_handle == SDMX_INVALID_SESSION_HANDLE) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: sdmx filters aborted, filter-count %d, session %d\n",
+			__func__, mpq_demux->sdmx_filter_count,
+			mpq_demux->sdmx_session_handle);
+		mutex_unlock(&mpq_demux->mutex);
+		return 0;
+	}
+
+	/* Set input flags */
+	if (mpq_demux->sdmx_eos)
+		flags |= SDMX_INPUT_FLAG_EOS;
+	if (mpq_sdmx_debug)
+		flags |= SDMX_INPUT_FLAG_DBG_ENABLE;
+
+	/* Build up to date filter status array */
+	for (i = 0; i < MPQ_MAX_DMX_FILES; i++) {
+		mpq_feed = &mpq_demux->feeds[i];
+		if ((mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE)
+			&& (!mpq_feed->secondary_feed)) {
+			sts = mpq_demux->sdmx_filters_state.status +
+				filter_index;
+			mpq_sdmx_prepare_filter_status(mpq_demux, sts,
+				mpq_feed);
+			mpq_demux->sdmx_filters_state.mpq_feed_idx[filter_index]
+				 = i;
+			mpq_demux->sdmx_filters_state.session_id[filter_index] =
+				mpq_feed->session_id;
+			filter_index++;
+		}
+	}
+
+	/* Sanity check */
+	if (filter_index != mpq_demux->sdmx_filter_count) {
+		mutex_unlock(&mpq_demux->mutex);
+		MPQ_DVB_ERR_PRINT(
+			"%s: Updated %d SDMX filters status but should be %d\n",
+			__func__, filter_index, mpq_demux->sdmx_filter_count);
+		return -ERESTART;
+	}
+
+	MPQ_DVB_DBG_PRINT(
+		"%s: Before SDMX_process: input read_offset=%u, fill count=%u\n",
+		__func__, read_offset, fill_count);
+
+	process_start_time = ktime_get();
+
+	prev_read_offset = read_offset;
+	prev_fill_count = fill_count;
+	sdmx_res = sdmx_process(mpq_demux->sdmx_session_handle, flags, input,
+		&fill_count, &read_offset, &errors, &status,
+		mpq_demux->sdmx_filter_count,
+		mpq_demux->sdmx_filters_state.status);
+
+	process_end_time = ktime_get();
+	bytes_read = prev_fill_count - fill_count;
+
+	mpq_dmx_update_sdmx_stat(mpq_demux, bytes_read,
+			process_start_time, process_end_time);
+
+	MPQ_DVB_DBG_PRINT(
+		"%s: SDMX result=%d, input_fill_count=%u, read_offset=%u, read %d bytes from input, status=0x%X, errors=0x%X\n",
+		__func__, sdmx_res, fill_count, read_offset, bytes_read,
+		status, errors);
+
+	if ((sdmx_res == SDMX_SUCCESS) ||
+		(sdmx_res == SDMX_STATUS_STALLED_IN_PULL_MODE)) {
+		if (sdmx_res == SDMX_STATUS_STALLED_IN_PULL_MODE)
+			MPQ_DVB_DBG_PRINT("%s: SDMX stalled for PULL mode\n",
+				__func__);
+
+		mpq_sdmx_process_results(mpq_demux);
+	} else {
+		MPQ_DVB_ERR_PRINT(
+			"%s: SDMX Process returned %d\n",
+			__func__, sdmx_res);
+	}
+
+	mutex_unlock(&mpq_demux->mutex);
+
+	return bytes_read;
+}
+
+int mpq_sdmx_process(struct mpq_demux *mpq_demux,
+	struct sdmx_buff_descr *input,
+	u32 fill_count,
+	u32 read_offset,
+	size_t tsp_size)
+{
+	int ret;
+	int todo;
+	int total_bytes_read = 0;
+	int limit = mpq_sdmx_proc_limit * tsp_size;
+
+	MPQ_DVB_DBG_PRINT(
+		"\n\n%s: read_offset=%u, fill_count=%u, tsp_size=%zu\n",
+		__func__, read_offset, fill_count, tsp_size);
+
+	while (fill_count >= tsp_size) {
+		todo = fill_count > limit ? limit : fill_count;
+		ret = mpq_sdmx_process_buffer(mpq_demux, input, todo,
+			read_offset);
+
+		if (mpq_demux->demux.sw_filter_abort) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: Demuxing from DVR was aborted\n",
+				__func__);
+			return -ENODEV;
+		}
+
+		if (ret > 0) {
+			total_bytes_read += ret;
+			fill_count -= ret;
+			read_offset += ret;
+			if (read_offset >= input->size)
+				read_offset -= input->size;
+		} else {
+			/*
+			 * ret < 0:	some error occurred
+			 * ret == 0:	not enough data (less than 1 TS packet)
+			 */
+			if (ret < 0)
+				MPQ_DVB_ERR_PRINT(
+					"%s: mpq_sdmx_process_buffer failed, returned %d\n",
+					__func__, ret);
+			break;
+		}
+	}
+
+	return total_bytes_read;
+}
+
+static int mpq_sdmx_write(struct mpq_demux *mpq_demux,
+	struct ion_handle *input_handle,
+	const char *buf,
+	size_t count)
+{
+	struct ion_handle *ion_handle;
+	struct dvb_ringbuffer *rbuf;
+	struct sdmx_buff_descr buf_desc;
+	u32 read_offset;
+	int ret;
+
+	if (mpq_demux == NULL || input_handle == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	ion_handle = mpq_demux->demux.dmx.dvr_input.priv_handle;
+	rbuf = (struct dvb_ringbuffer *)mpq_demux->demux.dmx.dvr_input.ringbuff;
+
+	ret = mpq_sdmx_dvr_buffer_desc(mpq_demux, &buf_desc);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+		"%s: Failed to init input buffer descriptor. ret = %d\n",
+			__func__, ret);
+		return ret;
+	}
+	read_offset = mpq_demux->demux.dmx.dvr_input.ringbuff->pread;
+
+
+	/*
+	 * We must flush the buffer before SDMX starts reading from it
+	 * so that it gets a valid data in memory.
+	 */
+	ret = msm_ion_do_cache_op(mpq_demux->ion_client,
+		ion_handle, rbuf->data,
+		rbuf->size, ION_IOC_CLEAN_CACHES);
+	if (ret)
+		MPQ_DVB_ERR_PRINT(
+			"%s: msm_ion_do_cache_op failed, ret = %d\n",
+			__func__, ret);
+
+	return mpq_sdmx_process(mpq_demux, &buf_desc, count,
+				read_offset, mpq_demux->demux.ts_packet_size);
+}
+
+int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count)
+{
+	struct dvb_demux *dvb_demux;
+	struct mpq_demux *mpq_demux;
+	int ret = count;
+
+	if (demux == NULL)
+		return -EINVAL;
+
+	dvb_demux = demux->priv;
+	mpq_demux = dvb_demux->priv;
+
+	/* Route through secure demux - process secure feeds if any exist */
+	if (mpq_sdmx_is_loaded() && mpq_demux->sdmx_filter_count) {
+		ret = mpq_sdmx_write(mpq_demux,
+			demux->dvr_input.priv_handle,
+			buf,
+			count);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_sdmx_write failed. ret = %d\n",
+				__func__, ret);
+			ret = count;
+		}
+	}
+
+	/*
+	 * Route through sw filter - process non-secure feeds if any exist.
+	 * For sw filter, should process the same amount of bytes the sdmx
+	 * process managed to consume, unless some sdmx error occurred, for
+	 * which should process the whole buffer
+	 */
+	if (mpq_demux->num_active_feeds > mpq_demux->num_secure_feeds)
+		dvb_dmx_swfilter_format(dvb_demux, buf, ret,
+			dvb_demux->tsp_format);
+
+	if (signal_pending(current))
+		return -EINTR;
+
+	return ret;
+}
+
+int mpq_sdmx_is_loaded(void)
+{
+	static int sdmx_load_checked;
+
+	if (!sdmx_load_checked) {
+		mpq_sdmx_check_app_loaded();
+		sdmx_load_checked = 1;
+	}
+
+	return mpq_dmx_info.secure_demux_app_loaded;
+}
+
+int mpq_dmx_oob_command(struct dvb_demux_feed *feed,
+	struct dmx_oob_command *cmd)
+{
+	struct mpq_feed *mpq_feed = feed->priv;
+	struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+	struct dmx_data_ready event;
+	int ret = 0;
+
+	mutex_lock(&mpq_demux->mutex);
+	mpq_feed = feed->priv;
+
+	if (!dvb_dmx_is_video_feed(feed) && !dvb_dmx_is_pcr_feed(feed) &&
+		!feed->secure_mode.is_secured) {
+		mutex_unlock(&mpq_demux->mutex);
+		return 0;
+	}
+
+	event.data_length = 0;
+
+	switch (cmd->type) {
+	case DMX_OOB_CMD_EOS:
+		event.status = DMX_OK_EOS;
+		if (!feed->secure_mode.is_secured) {
+			if (dvb_dmx_is_video_feed(feed)) {
+				if (!video_framing)
+					mpq_dmx_decoder_pes_closure(mpq_demux,
+						mpq_feed);
+				else
+					mpq_dmx_decoder_frame_closure(mpq_demux,
+						mpq_feed);
+				ret = mpq_dmx_decoder_eos_cmd(mpq_feed, 1);
+				if (ret)
+					MPQ_DVB_ERR_PRINT(
+						"%s: Couldn't write oob eos packet\n",
+						__func__);
+			} else if (dvb_dmx_is_audio_feed(feed)) {
+				mpq_dmx_decoder_audio_pes_closure(mpq_demux,
+								  mpq_feed);
+				ret = mpq_dmx_decoder_eos_cmd(mpq_feed, 2);
+				if (ret)
+					MPQ_DVB_ERR_PRINT(
+							  "%s: Couldn't write oob eos packet\n",
+							  __func__);
+			}
+			ret = feed->data_ready_cb.ts(&feed->feed.ts, &event);
+		} else if (!mpq_demux->sdmx_eos) {
+			struct sdmx_buff_descr buf_desc;
+
+			mpq_demux->sdmx_eos = 1;
+			ret = mpq_sdmx_dvr_buffer_desc(mpq_demux, &buf_desc);
+			if (!ret) {
+				mutex_unlock(&mpq_demux->mutex);
+				mpq_sdmx_process_buffer(mpq_demux, &buf_desc,
+					0, 0);
+				return 0;
+			}
+		}
+		break;
+	case DMX_OOB_CMD_MARKER:
+		event.status = DMX_OK_MARKER;
+		event.marker.id = cmd->params.marker.id;
+
+		if (feed->type == DMX_TYPE_SEC)
+			ret = dvb_dmx_notify_section_event(feed, &event, 1);
+		else
+			/* MPQ_TODO: Notify decoder via the stream buffer */
+			ret = feed->data_ready_cb.ts(&feed->feed.ts, &event);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&mpq_demux->mutex);
+	return ret;
+}
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
new file mode 100644
index 0000000..0c20a89
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
@@ -0,0 +1,1116 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MPQ_DMX_PLUGIN_COMMON_H
+#define _MPQ_DMX_PLUGIN_COMMON_H
+
+#include <linux/msm_ion.h>
+
+#include "dvbdev.h"
+#include "dmxdev.h"
+#include "demux.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "mpq_adapter.h"
+#include "mpq_sdmx.h"
+
+#define TS_PACKET_SYNC_BYTE	(0x47)
+#define TS_PACKET_SIZE		(188)
+#define TS_PACKET_HEADER_LENGTH (4)
+
+/* Length of mandatory fields that must exist in header of video PES */
+#define PES_MANDATORY_FIELDS_LEN			9
+
+/*
+ * 500 PES header packets in the meta-data buffer,
+ * should be more than enough
+ */
+#define VIDEO_NUM_OF_PES_PACKETS			500
+
+#define VIDEO_META_DATA_PACKET_SIZE	\
+	(DVB_RINGBUFFER_PKTHDRSIZE +	\
+		sizeof(struct mpq_streambuffer_packet_header) + \
+		sizeof(struct mpq_adapter_video_meta_data))
+
+#define VIDEO_META_DATA_BUFFER_SIZE	\
+	(VIDEO_NUM_OF_PES_PACKETS * VIDEO_META_DATA_PACKET_SIZE)
+
+#define AUDIO_NUM_OF_PES_PACKETS			100
+
+#define AUDIO_META_DATA_PACKET_SIZE	\
+	(DVB_RINGBUFFER_PKTHDRSIZE +	\
+		sizeof(struct mpq_streambuffer_packet_header) + \
+		sizeof(struct mpq_adapter_audio_meta_data))
+
+#define AUDIO_META_DATA_BUFFER_SIZE	\
+	(AUDIO_NUM_OF_PES_PACKETS * AUDIO_META_DATA_PACKET_SIZE)
+
+/* Max number open() request can be done on demux device */
+#define MPQ_MAX_DMX_FILES				128
+
+/* TSIF alias name length */
+#define TSIF_NAME_LENGTH				20
+
+/**
+ * struct ts_packet_header - Transport packet header
+ * as defined in MPEG2 transport stream standard.
+ */
+struct ts_packet_header {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned sync_byte:8;
+	unsigned transport_error_indicator:1;
+	unsigned payload_unit_start_indicator:1;
+	unsigned transport_priority:1;
+	unsigned pid_msb:5;
+	unsigned pid_lsb:8;
+	unsigned transport_scrambling_control:2;
+	unsigned adaptation_field_control:2;
+	unsigned continuity_counter:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned sync_byte:8;
+	unsigned pid_msb:5;
+	unsigned transport_priority:1;
+	unsigned payload_unit_start_indicator:1;
+	unsigned transport_error_indicator:1;
+	unsigned pid_lsb:8;
+	unsigned continuity_counter:4;
+	unsigned adaptation_field_control:2;
+	unsigned transport_scrambling_control:2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
+/**
+ * struct ts_adaptation_field - Adaptation field prefix
+ * as defined in MPEG2 transport stream standard.
+ */
+struct ts_adaptation_field {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned adaptation_field_length:8;
+	unsigned discontinuity_indicator:1;
+	unsigned random_access_indicator:1;
+	unsigned elementary_stream_priority_indicator:1;
+	unsigned PCR_flag:1;
+	unsigned OPCR_flag:1;
+	unsigned splicing_point_flag:1;
+	unsigned transport_private_data_flag:1;
+	unsigned adaptation_field_extension_flag:1;
+	unsigned program_clock_reference_base_1:8;
+	unsigned program_clock_reference_base_2:8;
+	unsigned program_clock_reference_base_3:8;
+	unsigned program_clock_reference_base_4:8;
+	unsigned program_clock_reference_base_5:1;
+	unsigned reserved:6;
+	unsigned program_clock_reference_ext_1:1;
+	unsigned program_clock_reference_ext_2:8;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned adaptation_field_length:8;
+	unsigned adaptation_field_extension_flag:1;
+	unsigned transport_private_data_flag:1;
+	unsigned splicing_point_flag:1;
+	unsigned OPCR_flag:1;
+	unsigned PCR_flag:1;
+	unsigned elementary_stream_priority_indicator:1;
+	unsigned random_access_indicator:1;
+	unsigned discontinuity_indicator:1;
+	unsigned program_clock_reference_base_1:8;
+	unsigned program_clock_reference_base_2:8;
+	unsigned program_clock_reference_base_3:8;
+	unsigned program_clock_reference_base_4:8;
+	unsigned program_clock_reference_ext_1:1;
+	unsigned reserved:6;
+	unsigned program_clock_reference_base_5:1;
+	unsigned program_clock_reference_ext_2:8;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
+
+/*
+ * PES packet header containing dts and/or pts values
+ * as defined in MPEG2 transport stream standard.
+ */
+struct pes_packet_header {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned packet_start_code_prefix_1:8;
+	unsigned packet_start_code_prefix_2:8;
+	unsigned packet_start_code_prefix_3:8;
+	unsigned stream_id:8;
+	unsigned pes_packet_length_msb:8;
+	unsigned pes_packet_length_lsb:8;
+	unsigned reserved_bits0:2;
+	unsigned pes_scrambling_control:2;
+	unsigned pes_priority:1;
+	unsigned data_alignment_indicator:1;
+	unsigned copyright:1;
+	unsigned original_or_copy:1;
+	unsigned pts_dts_flag:2;
+	unsigned escr_flag:1;
+	unsigned es_rate_flag:1;
+	unsigned dsm_trick_mode_flag:1;
+	unsigned additional_copy_info_flag:1;
+	unsigned pes_crc_flag:1;
+	unsigned pes_extension_flag:1;
+	unsigned pes_header_data_length:8;
+	unsigned reserved_bits1:4;
+	unsigned pts_1:3;
+	unsigned marker_bit0:1;
+	unsigned pts_2:8;
+	unsigned pts_3:7;
+	unsigned marker_bit1:1;
+	unsigned pts_4:8;
+	unsigned pts_5:7;
+	unsigned marker_bit2:1;
+	unsigned reserved_bits2:4;
+	unsigned dts_1:3;
+	unsigned marker_bit3:1;
+	unsigned dts_2:8;
+	unsigned dts_3:7;
+	unsigned marker_bit4:1;
+	unsigned dts_4:8;
+	unsigned dts_5:7;
+	unsigned marker_bit5:1;
+	unsigned reserved_bits3:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned packet_start_code_prefix_1:8;
+	unsigned packet_start_code_prefix_2:8;
+	unsigned packet_start_code_prefix_3:8;
+	unsigned stream_id:8;
+	unsigned pes_packet_length_lsb:8;
+	unsigned pes_packet_length_msb:8;
+	unsigned original_or_copy:1;
+	unsigned copyright:1;
+	unsigned data_alignment_indicator:1;
+	unsigned pes_priority:1;
+	unsigned pes_scrambling_control:2;
+	unsigned reserved_bits0:2;
+	unsigned pes_extension_flag:1;
+	unsigned pes_crc_flag:1;
+	unsigned additional_copy_info_flag:1;
+	unsigned dsm_trick_mode_flag:1;
+	unsigned es_rate_flag:1;
+	unsigned escr_flag:1;
+	unsigned pts_dts_flag:2;
+	unsigned pes_header_data_length:8;
+	unsigned marker_bit0:1;
+	unsigned pts_1:3;
+	unsigned reserved_bits1:4;
+	unsigned pts_2:8;
+	unsigned marker_bit1:1;
+	unsigned pts_3:7;
+	unsigned pts_4:8;
+	unsigned marker_bit2:1;
+	unsigned pts_5:7;
+	unsigned marker_bit3:1;
+	unsigned dts_1:3;
+	unsigned reserved_bits2:4;
+	unsigned dts_2:8;
+	unsigned marker_bit4:1;
+	unsigned dts_3:7;
+	unsigned dts_4:8;
+	unsigned marker_bit5:1;
+	unsigned dts_5:7;
+	unsigned reserved_bits3:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
+/**
+ * mpq_decoder_buffers_desc - decoder buffer(s) management information.
+ *
+ * @desc: Array of buffer descriptors as they are passed to mpq_streambuffer
+ * upon its initialization. These descriptors must remain valid as long as
+ * the mpq_streambuffer object is used.
+ * @ion_handle: Array of ION handles, one for each decoder buffer, used for
+ * kernel memory mapping or allocation. Handles are saved in order to release
+ * resources properly later on.
+ * @decoder_buffers_num: number of buffers that are managed, either externally
+ * or internally by the mpq_streambuffer object
+ * @shared_file: File handle of internally allocated video buffer shared
+ * with video consumer.
+ */
+struct mpq_decoder_buffers_desc {
+	struct mpq_streambuffer_buffer_desc desc[DMX_MAX_DECODER_BUFFER_NUM];
+	struct ion_handle *ion_handle[DMX_MAX_DECODER_BUFFER_NUM];
+	u32 decoder_buffers_num;
+	struct file *shared_file;
+};
+
+/*
+ * mpq_video_feed_info - private data used for video feed.
+ *
+ * @video_buffer: Holds the streamer buffer shared with
+ * the decoder for feeds having the data going to the decoder.
+ * @video_buffer_lock: Lock protecting against video output buffer.
+ * The lock protects against API calls to manipulate the output buffer
+ * (initialize, free, re-use buffers) and dvb-sw demux parsing the video
+ * data through mpq_dmx_process_video_packet().
+ * @buffer_desc: Holds decoder buffer(s) information used for stream buffer.
+ * @pes_header: Used for feeds that output data to decoder,
+ * holds PES header of current processed PES.
+ * @pes_header_left_bytes: Used for feeds that output data to decoder,
+ * holds remaining PES header bytes of current processed PES.
+ * @pes_header_offset: Holds the offset within the current processed
+ * pes header.
+ * @fullness_wait_cancel: Flag used to signal to abort waiting for
+ * decoder's fullness.
+ * @stream_interface: The ID of the video stream interface registered
+ * with this stream buffer.
+ * @patterns: pointer to the framing patterns to look for.
+ * @patterns_num: number of framing patterns.
+ * @prev_pattern: holds the trailing data of the last processed video packet.
+ * @frame_offset: Saves data buffer offset to which a new frame will be written
+ * @last_pattern_offset: Holds the previous pattern offset
+ * @pending_pattern_len: Accumulated number of data bytes that will be
+ * reported for this frame.
+ * @last_framing_match_type: Used for saving the type of
+ * the previous pattern match found in this video feed.
+ * @last_framing_match_stc: Used for saving the STC attached to TS packet
+ * of the previous pattern match found in this video feed.
+ * @found_sequence_header_pattern: Flag used to note that an MPEG-2
+ * Sequence Header, H.264 SPS or VC-1 Sequence Header pattern
+ * (whichever is relevant according to the video standard) had already
+ * been found.
+ * @prefix_size: a bit mask representing the size(s) of possible prefixes
+ * to the pattern, already found in the previous buffer. If bit 0 is set,
+ * a prefix of size 1 was found. If bit 1 is set, a prefix of size 2 was
+ * found, etc. This supports a prefix size of up to 32, which is more
+ * than we need. The search function updates prefix_size as needed
+ * for the next buffer search.
+ * @first_prefix_size: used to save the prefix size used to find the first
+ * pattern written to the stream buffer.
+ * @saved_pts_dts_info: used to save PTS/DTS information until it is written.
+ * @new_pts_dts_info: used to store PTS/DTS information from current PES header.
+ * @saved_info_used: indicates if saved PTS/DTS information was used.
+ * @new_info_exists: indicates if new PTS/DTS information exists in
+ * new_pts_dts_info that should be saved to saved_pts_dts_info.
+ * @first_pts_dts_copy: a flag used to indicate if PTS/DTS information needs
+ * to be copied from the currently parsed PES header to the saved_pts_dts_info.
+ * @tei_errs: Transport stream Transport Error Indicator (TEI) counter.
+ * @last_continuity: last continuity counter value found in TS packet header.
+ * Initialized to -1.
+ * @continuity_errs: Transport stream continuity error counter.
+ * @ts_packets_num: TS packets counter.
+ * @ts_dropped_bytes: counts the number of bytes dropped due to insufficient
+ * buffer space.
+ * @prev_stc: STC attached to the previous video TS packet
+ */
+struct mpq_video_feed_info {
+	struct mpq_streambuffer *video_buffer;
+	spinlock_t video_buffer_lock;
+	struct mpq_decoder_buffers_desc buffer_desc;
+	struct pes_packet_header pes_header;
+	u32 pes_header_left_bytes;
+	u32 pes_header_offset;
+	int fullness_wait_cancel;
+	enum mpq_adapter_stream_if stream_interface;
+const struct dvb_dmx_video_patterns *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM];
+	int patterns_num;
+	char prev_pattern[DVB_DMX_MAX_PATTERN_LEN];
+	u32 frame_offset;
+	u32 last_pattern_offset;
+	u32 pending_pattern_len;
+	u64 last_framing_match_type;
+	u64 last_framing_match_stc;
+	int found_sequence_header_pattern;
+	struct dvb_dmx_video_prefix_size_masks prefix_size;
+	u32 first_prefix_size;
+	struct dmx_pts_dts_info saved_pts_dts_info;
+	struct dmx_pts_dts_info new_pts_dts_info;
+	int saved_info_used;
+	int new_info_exists;
+	int first_pts_dts_copy;
+	u32 tei_errs;
+	int last_continuity;
+	u32 continuity_errs;
+	u32 ts_packets_num;
+	u32 ts_dropped_bytes;
+	u64 prev_stc;
+};
+
+/* require a bare minimal mpq_audio_feed_info struct */
+struct mpq_audio_feed_info {
+	struct mpq_streambuffer *audio_buffer;
+	spinlock_t audio_buffer_lock;
+	struct mpq_decoder_buffers_desc buffer_desc;
+	struct pes_packet_header pes_header;
+	u32 pes_header_left_bytes;
+	u32 pes_header_offset;
+	int fullness_wait_cancel;
+	enum mpq_adapter_stream_if stream_interface;
+	u32 frame_offset; /* pes frame offset */
+	struct dmx_pts_dts_info saved_pts_dts_info;
+	struct dmx_pts_dts_info new_pts_dts_info;
+	int saved_info_used;
+	int new_info_exists;
+	int first_pts_dts_copy;
+	u32 tei_errs;
+	int last_continuity;
+	u32 continuity_errs;
+	u32 ts_packets_num;
+	u32 ts_dropped_bytes;
+	u64 prev_stc;
+};
+
+/**
+ * mpq feed object - mpq common plugin feed information
+ *
+ * @dvb_demux_feed: Back pointer to dvb demux level feed object
+ * @mpq_demux: Pointer to common mpq demux object
+ * @plugin_priv: Plugin specific private data
+ * @sdmx_filter_handle: Secure demux filter handle. Recording feed may share
+ * same filter handle
+ * @secondary_feed: Specifies if this feed shares filter handle with
+ * other feeds
+ * @metadata_buf: Ring buffer object for managing the metadata buffer
+ * @metadata_buf_handle: Allocation handle for the metadata buffer
+ * @session_id: Counter that is incremented every time feed is initialized
+ * through mpq_dmx_init_mpq_feed
+ * @sdmx_buf: Ring buffer object for intermediate output data from the sdmx
+ * @sdmx_buf_handle: Allocation handle for the sdmx intermediate data buffer
+ * @video_info: Video feed specific information
+ */
+struct mpq_feed {
+	struct dvb_demux_feed *dvb_demux_feed;
+	struct mpq_demux *mpq_demux;
+	void *plugin_priv;
+
+	/* Secure demux related */
+	int sdmx_filter_handle;
+	int secondary_feed;
+	enum sdmx_filter filter_type;
+	struct dvb_ringbuffer metadata_buf;
+	struct ion_handle *metadata_buf_handle;
+
+	u8 session_id;
+	struct dvb_ringbuffer sdmx_buf;
+	struct ion_handle *sdmx_buf_handle;
+
+	struct mpq_video_feed_info video_info;
+	struct mpq_audio_feed_info audio_info;
+};
+
+/**
+ * struct mpq_demux - mpq demux information
+ * @idx: Instance index
+ * @demux: The dvb_demux instance used by mpq_demux
+ * @dmxdev: The dmxdev instance used by mpq_demux
+ * @fe_memory: Handle of front-end memory source to mpq_demux
+ * @source: The current source connected to the demux
+ * @is_initialized: Indicates whether this demux device was
+ *                  initialized or not.
+ * @ion_client: ION demux client used to allocate memory from ION.
+ * @mutex: Lock used to protect against private feed data
+ * @feeds: mpq common feed object pool
+ * @num_active_feeds: Number of active mpq feeds
+ * @num_secure_feeds: Number of secure feeds (have a sdmx filter associated)
+ * currently allocated.
+ * Used before each call to sdmx_process() to build up to date state.
+ * @sdmx_session_handle: Secure demux open session handle
+ * @sdmx_filter_count: Number of active secure demux filters
+ * @sdmx_eos: End-of-stream indication flag for current sdmx session
+ * @sdmx_filters_state: Array holding buffers status for each secure
+ * demux filter.
+ * @decoder_alloc_flags: ION flags to be used when allocating internally
+ * @plugin_priv: Underlying plugin's own private data
+ * @mpq_dmx_plugin_release: Underlying plugin's release function
+ * @hw_notification_interval: Notification interval in msec,
+ * exposed in debugfs.
+ * @hw_notification_min_interval: Minimum notification internal in msec,
+ * exposed in debugfs.
+ * @hw_notification_count: Notification count, exposed in debugfs.
+ * @hw_notification_size: Notification size in bytes, exposed in debugfs.
+ * @hw_notification_min_size: Minimum notification size in bytes,
+ * exposed in debugfs.
+ * @decoder_stat: Decoder output statistics, exposed in debug-fs.
+ * @sdmx_process_count: Total number of times sdmx_process is called.
+ * @sdmx_process_time_sum: Total time sdmx_process takes.
+ * @sdmx_process_time_average: Average time sdmx_process takes.
+ * @sdmx_process_time_max: Max time sdmx_process takes.
+ * @sdmx_process_packets_sum: Total packets number sdmx_process handled.
+ * @sdmx_process_packets_average: Average packets number sdmx_process handled.
+ * @sdmx_process_packets_min: Minimum packets number sdmx_process handled.
+ * @last_notification_time: Time of last HW notification.
+ */
+struct mpq_demux {
+	int idx;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend fe_memory;
+	dmx_source_t source;
+	int is_initialized;
+	struct ion_client *ion_client;
+	struct mutex mutex;
+	struct mpq_feed feeds[MPQ_MAX_DMX_FILES];
+	u32 num_active_feeds;
+	u32 num_secure_feeds;
+	int sdmx_session_handle;
+	int sdmx_session_ref_count;
+	int sdmx_filter_count;
+	int sdmx_eos;
+	struct {
+		/* SDMX filters status */
+		struct sdmx_filter_status status[MPQ_MAX_DMX_FILES];
+
+		/* Index of the feed respective to SDMX filter */
+		u8 mpq_feed_idx[MPQ_MAX_DMX_FILES];
+
+		/*
+		 * Snapshot of session_id of the feed
+		 * when SDMX process was called. This is used
+		 * to identify whether the feed has been
+		 * restarted when processing SDMX results.
+		 * May happen when demux is stalled in playback
+		 * from memory with PULL mode.
+		 */
+		u8 session_id[MPQ_MAX_DMX_FILES];
+	} sdmx_filters_state;
+
+	unsigned int decoder_alloc_flags;
+
+	/* HW plugin specific */
+	void *plugin_priv;
+	int (*mpq_dmx_plugin_release)(struct mpq_demux *mpq_demux);
+
+	/* debug-fs */
+	u32 hw_notification_interval;
+	u32 hw_notification_min_interval;
+	u32 hw_notification_count;
+	u32 hw_notification_size;
+	u32 hw_notification_min_size;
+
+	struct {
+		/*
+		 * Accumulated number of bytes
+		 * dropped due to decoder buffer fullness.
+		 */
+		u32 drop_count;
+
+		/* Counter incremeneted for each video frame output by demux */
+		u32 out_count;
+
+		/*
+		 * Sum of intervals (msec) holding the time
+		 * between two successive video frames output.
+		 */
+		u32 out_interval_sum;
+
+		/*
+		 * Average interval (msec) between two
+		 * successive video frames output.
+		 */
+		u32 out_interval_average;
+
+		/*
+		 * Max interval (msec) between two
+		 * successive video frames output.
+		 */
+		u32 out_interval_max;
+
+		/* Counter for number of decoder packets with TEI bit set */
+		u32 ts_errors;
+
+		/*
+		 * Counter for number of decoder packets
+		 * with continuity counter errors.
+		 */
+		u32 cc_errors;
+
+		/* Time of last video frame output */
+		ktime_t out_last_time;
+	} decoder_stat[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES];
+
+	u32 sdmx_process_count;
+	u32 sdmx_process_time_sum;
+	u32 sdmx_process_time_average;
+	u32 sdmx_process_time_max;
+	u32 sdmx_process_packets_sum;
+	u32 sdmx_process_packets_average;
+	u32 sdmx_process_packets_min;
+	enum sdmx_log_level sdmx_log_level;
+
+	ktime_t last_notification_time;
+	int ts_packet_timestamp_source;
+};
+
+/**
+ * mpq_dmx_init - initialization and registration function of
+ * single MPQ demux device
+ *
+ * @adapter: The adapter to register mpq_demux to
+ * @mpq_demux: The mpq demux to initialize
+ *
+ * Every HW plug-in needs to provide implementation of such
+ * function that will be called for each demux device on the
+ * module initialization. The function mpq_demux_plugin_init
+ * should be called during the HW plug-in module initialization.
+ */
+typedef int (*mpq_dmx_init)(struct dvb_adapter *mpq_adapter,
+	struct mpq_demux *demux);
+
+/**
+ * mpq_demux_plugin_init - Initialize demux devices and register
+ * them to the dvb adapter.
+ *
+ * @dmx_init_func: Pointer to the function to be used
+ *  to initialize demux of the underlying HW plugin.
+ *
+ * Return     error code
+ *
+ * Should be called at the HW plugin module initialization.
+ */
+int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func);
+
+/**
+ * mpq_demux_plugin_exit - terminate demux devices.
+ *
+ * Should be called at the HW plugin module termination.
+ */
+void mpq_dmx_plugin_exit(void);
+
+/**
+ * mpq_dmx_set_source - implmenetation of set_source routine.
+ *
+ * @demux: The demux device to set its source.
+ * @src: The source to be set.
+ *
+ * Return     error code
+ *
+ * Can be used by the underlying plugins to implement kernel
+ * demux API set_source routine.
+ */
+int mpq_dmx_set_source(struct dmx_demux *demux, const dmx_source_t *src);
+
+/**
+ * mpq_dmx_map_buffer - map user-space buffer into kernel space.
+ *
+ * @demux: The demux device.
+ * @dmx_buffer: The demux buffer from user-space, assumes that
+ * buffer handle is ION file-handle.
+ * @priv_handle: Saves ION-handle of the buffer imported by this function.
+ * @kernel_mem: Saves kernel mapped address of the buffer.
+ *
+ * Return     error code
+ *
+ * The function maps the buffer into kernel memory only if the buffer
+ * was not allocated with secure flag, otherwise the returned kernel
+ * memory address is set to NULL.
+ */
+int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer,
+		void **priv_handle, void **kernel_mem);
+
+/**
+ * mpq_dmx_unmap_buffer - unmap user-space buffer from kernel space memory.
+ *
+ * @demux: The demux device.
+ * @priv_handle: ION-handle of the buffer returned from mpq_dmx_map_buffer.
+ *
+ * Return     error code
+ *
+ * The function unmaps the buffer from kernel memory only if the buffer
+ * was not allocated with secure flag.
+ */
+int mpq_dmx_unmap_buffer(struct dmx_demux *demux, void *priv_handle);
+
+/**
+ * mpq_dmx_decoder_fullness_init - Initialize waiting
+ * mechanism on decoder's buffer fullness.
+ *
+ * @feed: The decoder's feed
+ *
+ * Return     error code.
+ */
+int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_decoder_fullness_wait - Checks whether decoder buffer
+ * have free space as required, if not, wait for it.
+ *
+ * @feed: The decoder's feed
+ * @required_space: the required free space to wait for
+ *
+ * Return     error code.
+ */
+int mpq_dmx_decoder_fullness_wait(struct dvb_demux_feed *feed,
+		size_t required_space);
+
+/**
+ * mpq_dmx_decoder_fullness_abort - Aborts waiting
+ * on decoder's buffer fullness if any waiting is done
+ * now. After calling this, to wait again the user must
+ * call mpq_dmx_decoder_fullness_init.
+ *
+ * @feed: The decoder's feed
+ *
+ * Return     error code.
+ */
+int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_decoder_buffer_status - Returns the
+ * status of the decoder's buffer.
+ *
+ * @feed: The decoder's feed
+ * @dmx_buffer_status: Status of decoder's buffer
+ *
+ * Return     error code.
+ */
+int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed,
+		struct dmx_buffer_status *dmx_buffer_status);
+
+/**
+ * mpq_dmx_reuse_decoder_buffer - release buffer passed to decoder for reuse
+ * by the stream-buffer.
+ *
+ * @feed: The decoder's feed.
+ * @cookie: stream-buffer handle of the buffer.
+ *
+ * Return     error code
+ *
+ * The function releases the buffer provided by the stream-buffer
+ * connected to the decoder back to the stream-buffer for reuse.
+ */
+int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie);
+
+/**
+ * mpq_dmx_process_video_packet - Assemble PES data and output it
+ * to the stream-buffer connected to the decoder.
+ *
+ * @feed: The feed used for the video TS packets
+ * @buf: The buffer holding video TS packet.
+ *
+ * Return     error code.
+ *
+ * The function assumes it receives buffer with single TS packet
+ * of the relevant PID.
+ * If the output buffer is full while assembly, the function drops
+ * the packet and does not write them to the output buffer.
+ * Scrambled packets are bypassed.
+ */
+int mpq_dmx_process_video_packet(struct dvb_demux_feed *feed, const u8 *buf);
+
+/**
+ * mpq_dmx_process_pcr_packet - Extract PCR/STC pairs from
+ * a 192 bytes packet.
+ *
+ * @feed: The feed used for the PCR TS packets
+ * @buf: The buffer holding pcr/stc packet.
+ *
+ * Return     error code.
+ *
+ * The function assumes it receives buffer with single TS packet
+ * of the relevant PID, and that it has 4 bytes
+ * suffix as extra timestamp in the following format:
+ *
+ * Byte3: TSIF flags
+ * Byte0-2: TTS, 0..2^24-1 at 105.47 Khz (27*10^6/256).
+ *
+ * The function callbacks dmxdev after extraction of the pcr/stc
+ * pair.
+ */
+int mpq_dmx_process_pcr_packet(struct dvb_demux_feed *feed, const u8 *buf);
+
+/**
+ * mpq_dmx_extract_pcr_and_dci() - Extract the PCR field and discontinuity
+ * indicator from a TS packet buffer.
+ *
+ * @buf: TS packet buffer
+ * @pcr: returned PCR value
+ * @dci: returned discontinuity indicator
+ *
+ * Returns 1 if PCR was extracted, 0 otherwise.
+ */
+int mpq_dmx_extract_pcr_and_dci(const u8 *buf, u64 *pcr, int *dci);
+
+/**
+ * mpq_dmx_init_debugfs_entries -
+ * Extend dvb-demux debugfs with mpq related entries (HW statistics and secure
+ * demux log level).
+ *
+ * @mpq_demux: The mpq_demux device to initialize.
+ */
+void mpq_dmx_init_debugfs_entries(struct mpq_demux *mpq_demux);
+
+/**
+ * mpq_dmx_update_hw_statistics -
+ * Update dvb-demux debugfs with HW notification statistics.
+ *
+ * @mpq_demux: The mpq_demux device to update.
+ */
+void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux);
+
+/**
+ * mpq_dmx_set_cipher_ops - Handles setting of cipher operations
+ *
+ * @feed: The feed to set its cipher operations
+ * @cipher_ops: Cipher operations to be set
+ *
+ * This common function handles only the case when working with
+ * secure-demux. When working with secure demux a single decrypt cipher
+ * operation is allowed.
+ *
+ * Return error code
+ */
+int mpq_dmx_set_cipher_ops(struct dvb_demux_feed *feed,
+		struct dmx_cipher_operations *cipher_ops);
+
+/**
+ * mpq_dmx_convert_tts - Convert timestamp attached by HW to each TS
+ * packet to 27MHz.
+ *
+ * @feed: The feed with TTS attached
+ * @timestamp: Buffer holding the timestamp attached by the HW
+ * @timestampIn27Mhz: Timestamp result in 27MHz
+ *
+ * Return error code
+ */
+void mpq_dmx_convert_tts(struct dvb_demux_feed *feed,
+		const u8 timestamp[TIMESTAMP_LEN],
+		u64 *timestampIn27Mhz);
+
+/**
+ * mpq_sdmx_open_session - Handle the details of opening a new secure demux
+ * session for the specified mpq demux instance. Multiple calls to this
+ * is allowed, reference counting is managed to open it only when needed.
+ *
+ * @mpq_demux: mpq demux instance
+ *
+ * Return error code
+ */
+int mpq_sdmx_open_session(struct mpq_demux *mpq_demux);
+
+/**
+ * mpq_sdmx_close_session - Closes secure demux session. The session
+ * is closed only if reference counter of the session reaches 0.
+ *
+ * @mpq_demux: mpq demux instance
+ *
+ * Return error code
+ */
+int mpq_sdmx_close_session(struct mpq_demux *mpq_demux);
+
+/**
+ * mpq_dmx_init_mpq_feed - Initialize an mpq feed object
+ * The function allocates mpq_feed object and saves in the dvb_demux_feed
+ * priv field.
+ *
+ * @feed: A dvb demux level feed parent object
+ *
+ * Return error code
+ */
+int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_terminate_feed - Destroy an mpq feed object
+ *
+ * @feed: A dvb demux level feed parent object
+ *
+ * Return error code
+ */
+int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_init_video_feed() - Initializes video related data structures
+ *
+ * @mpq_feed:	mpq_feed object to initialize
+ *
+ * Return error code
+ */
+int mpq_dmx_init_video_feed(struct mpq_feed *mpq_feed);
+
+/**
+ * mpq_dmx_terminate_video_feed() - Release video related feed resources
+ *
+ * @mpq_feed:	mpq_feed object to terminate
+ *
+ * Return error code
+ */
+int mpq_dmx_terminate_video_feed(struct mpq_feed *mpq_feed);
+
+/**
+ * mpq_dmx_write - demux write() function implementation.
+ *
+ * A wrapper function used for writing new data into the demux via DVR.
+ * It checks where new data should actually go, the secure demux or the normal
+ * dvb demux software demux.
+ *
+ * @demux: demux interface
+ * @buf: input buffer
+ * @count: number of data bytes in input buffer
+ *
+ * Return number of bytes processed or error code
+ */
+int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count);
+
+/**
+ * mpq_sdmx_process - Perform demuxing process on the specified input buffer
+ * in the secure demux instance
+ *
+ * @mpq_demux: mpq demux instance
+ * @input: input buffer descriptor
+ * @fill_count: number of data bytes in input buffer that can be read
+ * @read_offset: offset in buffer for reading
+ * @tsp_size: size of single TS packet
+ *
+ * Return number of bytes read or error code
+ */
+int mpq_sdmx_process(struct mpq_demux *mpq_demux,
+	struct sdmx_buff_descr *input,
+	u32 fill_count,
+	u32 read_offset,
+	size_t tsp_size);
+
+/**
+ * mpq_sdmx_loaded - Returns 1 if secure demux application is loaded,
+ * 0 otherwise. This function should be used to determine whether or not
+ * processing should take place in the SDMX.
+ */
+int mpq_sdmx_is_loaded(void);
+
+/**
+ * mpq_dmx_oob_command - Handles OOB command from dvb-demux.
+ *
+ * OOB marker commands trigger callback to the dmxdev.
+ * Handling of EOS command may trigger current (last on stream) PES/Frame to
+ * be reported, in addition to callback to the dmxdev.
+ * In case secure demux is active for the feed, EOS command is passed to the
+ * secure demux for handling.
+ *
+ * @feed: dvb demux feed object
+ * @cmd: oob command data
+ *
+ * returns 0 on success or error
+ */
+int mpq_dmx_oob_command(struct dvb_demux_feed *feed,
+	struct dmx_oob_command *cmd);
+
+/**
+ * mpq_dmx_peer_rec_feed() - For a recording filter with multiple feeds objects
+ * search for a feed object that shares the same filter as the specified feed
+ * object, and return it.
+ * This can be used to test whether the specified feed object is the first feed
+ * allocate for the recording filter - return value is NULL.
+ *
+ * @feed: dvb demux feed object
+ *
+ * Return the dvb_demux_feed sharing the same filter's buffer or NULL if no
+ * such is found.
+ */
+struct dvb_demux_feed *mpq_dmx_peer_rec_feed(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_decoder_eos_cmd() - Report EOS event to the mpq_streambuffer
+ *
+ * @mpq_feed: Audio/Video mpq_feed object for notification
+ * @feed_type: Feed type( Audio or Video )
+ *
+ * Return error code
+ */
+int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed, int feed_type);
+
+/**
+ * mpq_dmx_parse_mandatory_pes_header() - Parse non-optional PES header fields
+ * from TS packet buffer and save results in the feed object.
+ *
+ * @feed:		Video dvb demux feed object
+ * @feed_data:		Structure where results will be saved
+ * @pes_header:		Saved PES header
+ * @buf:		Input buffer containing TS packet with the PES header
+ * @ts_payload_offset:	Offset in 'buf' where payload begins
+ * @bytes_avail:	Length of actual payload
+ *
+ * Return error code
+ */
+int mpq_dmx_parse_mandatory_pes_header(
+				struct dvb_demux_feed *feed,
+				struct mpq_video_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				const u8 *buf,
+				u32 *ts_payload_offset,
+				int *bytes_avail);
+
+/**
+ * mpq_dmx_parse_remaining_pes_header() - Parse optional PES header fields
+ * from TS packet buffer and save results in the feed object.
+ * This function depends on mpq_dmx_parse_mandatory_pes_header being called
+ * first for state to be valid.
+ *
+ * @feed:		Video dvb demux feed object
+ * @feed_data:		Structure where results will be saved
+ * @pes_header:		Saved PES header
+ * @buf:		Input buffer containing TS packet with the PES header
+ * @ts_payload_offset:	Offset in 'buf' where payload begins
+ * @bytes_avail:	Length of actual payload
+ *
+ * Return error code
+ */
+int mpq_dmx_parse_remaining_pes_header(
+				struct dvb_demux_feed *feed,
+				struct mpq_video_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				const u8 *buf,
+				u32 *ts_payload_offset,
+				int *bytes_avail);
+
+/**
+ * mpq_dmx_flush_stream_buffer() - Flush video stream buffer object of the
+ * specific video feed, both meta-data packets and data.
+ *
+ * @feed:	dvb demux video feed object
+ *
+ * Return error code
+ */
+int mpq_dmx_flush_stream_buffer(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_save_pts_dts() - Save the current PTS/DTS data
+ *
+ * @feed_data: Video feed structure where PTS/DTS is saved
+ */
+static inline void mpq_dmx_save_pts_dts(struct mpq_video_feed_info *feed_data)
+{
+	if (feed_data->new_info_exists) {
+		feed_data->saved_pts_dts_info.pts_exist =
+			feed_data->new_pts_dts_info.pts_exist;
+		feed_data->saved_pts_dts_info.pts =
+			feed_data->new_pts_dts_info.pts;
+		feed_data->saved_pts_dts_info.dts_exist =
+			feed_data->new_pts_dts_info.dts_exist;
+		feed_data->saved_pts_dts_info.dts =
+			feed_data->new_pts_dts_info.dts;
+
+		feed_data->new_info_exists = 0;
+		feed_data->saved_info_used = 0;
+	}
+}
+
+/**
+ * mpq_dmx_write_pts_dts() - Write out the saved PTS/DTS data and mark as used
+ *
+ * @feed_data:	Video feed structure where PTS/DTS was saved
+ * @info:	PTS/DTS structure to write to
+ */
+static inline void mpq_dmx_write_pts_dts(struct mpq_video_feed_info *feed_data,
+					struct dmx_pts_dts_info *info)
+{
+	if (!feed_data->saved_info_used) {
+		info->pts_exist = feed_data->saved_pts_dts_info.pts_exist;
+		info->pts = feed_data->saved_pts_dts_info.pts;
+		info->dts_exist = feed_data->saved_pts_dts_info.dts_exist;
+		info->dts = feed_data->saved_pts_dts_info.dts;
+
+		feed_data->saved_info_used = 1;
+	} else {
+		info->pts_exist = 0;
+		info->dts_exist = 0;
+	}
+}
+
+/*
+ * mpq_dmx_calc_time_delta -
+ * Calculate delta in msec between two time snapshots.
+ *
+ * @curr_time: value of current time
+ * @prev_time: value of previous time
+ *
+ * Return	time-delta in msec
+ */
+static inline u32 mpq_dmx_calc_time_delta(ktime_t curr_time, ktime_t prev_time)
+{
+	s64 delta_time_ms = ktime_ms_delta(curr_time, prev_time);
+
+	return (u32)delta_time_ms;
+}
+
+void mpq_dmx_update_decoder_stat(struct mpq_feed *mpq_feed);
+
+/* Return the common module parameter tsif_mode */
+int mpq_dmx_get_param_tsif_mode(void);
+
+/* Return the common module parameter clock_inv */
+int mpq_dmx_get_param_clock_inv(void);
+
+/* Return the common module parameter mpq_sdmx_scramble_odd */
+int mpq_dmx_get_param_scramble_odd(void);
+
+/* Return the common module parameter mpq_sdmx_scramble_even */
+int mpq_dmx_get_param_scramble_even(void);
+
+/* Return the common module parameter mpq_sdmx_scramble_default_discard */
+int mpq_dmx_get_param_scramble_default_discard(void);
+
+/* APIs for Audio stream buffers interface -- Added for broadcase use case */
+/*
+ * The Audio/Video drivers (or consumers) require the stream_buffer information
+ * for consuming packet headers and compressed AV data from the
+ * ring buffer filled by demux driver which is the producer
+ */
+struct mpq_streambuffer *consumer_audio_streambuffer(int dmx_ts_pes_audio);
+struct mpq_streambuffer *consumer_video_streambuffer(int dmx_ts_pes_video);
+
+int mpq_dmx_init_audio_feed(struct mpq_feed *mpq_feed);
+
+int mpq_dmx_terminate_audio_feed(struct mpq_feed *mpq_feed);
+
+int mpq_dmx_parse_remaining_audio_pes_header(
+				struct dvb_demux_feed *feed,
+				struct mpq_audio_feed_info *feed_data,
+				struct pes_packet_header *pes_header,
+				const u8 *buf,
+				u32 *ts_payload_offset,
+				int *bytes_avail);
+
+static inline void mpq_dmx_save_audio_pts_dts(
+				struct mpq_audio_feed_info *feed_data)
+{
+	if (feed_data->new_info_exists) {
+		feed_data->saved_pts_dts_info.pts_exist =
+			feed_data->new_pts_dts_info.pts_exist;
+		feed_data->saved_pts_dts_info.pts =
+			feed_data->new_pts_dts_info.pts;
+		feed_data->saved_pts_dts_info.dts_exist =
+			feed_data->new_pts_dts_info.dts_exist;
+		feed_data->saved_pts_dts_info.dts =
+			feed_data->new_pts_dts_info.dts;
+
+		feed_data->new_info_exists = 0;
+		feed_data->saved_info_used = 0;
+	}
+}
+
+/*
+ * mpq_dmx_process_audio_packet - Assemble Audio PES data and output to
+ * stream buffer connected to decoder.
+ */
+int mpq_dmx_process_audio_packet(struct dvb_demux_feed *feed, const u8 *buf);
+
+static inline void mpq_dmx_write_audio_pts_dts(
+					struct mpq_audio_feed_info *feed_data,
+					struct dmx_pts_dts_info *info)
+{
+	if (!feed_data->saved_info_used) {
+		info->pts_exist = feed_data->saved_pts_dts_info.pts_exist;
+		info->pts = feed_data->saved_pts_dts_info.pts;
+		info->dts_exist = feed_data->saved_pts_dts_info.dts_exist;
+		info->dts = feed_data->saved_pts_dts_info.dts;
+
+		feed_data->saved_info_used = 1;
+	} else {
+		info->pts_exist = 0;
+		info->dts_exist = 0;
+	}
+}
+
+#endif /* _MPQ_DMX_PLUGIN_COMMON_H */
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c
new file mode 100644
index 0000000..16e1ba4
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c
@@ -0,0 +1,280 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+
+static int mpq_sw_dmx_start_filtering(struct dvb_demux_feed *feed)
+{
+	int ret = -EINVAL;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	MPQ_DVB_DBG_PRINT("%s(pid=%d) executed\n", __func__, feed->pid);
+
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid mpq_demux handle\n", __func__);
+		goto out;
+	}
+
+	if (mpq_demux->source < DMX_SOURCE_DVR0) {
+		MPQ_DVB_ERR_PRINT("%s: only DVR source is supported (%d)\n",
+			__func__, mpq_demux->source);
+		goto out;
+	}
+
+	/*
+	 * Always feed sections/PES starting from a new one and
+	 * do not partial transfer data from older one
+	 */
+	feed->pusi_seen = 0;
+
+	ret = mpq_dmx_init_mpq_feed(feed);
+	if (ret)
+		MPQ_DVB_ERR_PRINT("%s: mpq_dmx_init_mpq_feed failed(%d)\n",
+			__func__, ret);
+out:
+	return ret;
+}
+
+static int mpq_sw_dmx_stop_filtering(struct dvb_demux_feed *feed)
+{
+	int ret;
+
+	MPQ_DVB_DBG_PRINT("%s(%d) executed\n", __func__, feed->pid);
+
+	ret = mpq_dmx_terminate_feed(feed);
+	if (ret)
+		MPQ_DVB_ERR_PRINT("%s: mpq_dmx_terminate_feed failed(%d)\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static int mpq_sw_dmx_write_to_decoder(struct dvb_demux_feed *feed,
+		const u8 *buf, size_t len)
+{
+	/*
+	 * It is assumed that this function is called once for each
+	 * TS packet of the relevant feed.
+	 */
+	if (len > (TIMESTAMP_LEN + TS_PACKET_SIZE))
+		MPQ_DVB_DBG_PRINT(
+				"%s: warnning - len larger than one packet\n",
+				__func__);
+
+	if (dvb_dmx_is_video_feed(feed))
+		return mpq_dmx_process_video_packet(feed, buf);
+
+	if (dvb_dmx_is_pcr_feed(feed))
+		return mpq_dmx_process_pcr_packet(feed, buf);
+
+	return 0;
+}
+
+static int mpq_sw_dmx_set_source(struct dmx_demux *demux,
+		const dmx_source_t *src)
+{
+	int ret = -EINVAL;
+
+	if (demux == NULL || demux->priv == NULL || src == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		goto out;
+	}
+
+	if (*src >= DMX_SOURCE_DVR0 && *src <= DMX_SOURCE_DVR3) {
+		ret = mpq_dmx_set_source(demux, src);
+		if (ret)
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_dmx_set_source(%d) failed, ret=%d\n",
+				__func__, *src, ret);
+	} else {
+		MPQ_DVB_ERR_PRINT("%s: not a DVR source\n", __func__);
+	}
+
+out:
+	return ret;
+}
+
+static int mpq_sw_dmx_get_caps(struct dmx_demux *demux, struct dmx_caps *caps)
+{
+	struct dvb_demux *dvb_demux = demux->priv;
+
+	if (dvb_demux == NULL || caps == NULL) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA |
+		DMX_CAP_TS_INSERTION | DMX_CAP_VIDEO_INDEXING |
+		DMX_CAP_AUTO_BUFFER_FLUSH;
+	caps->recording_max_video_pids_indexed = 0;
+	caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES;
+	caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+	caps->num_pid_filters = MPQ_MAX_DMX_FILES;
+	caps->num_section_filters = dvb_demux->filternum;
+	caps->num_section_filters_per_pid = dvb_demux->filternum;
+	caps->section_filter_length = DMX_FILTER_SIZE;
+	caps->num_demod_inputs = 0;
+	caps->num_memory_inputs = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+	caps->max_bitrate = 192;
+	caps->demod_input_max_bitrate = 96;
+	caps->memory_input_max_bitrate = 96;
+	caps->num_cipher_ops = 1;
+
+	/* No STC support */
+	caps->max_stc = 0;
+
+	/* Buffer requirements */
+	caps->section.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT |
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->section.max_buffer_num = 1;
+	caps->section.max_size = 0xFFFFFFFF;
+	caps->section.size_alignment = 0;
+	caps->pes.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT |
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->pes.max_buffer_num = 1;
+	caps->pes.max_size = 0xFFFFFFFF;
+	caps->pes.size_alignment = 0;
+	caps->recording_188_tsp.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT |
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->recording_188_tsp.max_buffer_num = 1;
+	caps->recording_188_tsp.max_size = 0xFFFFFFFF;
+	caps->recording_188_tsp.size_alignment = 0;
+	caps->recording_192_tsp.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT |
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->recording_192_tsp.max_buffer_num = 1;
+	caps->recording_192_tsp.max_size = 0xFFFFFFFF;
+	caps->recording_192_tsp.size_alignment = 0;
+	caps->playback_188_tsp.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT |
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->playback_188_tsp.max_buffer_num = 1;
+	caps->playback_188_tsp.max_size = 0xFFFFFFFF;
+	caps->playback_188_tsp.size_alignment = 188;
+	caps->playback_192_tsp.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT |
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->playback_192_tsp.max_buffer_num = 1;
+	caps->playback_192_tsp.max_size = 0xFFFFFFFF;
+	caps->playback_192_tsp.size_alignment = 192;
+	caps->decoder.flags =
+		DMX_BUFFER_SECURED_IF_DECRYPTED	|
+		DMX_BUFFER_EXTERNAL_SUPPORT	|
+		DMX_BUFFER_INTERNAL_SUPPORT	|
+		DMX_BUFFER_LINEAR_GROUP_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->decoder.max_buffer_num = DMX_MAX_DECODER_BUFFER_NUM;
+	caps->decoder.max_size = 0xFFFFFFFF;
+	caps->decoder.size_alignment = SZ_4K;
+
+	return 0;
+}
+
+static int mpq_sw_dmx_init(struct dvb_adapter *mpq_adapter,
+		struct mpq_demux *mpq_demux)
+{
+	int ret;
+	struct dvb_demux *dvb_demux = &mpq_demux->demux;
+
+	/* Set the kernel-demux object capabilities */
+	mpq_demux->demux.dmx.capabilities =
+		DMX_TS_FILTERING			|
+		DMX_PES_FILTERING			|
+		DMX_SECTION_FILTERING			|
+		DMX_MEMORY_BASED_FILTERING		|
+		DMX_CRC_CHECKING			|
+		DMX_TS_DESCRAMBLING;
+
+	mpq_demux->decoder_alloc_flags = ION_FLAG_CACHED;
+
+	/* Set dvb-demux "virtual" function pointers */
+	dvb_demux->priv = (void *)mpq_demux;
+	dvb_demux->filternum = MPQ_MAX_DMX_FILES;
+	dvb_demux->feednum = MPQ_MAX_DMX_FILES;
+	dvb_demux->start_feed = mpq_sw_dmx_start_filtering;
+	dvb_demux->stop_feed = mpq_sw_dmx_stop_filtering;
+	dvb_demux->write_to_decoder = mpq_sw_dmx_write_to_decoder;
+	dvb_demux->decoder_fullness_init = mpq_dmx_decoder_fullness_init;
+	dvb_demux->decoder_fullness_wait = mpq_dmx_decoder_fullness_wait;
+	dvb_demux->decoder_fullness_abort = mpq_dmx_decoder_fullness_abort;
+	dvb_demux->decoder_buffer_status = mpq_dmx_decoder_buffer_status;
+	dvb_demux->reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer;
+	dvb_demux->set_cipher_op = mpq_dmx_set_cipher_ops;
+	dvb_demux->oob_command = mpq_dmx_oob_command;
+	dvb_demux->convert_ts = mpq_dmx_convert_tts;
+	dvb_demux->flush_decoder_buffer = NULL;
+
+	/* Initialize dvb_demux object */
+	ret = dvb_dmx_init(dvb_demux);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed, ret=%d\n",
+			__func__, ret);
+		goto init_failed;
+	}
+
+	/* Now initialize the dmx-dev object */
+	mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES;
+	mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
+	mpq_demux->dmxdev.capabilities = DMXDEV_CAP_DUPLEX;
+
+	mpq_demux->dmxdev.demux->set_source = mpq_sw_dmx_set_source;
+	mpq_demux->dmxdev.demux->get_stc = NULL;
+	mpq_demux->dmxdev.demux->get_caps = mpq_sw_dmx_get_caps;
+	mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer;
+	mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer;
+	mpq_demux->dmxdev.demux->write = mpq_dmx_write;
+	ret = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed, ret=%d\n",
+			__func__, ret);
+		goto init_failed_dmx_release;
+	}
+
+	/* Extend dvb-demux debugfs with mpq demux statistics. */
+	mpq_dmx_init_debugfs_entries(mpq_demux);
+
+	return 0;
+
+init_failed_dmx_release:
+	dvb_dmx_release(dvb_demux);
+init_failed:
+	return ret;
+}
+
+static int __init mpq_dmx_sw_plugin_init(void)
+{
+	return mpq_dmx_plugin_init(mpq_sw_dmx_init);
+}
+
+static void __exit mpq_dmx_sw_plugin_exit(void)
+{
+	mpq_dmx_plugin_exit();
+}
+
+
+module_init(mpq_dmx_sw_plugin_init);
+module_exit(mpq_dmx_sw_plugin_exit);
+
+MODULE_DESCRIPTION("Qualcomm Technologies Inc. demux software plugin");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
new file mode 100644
index 0000000..da7ecce
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -0,0 +1,1984 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/vmalloc.h>
+#include <linux/qcom_tspp.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+#define TSIF_COUNT			2
+
+/* Max number of PID filters */
+#define TSPP_MAX_PID_FILTER_NUM		128
+
+/* Max number of user-defined HW PID filters */
+#define TSPP_MAX_HW_PID_FILTER_NUM	15
+
+/* HW index  of the last entry in the TSPP HW filter table */
+#define TSPP_LAST_HW_FILTER_INDEX	15
+
+/* Number of filters required to accept all packets except NULL packets */
+#define TSPP_BLOCK_NULLS_FILTERS_NUM	13
+
+/* Max number of section filters */
+#define TSPP_MAX_SECTION_FILTER_NUM	128
+
+/* For each TSIF we use a single pipe holding the data after PID filtering */
+#define TSPP_CHANNEL			0
+
+/* the channel_id set to TSPP driver based on TSIF number and channel type */
+#define TSPP_CHANNEL_ID(tsif, ch)		((tsif << 1) + ch)
+#define TSPP_GET_TSIF_NUM(ch_id)		(ch_id >> 1)
+
+/* mask that set to care for all bits in pid filter */
+#define TSPP_PID_MASK			0x1FFF
+
+/* dvb-demux defines pid 0x2000 as full capture pid */
+#define TSPP_PASS_THROUGH_PID		0x2000
+
+/* NULL packets pid */
+#define TSPP_NULL_PACKETS_PID		0x1FFF
+
+#define TSPP_RAW_TTS_SIZE		192
+#define TSPP_RAW_SIZE			188
+
+#define MAX_BAM_DESCRIPTOR_SIZE	(32 * 1024 - 1)
+
+#define MAX_BAM_DESCRIPTOR_COUNT	(8 * 1024 - 2)
+
+#define TSPP_BUFFER_SIZE		(500 * 1024) /* 500KB */
+
+#define TSPP_DEFAULT_DESCRIPTOR_SIZE	(TSPP_RAW_TTS_SIZE)
+
+#define TSPP_BUFFER_COUNT(buffer_size)	\
+	((buffer_size) / tspp_desc_size)
+
+/* When TSPP notifies demux that new packets are received.
+ * Using max descriptor size (170 packets).
+ * Assuming 20MBit/sec stream, with 170 packets
+ * per descriptor there would be about 82 descriptors,
+ * Meaning about 82 notifications per second.
+ */
+#define TSPP_NOTIFICATION_SIZE(desc_size)		\
+	(MAX_BAM_DESCRIPTOR_SIZE / (desc_size))
+
+/* Channel timeout in msec */
+#define TSPP_CHANNEL_TIMEOUT			100
+
+enum mem_buffer_allocation_mode {
+	MPQ_DMX_TSPP_INTERNAL_ALLOC = 0,
+	MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC = 1
+};
+
+/* module parameters for load time configuration */
+static int allocation_mode = MPQ_DMX_TSPP_INTERNAL_ALLOC;
+static int tspp_out_buffer_size = TSPP_BUFFER_SIZE;
+static int tspp_desc_size = TSPP_DEFAULT_DESCRIPTOR_SIZE;
+static int tspp_notification_size =
+	TSPP_NOTIFICATION_SIZE(TSPP_DEFAULT_DESCRIPTOR_SIZE);
+static int tspp_channel_timeout = TSPP_CHANNEL_TIMEOUT;
+static int tspp_out_ion_heap = ION_QSECOM_HEAP_ID;
+
+module_param(allocation_mode, int, 0644);
+module_param(tspp_out_buffer_size, int, 0644);
+module_param(tspp_desc_size, int, 0644);
+module_param(tspp_notification_size, int, 0644);
+module_param(tspp_channel_timeout, int, 0644);
+module_param(tspp_out_ion_heap, int, 0644);
+
+/* The following structure hold singleton information
+ * required for dmx implementation on top of TSPP.
+ */
+static struct
+{
+	/* Information for each TSIF input processing */
+	struct {
+		/*
+		 * TSPP pipe holding all TS packets after PID filtering.
+		 * The following is reference count for number of feeds
+		 * allocated on that pipe.
+		 */
+		int channel_ref;
+
+		/* Counter for data notifications on the pipe */
+		atomic_t data_cnt;
+
+		/* flag to indicate control operation is in progress */
+		atomic_t control_op;
+
+		/* ION handle used for TSPP data buffer allocation */
+		struct ion_handle *ch_mem_heap_handle;
+
+		/* TSPP data buffer heap virtual base address */
+		void *ch_mem_heap_virt_base;
+
+		/* TSPP data buffer heap physical base address */
+		ion_phys_addr_t ch_mem_heap_phys_base;
+
+		/* Buffer allocation index */
+		int buff_index;
+
+		/* Number of buffers */
+		u32 buffer_count;
+
+		/*
+		 * Array holding the IDs of the TSPP buffer descriptors in the
+		 * current aggregate, in order to release these descriptors at
+		 * the end of processing.
+		 */
+		int *aggregate_ids;
+
+		/*
+		 * Holds PIDs of allocated filters along with
+		 * how many feeds are opened on the same PID. For
+		 * TSPP HW filters, holds also the filter table index.
+		 * When pid == -1, the entry is free.
+		 */
+		struct {
+			int pid;
+			int ref_count;
+			int hw_index;
+		} filters[TSPP_MAX_PID_FILTER_NUM];
+
+		/* Indicates available/allocated filter table indexes */
+		int hw_indexes[TSPP_MAX_HW_PID_FILTER_NUM];
+
+		/* Number of currently allocated PID filters */
+		u16 current_filter_count;
+
+		/*
+		 * Flag to indicate whether the user added a filter to accept
+		 * NULL packets (PID = 0x1FFF)
+		 */
+		int pass_nulls_flag;
+
+		/*
+		 * Flag to indicate whether the user added a filter to accept
+		 * all packets (PID = 0x2000)
+		 */
+		int pass_all_flag;
+
+		/*
+		 * Flag to indicate whether the filter that accepts
+		 * all packets has already been added and is
+		 * currently enabled
+		 */
+		int accept_all_filter_exists_flag;
+
+		/* Thread processing TS packets from TSPP */
+		struct task_struct *thread;
+		wait_queue_head_t wait_queue;
+
+		/* TSIF alias */
+		char name[TSIF_NAME_LENGTH];
+
+		/* Pointer to the demux connected to this TSIF */
+		struct mpq_demux *mpq_demux;
+
+		/* Mutex protecting the data-structure */
+		struct mutex mutex;
+	} tsif[TSIF_COUNT];
+
+	/* ION client used for TSPP data buffer allocation */
+	struct ion_client *ion_client;
+} mpq_dmx_tspp_info;
+
+static void *tspp_mem_allocator(int channel_id, u32 size,
+				phys_addr_t *phys_base, void *user)
+{
+	void *virt_addr = NULL;
+	int i = TSPP_GET_TSIF_NUM(channel_id);
+
+	if (mpq_dmx_tspp_info.tsif[i].buff_index ==
+		mpq_dmx_tspp_info.tsif[i].buffer_count)
+		return NULL;
+
+	virt_addr =
+		(mpq_dmx_tspp_info.tsif[i].ch_mem_heap_virt_base +
+		(mpq_dmx_tspp_info.tsif[i].buff_index * size));
+
+	*phys_base =
+		(mpq_dmx_tspp_info.tsif[i].ch_mem_heap_phys_base +
+		(mpq_dmx_tspp_info.tsif[i].buff_index * size));
+
+	mpq_dmx_tspp_info.tsif[i].buff_index++;
+
+	return virt_addr;
+}
+
+static void tspp_mem_free(int channel_id, u32 size,
+			void *virt_base, phys_addr_t phys_base, void *user)
+{
+	int i = TSPP_GET_TSIF_NUM(channel_id);
+
+	/*
+	 * actual buffer heap free is done in mpq_dmx_tspp_plugin_exit().
+	 * we update index here, so if this function is called repetitively
+	 * for all the buffers, then afterwards tspp_mem_allocator()
+	 * can be called again.
+	 * Note: it would be incorrect to call tspp_mem_allocator()
+	 * a few times, then call tspp_mem_free(), then call
+	 * tspp_mem_allocator() again.
+	 */
+	if (mpq_dmx_tspp_info.tsif[i].buff_index > 0)
+		mpq_dmx_tspp_info.tsif[i].buff_index--;
+}
+
+/**
+ * Returns a free HW filter index that can be used.
+ *
+ * @tsif: The TSIF to allocate filter from
+ *
+ * Return  HW filter index or -ENOMEM if no filters available
+ */
+static int mpq_tspp_allocate_hw_filter_index(int tsif)
+{
+	int i;
+
+	for (i = 0; i < TSPP_MAX_HW_PID_FILTER_NUM; i++) {
+		if (mpq_dmx_tspp_info.tsif[tsif].hw_indexes[i] == 0) {
+			mpq_dmx_tspp_info.tsif[tsif].hw_indexes[i] = 1;
+			return i;
+		}
+	}
+
+	return -ENOMEM;
+}
+
+/**
+ * Releases a HW filter index for future reuse.
+ *
+ * @tsif: The TSIF from which the filter should be released
+ * @hw_index: The HW index to release
+ *
+ */
+static inline void mpq_tspp_release_hw_filter_index(int tsif, int hw_index)
+{
+	if ((hw_index >= 0) && (hw_index < TSPP_MAX_HW_PID_FILTER_NUM))
+		mpq_dmx_tspp_info.tsif[tsif].hw_indexes[hw_index] = 0;
+}
+
+
+/**
+ * Returns a free filter slot that can be used.
+ *
+ * @tsif: The TSIF to allocate filter from
+ *
+ * Return  filter index or -ENOMEM if no filters available
+ */
+static int mpq_tspp_get_free_filter_slot(int tsif)
+{
+	int slot;
+
+	for (slot = 0; slot < TSPP_MAX_PID_FILTER_NUM; slot++)
+		if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == -1)
+			return slot;
+
+	return -ENOMEM;
+}
+
+/**
+ * Returns filter index of specific pid.
+ *
+ * @tsif: The TSIF to which the pid is allocated
+ * @pid: The pid to search for
+ *
+ * Return  filter index or -1 if no filter available
+ */
+static int mpq_tspp_get_filter_slot(int tsif, int pid)
+{
+	int slot;
+
+	for (slot = 0; slot < TSPP_MAX_PID_FILTER_NUM; slot++)
+		if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == pid)
+			return slot;
+
+	return -EINVAL;
+}
+
+/**
+ * mpq_dmx_tspp_swfilter_desc - helper function
+ *
+ * Takes a tspp buffer descriptor and send it to the SW filter for demuxing,
+ * one TS packet at a time.
+ *
+ * @mpq_demux - mpq demux object
+ * @tspp_data_desc - tspp buffer descriptor
+ */
+static inline void mpq_dmx_tspp_swfilter_desc(struct mpq_demux *mpq_demux,
+	const struct tspp_data_descriptor *tspp_data_desc)
+{
+	u32 notif_size;
+	int i;
+
+	notif_size = tspp_data_desc->size / TSPP_RAW_TTS_SIZE;
+	for (i = 0; i < notif_size; i++)
+		dvb_dmx_swfilter_packet(&mpq_demux->demux,
+			((u8 *)tspp_data_desc->virt_base) +
+			i * TSPP_RAW_TTS_SIZE,
+			((u8 *)tspp_data_desc->virt_base) +
+			i * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE);
+}
+
+/**
+ * Demux TS packets from TSPP by secure-demux.
+ * The function assumes the buffer is physically contiguous
+ * and that TSPP descriptors are continuous in memory.
+ *
+ * @tsif: The TSIF interface to process its packets
+ * @channel_id: the TSPP output pipe with the TS packets
+ */
+static void mpq_dmx_tspp_aggregated_process(int tsif, int channel_id)
+{
+	const struct tspp_data_descriptor *tspp_data_desc;
+	struct mpq_demux *mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+	struct sdmx_buff_descr input;
+	size_t aggregate_len = 0;
+	size_t aggregate_count = 0;
+	phys_addr_t buff_start_addr_phys;
+	phys_addr_t buff_current_addr_phys = 0;
+	u32 notif_size;
+	int i;
+
+	while ((tspp_data_desc = tspp_get_buffer(0, channel_id)) != NULL) {
+		if (aggregate_count == 0)
+			buff_current_addr_phys = tspp_data_desc->phys_base;
+		notif_size = tspp_data_desc->size / TSPP_RAW_TTS_SIZE;
+		mpq_dmx_tspp_info.tsif[tsif].aggregate_ids[aggregate_count] =
+			tspp_data_desc->id;
+		aggregate_len += tspp_data_desc->size;
+		aggregate_count++;
+		mpq_demux->hw_notification_size += notif_size;
+
+		/* Let SW filter process only if it might be relevant */
+		if (mpq_demux->num_active_feeds > mpq_demux->num_secure_feeds)
+			mpq_dmx_tspp_swfilter_desc(mpq_demux, tspp_data_desc);
+
+	}
+
+	if (!aggregate_count)
+		return;
+
+	buff_start_addr_phys =
+		mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base;
+
+	input.base_addr = (u64)buff_start_addr_phys;
+	input.size = mpq_dmx_tspp_info.tsif[tsif].buffer_count * tspp_desc_size;
+
+	if (mpq_sdmx_is_loaded() && mpq_demux->sdmx_filter_count) {
+		MPQ_DVB_DBG_PRINT(
+			"%s: SDMX Processing %zu descriptors: %zu bytes at start address 0x%llx, read offset %d\n",
+			__func__, aggregate_count, aggregate_len,
+			input.base_addr,
+			(int)(buff_current_addr_phys - buff_start_addr_phys));
+
+		mpq_sdmx_process(mpq_demux, &input, aggregate_len,
+			buff_current_addr_phys - buff_start_addr_phys,
+			TSPP_RAW_TTS_SIZE);
+	}
+
+	for (i = 0; i < aggregate_count; i++)
+		tspp_release_buffer(0, channel_id,
+			mpq_dmx_tspp_info.tsif[tsif].aggregate_ids[i]);
+}
+
+
+/**
+ * Demux thread function handling data from specific TSIF.
+ *
+ * @arg: TSIF number
+ */
+static int mpq_dmx_tspp_thread(void *arg)
+{
+	int tsif = (int)(uintptr_t)arg;
+	struct mpq_demux *mpq_demux;
+	const struct tspp_data_descriptor *tspp_data_desc;
+	atomic_t *data_cnt;
+	u32 notif_size;
+	int channel_id;
+	int ref_count;
+	int ret;
+
+	do {
+		ret = wait_event_interruptible(
+			mpq_dmx_tspp_info.tsif[tsif].wait_queue,
+			(atomic_read(&mpq_dmx_tspp_info.tsif[tsif].data_cnt) &&
+			!atomic_read(&mpq_dmx_tspp_info.tsif[tsif].control_op))
+			|| kthread_should_stop());
+
+		if ((ret < 0) || kthread_should_stop()) {
+			MPQ_DVB_ERR_PRINT("%s: exit\n", __func__);
+			break;
+		}
+
+		/* Lock against the TSPP filters data-structure */
+		if (mutex_lock_interruptible(
+			&mpq_dmx_tspp_info.tsif[tsif].mutex))
+			return -ERESTARTSYS;
+
+		channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL);
+
+		ref_count = mpq_dmx_tspp_info.tsif[tsif].channel_ref;
+		data_cnt = &mpq_dmx_tspp_info.tsif[tsif].data_cnt;
+
+		/* Make sure channel is still active */
+		if (ref_count == 0) {
+			mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+			continue;
+		}
+
+		atomic_dec(data_cnt);
+
+		mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+		mpq_demux->hw_notification_size = 0;
+
+		if (allocation_mode != MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC &&
+			mpq_sdmx_is_loaded())
+			pr_err_once(
+				"%s: TSPP Allocation mode does not support secure demux.\n",
+				__func__);
+
+		if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC &&
+			mpq_sdmx_is_loaded()) {
+			mpq_dmx_tspp_aggregated_process(tsif, channel_id);
+		} else {
+			/*
+			 * Go through all filled descriptors
+			 * and perform demuxing on them
+			 */
+			do {
+				if (atomic_read(&mpq_dmx_tspp_info.tsif[tsif].
+						control_op)) {
+					/* restore for next iteration */
+					atomic_inc(data_cnt);
+					break;
+				}
+				tspp_data_desc = tspp_get_buffer(0, channel_id);
+				if (!tspp_data_desc)
+					break;
+
+				notif_size = tspp_data_desc->size /
+					TSPP_RAW_TTS_SIZE;
+				mpq_demux->hw_notification_size += notif_size;
+
+				mpq_dmx_tspp_swfilter_desc(mpq_demux,
+					tspp_data_desc);
+				/*
+				 * Notify TSPP that the buffer
+				 * is no longer needed
+				 */
+				tspp_release_buffer(0, channel_id,
+					tspp_data_desc->id);
+			} while (1);
+		}
+
+		if (mpq_demux->hw_notification_size &&
+			(mpq_demux->hw_notification_size <
+			mpq_demux->hw_notification_min_size))
+			mpq_demux->hw_notification_min_size =
+				mpq_demux->hw_notification_size;
+
+		mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+	} while (1);
+
+	return 0;
+}
+
+/**
+ * Callback function from TSPP when new data is ready.
+ *
+ * @channel_id: Channel with new TS packets
+ * @user: user-data holding TSIF number
+ */
+static void mpq_tspp_callback(int channel_id, void *user)
+{
+	int tsif = (int)(uintptr_t)user;
+	struct mpq_demux *mpq_demux;
+
+	/* Save statistics on TSPP notifications */
+	mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+	mpq_dmx_update_hw_statistics(mpq_demux);
+
+	atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].data_cnt);
+	wake_up(&mpq_dmx_tspp_info.tsif[tsif].wait_queue);
+}
+
+/**
+ * Free memory of channel output of specific TSIF.
+ *
+ * @tsif: The TSIF id to which memory should be freed.
+ */
+static void mpq_dmx_channel_mem_free(int tsif)
+{
+	MPQ_DVB_DBG_PRINT("%s(%d)\n", __func__, tsif);
+
+	mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base = 0;
+
+	if (!IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle)) {
+		if (!IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[tsif].
+				ch_mem_heap_virt_base))
+			ion_unmap_kernel(mpq_dmx_tspp_info.ion_client,
+				mpq_dmx_tspp_info.tsif[tsif].
+					ch_mem_heap_handle);
+
+		ion_free(mpq_dmx_tspp_info.ion_client,
+			mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle);
+	}
+
+	mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base = NULL;
+	mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle = NULL;
+}
+
+/**
+ * Allocate memory for channel output of specific TSIF.
+ *
+ * @tsif: The TSIF id to which memory should be allocated.
+ *
+ * Return  error status
+ */
+static int mpq_dmx_channel_mem_alloc(int tsif)
+{
+	int result;
+	size_t len;
+
+	MPQ_DVB_DBG_PRINT("%s(%d)\n", __func__, tsif);
+
+	mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle =
+		ion_alloc(mpq_dmx_tspp_info.ion_client,
+		 (mpq_dmx_tspp_info.tsif[tsif].buffer_count * tspp_desc_size),
+		 SZ_4K,
+		 ION_HEAP(tspp_out_ion_heap),
+		 0); /* non-cached */
+
+	if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle)) {
+		MPQ_DVB_ERR_PRINT("%s: ion_alloc() failed\n", __func__);
+		mpq_dmx_channel_mem_free(tsif);
+		return -ENOMEM;
+	}
+
+	/* save virtual base address of heap */
+	mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base =
+		ion_map_kernel(mpq_dmx_tspp_info.ion_client,
+			mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle);
+	if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[tsif].
+				ch_mem_heap_virt_base)) {
+		MPQ_DVB_ERR_PRINT("%s: ion_map_kernel() failed\n", __func__);
+		mpq_dmx_channel_mem_free(tsif);
+		return -ENOMEM;
+	}
+
+	/* save physical base address of heap */
+	result = ion_phys(mpq_dmx_tspp_info.ion_client,
+		mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle,
+		&(mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base), &len);
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT("%s: ion_phys() failed\n", __func__);
+		mpq_dmx_channel_mem_free(tsif);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ * Add a filter to accept all packets as the last entry
+ * of the TSPP HW filter table.
+ *
+ * @channel_id: Channel ID number.
+ * @source: TSPP source.
+ *
+ * Return  error status
+ */
+static int mpq_tspp_add_accept_all_filter(int channel_id,
+				enum tspp_source source)
+{
+	struct tspp_filter tspp_filter;
+	int tsif = TSPP_GET_TSIF_NUM(channel_id);
+	int ret;
+
+	MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n",
+		__func__, channel_id, source);
+
+	if (mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag) {
+		MPQ_DVB_DBG_PRINT("%s: accept all filter already exists\n",
+				__func__);
+		return 0;
+	}
+
+	/* This filter will be the last entry in the table */
+	tspp_filter.priority = TSPP_LAST_HW_FILTER_INDEX;
+	/* Pass all pids - set mask to 0 */
+	tspp_filter.pid = 0;
+	tspp_filter.mask = 0;
+	/*
+	 * Include TTS in RAW packets, if you change this to
+	 * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE
+	 * accordingly.
+	 */
+	tspp_filter.mode = TSPP_MODE_RAW;
+	tspp_filter.source = source;
+	tspp_filter.decrypt = 0;
+
+	ret = tspp_add_filter(0, channel_id, &tspp_filter);
+	if (!ret) {
+		mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag = 1;
+		MPQ_DVB_DBG_PRINT(
+				"%s: accept all filter added successfully\n",
+				__func__);
+	}
+
+	return ret;
+}
+
+/**
+ * Remove the filter that accepts all packets from the last entry
+ * of the TSPP HW filter table.
+ *
+ * @channel_id: Channel ID number.
+ * @source: TSPP source.
+ *
+ * Return  error status
+ */
+static int mpq_tspp_remove_accept_all_filter(int channel_id,
+				enum tspp_source source)
+{
+	struct tspp_filter tspp_filter;
+	int tsif = TSPP_GET_TSIF_NUM(channel_id);
+	int ret;
+
+	MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n",
+		__func__, channel_id, source);
+
+	if (mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag == 0) {
+		MPQ_DVB_DBG_PRINT("%s: accept all filter doesn't exist\n",
+				__func__);
+		return 0;
+	}
+
+	tspp_filter.priority = TSPP_LAST_HW_FILTER_INDEX;
+
+	ret = tspp_remove_filter(0, channel_id, &tspp_filter);
+	if (!ret) {
+		mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag = 0;
+		MPQ_DVB_DBG_PRINT(
+			"%s: accept all filter removed successfully\n",
+			__func__);
+	}
+
+	return ret;
+}
+
+/**
+ * Add filters designed to accept all packets except NULL packets, i.e.
+ * packets with PID = 0x1FFF.
+ * This function is called after user-defined filters were removed,
+ * so it assumes that the first 13 HW filters in the TSPP filter
+ * table are free for use.
+ *
+ * @channel_id: Channel ID number.
+ * @source: TSPP source.
+ *
+ * Return  0 on success, -1 otherwise
+ */
+static int mpq_tspp_add_null_blocking_filters(int channel_id,
+				enum tspp_source source)
+{
+	struct tspp_filter tspp_filter;
+	int ret = 0;
+	int i, j;
+	u16 full_pid_mask = 0x1FFF;
+	u8 mask_shift;
+	u8 pid_shift;
+	int tsif = TSPP_GET_TSIF_NUM(channel_id);
+
+	MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n",
+		__func__, channel_id, source);
+
+	/*
+	 * Add a total of 13 filters that will accept packets with
+	 * every PID other than 0x1FFF, which is the NULL PID.
+	 *
+	 * Filter 0: accept all PIDs with bit 12 clear, i.e.
+	 * PID = 0x0000 .. 0x0FFF (4096 PIDs in total):
+	 * Mask = 0x1000, PID = 0x0000.
+	 *
+	 * Filter 12: Accept PID 0x1FFE:
+	 * Mask = 0x1FFF, PID = 0x1FFE.
+	 *
+	 * In general: For N = 0 .. 12,
+	 * Filter <N>: accept all PIDs with <N> MSBits set and bit <N-1> clear.
+	 * Filter <N> Mask = N+1 MSBits set, others clear.
+	 * Filter <N> PID = <N> MSBits set, others clear.
+	 */
+
+	/*
+	 * Include TTS in RAW packets, if you change this to
+	 * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE
+	 * accordingly.
+	 */
+	tspp_filter.mode = TSPP_MODE_RAW;
+	tspp_filter.source = source;
+	tspp_filter.decrypt = 0;
+
+	for (i = 0; i < TSPP_BLOCK_NULLS_FILTERS_NUM; i++) {
+		tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif);
+		if (tspp_filter.priority != i) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: got unexpected HW index %d, expected %d\n",
+				__func__, tspp_filter.priority, i);
+			ret = -1;
+			break;
+		}
+		mask_shift = (TSPP_BLOCK_NULLS_FILTERS_NUM - 1 - i);
+		pid_shift = (TSPP_BLOCK_NULLS_FILTERS_NUM - i);
+		tspp_filter.mask =
+			((full_pid_mask >> mask_shift) << mask_shift);
+		tspp_filter.pid = ((full_pid_mask >> pid_shift) << pid_shift);
+
+		if (tspp_add_filter(0, channel_id, &tspp_filter)) {
+			ret = -1;
+			break;
+		}
+	}
+
+	if (ret) {
+		/* cleanup on failure */
+		for (j = 0; j < i; j++) {
+			tspp_filter.priority = j;
+			mpq_tspp_release_hw_filter_index(tsif, j);
+			tspp_remove_filter(0, channel_id, &tspp_filter);
+		}
+	} else {
+		MPQ_DVB_DBG_PRINT(
+			"%s: NULL blocking filters added successfully\n",
+			__func__);
+	}
+
+	return ret;
+}
+
+/**
+ * Remove filters designed to accept all packets except NULL packets, i.e.
+ * packets with PID = 0x1FFF.
+ *
+ * @channel_id: Channel ID number.
+ *
+ * @source: TSPP source.
+ *
+ * Return  0 on success, -1 otherwise
+ */
+static int mpq_tspp_remove_null_blocking_filters(int channel_id,
+				enum tspp_source source)
+{
+	struct tspp_filter tspp_filter;
+	int tsif = TSPP_GET_TSIF_NUM(channel_id);
+	int ret = 0;
+	int i;
+
+	MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n",
+		__func__, channel_id, source);
+
+	for (i = 0; i < TSPP_BLOCK_NULLS_FILTERS_NUM; i++) {
+		tspp_filter.priority = i;
+		if (tspp_remove_filter(0, channel_id, &tspp_filter)) {
+			MPQ_DVB_ERR_PRINT("%s: failed to remove filter %d\n",
+				__func__, i);
+			ret = -1;
+		}
+
+		mpq_tspp_release_hw_filter_index(tsif, i);
+	}
+
+	return ret;
+}
+
+/**
+ * Add all current user-defined filters (up to 15) as HW filters
+ *
+ * @channel_id: Channel ID number.
+ *
+ * @source: TSPP source.
+ *
+ * Return  0 on success, -1 otherwise
+ */
+static int mpq_tspp_add_all_user_filters(int channel_id,
+				enum tspp_source source)
+{
+	struct tspp_filter tspp_filter;
+	int tsif = TSPP_GET_TSIF_NUM(channel_id);
+	int slot;
+	u16 added_count = 0;
+	u16 total_filters_count = 0;
+
+	MPQ_DVB_DBG_PRINT("%s: executed\n", __func__);
+
+	/*
+	 * Include TTS in RAW packets, if you change this to
+	 * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE
+	 * accordingly.
+	 */
+	tspp_filter.mode = TSPP_MODE_RAW;
+	tspp_filter.source = source;
+	tspp_filter.decrypt = 0;
+
+	for (slot = 0; slot < TSPP_MAX_PID_FILTER_NUM; slot++) {
+		if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == -1)
+			continue;
+
+		/*
+		 * count total number of user filters to verify that it is
+		 * exactly TSPP_MAX_HW_PID_FILTER_NUM as expected.
+		 */
+		total_filters_count++;
+
+		if (added_count > TSPP_MAX_HW_PID_FILTER_NUM)
+			continue;
+
+		tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif);
+
+		if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid ==
+				TSPP_PASS_THROUGH_PID) {
+			/* pass all pids */
+			tspp_filter.pid = 0;
+			tspp_filter.mask = 0;
+		} else {
+			tspp_filter.pid =
+				mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid;
+			tspp_filter.mask = TSPP_PID_MASK;
+		}
+
+		MPQ_DVB_DBG_PRINT(
+			"%s: adding HW filter, PID = %d, mask = 0x%X, index = %d\n",
+				__func__, tspp_filter.pid, tspp_filter.mask,
+				tspp_filter.priority);
+
+		if (!tspp_add_filter(0, channel_id, &tspp_filter)) {
+			mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index =
+				tspp_filter.priority;
+			added_count++;
+		} else {
+			MPQ_DVB_ERR_PRINT("%s: tspp_add_filter failed\n",
+						__func__);
+		}
+	}
+
+	if ((added_count != TSPP_MAX_HW_PID_FILTER_NUM) ||
+		(added_count != total_filters_count))
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * Remove all user-defined HW filters
+ *
+ * @channel_id: Channel ID number.
+ *
+ * @source: TSPP source.
+ *
+ * Return  0 on success, -1 otherwise
+ */
+static int mpq_tspp_remove_all_user_filters(int channel_id,
+				enum tspp_source source)
+{
+	struct tspp_filter tspp_filter;
+	int ret = 0;
+	int tsif = TSPP_GET_TSIF_NUM(channel_id);
+	int i;
+
+	MPQ_DVB_DBG_PRINT("%s: executed\n", __func__);
+
+	for (i = 0; i < TSPP_MAX_HW_PID_FILTER_NUM; i++) {
+		tspp_filter.priority = i;
+		MPQ_DVB_DBG_PRINT("%s: Removing HW filter %d\n",
+			__func__, tspp_filter.priority);
+		if (tspp_remove_filter(0, channel_id, &tspp_filter))
+			ret = -1;
+
+		mpq_tspp_release_hw_filter_index(tsif, i);
+		mpq_dmx_tspp_info.tsif[tsif].filters[i].hw_index = -1;
+	}
+
+	return ret;
+}
+
+/**
+ * Configure TSPP channel to filter the PID of new feed.
+ *
+ * @feed: The feed to configure the channel with
+ *
+ * Return  error status
+ *
+ * The function checks if the new PID can be added to an already
+ * allocated channel, if not, a new channel is allocated and configured.
+ */
+static int mpq_tspp_dmx_add_channel(struct dvb_demux_feed *feed)
+{
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+	struct tspp_select_source tspp_source;
+	struct tspp_filter tspp_filter;
+	int tsif;
+	int tsif_mode = mpq_dmx_get_param_tsif_mode();
+	int ret = 0;
+	int slot;
+	int channel_id;
+	int *channel_ref_count;
+	u32 buffer_size;
+	int restore_user_filters = 0;
+	int remove_accept_all_filter = 0;
+	int remove_null_blocking_filters = 0;
+	size_t agg_size;
+
+	tspp_source.clk_inverse = mpq_dmx_get_param_clock_inv();
+	tspp_source.data_inverse = 0;
+	tspp_source.sync_inverse = 0;
+	tspp_source.enable_inverse = 0;
+
+	MPQ_DVB_DBG_PRINT("%s: executed, PID = %d\n", __func__, feed->pid);
+
+	switch (tsif_mode) {
+	case 1:
+		tspp_source.mode = TSPP_TSIF_MODE_1;
+		break;
+	case 2:
+		tspp_source.mode = TSPP_TSIF_MODE_2;
+		break;
+	default:
+		tspp_source.mode = TSPP_TSIF_MODE_LOOPBACK;
+		break;
+	}
+
+	/* determine the TSIF we are reading from */
+	if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+		tsif = 0;
+		tspp_source.source = TSPP_SOURCE_TSIF0;
+	} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+		tsif = 1;
+		tspp_source.source = TSPP_SOURCE_TSIF1;
+	} else {
+		/* invalid source */
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid input source (%d)\n",
+			__func__,
+			mpq_demux->source);
+
+		return -EINVAL;
+	}
+
+	atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].control_op);
+	if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex)) {
+		atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op);
+		return -ERESTARTSYS;
+	}
+
+	/*
+	 * It is possible that this PID was already requested before.
+	 * Can happen if we play and record same PES or PCR
+	 * piggypacked on video packet.
+	 */
+	slot = mpq_tspp_get_filter_slot(tsif, feed->pid);
+	if (slot >= 0) {
+		/* PID already configured */
+		mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++;
+		goto out;
+	}
+
+
+	channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL);
+	channel_ref_count = &mpq_dmx_tspp_info.tsif[tsif].channel_ref;
+
+	/*
+	 * Recalculate 'tspp_notification_size' and buffer count in case
+	 * 'tspp_desc_size' or 'tspp_out_buffer_size' parameters have changed.
+	 */
+	buffer_size = tspp_desc_size;
+	tspp_notification_size = TSPP_NOTIFICATION_SIZE(tspp_desc_size);
+	mpq_dmx_tspp_info.tsif[tsif].buffer_count =
+			TSPP_BUFFER_COUNT(tspp_out_buffer_size);
+	if (mpq_dmx_tspp_info.tsif[tsif].buffer_count >
+			MAX_BAM_DESCRIPTOR_COUNT)
+		mpq_dmx_tspp_info.tsif[tsif].buffer_count =
+			MAX_BAM_DESCRIPTOR_COUNT;
+
+	/* check if required TSPP pipe is already allocated or not */
+	if (*channel_ref_count == 0) {
+		if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
+			agg_size = mpq_dmx_tspp_info.tsif[tsif].buffer_count *
+				sizeof(int);
+			mpq_dmx_tspp_info.tsif[tsif].aggregate_ids =
+					vzalloc(agg_size);
+			if (!mpq_dmx_tspp_info.tsif[tsif].aggregate_ids) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: Failed to allocate memory for buffer descriptors aggregation\n",
+					__func__);
+				ret = -ENOMEM;
+				goto out;
+			}
+
+			ret = mpq_dmx_channel_mem_alloc(tsif);
+			if (ret < 0) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: mpq_dmx_channel_mem_alloc(%d) failed (%d)\n",
+					__func__,
+					channel_id,
+					ret);
+
+				goto add_channel_failed;
+			}
+		}
+
+		ret = tspp_open_channel(0, channel_id);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tspp_open_channel(%d) failed (%d)\n",
+				__func__,
+				channel_id,
+				ret);
+
+			goto add_channel_failed;
+		}
+
+		/* set TSPP source */
+		ret = tspp_open_stream(0, channel_id, &tspp_source);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tspp_select_source(%d,%d) failed (%d)\n",
+				__func__,
+				channel_id,
+				tspp_source.source,
+				ret);
+
+			goto add_channel_close_ch;
+		}
+
+		/* register notification on TS packets */
+		tspp_register_notification(0,
+					   channel_id,
+					   mpq_tspp_callback,
+					   (void *)(uintptr_t)tsif,
+					   tspp_channel_timeout);
+
+		/*
+		 * Register allocator and provide allocation function
+		 * that allocates from contiguous memory so that we can have
+		 * big notification size, smallest descriptor, and still provide
+		 * TZ with single big buffer based on notification size.
+		 */
+		if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
+			ret = tspp_allocate_buffers(0, channel_id,
+				   mpq_dmx_tspp_info.tsif[tsif].buffer_count,
+				   buffer_size, tspp_notification_size,
+				   tspp_mem_allocator, tspp_mem_free, NULL);
+		} else {
+			ret = tspp_allocate_buffers(0, channel_id,
+				   mpq_dmx_tspp_info.tsif[tsif].buffer_count,
+				   buffer_size, tspp_notification_size,
+				   NULL, NULL, NULL);
+		}
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tspp_allocate_buffers(%d) failed (%d)\n",
+				__func__,
+				channel_id,
+				ret);
+
+			goto add_channel_unregister_notif;
+		}
+
+		mpq_dmx_tspp_info.tsif[tsif].mpq_demux = mpq_demux;
+	}
+
+	/* add new PID to the existing pipe */
+	slot = mpq_tspp_get_free_filter_slot(tsif);
+	if (slot < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_tspp_get_free_filter_slot(%d) failed\n",
+			__func__, tsif);
+
+		goto add_channel_unregister_notif;
+	}
+
+	if (feed->pid == TSPP_PASS_THROUGH_PID)
+		mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 1;
+	else if (feed->pid == TSPP_NULL_PACKETS_PID)
+		mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 1;
+
+	mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = feed->pid;
+	mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++;
+
+	tspp_filter.priority = -1;
+
+	if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count <
+					TSPP_MAX_HW_PID_FILTER_NUM) {
+		/* HW filtering mode */
+		tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif);
+		if (tspp_filter.priority < 0)
+			goto add_channel_free_filter_slot;
+
+		if (feed->pid == TSPP_PASS_THROUGH_PID) {
+			/* pass all pids */
+			tspp_filter.pid = 0;
+			tspp_filter.mask = 0;
+		} else {
+			tspp_filter.pid = feed->pid;
+			tspp_filter.mask = TSPP_PID_MASK;
+		}
+
+		/*
+		 * Include TTS in RAW packets, if you change this to
+		 * TSPP_MODE_RAW_NO_SUFFIX you must also change
+		 * TSPP_RAW_TTS_SIZE accordingly.
+		 */
+		tspp_filter.mode = TSPP_MODE_RAW;
+		tspp_filter.source = tspp_source.source;
+		tspp_filter.decrypt = 0;
+		ret = tspp_add_filter(0, channel_id, &tspp_filter);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tspp_add_filter(%d) failed (%d)\n",
+				__func__,
+				channel_id,
+				ret);
+
+			goto add_channel_free_filter_slot;
+		}
+		mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index =
+			tspp_filter.priority;
+
+		MPQ_DVB_DBG_PRINT(
+			"%s: HW filtering mode: added TSPP HW filter, PID = %d, mask = 0x%X, index = %d\n",
+			__func__, tspp_filter.pid, tspp_filter.mask,
+			tspp_filter.priority);
+	} else if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count ==
+					TSPP_MAX_HW_PID_FILTER_NUM) {
+		/* Crossing the threshold - from HW to SW filtering mode */
+
+		/* Add a temporary filter to accept all packets */
+		ret = mpq_tspp_add_accept_all_filter(channel_id,
+					tspp_source.source);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n",
+				__func__, channel_id, tspp_source.source);
+
+			goto add_channel_free_filter_slot;
+		}
+
+		/* Remove all existing user filters */
+		ret = mpq_tspp_remove_all_user_filters(channel_id,
+					tspp_source.source);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_tspp_remove_all_user_filters(%d, %d) failed\n",
+				__func__, channel_id, tspp_source.source);
+
+			restore_user_filters = 1;
+			remove_accept_all_filter = 1;
+
+			goto add_channel_free_filter_slot;
+		}
+
+		/* Add HW filters to block NULL packets */
+		ret = mpq_tspp_add_null_blocking_filters(channel_id,
+					tspp_source.source);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_tspp_add_null_blocking_filters(%d, %d) failed\n",
+				__func__, channel_id, tspp_source.source);
+
+			restore_user_filters = 1;
+			remove_accept_all_filter = 1;
+
+			goto add_channel_free_filter_slot;
+		}
+
+		/* Remove filters that accepts all packets, if necessary */
+		if ((mpq_dmx_tspp_info.tsif[tsif].pass_all_flag == 0) &&
+			(mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag == 0)) {
+
+			ret = mpq_tspp_remove_accept_all_filter(channel_id,
+						tspp_source.source);
+			if (ret < 0) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n",
+					__func__, channel_id,
+					tspp_source.source);
+
+				remove_null_blocking_filters = 1;
+				restore_user_filters = 1;
+				remove_accept_all_filter = 1;
+
+				goto add_channel_free_filter_slot;
+			}
+		}
+	} else {
+		/* Already working in SW filtering mode */
+		if (mpq_dmx_tspp_info.tsif[tsif].pass_all_flag ||
+			mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag) {
+
+			ret = mpq_tspp_add_accept_all_filter(channel_id,
+						tspp_source.source);
+			if (ret < 0) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n",
+					__func__, channel_id,
+					tspp_source.source);
+
+				goto add_channel_free_filter_slot;
+			}
+		}
+	}
+
+	(*channel_ref_count)++;
+	mpq_dmx_tspp_info.tsif[tsif].current_filter_count++;
+
+	MPQ_DVB_DBG_PRINT("%s: success, current_filter_count = %d\n",
+		__func__, mpq_dmx_tspp_info.tsif[tsif].current_filter_count);
+
+	goto out;
+
+add_channel_free_filter_slot:
+	/* restore internal database state */
+	mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = -1;
+	mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count--;
+
+	/* release HW index if we allocated one */
+	if (tspp_filter.priority >= 0) {
+		mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = -1;
+		mpq_tspp_release_hw_filter_index(tsif, tspp_filter.priority);
+	}
+
+	/* restore HW filter table state if necessary */
+	if (remove_null_blocking_filters)
+		mpq_tspp_remove_null_blocking_filters(channel_id,
+						tspp_source.source);
+
+	if (restore_user_filters)
+		mpq_tspp_add_all_user_filters(channel_id, tspp_source.source);
+
+	if (remove_accept_all_filter)
+		mpq_tspp_remove_accept_all_filter(channel_id,
+						tspp_source.source);
+
+	/* restore flags. we can only get here if we changed the flags. */
+	if (feed->pid == TSPP_PASS_THROUGH_PID)
+		mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 0;
+	else if (feed->pid == TSPP_NULL_PACKETS_PID)
+		mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 0;
+
+add_channel_unregister_notif:
+	if (*channel_ref_count == 0) {
+		tspp_unregister_notification(0, channel_id);
+		tspp_close_stream(0, channel_id);
+	}
+add_channel_close_ch:
+	if (*channel_ref_count == 0)
+		tspp_close_channel(0, channel_id);
+add_channel_failed:
+	if (*channel_ref_count == 0)
+		if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
+			vfree(mpq_dmx_tspp_info.tsif[tsif].aggregate_ids);
+			mpq_dmx_tspp_info.tsif[tsif].aggregate_ids = NULL;
+			mpq_dmx_channel_mem_free(tsif);
+		}
+
+out:
+	mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+	atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op);
+	return ret;
+}
+
+/**
+ * Removes filter from TSPP.
+ *
+ * @feed: The feed to remove
+ *
+ * Return  error status
+ *
+ * The function checks if this is the only PID allocated within
+ * the channel, if so, the channel is closed as well.
+ */
+static int mpq_tspp_dmx_remove_channel(struct dvb_demux_feed *feed)
+{
+	int tsif;
+	int ret = 0;
+	int channel_id;
+	int slot;
+	atomic_t *data_cnt;
+	int *channel_ref_count;
+	enum tspp_source tspp_source;
+	struct tspp_filter tspp_filter;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+	int restore_null_blocking_filters = 0;
+	int remove_accept_all_filter = 0;
+	int remove_user_filters = 0;
+	int accept_all_filter_existed = 0;
+
+	MPQ_DVB_DBG_PRINT("%s: executed, PID = %d\n", __func__, feed->pid);
+
+	/* determine the TSIF we are reading from */
+	if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+		tsif = 0;
+		tspp_source = TSPP_SOURCE_TSIF0;
+	} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+		tsif = 1;
+		tspp_source = TSPP_SOURCE_TSIF1;
+	} else {
+		/* invalid source */
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid input source (%d)\n",
+			__func__,
+			mpq_demux->source);
+
+		return -EINVAL;
+	}
+
+	atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].control_op);
+	if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex)) {
+		atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op);
+		return -ERESTARTSYS;
+	}
+
+	channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL);
+	channel_ref_count = &mpq_dmx_tspp_info.tsif[tsif].channel_ref;
+	data_cnt = &mpq_dmx_tspp_info.tsif[tsif].data_cnt;
+
+	/* check if required TSPP pipe is already allocated or not */
+	if (*channel_ref_count == 0) {
+		/* invalid feed provided as the channel is not allocated */
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid feed (%d)\n",
+			__func__,
+			channel_id);
+
+		ret = -EINVAL;
+		goto out;
+	}
+
+	slot = mpq_tspp_get_filter_slot(tsif, feed->pid);
+
+	if (slot < 0) {
+		/* invalid feed provided as it has no filter allocated */
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_tspp_get_filter_slot failed (%d,%d)\n",
+			__func__,
+			feed->pid,
+			tsif);
+
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* since filter was found, ref_count > 0 so it's ok to decrement it */
+	mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count--;
+
+	if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count) {
+		/*
+		 * there are still references to this pid, do not
+		 * remove the filter yet
+		 */
+		goto out;
+	}
+
+	if (feed->pid == TSPP_PASS_THROUGH_PID)
+		mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 0;
+	else if (feed->pid == TSPP_NULL_PACKETS_PID)
+		mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 0;
+
+	mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = -1;
+
+	if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count <=
+					TSPP_MAX_HW_PID_FILTER_NUM) {
+		/* staying in HW filtering mode */
+		tspp_filter.priority =
+			mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index;
+		ret = tspp_remove_filter(0, channel_id, &tspp_filter);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tspp_remove_filter failed (%d,%d)\n",
+				__func__,
+				channel_id,
+				tspp_filter.priority);
+
+			goto remove_channel_failed_restore_count;
+		}
+		mpq_tspp_release_hw_filter_index(tsif, tspp_filter.priority);
+		mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = -1;
+
+		MPQ_DVB_DBG_PRINT(
+			"%s: HW filtering mode: Removed TSPP HW filter, PID = %d, index = %d\n",
+			__func__, feed->pid, tspp_filter.priority);
+	} else  if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count ==
+					(TSPP_MAX_HW_PID_FILTER_NUM + 1)) {
+		/* Crossing the threshold - from SW to HW filtering mode */
+
+		accept_all_filter_existed =
+			mpq_dmx_tspp_info.tsif[tsif].
+				accept_all_filter_exists_flag;
+
+		/* Add a temporary filter to accept all packets */
+		ret = mpq_tspp_add_accept_all_filter(channel_id,
+					tspp_source);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n",
+				__func__, channel_id, tspp_source);
+
+			goto remove_channel_failed_restore_count;
+		}
+
+		ret = mpq_tspp_remove_null_blocking_filters(channel_id,
+					tspp_source);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_tspp_remove_null_blocking_filters(%d, %d) failed\n",
+				__func__, channel_id, tspp_source);
+
+			restore_null_blocking_filters = 1;
+			if (!accept_all_filter_existed)
+				remove_accept_all_filter = 1;
+
+			goto remove_channel_failed_restore_count;
+		}
+
+		ret = mpq_tspp_add_all_user_filters(channel_id,
+					tspp_source);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_tspp_add_all_user_filters(%d, %d) failed\n",
+				__func__, channel_id, tspp_source);
+
+			remove_user_filters = 1;
+			restore_null_blocking_filters = 1;
+			if (!accept_all_filter_existed)
+				remove_accept_all_filter = 1;
+
+			goto remove_channel_failed_restore_count;
+		}
+
+		ret = mpq_tspp_remove_accept_all_filter(channel_id,
+					tspp_source);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n",
+				__func__, channel_id, tspp_source);
+
+			remove_user_filters = 1;
+			restore_null_blocking_filters = 1;
+			if (!accept_all_filter_existed)
+				remove_accept_all_filter = 1;
+
+			goto remove_channel_failed_restore_count;
+		}
+	} else {
+		/* staying in SW filtering mode */
+		if ((mpq_dmx_tspp_info.tsif[tsif].pass_all_flag == 0) &&
+			(mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag == 0)) {
+
+			ret = mpq_tspp_remove_accept_all_filter(channel_id,
+						tspp_source);
+			if (ret < 0) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n",
+					__func__, channel_id,
+					tspp_source);
+
+				goto remove_channel_failed_restore_count;
+			}
+		}
+	}
+
+	mpq_dmx_tspp_info.tsif[tsif].current_filter_count--;
+	(*channel_ref_count)--;
+
+	MPQ_DVB_DBG_PRINT("%s: success, current_filter_count = %d\n",
+		__func__, mpq_dmx_tspp_info.tsif[tsif].current_filter_count);
+
+	if (*channel_ref_count == 0) {
+		/* channel is not used any more, release it */
+		tspp_unregister_notification(0, channel_id);
+		tspp_close_stream(0, channel_id);
+		tspp_close_channel(0, channel_id);
+		atomic_set(data_cnt, 0);
+
+		if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
+			vfree(mpq_dmx_tspp_info.tsif[tsif].aggregate_ids);
+			mpq_dmx_tspp_info.tsif[tsif].aggregate_ids = NULL;
+			mpq_dmx_channel_mem_free(tsif);
+		}
+	}
+
+	goto out;
+
+remove_channel_failed_restore_count:
+	/* restore internal database state */
+	mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = feed->pid;
+	mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++;
+
+	if (remove_user_filters)
+		mpq_tspp_remove_all_user_filters(channel_id, tspp_source);
+
+	if (restore_null_blocking_filters)
+		mpq_tspp_add_null_blocking_filters(channel_id, tspp_source);
+
+	if (remove_accept_all_filter)
+		mpq_tspp_remove_accept_all_filter(channel_id, tspp_source);
+
+	/* restore flags. we can only get here if we changed the flags. */
+	if (feed->pid == TSPP_PASS_THROUGH_PID)
+		mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 1;
+	else if (feed->pid == TSPP_NULL_PACKETS_PID)
+		mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 1;
+
+out:
+	mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+	atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op);
+	return ret;
+}
+
+static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed)
+{
+	int ret;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	MPQ_DVB_DBG_PRINT(
+		"%s(pid=%d) executed\n",
+		__func__,
+		feed->pid);
+
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid mpq_demux handle\n",
+			__func__);
+
+		return -EINVAL;
+	}
+
+	if (mpq_demux->source < DMX_SOURCE_DVR0) {
+		/* source from TSPP, need to configure tspp pipe */
+		ret = mpq_tspp_dmx_add_channel(feed);
+
+		if (ret < 0) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: mpq_tspp_dmx_add_channel failed(%d)\n",
+				__func__,
+				ret);
+			return ret;
+		}
+	}
+
+	/*
+	 * Always feed sections/PES starting from a new one and
+	 * do not partial transfer data from older one
+	 */
+	feed->pusi_seen = 0;
+
+	ret = mpq_dmx_init_mpq_feed(feed);
+	if (ret) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_dmx_init_mpq_feed failed(%d)\n",
+			__func__,
+			ret);
+		if (mpq_demux->source < DMX_SOURCE_DVR0)
+			mpq_tspp_dmx_remove_channel(feed);
+
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mpq_tspp_dmx_stop_filtering(struct dvb_demux_feed *feed)
+{
+	int ret = 0;
+	struct mpq_demux *mpq_demux = feed->demux->priv;
+
+	MPQ_DVB_DBG_PRINT("%s(%d) executed\n", __func__, feed->pid);
+
+	mpq_dmx_terminate_feed(feed);
+
+	if (mpq_demux->source < DMX_SOURCE_DVR0) {
+		/* source from TSPP, need to configure tspp pipe */
+		ret = mpq_tspp_dmx_remove_channel(feed);
+	}
+
+	return ret;
+}
+
+static int mpq_tspp_dmx_write_to_decoder(
+					struct dvb_demux_feed *feed,
+					const u8 *buf,
+					size_t len)
+{
+	/*
+	 * It is assumed that this function is called once for each
+	 * TS packet of the relevant feed.
+	 */
+	if (len > TSPP_RAW_TTS_SIZE)
+		MPQ_DVB_DBG_PRINT(
+				"%s: warnning - len larger than one packet\n",
+				__func__);
+
+	if (dvb_dmx_is_video_feed(feed))
+		return mpq_dmx_process_video_packet(feed, buf);
+
+	if (dvb_dmx_is_audio_feed(feed))
+		return mpq_dmx_process_audio_packet(feed, buf);
+
+	if (dvb_dmx_is_pcr_feed(feed))
+		return mpq_dmx_process_pcr_packet(feed, buf);
+
+	return 0;
+}
+
+/**
+ * Returns demux capabilities of TSPPv1 plugin
+ *
+ * @demux: demux device
+ * @caps: Returned capbabilities
+ *
+ * Return     error code
+ */
+static int mpq_tspp_dmx_get_caps(struct dmx_demux *demux,
+				struct dmx_caps *caps)
+{
+	struct dvb_demux *dvb_demux = demux->priv;
+
+	if ((dvb_demux == NULL) || (caps == NULL)) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid parameters\n",
+			__func__);
+
+		return -EINVAL;
+	}
+
+	caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA |
+		DMX_CAP_TS_INSERTION | DMX_CAP_VIDEO_INDEXING |
+		DMX_CAP_AUDIO_DECODER_DATA | DMX_CAP_AUTO_BUFFER_FLUSH;
+	caps->recording_max_video_pids_indexed = 0;
+	caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES;
+	caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+	caps->num_pid_filters = TSPP_MAX_PID_FILTER_NUM;
+	caps->num_section_filters = dvb_demux->filternum;
+	caps->num_section_filters_per_pid = dvb_demux->filternum;
+	caps->section_filter_length = DMX_FILTER_SIZE;
+	caps->num_demod_inputs = TSIF_COUNT;
+	caps->num_memory_inputs = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+	caps->max_bitrate = 192;
+	caps->demod_input_max_bitrate = 96;
+	caps->memory_input_max_bitrate = 96;
+	caps->num_cipher_ops = 1;
+
+	/* TSIF reports 3 bytes STC at unit of 27MHz/256 */
+	caps->max_stc = (u64)0xFFFFFF * 256;
+
+	/* Buffer requirements */
+	caps->section.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT	|
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->section.max_buffer_num = 1;
+	caps->section.max_size = 0xFFFFFFFF;
+	caps->section.size_alignment = 0;
+	caps->pes.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT	|
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->pes.max_buffer_num = 1;
+	caps->pes.max_size = 0xFFFFFFFF;
+	caps->pes.size_alignment = 0;
+	caps->recording_188_tsp.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT	|
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->recording_188_tsp.max_buffer_num = 1;
+	caps->recording_188_tsp.max_size = 0xFFFFFFFF;
+	caps->recording_188_tsp.size_alignment = 0;
+	caps->recording_192_tsp.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT	|
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->recording_192_tsp.max_buffer_num = 1;
+	caps->recording_192_tsp.max_size = 0xFFFFFFFF;
+	caps->recording_192_tsp.size_alignment = 0;
+	caps->playback_188_tsp.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT	|
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->playback_188_tsp.max_buffer_num = 1;
+	caps->playback_188_tsp.max_size = 0xFFFFFFFF;
+	caps->playback_188_tsp.size_alignment = 188;
+	caps->playback_192_tsp.flags =
+		DMX_BUFFER_EXTERNAL_SUPPORT	|
+		DMX_BUFFER_INTERNAL_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->playback_192_tsp.max_buffer_num = 1;
+	caps->playback_192_tsp.max_size = 0xFFFFFFFF;
+	caps->playback_192_tsp.size_alignment = 192;
+	caps->decoder.flags =
+		DMX_BUFFER_SECURED_IF_DECRYPTED	|
+		DMX_BUFFER_EXTERNAL_SUPPORT	|
+		DMX_BUFFER_INTERNAL_SUPPORT	|
+		DMX_BUFFER_LINEAR_GROUP_SUPPORT |
+		DMX_BUFFER_CACHED;
+	caps->decoder.max_buffer_num = DMX_MAX_DECODER_BUFFER_NUM;
+	caps->decoder.max_size = 0xFFFFFFFF;
+	caps->decoder.size_alignment = SZ_4K;
+
+	return 0;
+}
+
+
+/**
+ * Reads TSIF STC from TSPP
+ *
+ * @demux: demux device
+ * @num: STC number. 0 for TSIF0 and 1 for TSIF1.
+ * @stc: STC value
+ * @base: divisor to get 90KHz value
+ *
+ * Return     error code
+ */
+static int mpq_tspp_dmx_get_stc(struct dmx_demux *demux, unsigned int num,
+		u64 *stc, unsigned int *base)
+{
+	enum tspp_source source;
+	u32 tcr_counter;
+	u64 avtimer_stc = 0;
+	int tts_source = 0;
+
+	if (!demux || !stc || !base)
+		return -EINVAL;
+
+	if (num == 0)
+		source = TSPP_SOURCE_TSIF0;
+	else if (num == 1)
+		source = TSPP_SOURCE_TSIF1;
+	else
+		return -EINVAL;
+
+	if (tspp_get_tts_source(0, &tts_source) < 0)
+		tts_source = TSIF_TTS_TCR;
+
+	if (tts_source != TSIF_TTS_LPASS_TIMER) {
+		tspp_get_ref_clk_counter(0, source, &tcr_counter);
+		*stc = ((u64)tcr_counter) * 256; /* conversion to 27MHz */
+		*base = 300; /* divisor to get 90KHz clock from stc value */
+	} else {
+		if (tspp_get_lpass_time_counter(0, source, &avtimer_stc) < 0)
+			return -EINVAL;
+		*stc = avtimer_stc;
+	}
+	return 0;
+}
+
+static int mpq_tspp_dmx_init(
+			struct dvb_adapter *mpq_adapter,
+			struct mpq_demux *mpq_demux)
+{
+	int result;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	mpq_dmx_tspp_info.ion_client = mpq_demux->ion_client;
+
+	/* Set the kernel-demux object capabilities */
+	mpq_demux->demux.dmx.capabilities =
+		DMX_TS_FILTERING			|
+		DMX_PES_FILTERING			|
+		DMX_SECTION_FILTERING			|
+		DMX_MEMORY_BASED_FILTERING		|
+		DMX_CRC_CHECKING			|
+		DMX_TS_DESCRAMBLING;
+
+	mpq_demux->decoder_alloc_flags = ION_FLAG_CACHED;
+
+	/* Set dvb-demux "virtual" function pointers */
+	mpq_demux->demux.priv = (void *)mpq_demux;
+	mpq_demux->demux.filternum = TSPP_MAX_SECTION_FILTER_NUM;
+	mpq_demux->demux.feednum = MPQ_MAX_DMX_FILES;
+	mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering;
+	mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering;
+	mpq_demux->demux.write_to_decoder = mpq_tspp_dmx_write_to_decoder;
+	mpq_demux->demux.decoder_fullness_init = mpq_dmx_decoder_fullness_init;
+	mpq_demux->demux.decoder_fullness_wait = mpq_dmx_decoder_fullness_wait;
+	mpq_demux->demux.decoder_fullness_abort =
+		mpq_dmx_decoder_fullness_abort;
+	mpq_demux->demux.decoder_buffer_status = mpq_dmx_decoder_buffer_status;
+	mpq_demux->demux.reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer;
+	mpq_demux->demux.set_cipher_op = mpq_dmx_set_cipher_ops;
+	mpq_demux->demux.oob_command = mpq_dmx_oob_command;
+	mpq_demux->demux.convert_ts = mpq_dmx_convert_tts;
+	mpq_demux->demux.flush_decoder_buffer = NULL;
+
+	/* Initialize dvb_demux object */
+	result = dvb_dmx_init(&mpq_demux->demux);
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__);
+		goto init_failed;
+	}
+
+	/* Now initailize the dmx-dev object */
+	mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES;
+	mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
+	mpq_demux->dmxdev.capabilities = DMXDEV_CAP_DUPLEX;
+
+	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+	mpq_demux->dmxdev.demux->get_stc = mpq_tspp_dmx_get_stc;
+	mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
+	mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer;
+	mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer;
+	mpq_demux->dmxdev.demux->write = mpq_dmx_write;
+	result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
+						  __func__,
+						  result);
+		goto init_failed_dmx_release;
+	}
+
+	/* Extend dvb-demux debugfs with TSPP statistics. */
+	mpq_dmx_init_debugfs_entries(mpq_demux);
+
+	/* Get the TSIF TTS info */
+	if (tspp_get_tts_source(0, &mpq_demux->ts_packet_timestamp_source) < 0)
+		mpq_demux->ts_packet_timestamp_source = TSIF_TTS_TCR;
+
+	return 0;
+
+init_failed_dmx_release:
+	dvb_dmx_release(&mpq_demux->demux);
+init_failed:
+	return result;
+}
+
+static int __init mpq_dmx_tspp_plugin_init(void)
+{
+	int i;
+	int j;
+	int ret;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	for (i = 0; i < TSIF_COUNT; i++) {
+		mpq_dmx_tspp_info.tsif[i].aggregate_ids = NULL;
+		mpq_dmx_tspp_info.tsif[i].channel_ref = 0;
+		mpq_dmx_tspp_info.tsif[i].buff_index = 0;
+		mpq_dmx_tspp_info.tsif[i].ch_mem_heap_handle = NULL;
+		mpq_dmx_tspp_info.tsif[i].ch_mem_heap_virt_base = NULL;
+		mpq_dmx_tspp_info.tsif[i].ch_mem_heap_phys_base = 0;
+		atomic_set(&mpq_dmx_tspp_info.tsif[i].data_cnt, 0);
+		atomic_set(&mpq_dmx_tspp_info.tsif[i].control_op, 0);
+
+		for (j = 0; j < TSPP_MAX_PID_FILTER_NUM; j++) {
+			mpq_dmx_tspp_info.tsif[i].filters[j].pid = -1;
+			mpq_dmx_tspp_info.tsif[i].filters[j].ref_count = 0;
+			mpq_dmx_tspp_info.tsif[i].filters[j].hw_index = -1;
+		}
+
+		for (j = 0; j < TSPP_MAX_HW_PID_FILTER_NUM; j++)
+			mpq_dmx_tspp_info.tsif[i].hw_indexes[j] = 0;
+
+		mpq_dmx_tspp_info.tsif[i].current_filter_count = 0;
+		mpq_dmx_tspp_info.tsif[i].pass_nulls_flag = 0;
+		mpq_dmx_tspp_info.tsif[i].pass_all_flag = 0;
+		mpq_dmx_tspp_info.tsif[i].accept_all_filter_exists_flag = 0;
+
+		snprintf(mpq_dmx_tspp_info.tsif[i].name,
+				TSIF_NAME_LENGTH,
+				"dmx_tsif%d",
+				i);
+
+		init_waitqueue_head(&mpq_dmx_tspp_info.tsif[i].wait_queue);
+		mpq_dmx_tspp_info.tsif[i].thread =
+			kthread_run(
+				mpq_dmx_tspp_thread, (void *)(uintptr_t)i,
+				mpq_dmx_tspp_info.tsif[i].name);
+
+		if (IS_ERR(mpq_dmx_tspp_info.tsif[i].thread)) {
+			for (j = 0; j < i; j++) {
+				kthread_stop(mpq_dmx_tspp_info.tsif[j].thread);
+				mutex_destroy(&mpq_dmx_tspp_info.tsif[j].mutex);
+			}
+
+			MPQ_DVB_ERR_PRINT(
+				"%s: kthread_run failed\n",
+				__func__);
+
+			return -ENOMEM;
+		}
+
+		mutex_init(&mpq_dmx_tspp_info.tsif[i].mutex);
+	}
+
+	ret = mpq_dmx_plugin_init(mpq_tspp_dmx_init);
+
+	if (ret < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_dmx_plugin_init failed (errno=%d)\n",
+			__func__,
+			ret);
+
+		for (i = 0; i < TSIF_COUNT; i++) {
+			kthread_stop(mpq_dmx_tspp_info.tsif[i].thread);
+			mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
+		}
+	}
+
+	return ret;
+}
+
+static void __exit mpq_dmx_tspp_plugin_exit(void)
+{
+	int i;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	for (i = 0; i < TSIF_COUNT; i++) {
+		mutex_lock(&mpq_dmx_tspp_info.tsif[i].mutex);
+
+		/*
+		 * Note: tspp_close_channel will also free the TSPP buffers
+		 * even if we allocated them ourselves,
+		 * using our free function.
+		 */
+		if (mpq_dmx_tspp_info.tsif[i].channel_ref) {
+			tspp_unregister_notification(0,
+				TSPP_CHANNEL_ID(i, TSPP_CHANNEL));
+			tspp_close_channel(0,
+				TSPP_CHANNEL_ID(i, TSPP_CHANNEL));
+
+			if (allocation_mode ==
+				MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
+				vfree(mpq_dmx_tspp_info.tsif[i].aggregate_ids);
+				mpq_dmx_tspp_info.tsif[i].aggregate_ids = NULL;
+				mpq_dmx_channel_mem_free(i);
+			}
+		}
+
+		mutex_unlock(&mpq_dmx_tspp_info.tsif[i].mutex);
+		kthread_stop(mpq_dmx_tspp_info.tsif[i].thread);
+		mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
+	}
+
+	mpq_dmx_plugin_exit();
+}
+
+
+module_init(mpq_dmx_tspp_plugin_init);
+module_exit(mpq_dmx_tspp_plugin_exit);
+
+MODULE_DESCRIPTION("Qualcomm Technologies Inc. demux TSPP version 1 HW Plugin");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c
new file mode 100644
index 0000000..860c365
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c
@@ -0,0 +1,1023 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include "qseecom_kernel.h"
+#include "mpq_sdmx.h"
+
+static struct qseecom_handle *sdmx_qseecom_handles[SDMX_MAX_SESSIONS];
+static struct mutex sdmx_lock[SDMX_MAX_SESSIONS];
+
+#define QSEECOM_SBUFF_SIZE	SZ_128K
+
+enum sdmx_cmd_id {
+	SDMX_OPEN_SESSION_CMD,
+	SDMX_CLOSE_SESSION_CMD,
+	SDMX_SET_SESSION_CFG_CMD,
+	SDMX_ADD_FILTER_CMD,
+	SDMX_REMOVE_FILTER_CMD,
+	SDMX_SET_KL_IDX_CMD,
+	SDMX_ADD_RAW_PID_CMD,
+	SDMX_REMOVE_RAW_PID_CMD,
+	SDMX_PROCESS_CMD,
+	SDMX_GET_DBG_COUNTERS_CMD,
+	SDMX_RESET_DBG_COUNTERS_CMD,
+	SDMX_GET_VERSION_CMD,
+	SDMX_INVALIDATE_KL_CMD,
+	SDMX_SET_LOG_LEVEL_CMD
+};
+
+#pragma pack(push, sdmx, 1)
+
+struct sdmx_proc_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+	u8 flags;
+	struct sdmx_buff_descr in_buf_descr;
+	u32 inp_fill_cnt;
+	u32 in_rd_offset;
+	u32 num_filters;
+	struct sdmx_filter_status filters_status[];
+};
+
+struct sdmx_proc_rsp {
+	enum sdmx_status ret;
+	u32 inp_fill_cnt;
+	u32 in_rd_offset;
+	u32 err_indicators;
+	u32 status_indicators;
+};
+
+struct sdmx_open_ses_req {
+	enum sdmx_cmd_id cmd_id;
+};
+
+struct sdmx_open_ses_rsp {
+	enum sdmx_status ret;
+	u32 session_handle;
+};
+
+struct sdmx_close_ses_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+};
+
+struct sdmx_close_ses_rsp {
+	enum sdmx_status ret;
+};
+
+struct sdmx_ses_cfg_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+	enum sdmx_proc_mode process_mode;
+	enum sdmx_inp_mode input_mode;
+	enum sdmx_pkt_format packet_len;
+	u8 odd_scramble_bits;
+	u8 even_scramble_bits;
+};
+
+struct sdmx_ses_cfg_rsp {
+	enum sdmx_status ret;
+};
+
+struct sdmx_set_kl_ind_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+	u32 pid;
+	u32 kl_index;
+};
+
+struct sdmx_set_kl_ind_rsp {
+	enum sdmx_status ret;
+};
+
+struct sdmx_add_filt_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+	u32 pid;
+	enum sdmx_filter filter_type;
+	struct sdmx_buff_descr meta_data_buf;
+	enum sdmx_buf_mode buffer_mode;
+	enum sdmx_raw_out_format ts_out_format;
+	u32 flags;
+	u32 num_data_bufs;
+	struct sdmx_data_buff_descr data_bufs[];
+};
+
+struct sdmx_add_filt_rsp {
+	enum sdmx_status ret;
+	u32 filter_handle;
+};
+
+struct sdmx_rem_filt_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+	u32 filter_handle;
+};
+
+struct sdmx_rem_filt_rsp {
+	enum sdmx_status ret;
+};
+
+struct sdmx_add_raw_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+	u32 filter_handle;
+	u32 pid;
+};
+
+struct sdmx_add_raw_rsp {
+	enum sdmx_status ret;
+};
+
+struct sdmx_rem_raw_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+	u32 filter_handle;
+	u32 pid;
+};
+
+struct sdmx_rem_raw_rsp {
+	enum sdmx_status ret;
+};
+
+struct sdmx_get_counters_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+	u32 num_filters;
+};
+
+struct sdmx_get_counters_rsp {
+	enum sdmx_status ret;
+	struct sdmx_session_dbg_counters session_counters;
+	u32 num_filters;
+	struct sdmx_filter_dbg_counters filter_counters[];
+};
+
+struct sdmx_rst_counters_req {
+	enum sdmx_cmd_id cmd_id;
+	u32 session_handle;
+};
+
+struct sdmx_rst_counters_rsp {
+	enum sdmx_status ret;
+};
+
+struct sdmx_get_version_req {
+	enum sdmx_cmd_id cmd_id;
+};
+
+struct sdmx_get_version_rsp {
+	enum sdmx_status ret;
+	int32_t version;
+};
+
+struct sdmx_set_log_level_req {
+	enum sdmx_cmd_id cmd_id;
+	enum sdmx_log_level level;
+	u32 session_handle;
+};
+
+struct sdmx_set_log_level_rsp {
+	enum sdmx_status ret;
+};
+
+#pragma pack(pop, sdmx)
+
+static int get_cmd_rsp_buffers(int handle_index,
+	void **cmd,
+	int *cmd_len,
+	void **rsp,
+	int *rsp_len)
+{
+	if (*cmd_len & QSEECOM_ALIGN_MASK)
+		*cmd_len = QSEECOM_ALIGN(*cmd_len);
+
+	if (*rsp_len & QSEECOM_ALIGN_MASK)
+		*rsp_len = QSEECOM_ALIGN(*rsp_len);
+
+	if ((*rsp_len + *cmd_len) > QSEECOM_SBUFF_SIZE) {
+		pr_err("%s: shared buffer too small to hold cmd=%d and rsp=%d\n",
+			__func__, *cmd_len, *rsp_len);
+		return SDMX_STATUS_OUT_OF_MEM;
+	}
+
+	*cmd = sdmx_qseecom_handles[handle_index]->sbuf;
+	*rsp = sdmx_qseecom_handles[handle_index]->sbuf + *cmd_len;
+	return SDMX_SUCCESS;
+}
+
+/*
+ * Returns version of secure-demux app.
+ *
+ * @session_handle: Returned instance handle. Must not be NULL.
+ * Return error code
+ */
+int sdmx_get_version(int session_handle, int32_t *version)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_get_version_req *cmd;
+	struct sdmx_get_version_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
+		(version == NULL))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_get_version_req);
+	rsp_len = sizeof(struct sdmx_get_version_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_GET_VERSION_CMD;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	ret = rsp->ret;
+	*version = rsp->version;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+
+}
+EXPORT_SYMBOL(sdmx_get_version);
+
+/*
+ * Initializes a new secure demux instance and returns a handle of the instance.
+ *
+ * @session_handle: handle of a secure demux instance to get its version.
+ * Return the version if successful or an error code.
+ */
+int sdmx_open_session(int *session_handle)
+{
+	int res, cmd_len, rsp_len;
+	enum sdmx_status ret, version_ret;
+	struct sdmx_open_ses_req *cmd;
+	struct sdmx_open_ses_rsp *rsp;
+	struct qseecom_handle *qseecom_handle = NULL;
+	int32_t version;
+
+	/* Input validation */
+	if (session_handle == NULL)
+		return SDMX_STATUS_GENERAL_FAILURE;
+
+	/* Start the TZ app */
+	res = qseecom_start_app(&qseecom_handle, "securemm",
+		QSEECOM_SBUFF_SIZE);
+
+	if (res < 0)
+		return SDMX_STATUS_GENERAL_FAILURE;
+
+	cmd_len = sizeof(struct sdmx_open_ses_req);
+	rsp_len = sizeof(struct sdmx_open_ses_rsp);
+
+	/* Get command and response buffers */
+	cmd = (struct sdmx_open_ses_req *)qseecom_handle->sbuf;
+
+	if (cmd_len & QSEECOM_ALIGN_MASK)
+		cmd_len = QSEECOM_ALIGN(cmd_len);
+
+	rsp = (struct sdmx_open_ses_rsp *)qseecom_handle->sbuf + cmd_len;
+
+	if (rsp_len & QSEECOM_ALIGN_MASK)
+		rsp_len = QSEECOM_ALIGN(rsp_len);
+
+	/* Will be later overridden by SDMX response */
+	*session_handle = SDMX_INVALID_SESSION_HANDLE;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_OPEN_SESSION_CMD;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(qseecom_handle, (void *)cmd, cmd_len,
+		(void *)rsp, rsp_len);
+
+	if (res < 0) {
+		qseecom_shutdown_app(&qseecom_handle);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	/* Parse response struct */
+	*session_handle = rsp->session_handle;
+
+	/* Initialize handle and mutex */
+	sdmx_qseecom_handles[*session_handle] = qseecom_handle;
+	mutex_init(&sdmx_lock[*session_handle]);
+	ret = rsp->ret;
+
+	/* Get and print the app version */
+	version_ret = sdmx_get_version(*session_handle, &version);
+	if (version_ret == SDMX_SUCCESS)
+		pr_info("TZ SDMX version is %x.%x\n", version >> 8,
+			version & 0xFF);
+	else
+		pr_err("Error reading TZ SDMX version\n");
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_open_session);
+
+/*
+ * Closes a secure demux instance.
+ *
+ * @session_handle: handle of a secure demux instance to close.
+ * Return error code
+ */
+int sdmx_close_session(int session_handle)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_close_ses_req *cmd;
+	struct sdmx_close_ses_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_close_ses_req);
+	rsp_len = sizeof(struct sdmx_close_ses_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_CLOSE_SESSION_CMD;
+	cmd->session_handle = session_handle;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	ret = rsp->ret;
+
+	/* Shutdown the TZ app (or at least free the current handle) */
+	res = qseecom_shutdown_app(&sdmx_qseecom_handles[session_handle]);
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	sdmx_qseecom_handles[session_handle] = NULL;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_close_session);
+
+/*
+ * Configures an open secure demux instance.
+ *
+ * @session_handle: secure demux instance
+ * @proc_mode: Defines secure demux's behavior in case of output
+ *             buffer overflow.
+ * @inp_mode: Defines the input encryption settings.
+ * @pkt_format: TS packet length in input buffer.
+ * @odd_scramble_bits: Value of the scramble bits indicating the ODD key.
+ * @even_scramble_bits: Value of the scramble bits indicating the EVEN key.
+ * Return error code
+ */
+int sdmx_set_session_cfg(int session_handle,
+	enum sdmx_proc_mode proc_mode,
+	enum sdmx_inp_mode inp_mode,
+	enum sdmx_pkt_format pkt_format,
+	u8 odd_scramble_bits,
+	u8 even_scramble_bits)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_ses_cfg_req *cmd;
+	struct sdmx_ses_cfg_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_ses_cfg_req);
+	rsp_len = sizeof(struct sdmx_ses_cfg_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_SET_SESSION_CFG_CMD;
+	cmd->session_handle = session_handle;
+	cmd->process_mode = proc_mode;
+	cmd->input_mode = inp_mode;
+	cmd->packet_len = pkt_format;
+	cmd->odd_scramble_bits = odd_scramble_bits;
+	cmd->even_scramble_bits = even_scramble_bits;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	ret = rsp->ret;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_set_session_cfg);
+
+/*
+ * Creates a new secure demux filter and returns a filter handle
+ *
+ * @session_handle: secure demux instance
+ * @pid: pid to filter
+ * @filter_type: type of filtering
+ * @meta_data_buf: meta data buffer descriptor
+ * @data_buf_mode: data buffer mode (ring/linear)
+ * @num_data_bufs: number of data buffers (use 1 for a ring buffer)
+ * @data_bufs: data buffers descriptors array
+ * @filter_handle: returned filter handle
+ * @ts_out_format: output format for raw filters
+ * @flags: optional flags for filter
+ *	   (currently only clear section CRC verification is supported)
+ *
+ * Return error code
+ */
+int sdmx_add_filter(int session_handle,
+	u16 pid,
+	enum sdmx_filter filterype,
+	struct sdmx_buff_descr *meta_data_buf,
+	enum sdmx_buf_mode d_buf_mode,
+	u32 num_data_bufs,
+	struct sdmx_data_buff_descr *data_bufs,
+	int *filter_handle,
+	enum sdmx_raw_out_format ts_out_format,
+	u32 flags)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_add_filt_req *cmd;
+	struct sdmx_add_filt_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
+		(filter_handle == NULL))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_add_filt_req)
+		+ num_data_bufs * sizeof(struct sdmx_data_buff_descr);
+	rsp_len = sizeof(struct sdmx_add_filt_rsp);
+
+	/* Will be later overridden by SDMX response */
+	*filter_handle = SDMX_INVALID_FILTER_HANDLE;
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_ADD_FILTER_CMD;
+	cmd->session_handle = session_handle;
+	cmd->pid = (u32)pid;
+	cmd->filter_type = filterype;
+	cmd->ts_out_format = ts_out_format;
+	cmd->flags = flags;
+	if (meta_data_buf != NULL)
+		memcpy(&(cmd->meta_data_buf), meta_data_buf,
+				sizeof(struct sdmx_buff_descr));
+	else
+		memset(&(cmd->meta_data_buf), 0, sizeof(cmd->meta_data_buf));
+
+	cmd->buffer_mode = d_buf_mode;
+	cmd->num_data_bufs = num_data_bufs;
+	memcpy(cmd->data_bufs, data_bufs,
+			num_data_bufs * sizeof(struct sdmx_data_buff_descr));
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	/* Parse response struct */
+	*filter_handle = rsp->filter_handle;
+	ret = rsp->ret;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_add_filter);
+
+/*
+ * Removes a secure demux filter
+ *
+ * @session_handle: secure demux instance
+ * @filter_handle: filter handle to remove
+ *
+ * Return error code
+ */
+int sdmx_remove_filter(int session_handle, int filter_handle)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_rem_filt_req *cmd;
+	struct sdmx_rem_filt_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_rem_filt_req);
+	rsp_len = sizeof(struct sdmx_rem_filt_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_REMOVE_FILTER_CMD;
+	cmd->session_handle = session_handle;
+	cmd->filter_handle = filter_handle;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	ret = rsp->ret;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_remove_filter);
+
+/*
+ * Associates a key ladder index for the specified pid
+ *
+ * @session_handle: secure demux instance
+ * @pid: pid
+ * @key_ladder_index: key ladder index to associate to the pid
+ *
+ * Return error code
+ *
+ * Note: if pid already has some key ladder index associated, it will be
+ * overridden.
+ */
+int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_set_kl_ind_req *cmd;
+	struct sdmx_set_kl_ind_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_set_kl_ind_req);
+	rsp_len = sizeof(struct sdmx_set_kl_ind_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_SET_KL_IDX_CMD;
+	cmd->session_handle = session_handle;
+	cmd->pid = (u32)pid;
+	cmd->kl_index = key_ladder_index;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	ret = rsp->ret;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_set_kl_ind);
+
+/*
+ * Adds the specified pid to an existing raw (recording) filter
+ *
+ * @session_handle: secure demux instance
+ * @filter_handle: raw filter handle
+ * @pid: pid
+ *
+ * Return error code
+ */
+int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_add_raw_req *cmd;
+	struct sdmx_add_raw_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_add_raw_req);
+	rsp_len = sizeof(struct sdmx_add_raw_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_ADD_RAW_PID_CMD;
+	cmd->session_handle = session_handle;
+	cmd->filter_handle = filter_handle;
+	cmd->pid = (u32)pid;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	ret = rsp->ret;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_add_raw_pid);
+
+/*
+ * Removes the specified pid from a raw (recording) filter
+ *
+ * @session_handle: secure demux instance
+ * @filter_handle: raw filter handle
+ * @pid: pid
+ *
+ * Return error code
+ */
+int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_rem_raw_req *cmd;
+	struct sdmx_rem_raw_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_rem_raw_req);
+	rsp_len = sizeof(struct sdmx_rem_raw_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_REMOVE_RAW_PID_CMD;
+	cmd->session_handle = session_handle;
+	cmd->filter_handle = filter_handle;
+	cmd->pid = (u32)pid;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	ret = rsp->ret;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_remove_raw_pid);
+
+/*
+ * Call secure demux to perform processing on the specified input buffer
+ *
+ * @session_handle: secure demux instance
+ * @flags: input flags. Currently only EOS marking is supported.
+ * @input_buf_desc: input buffer descriptor
+ * @input_fill_count: number of bytes available in input buffer
+ * @input_read_offset: offset inside input buffer where data starts
+ * @error_indicators: returned general error indicators
+ * @status_indicators: returned general status indicators
+ * @num_filters: number of filters in filter status array
+ * @filter_status: filter status descriptor array
+ *
+ * Return error code
+ */
+int sdmx_process(int session_handle, u8 flags,
+	struct sdmx_buff_descr *input_buf_desc,
+	u32 *input_fill_count,
+	u32 *input_read_offset,
+	u32 *error_indicators,
+	u32 *status_indicators,
+	u32 num_filters,
+	struct sdmx_filter_status *filter_status)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_proc_req *cmd;
+	struct sdmx_proc_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
+		(input_buf_desc == NULL) ||
+		(input_fill_count == NULL) || (input_read_offset == NULL) ||
+		(error_indicators == NULL) || (status_indicators == NULL) ||
+		(filter_status == NULL))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_proc_req)
+		+ num_filters * sizeof(struct sdmx_filter_status);
+	rsp_len = sizeof(struct sdmx_proc_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_PROCESS_CMD;
+	cmd->session_handle = session_handle;
+	cmd->flags = flags;
+	cmd->in_buf_descr.base_addr = input_buf_desc->base_addr;
+	cmd->in_buf_descr.size = input_buf_desc->size;
+	cmd->inp_fill_cnt = *input_fill_count;
+	cmd->in_rd_offset = *input_read_offset;
+	cmd->num_filters = num_filters;
+	memcpy(cmd->filters_status, filter_status,
+		num_filters * sizeof(struct sdmx_filter_status));
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	/* Parse response struct */
+	*input_fill_count = rsp->inp_fill_cnt;
+	*input_read_offset = rsp->in_rd_offset;
+	*error_indicators = rsp->err_indicators;
+	*status_indicators = rsp->status_indicators;
+	memcpy(filter_status, cmd->filters_status,
+		num_filters * sizeof(struct sdmx_filter_status));
+	ret = rsp->ret;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_process);
+
+/*
+ * Returns session-level & filter-level debug counters
+ *
+ * @session_handle: secure demux instance
+ * @session_counters: returned session-level debug counters
+ * @num_filters: returned number of filters reported in filter_counters
+ * @filter_counters: returned filter-level debug counters array
+ *
+ * Return error code
+ */
+int sdmx_get_dbg_counters(int session_handle,
+	struct sdmx_session_dbg_counters *session_counters,
+	u32 *num_filters,
+	struct sdmx_filter_dbg_counters *filter_counters)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_get_counters_req *cmd;
+	struct sdmx_get_counters_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
+		(session_counters == NULL) || (num_filters == NULL) ||
+		(filter_counters == NULL))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_get_counters_req);
+	rsp_len = sizeof(struct sdmx_get_counters_rsp)
+		+ *num_filters * sizeof(struct sdmx_filter_dbg_counters);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_GET_DBG_COUNTERS_CMD;
+	cmd->session_handle = session_handle;
+	cmd->num_filters = *num_filters;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	/* Parse response struct */
+	*session_counters = rsp->session_counters;
+	*num_filters = rsp->num_filters;
+	memcpy(filter_counters, rsp->filter_counters,
+		*num_filters * sizeof(struct sdmx_filter_dbg_counters));
+	ret = rsp->ret;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_get_dbg_counters);
+
+/*
+ * Reset debug counters
+ *
+ * @session_handle: secure demux instance
+ *
+ * Return error code
+ */
+int sdmx_reset_dbg_counters(int session_handle)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_rst_counters_req *cmd;
+	struct sdmx_rst_counters_rsp *rsp;
+	enum sdmx_status ret;
+
+	if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
+		return SDMX_STATUS_INVALID_INPUT_PARAMS;
+
+	cmd_len = sizeof(struct sdmx_rst_counters_req);
+	rsp_len = sizeof(struct sdmx_rst_counters_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_RESET_DBG_COUNTERS_CMD;
+	cmd->session_handle = session_handle;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+
+	ret = rsp->ret;
+out:
+	mutex_unlock(&sdmx_lock[session_handle]);
+
+	return ret;
+}
+EXPORT_SYMBOL(sdmx_reset_dbg_counters);
+
+/*
+ * Set debug log verbosity level
+ *
+ * @session_handle: secure demux instance
+ * @level: requested log level
+ *
+ * Return error code
+ */
+int sdmx_set_log_level(int session_handle, enum sdmx_log_level level)
+{
+	int res, cmd_len, rsp_len;
+	struct sdmx_set_log_level_req *cmd;
+	struct sdmx_set_log_level_rsp *rsp;
+	enum sdmx_status ret;
+
+	cmd_len = sizeof(struct sdmx_set_log_level_req);
+	rsp_len = sizeof(struct sdmx_set_log_level_rsp);
+
+	/* Lock shared memory */
+	mutex_lock(&sdmx_lock[session_handle]);
+
+	/* Get command and response buffers */
+	ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
+		(void **)&rsp, &rsp_len);
+	if (ret)
+		goto out;
+
+	/* Populate command struct */
+	cmd->cmd_id = SDMX_SET_LOG_LEVEL_CMD;
+	cmd->session_handle = session_handle;
+	cmd->level = level;
+
+	/* Issue QSEECom command */
+	res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
+		(void *)cmd, cmd_len, (void *)rsp, rsp_len);
+	if (res < 0) {
+		mutex_unlock(&sdmx_lock[session_handle]);
+		return SDMX_STATUS_GENERAL_FAILURE;
+	}
+	ret = rsp->ret;
+out:
+	/* Unlock */
+	mutex_unlock(&sdmx_lock[session_handle]);
+	return ret;
+}
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
new file mode 100644
index 0000000..9be26ae5
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
@@ -0,0 +1,368 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MPQ_SDMX_H
+#define _MPQ_SDMX_H
+
+#include <linux/types.h>
+
+/* Constant declarations */
+#define SDMX_MAX_SESSIONS  (4)
+#define SDMX_LOOPBACK_PID  (0x2000)
+
+#define SDMX_MAX_PHYSICAL_CHUNKS (256)
+
+/* Filter-level error indicators */
+#define SDMX_FILTER_SUCCESS                       (0)
+#define SDMX_FILTER_ERR_MD_BUF_FULL               BIT(0)
+#define SDMX_FILTER_ERR_D_BUF_FULL                BIT(1)
+#define SDMX_FILTER_ERR_D_LIN_BUFS_FULL           BIT(2)
+#define SDMX_FILTER_ERR_INVALID_SCRAMBLE_BITS     BIT(3)
+#define SDMX_FILTER_ERR_KL_IND_NOT_SET            BIT(4)
+#define SDMX_FILTER_ERR_CAS_DECRYPT_ERROR         BIT(5)
+#define SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL      BIT(6)
+#define SDMX_FILTER_ERR_SEC_INTERNAL_MALLOC_FAIL  BIT(7)
+#define SDMX_FILTER_ERR_SEC_LEN_INVALID           BIT(8)
+#define SDMX_FILTER_ERR_SEC_PUSI_PTR_INVALID      BIT(9)
+#define SDMX_FILTER_ERR_TS_SYNC_BYTE_INVALID      BIT(10)
+#define SDMX_FILTER_ERR_TS_TRANSPORT_ERR          BIT(11)
+#define SDMX_FILTER_ERR_CONT_CNT_INVALID          BIT(12)
+#define SDMX_FILTER_ERR_CONT_CNT_DUPLICATE        BIT(13)
+#define SDMX_FILTER_ERR_INVALID_PES_HDR           BIT(14)
+#define SDMX_FILTER_ERR_INVALID_PES_LEN           BIT(15)
+#define SDMX_FILTER_ERR_INVALID_PES_ENCRYPTION    BIT(16)
+#define SDMX_FILTER_ERR_SECURITY_FAULT            BIT(17)
+#define SDMX_FILTER_ERR_IN_NS_BUFFER              BIT(18)
+
+/* Filter-level status indicators */
+#define SDMX_FILTER_STATUS_EOS                    BIT(0)
+#define SDMX_FILTER_STATUS_WR_PTR_CHANGED         BIT(1)
+
+/* Filter-level flags */
+#define SDMX_FILTER_FLAG_VERIFY_SECTION_CRC	BIT(0)
+
+#define SDMX_INVALID_SESSION_HANDLE		(-1)
+#define SDMX_INVALID_FILTER_HANDLE		(-1)
+
+/* Input flags */
+#define SDMX_INPUT_FLAG_EOS		BIT(0)
+#define SDMX_INPUT_FLAG_DBG_ENABLE	BIT(1)
+
+
+enum sdmx_buf_mode {
+	SDMX_RING_BUF,
+	SDMX_LINEAR_GROUP_BUF,
+};
+
+enum sdmx_proc_mode {
+	SDMX_PUSH_MODE,
+	SDMX_PULL_MODE,
+};
+
+enum sdmx_inp_mode {
+	SDMX_PKT_ENC_MODE,
+	SDMX_BULK_ENC_MODE,
+	SDMX_CLEAR_MODE,
+};
+
+enum sdmx_pkt_format {
+	SDMX_188_BYTE_PKT = 188,
+	SDMX_192_BYTE_PKT = 192,
+	SDMX_195_BYTE_PKT = 195,
+};
+
+enum sdmx_log_level {
+	SDMX_LOG_NO_PRINT,
+	SDMX_LOG_MSG_ERROR,
+	SDMX_LOG_DEBUG,
+	SDMX_LOG_VERBOSE
+};
+
+enum sdmx_status {
+	SDMX_SUCCESS = 0,
+	SDMX_STATUS_GENERAL_FAILURE = -1,
+	SDMX_STATUS_MAX_OPEN_SESSIONS_REACHED = -2,
+	SDMX_STATUS_INVALID_SESSION_HANDLE = -3,
+	SDMX_STATUS_INVALID_INPUT_PARAMS = -4,
+	SDMX_STATUS_UNSUPPORTED_MODE = -5,
+	SDMX_STATUS_INVALID_PID = -6,
+	SDMX_STATUS_OUT_OF_MEM = -7,
+	SDMX_STATUS_FILTER_EXISTS = -8,
+	SDMX_STATUS_INVALID_FILTER_HANDLE = -9,
+	SDMX_STATUS_MAX_RAW_PIDS_REACHED = -10,
+	SDMX_STATUS_SINGLE_PID_RAW_FILTER = -11,
+	SDMX_STATUS_INP_BUF_INVALID_PARAMS = -12,
+	SDMX_STATUS_INVALID_FILTER_CFG = -13,
+	SDMX_STATUS_STALLED_IN_PULL_MODE = -14,
+	SDMX_STATUS_SECURITY_FAULT = -15,
+	SDMX_STATUS_NS_BUFFER_ERROR = -16,
+};
+
+enum sdmx_filter {
+	SDMX_PES_FILTER,		/* Other PES */
+	SDMX_SEPARATED_PES_FILTER,	/* Separated PES (for decoder) */
+	SDMX_SECTION_FILTER,		/* Section */
+	SDMX_PCR_FILTER,		/* PCR */
+	SDMX_RAW_FILTER,		/* Recording */
+};
+
+enum sdmx_raw_out_format {
+	SDMX_188_OUTPUT,
+	SDMX_192_HEAD_OUTPUT,
+	SDMX_192_TAIL_OUTPUT
+};
+
+#pragma pack(push, sdmx, 1)
+
+struct sdmx_session_dbg_counters {
+	/* Total number of TS-packets input to SDMX. */
+	u32 ts_pkt_in;
+
+	/* Total number of TS-packets filtered out by SDMX. */
+	u32 ts_pkt_out;
+};
+
+struct sdmx_filter_dbg_counters {
+	int filter_handle;
+
+	/* Number of TS-packets filtered. */
+	u32 ts_pkt_count;
+
+	/* Number of TS-packets with adaptation field only (no payload). */
+	u32 ts_pkt_no_payload;
+
+	/* Number of TS-packets with the discontinuity indicator set. */
+	u32 ts_pkt_discont;
+
+	/* Number of duplicate TS-packets detected. */
+	u32 ts_pkt_dup;
+
+	/* Number of packets not decrypted because the key wasn't ready. */
+	u32 ts_pkt_key_not_ready;
+};
+
+struct sdmx_pes_counters {
+	/* Number of TS packets with the TEI flag set */
+	u32 transport_err_count;
+
+	/* Number of TS packets with continuity counter errors */
+	u32 continuity_err_count;
+
+	/* Number of TS packets composing this PES frame */
+	u32 pes_ts_count;
+
+	/* Number of TS packets dropped due to full buffer */
+	u32 drop_count;
+};
+
+struct sdmx_buff_descr {
+	/* Physical address where buffer starts */
+	u64 base_addr;
+
+	/* Size of buffer */
+	u32 size;
+};
+
+struct sdmx_data_buff_descr {
+	/* Physical chunks of the buffer */
+	struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS];
+
+	/* Length of buffer */
+	u32 length;
+};
+
+/*
+ * Data payload residing in the data buffers is described using this meta-data
+ * header. The meta data header specifies where the payload is located in the
+ * data buffer and how big it is.
+ * The meta data header optionally carries additional relevant meta data
+ * immediately following the meta-data header.
+ */
+struct sdmx_metadata_header {
+	/*
+	 * Payload start offset inside data buffer. In case data is managed
+	 * as a linear buffer group, this specifies buffer index.
+	 */
+	u32 payload_start;
+
+	/* Payload length */
+	u32 payload_length;
+
+	/* Number of meta data bytes immediately following this header */
+	u32 metadata_length;
+};
+
+
+struct sdmx_filter_status {
+	/* Secure demux filter handle */
+	int filter_handle;
+
+	/*
+	 * Number of pending bytes in filter's output data buffer.
+	 * For linear buffer mode, this is number of buffers pending.
+	 */
+	u32 data_fill_count;
+
+	/*
+	 * Offset in data buffer for next data payload to be written.
+	 * For linear buffer mode, this is a buffer index.
+	 */
+	u32 data_write_offset;
+
+	/* Number of pending bytes in filter's output meta data buffer */
+	u32 metadata_fill_count;
+
+	/* Offset in meta data buffer for next metadata header to be written */
+	u32 metadata_write_offset;
+
+	/* Errors (bitmap) reported by secure demux for this filter */
+	u32 error_indicators;
+
+	/* General status (bitmap) reported by secure demux for this filter */
+	u32 status_indicators;
+};
+#pragma pack(pop, sdmx)
+
+#ifdef CONFIG_QSEECOM
+
+int sdmx_open_session(int *session_handle);
+
+int sdmx_close_session(int session_handle);
+
+int sdmx_get_version(int session_handle, int32_t *version);
+
+int sdmx_set_session_cfg(int session_handle, enum sdmx_proc_mode proc_mode,
+	enum sdmx_inp_mode inp_mode, enum sdmx_pkt_format pkt_format,
+	u8 odd_scramble_bits, u8 even_scramble_bits);
+
+int sdmx_add_filter(int session_handle, u16 pid, enum sdmx_filter filter_type,
+	struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode,
+	u32 num_data_bufs, struct sdmx_data_buff_descr *data_bufs,
+	int *filter_handle, enum sdmx_raw_out_format ts_out_format, u32 flags);
+
+int sdmx_remove_filter(int session_handle, int filter_handle);
+
+int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index);
+
+int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid);
+
+int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid);
+
+int sdmx_process(int session_handle, u8 flags,
+	struct sdmx_buff_descr *input_buf_desc,
+	u32 *input_fill_count, u32 *input_read_offset,
+	u32 *error_indicators,
+	u32 *status_indicators,
+	u32 num_filters,
+	struct sdmx_filter_status *filter_status);
+
+int sdmx_get_dbg_counters(int session_handle,
+	struct sdmx_session_dbg_counters *session_counters,
+	u32 *num_filters,
+	struct sdmx_filter_dbg_counters *filter_counters);
+
+int sdmx_reset_dbg_counters(int session_handle);
+
+int sdmx_set_log_level(int session_handle, enum sdmx_log_level level);
+
+#else
+
+static inline int sdmx_open_session(int *session_handle)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_close_session(int session_handle)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_get_version(int session_handle, int32_t *version)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_set_session_cfg(int session_handle,
+	enum sdmx_proc_mode proc_mode,
+	enum sdmx_inp_mode inp_mode, enum sdmx_pkt_format pkt_format,
+	u8 odd_scramble_bits, u8 even_scramble_bits)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_add_filter(int session_handle, u16 pid,
+	enum sdmx_filter filter_type,
+	struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode,
+	u32 num_data_bufs, struct sdmx_data_buff_descr *data_bufs,
+	int *filter_handle, enum sdmx_raw_out_format ts_out_format, u32 flags)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_remove_filter(int session_handle, int filter_handle)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_set_kl_ind(int session_handle, u16 pid,
+	u32 key_ladder_index)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_add_raw_pid(int session_handle, int filter_handle,
+	u16 pid)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_remove_raw_pid(int session_handle, int filter_handle,
+	u16 pid)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_process(int session_handle, u8 flags,
+	struct sdmx_buff_descr *input_buf_desc,
+	u32 *input_fill_count, u32 *input_read_offset,
+	u32 *error_indicators,
+	u32 *status_indicators,
+	u32 num_filters,
+	struct sdmx_filter_status *filter_status)
+{
+	*status_indicators = 0;
+	*error_indicators = 0;
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_get_dbg_counters(int session_handle,
+	struct sdmx_session_dbg_counters *session_counters,
+	u32 *num_filters,
+	struct sdmx_filter_dbg_counters *filter_counters)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_reset_dbg_counters(int session_handle)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+static inline int sdmx_set_log_level(int session_handle,
+	enum sdmx_log_level level)
+{
+	return SDMX_STATUS_GENERAL_FAILURE;
+}
+
+#endif
+
+#endif /* _MPQ_SDMX_H */
diff --git a/drivers/media/platform/msm/dvb/include/mpq_adapter.h b/drivers/media/platform/msm/dvb/include/mpq_adapter.h
new file mode 100644
index 0000000..c55a5aa
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/include/mpq_adapter.h
@@ -0,0 +1,222 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MPQ_ADAPTER_H
+#define _MPQ_ADAPTER_H
+
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "mpq_stream_buffer.h"
+
+
+
+/** IDs of interfaces holding stream-buffers */
+enum mpq_adapter_stream_if {
+	/** Interface holding stream-buffer for video0 stream */
+	MPQ_ADAPTER_VIDEO0_STREAM_IF = 0,
+
+	/** Interface holding stream-buffer for video1 stream */
+	MPQ_ADAPTER_VIDEO1_STREAM_IF = 1,
+
+	/** Interface holding stream-buffer for video2 stream */
+	MPQ_ADAPTER_VIDEO2_STREAM_IF = 2,
+
+	/** Interface holding stream-buffer for video3 stream */
+	MPQ_ADAPTER_VIDEO3_STREAM_IF = 3,
+
+	/** Interface holding stream-buffer for audio0 stream */
+	MPQ_ADAPTER_AUDIO0_STREAM_IF = 4,
+
+	/** Interface holding stream-buffer for audio1 stream */
+	MPQ_ADAPTER_AUDIO1_STREAM_IF = 5,
+
+	/** Interface holding stream-buffer for audio2 stream */
+	MPQ_ADAPTER_AUDIO2_STREAM_IF = 6,
+
+	/** Interface holding stream-buffer for audio3 stream */
+	MPQ_ADAPTER_AUDIO3_STREAM_IF = 7,
+
+	/** Maximum number of interfaces holding stream-buffers */
+	MPQ_ADAPTER_MAX_NUM_OF_INTERFACES,
+};
+
+enum dmx_packet_type {
+	DMX_PES_PACKET,
+	DMX_FRAMING_INFO_PACKET,
+	DMX_EOS_PACKET,
+	DMX_MARKER_PACKET
+};
+
+struct dmx_pts_dts_info {
+	/** Indication whether PTS exist */
+	int pts_exist;
+
+	/** Indication whether DTS exist */
+	int dts_exist;
+
+	/** PTS value associated with the PES data if any */
+	u64 pts;
+
+	/** DTS value associated with the PES data if any */
+	u64 dts;
+};
+
+struct dmx_framing_packet_info {
+	/** framing pattern type, one of DMX_IDX_* definitions */
+	u64 pattern_type;
+
+	/** PTS/DTS information */
+	struct dmx_pts_dts_info pts_dts_info;
+
+	/** STC value attached to first TS packet holding the pattern */
+	u64 stc;
+
+	/*
+	 * Number of TS packets with Transport Error Indicator (TEI)
+	 * found while constructing the frame.
+	 */
+	__u32 transport_error_indicator_counter;
+
+	/* Number of continuity errors found while constructing the frame */
+	__u32 continuity_error_counter;
+
+	/*
+	 * Number of dropped bytes due to insufficient buffer space,
+	 * since last reported frame.
+	 */
+	__u32 ts_dropped_bytes;
+
+	/* Total number of TS packets holding the frame */
+	__u32 ts_packets_num;
+};
+
+struct dmx_pes_packet_info {
+	/** PTS/DTS information */
+	struct dmx_pts_dts_info pts_dts_info;
+
+	/** STC value attached to first TS packet holding the PES */
+	u64 stc;
+};
+
+struct dmx_marker_info {
+	/* marker id */
+	u64 id;
+};
+
+/** The meta-data used for video interface */
+struct mpq_adapter_video_meta_data {
+	/** meta-data packet type */
+	enum dmx_packet_type packet_type;
+
+	/** packet-type specific information */
+	union {
+		struct dmx_framing_packet_info framing;
+		struct dmx_pes_packet_info pes;
+		struct dmx_marker_info marker;
+	} info;
+} __packed;
+
+/** The meta-data used for audio interface */
+struct mpq_adapter_audio_meta_data {
+	/** meta-data packet type */
+	enum dmx_packet_type packet_type;
+
+	/** packet-type specific information */
+	union {
+		struct dmx_pes_packet_info pes;
+		struct dmx_marker_info marker;
+	} info;
+} __packed;
+
+/** Callback function to notify on registrations of specific interfaces */
+typedef void (*mpq_adapter_stream_if_callback)(
+				enum mpq_adapter_stream_if interface_id,
+				void *user_param);
+
+
+/**
+ * mpq_adapter_get - Returns pointer to Qualcomm Technologies Inc. DVB adapter
+ *
+ * Return     dvb adapter or NULL if not exist.
+ */
+struct dvb_adapter *mpq_adapter_get(void);
+
+
+/**
+ * mpq_adapter_register_stream_if - Register a stream interface.
+ *
+ * @interface_id: The interface id
+ * @stream_buffer: The buffer used for the interface
+ *
+ * Return     error status
+ *
+ * Stream interface used to connect between two units in tunneling
+ * mode using mpq_streambuffer implementation.
+ * The producer of the interface should register the new interface,
+ * consumer may get the interface using mpq_adapter_get_stream_if.
+ *
+ * Note that the function holds a pointer to this interface,
+ * stream_buffer pointer assumed to be valid as long as interface
+ * is active.
+ */
+int mpq_adapter_register_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		struct mpq_streambuffer *stream_buffer);
+
+
+/**
+ * mpq_adapter_unregister_stream_if - Un-register a stream interface.
+ *
+ * @interface_id: The interface id
+ *
+ * Return     error status
+ */
+int mpq_adapter_unregister_stream_if(
+		enum mpq_adapter_stream_if interface_id);
+
+
+/**
+ * mpq_adapter_get_stream_if - Get buffer used for a stream interface.
+ *
+ * @interface_id: The interface id
+ * @stream_buffer: The returned stream buffer
+ *
+ * Return     error status
+ */
+int mpq_adapter_get_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		struct mpq_streambuffer **stream_buffer);
+
+
+/**
+ * mpq_adapter_notify_stream_if - Register notification
+ * to be triggered when a stream interface is registered.
+ *
+ * @interface_id: The interface id
+ * @callback: The callback to be triggered when the interface is registered
+ * @user_param: A parameter that is passed back to the callback function
+ *				when triggered.
+ *
+ * Return     error status
+ *
+ * Producer may use this to register notification when desired
+ * interface registered in the system and query its information
+ * afterwards using mpq_adapter_get_stream_if.
+ * To remove the callback, this function should be called with NULL
+ * value in callback parameter.
+ */
+int mpq_adapter_notify_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		mpq_adapter_stream_if_callback callback,
+		void *user_param);
+
+#endif /* _MPQ_ADAPTER_H */
diff --git a/drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h b/drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h
new file mode 100644
index 0000000..6550ddd
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MPQ_DVB_DEBUG_H
+#define _MPQ_DVB_DEBUG_H
+
+/* Enable this line if you want to output debug printouts */
+#define MPG_DVB_DEBUG_ENABLE
+
+#undef MPQ_DVB_DBG_PRINT		/* undef it, just in case */
+
+#ifdef MPG_DVB_DEBUG_ENABLE
+#define MPQ_DVB_ERR_PRINT(fmt, args...) pr_err(fmt, ## args)
+#define MPQ_DVB_WARN_PRINT(fmt, args...) pr_warn(fmt, ## args)
+#define MPQ_DVB_NOTICE_PRINT(fmt, args...) pr_notice(fmt, ## args)
+#define MPQ_DVB_DBG_PRINT(fmt, args...) pr_debug(fmt, ## args)
+#else  /* MPG_DVB_DEBUG_ENABLE */
+#define MPQ_DVB_ERR_PRINT(fmt, args...)
+#define MPQ_DVB_WARN_PRINT(fmt, args...)
+#define MPQ_DVB_NOTICE_PRINT(fmt, args...)
+#define MPQ_DVB_DBG_PRINT(fmt, args...)
+#endif /* MPG_DVB_DEBUG_ENABLE */
+
+
+/*
+ * The following can be used to disable specific printout
+ * by adding a letter to the end of MPQ_DVB_DBG_PRINT
+ */
+#undef MPQ_DVB_DBG_PRINTT
+#define MPQ_DVB_DBG_PRINTT(fmt, args...)
+
+#endif /* _MPQ_DVB_DEBUG_H */
diff --git a/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
new file mode 100644
index 0000000..6240451
--- /dev/null
+++ b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
@@ -0,0 +1,494 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MPQ_STREAM_BUFFER_H
+#define _MPQ_STREAM_BUFFER_H
+
+#include "dvb_ringbuffer.h"
+
+/**
+ * DOC: MPQ Stream Buffer
+ *
+ * A stream buffer implementation is used to transfer data between two units
+ * such as demux and decoders. The implementation relies on dvb_ringbuffer
+ * implementation. Refer to dvb_ringbuffer.h for details.
+ *
+ * The implementation uses two dvb_ringbuffers, one to pass the
+ * raw-data (PES payload for example) and the other to pass
+ * meta-data (information from PES header for example).
+ *
+ * The meta-data uses dvb_ringbuffer packet interface. Each meta-data
+ * packet points to the data buffer, and includes the offset to the data in the
+ * buffer, the size of raw-data described by the meta-data packet, and also the
+ * size of user's own parameters if any required.
+ *
+ * Data can be managed in two ways: ring-buffer & linear buffers, as specified
+ * in initialization when calling the mpq_streambuffer_init function.
+ * For managing data as a ring buffer exactly 1 data buffer descriptor must be
+ * specified in initialization. For this mode, dvb_ringbuffer is used "as-is".
+ * For managing data in several linear buffers, an array of buffer descriptors
+ * must be passed.
+ * For both modes, data descriptor(s) must be remain valid throughout the life
+ * span of the mpq_streambuffer object.
+ * Apart from initialization API remains the same for both modes.
+ *
+ * Contrary to dvb_ringbuffer implementation, this API makes sure there's
+ * enough data to read/write when making read/write operations.
+ * Users interested to flush/reset specific buffer, check for bytes
+ * ready or space available for write should use the respective services
+ * in dvb_ringbuffer (dvb_ringbuffer_avail, dvb_ringbuffer_free,
+ * dvb_ringbuffer_reset, dvb_ringbuffer_flush,
+ * dvb_ringbuffer_flush_spinlock_wakeup).
+ *
+ * Concurrency protection is handled in the same manner as in
+ * dvb_ringbuffer implementation.
+ *
+ * Typical call flow from producer:
+ *
+ * - Start writing the raw-data of new packet, the following call is
+ *   repeated until end of data of the specific packet
+ *
+ *      mpq_streambuffer_data_write(...)
+ *
+ * - Now write a new packet describing the new available raw-data
+ *      mpq_streambuffer_pkt_write(...)
+ *
+ *   For linear buffer mode, writing a new packet with data size > 0, causes the
+ *   current buffer to be marked as pending for reading, and triggers moving to
+ *   the next available buffer, that shall now be the current write buffer.
+ *
+ * Typical call flow from consumer:
+ *
+ * - Poll for next available packet:
+ *      mpq_streambuffer_pkt_next(&streambuff,-1,&len)
+ *
+ *   In different approach, consumer can wait on event for new data and then
+ *   call mpq_streambuffer_pkt_next, waiting for data can be done as follows:
+ *
+ *      wait_event_interruptible(
+ *			streambuff->packet_data->queue,
+ *			!dvb_ringbuffer_empty(&streambuff->packet_data) ||
+ *			(streambuff->packet_data.error != 0);
+ *
+ * - Get the new packet information:
+ *      mpq_streambuffer_pkt_read(..)
+ *
+ * - Read the raw-data of the new packet. Here you can use two methods:
+ *
+ *   1. Read the data to a user supplied buffer:
+ *         mpq_streambuffer_data_read()
+ *
+ *      In this case memory copy is done, read pointer is updated in the raw
+ *      data buffer, the amount of raw-data is provided part of the
+ *      packet's information. User should then call mpq_streambuffer_pkt_dispose
+ *      with dispose_data set to 0 as the raw-data was already disposed.
+ *      Note that secure buffer cannot be accessed directly and an error will
+ *      occur.
+ *
+ *   2. Access the data directly using the raw-data address. The address
+ *      of the raw data is provided part of the packet's information. User
+ *      then should call mpq_streambuffer_pkt_dispose with dispose_data set
+ *      to 1 to dispose the packet along with it's raw-data.
+ *
+ * - Disposal of packets:
+ *      mpq_streambuffer_pkt_dispose(...)
+ *
+ *   For linear buffer mode, disposing of a packet with data size > 0,
+ *   regardless of the 'dispose_data' parameter, causes the current buffer's
+ *   data to be disposed and marked as free for writing, and triggers moving to
+ *   the next available buffer, that shall now be the current read buffer.
+ */
+
+struct mpq_streambuffer;
+struct mpq_streambuffer_packet_header;
+
+typedef void (*mpq_streambuffer_dispose_cb) (
+	struct mpq_streambuffer *sbuff,
+	u32 offset,
+	size_t len,
+	void *user_data);
+
+enum mpq_streambuffer_mode {
+	MPQ_STREAMBUFFER_BUFFER_MODE_RING,
+	MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR
+};
+
+/**
+ * struct mpq_streambuffer - mpq stream buffer representation
+ *
+ * @raw_data: The buffer used to hold raw-data, or linear buffer descriptors
+ * @packet_data: The buffer user to hold the meta-data
+ * @buffers: array of buffer descriptor(s) holding buffer initial & dynamic
+ *	     buffer information
+ * @mode: mpq_streambuffer buffer management work mode - Ring-buffer or Linear
+ *	  buffers
+ * @buffers_num: number of data buffers to manage
+ * @pending_buffers_count: for linear buffer management, counts the number of
+ * buffer that has been
+ */
+struct mpq_streambuffer {
+	struct dvb_ringbuffer raw_data;
+	struct dvb_ringbuffer packet_data;
+	struct mpq_streambuffer_buffer_desc *buffers;
+	enum mpq_streambuffer_mode mode;
+	u32 buffers_num;
+	u32 pending_buffers_count;
+	mpq_streambuffer_dispose_cb cb;
+	void *cb_user_data;
+};
+
+/**
+ * mpq_streambuffer_linear_desc
+ * @handle:	ION handle's file descriptor of buffer
+ * @base:	kernel mapped address to start of buffer.
+ *		Can be NULL for secured buffers
+ * @size:	size of buffer
+ * @read_ptr:	initial read pointer value (should normally be 0)
+ * @write_ptr:	initial write pointer value (should normally be 0)
+ */
+struct mpq_streambuffer_buffer_desc {
+	int	handle;
+	void	*base;
+	u32	size;
+	u32	read_ptr;
+	u32	write_ptr;
+};
+
+/**
+ * struct mpq_streambuffer_packet_header - packet header saved in packet buffer
+ * @user_data_len: length of private user (meta) data
+ * @raw_data_handle: ION handle's file descriptor of raw-data buffer
+ * @raw_data_offset: offset of raw-data from start of buffer (0 for linear)
+ * @raw_data_len: size of raw-data in the raw-data buffer (can be 0)
+ *
+ * The packet structure that is saved in each packet-buffer:
+ * user_data_len
+ * raw_data_handle
+ * raw_data_offset
+ * raw_data_len
+ * private user-data bytes
+ */
+struct mpq_streambuffer_packet_header {
+	u32 user_data_len;
+	int raw_data_handle;
+	u32 raw_data_offset;
+	u32 raw_data_len;
+} __packed;
+
+/**
+ * mpq_streambuffer_init - Initialize a new stream buffer
+ *
+ * @sbuff: The buffer to initialize
+ * @data_buffers: array of data buffer descriptor(s).
+ *		  Data descriptor(s) must be remain valid throughout the life
+ *		  span of the mpq_streambuffer object
+ * @data_buff_num: number of data buffer in array
+ * @packet_buff: The buffer holding meta-data
+ * @packet_buff_size: Size of meta-data buffer
+ *
+ * Return	Error status, -EINVAL if any of the arguments are invalid
+ *
+ * Note:
+ * for data_buff_num > 1, mpq_streambuffer object manages these buffers as a
+ * separated set of linear buffers. A linear buffer cannot wrap-around and one
+ * can only write as many data bytes as the buffer's size. Data will not be
+ * written to the next free buffer.
+ */
+int mpq_streambuffer_init(
+		struct mpq_streambuffer *sbuff,
+		enum mpq_streambuffer_mode mode,
+		struct mpq_streambuffer_buffer_desc *data_buffers,
+		u32 data_buff_num,
+		void *packet_buff,
+		size_t packet_buff_size);
+
+/**
+ * mpq_streambuffer_terminate - Terminate stream buffer
+ *
+ * @sbuff: The buffer to terminate
+ *
+ * The function sets the the buffers error flags to ENODEV
+ * and wakeup any waiting threads on the buffer queues.
+ * Threads waiting on the buffer queues should check if
+ * error was set.
+ */
+void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff);
+
+/**
+ * mpq_streambuffer_packet_next - Returns index of next available packet.
+ *
+ * @sbuff: The stream buffer
+ * @idx: Previous packet index or -1 to return index of the the first
+ *       available packet.
+ * @pktlen: The length of the ready packet
+ *
+ * Return index to the packet-buffer, -1 if buffer is empty
+ *
+ * After getting the index, the user of this function can either
+ * access the packet buffer directly using the returned index
+ * or ask to read the data back from the buffer using mpq_ringbuffer_pkt_read
+ */
+ssize_t mpq_streambuffer_pkt_next(
+		struct mpq_streambuffer *sbuff,
+		ssize_t idx, size_t *pktlen);
+
+/**
+ * mpq_streambuffer_pkt_read - Reads out the packet from the provided index.
+ *
+ * @sbuff: The stream buffer
+ * @idx: The index of the packet to be read
+ * @packet: The read packet's header
+ * @user_data: The read private user data
+ *
+ * Return  The actual number of bytes read, -EINVAL if the packet is
+ * already disposed or the packet-data is invalid.
+ *
+ * The packet is not disposed after this function is called, to dispose it
+ * along with the raw-data it points to use mpq_streambuffer_pkt_dispose.
+ * If there are no private user-data, the user-data pointer can be NULL.
+ * The caller of this function must make sure that the private user-data
+ * buffer has enough space for the private user-data length
+ */
+ssize_t mpq_streambuffer_pkt_read(
+		struct mpq_streambuffer *sbuff,
+		size_t idx,
+		struct mpq_streambuffer_packet_header *packet,
+		u8 *user_data);
+
+/**
+ * mpq_streambuffer_pkt_dispose - Disposes a packet from the packet buffer
+ *
+ * @sbuff: The stream buffer
+ * @idx: The index of the packet to be disposed
+ * @dispose_data: Indicates whether to update the read pointer inside the
+ * raw-data buffer for the respective data pointed by the packet.
+ *
+ * Return  error status, -EINVAL if the packet-data is invalid
+ *
+ * The function updates the read pointer inside the raw-data buffer
+ * for the respective data pointed by the packet if dispose_data is set.
+ */
+int mpq_streambuffer_pkt_dispose(
+		struct mpq_streambuffer *sbuff,
+		size_t idx,
+		int dispose_data);
+
+/**
+ * mpq_streambuffer_pkt_write - Write a new packet to the packet buffer.
+ *
+ * @sbuff: The stream buffer
+ * @packet: The packet header to write
+ * @user_data: The private user-data to be written
+ *
+ * Return  error status, -ENOSPC if there's no space to write the packet
+ */
+int mpq_streambuffer_pkt_write(
+		struct mpq_streambuffer *sbuff,
+		struct mpq_streambuffer_packet_header *packet,
+		u8 *user_data);
+
+/**
+ * mpq_streambuffer_data_write - Write data to raw-data buffer
+ *
+ * @sbuff: The stream buffer
+ * @buf: The buffer holding the data to be written
+ * @len: The length of the data buffer
+ *
+ * Return  The actual number of bytes written or -ENOSPC if
+ *			no space to write the data
+ */
+ssize_t mpq_streambuffer_data_write(
+		struct mpq_streambuffer *sbuff,
+		const u8 *buf, size_t len);
+
+/**
+ * mpq_streambuffer_data_write_deposit - Advances the raw-buffer write pointer.
+ * Assumes the raw-data was written by the user directly
+ *
+ * @sbuff: The stream buffer
+ * @len: The length of the raw-data that was already written
+ *
+ * Return  error status
+ */
+int mpq_streambuffer_data_write_deposit(
+		struct mpq_streambuffer *sbuff,
+		size_t len);
+
+/**
+ * mpq_streambuffer_data_read - Reads out raw-data to the provided buffer.
+ *
+ * @sbuff: The stream buffer
+ * @buf: The buffer to read the raw-data data to
+ * @len: The length of the buffer that will hold the raw-data
+ *
+ * Return  The actual number of bytes read or error code
+ *
+ * This function copies the data from the ring-buffer to the
+ * provided buf parameter. The user can save the extra copy by accessing
+ * the data pointer directly and reading from it, then update the
+ * read pointer by the amount of data that was read using
+ * mpq_streambuffer_data_read_dispose
+ */
+ssize_t mpq_streambuffer_data_read(
+		struct mpq_streambuffer *sbuff,
+		u8 *buf, size_t len);
+
+/**
+ * mpq_streambuffer_data_read_user
+ *
+ * Same as mpq_streambuffer_data_read except data can be copied to user-space
+ * buffer.
+ */
+ssize_t mpq_streambuffer_data_read_user(
+		struct mpq_streambuffer *sbuff,
+		u8 __user *buf, size_t len);
+
+/**
+ * mpq_streambuffer_data_read_dispose - Advances the raw-buffer read pointer.
+ * Assumes the raw-data was read by the user directly.
+ *
+ * @sbuff:	The stream buffer
+ * @len:	The length of the raw-data to be disposed
+ *
+ * Return  error status, -EINVAL if buffer there's no enough data to
+ *			be disposed
+ *
+ * The user can instead dispose a packet along with the data in the
+ * raw-data buffer using mpq_streambuffer_pkt_dispose.
+ */
+int mpq_streambuffer_data_read_dispose(
+		struct mpq_streambuffer *sbuff,
+		size_t len);
+/**
+ * mpq_streambuffer_get_buffer_handle - Returns the current linear buffer
+ * ION handle.
+ * @sbuff: The stream buffer
+ * @read_buffer: specifies if a read buffer handle is requested (when set),
+ *		 or a write buffer handle is requested.
+ *		 For linear buffer mode read & write buffers may be different
+ *		 buffers. For ring buffer mode, the same (single) buffer handle
+ *		 is returned.
+ * buffer handle
+ * @handle: returned handle
+ *
+ * Return error status
+ * -EINVAL is arguments are invalid.
+ * -EPERM if stream buffer specified was not initialized with linear support.
+ */
+int mpq_streambuffer_get_buffer_handle(
+	struct mpq_streambuffer *sbuff,
+	int read_buffer,
+	int *handle);
+
+/**
+ * mpq_streambuffer_data_free - Returns number of free bytes in data buffer.
+ * @sbuff: The stream buffer object
+ *
+ * Note: for linear buffer management this return number of free bytes in the
+ * current write buffer only.
+ */
+ssize_t mpq_streambuffer_data_free(
+	struct mpq_streambuffer *sbuff);
+
+/**
+ * mpq_streambuffer_data_avail - Returns number of bytes in data buffer that
+ * can be read.
+ * @sbuff: The stream buffer object
+ *
+ * Note: for linear buffer management this return number of data bytes in the
+ * current read buffer only.
+ */
+ssize_t mpq_streambuffer_data_avail(
+	struct mpq_streambuffer *sbuff);
+
+/**
+ * mpq_streambuffer_register_pkt_dispose - Registers a callback to notify on
+ * packet disposal events.
+ * can be read.
+ * @sbuff: The stream buffer object
+ * @cb_func: user callback function
+ * @user_data: user data to be passed to callback function.
+ *
+ * Returns error status
+ * -EINVAL if arguments are invalid
+ */
+int mpq_streambuffer_register_data_dispose(
+	struct mpq_streambuffer *sbuff,
+	mpq_streambuffer_dispose_cb cb_func,
+	void *user_data);
+
+/**
+ * mpq_streambuffer_data_rw_offset - returns read/write offsets of current data
+ * buffer.
+ * @sbuff: The stream buffer object
+ * @read_offset: returned read offset
+ * @write_offset: returned write offset
+ *
+ * Note: read offset or write offset may be NULL if not required.
+ * Returns error status
+ * -EINVAL if arguments are invalid
+ */
+int mpq_streambuffer_get_data_rw_offset(
+	struct mpq_streambuffer *sbuff,
+	u32 *read_offset,
+	u32 *write_offset);
+
+/**
+ * mpq_streambuffer_metadata_free - returns number of free bytes in the meta
+ * data buffer, or error status.
+ * @sbuff: the stream buffer object
+ */
+ssize_t mpq_streambuffer_metadata_free(struct mpq_streambuffer *sbuff);
+
+/**
+ * mpq_streambuffer_flush - flush both pending packets and data in buffer
+ *
+ * @sbuff: the stream buffer object
+ *
+ * Returns error status
+ */
+int mpq_streambuffer_flush(struct mpq_streambuffer *sbuff);
+
+/*
+ *  ------------------------------------------------------
+ *  Consumer or AV Decoder Stream Interface to Ring Buffer
+ *  ------------------------------------------------------
+ *  Producer is Demux Driver
+ *  ------------------------
+ *
+ *  call from Audio/Video Decoder Driver to find Audio/Video
+ *  streambuffer AV handles, "DMX_PES_AUDIO0 through 3" or
+ *  DMX_PES_VIDEO0 through 3" interfaces corresponding to 4 programs.
+ */
+
+/* call from Audio/Video Decoder Driver via POLLING to consume
+ * Headers and Compressed data from ring buffer using streambuffer handle.
+ * hdrdata[] and cdata[] buffers have to be malloc'd by consumer
+ *
+ *  --------------------------
+ *  Consumer Calling Sequence
+ *  --------------------------
+ *  Find the streambuffer corresponding to a DMX TS PES stream instance.
+ *  1. consumer_audio_streambuffer() or consumer_video_streambuffer()
+ *  Process the packet headers if required.
+ *  2. mpq_read_new_packet_hdr_data()
+ *  Process the compressed data by forwarding to AV decoder.
+ *  3. mpq_read_new_packet_compressed_data()
+ *  Dispose the packet.
+ *  4. mpq_dispose_new_packet_read()
+ *
+ *  The Audio/Video drivers (or consumers) require the stream_buffer information
+ *  for consuming packet headers and compressed AV data from the
+ *  ring buffer filled by demux driver which is the producer
+ */
+
+#endif /* _MPQ_STREAM_BUFFER_H */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 44a29aa..a195c15 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -1021,6 +1021,7 @@
 {
 	int i, size, ret = 0;
 	char name[32];
+	struct sched_param param = { .sched_priority = 5 };
 
 	size = sizeof(struct sde_rot_queue) * mgr->queue_count;
 	mgr->commitq = devm_kzalloc(mgr->device, size, GFP_KERNEL);
@@ -1031,11 +1032,21 @@
 		snprintf(name, sizeof(name), "rot_commitq_%d_%d",
 				mgr->device->id, i);
 		SDEROT_DBG("work queue name=%s\n", name);
-		mgr->commitq[i].rot_work_queue =
-			alloc_ordered_workqueue("%s",
-				WQ_MEM_RECLAIM | WQ_HIGHPRI, name);
-		if (!mgr->commitq[i].rot_work_queue) {
+		kthread_init_worker(&mgr->commitq[i].rot_kw);
+		mgr->commitq[i].rot_thread = kthread_run(kthread_worker_fn,
+				&mgr->commitq[i].rot_kw, name);
+		if (IS_ERR(mgr->commitq[i].rot_thread)) {
 			ret = -EPERM;
+			mgr->commitq[i].rot_thread = NULL;
+			break;
+		}
+
+		ret = sched_setscheduler(mgr->commitq[i].rot_thread,
+			SCHED_FIFO, &param);
+		if (ret) {
+			SDEROT_ERR(
+				"failed to set kthread priority for commitq %d\n",
+				ret);
 			break;
 		}
 
@@ -1052,10 +1063,21 @@
 		snprintf(name, sizeof(name), "rot_doneq_%d_%d",
 				mgr->device->id, i);
 		SDEROT_DBG("work queue name=%s\n", name);
-		mgr->doneq[i].rot_work_queue = alloc_ordered_workqueue("%s",
-				WQ_MEM_RECLAIM | WQ_HIGHPRI, name);
-		if (!mgr->doneq[i].rot_work_queue) {
+		kthread_init_worker(&mgr->doneq[i].rot_kw);
+		mgr->doneq[i].rot_thread = kthread_run(kthread_worker_fn,
+				&mgr->doneq[i].rot_kw, name);
+		if (IS_ERR(mgr->doneq[i].rot_thread)) {
 			ret = -EPERM;
+			mgr->doneq[i].rot_thread = NULL;
+			break;
+		}
+
+		ret = sched_setscheduler(mgr->doneq[i].rot_thread,
+			SCHED_FIFO, &param);
+		if (ret) {
+			SDEROT_ERR(
+				"failed to set kthread priority for doneq %d\n",
+				ret);
 			break;
 		}
 
@@ -1071,18 +1093,20 @@
 
 	if (mgr->commitq) {
 		for (i = 0; i < mgr->queue_count; i++) {
-			if (mgr->commitq[i].rot_work_queue)
-				destroy_workqueue(
-					mgr->commitq[i].rot_work_queue);
+			if (mgr->commitq[i].rot_thread) {
+				kthread_flush_worker(&mgr->commitq[i].rot_kw);
+				kthread_stop(mgr->commitq[i].rot_thread);
+			}
 		}
 		devm_kfree(mgr->device, mgr->commitq);
 		mgr->commitq = NULL;
 	}
 	if (mgr->doneq) {
 		for (i = 0; i < mgr->queue_count; i++) {
-			if (mgr->doneq[i].rot_work_queue)
-				destroy_workqueue(
-					mgr->doneq[i].rot_work_queue);
+			if (mgr->doneq[i].rot_thread) {
+				kthread_flush_worker(&mgr->doneq[i].rot_kw);
+				kthread_stop(mgr->doneq[i].rot_thread);
+			}
 		}
 		devm_kfree(mgr->device, mgr->doneq);
 		mgr->doneq = NULL;
@@ -1203,7 +1227,7 @@
 
 		if (entry->item.ts)
 			entry->item.ts[SDE_ROTATOR_TS_QUEUE] = ktime_get();
-		queue_work(queue->rot_work_queue, &entry->commit_work);
+		kthread_queue_work(&queue->rot_kw, &entry->commit_work);
 	}
 }
 
@@ -1423,12 +1447,13 @@
  *
  * Note this asynchronous handler is protected by hal lock.
  */
-static void sde_rotator_commit_handler(struct work_struct *work)
+static void sde_rotator_commit_handler(struct kthread_work *work)
 {
 	struct sde_rot_entry *entry;
 	struct sde_rot_entry_container *request;
 	struct sde_rot_hw_resource *hw;
 	struct sde_rot_mgr *mgr;
+	struct sched_param param = { .sched_priority = 5 };
 	int ret;
 
 	entry = container_of(work, struct sde_rot_entry, commit_work);
@@ -1439,6 +1464,12 @@
 		return;
 	}
 
+	ret = sched_setscheduler(entry->fenceq->rot_thread, SCHED_FIFO, &param);
+	if (ret) {
+		SDEROT_WARN("Fail to set kthread priority for fenceq: %d\n",
+				ret);
+	}
+
 	mgr = entry->private->mgr;
 
 	SDEROT_EVTLOG(
@@ -1514,7 +1545,7 @@
 
 	SDEROT_EVTLOG(entry->item.session_id, 1);
 
-	queue_work(entry->doneq->rot_work_queue, &entry->done_work);
+	kthread_queue_work(&entry->doneq->rot_kw, &entry->done_work);
 	sde_rot_mgr_unlock(mgr);
 	return;
 error:
@@ -1526,8 +1557,8 @@
 	sde_rotator_release_entry(mgr, entry);
 	atomic_dec(&request->pending_count);
 	atomic_inc(&request->failed_count);
-	if (request->retireq && request->retire_work)
-		queue_work(request->retireq, request->retire_work);
+	if (request->retire_kw && request->retire_work)
+		kthread_queue_work(request->retire_kw, request->retire_work);
 	sde_rot_mgr_unlock(mgr);
 }
 
@@ -1541,7 +1572,7 @@
  *
  * Note this asynchronous handler is protected by hal lock.
  */
-static void sde_rotator_done_handler(struct work_struct *work)
+static void sde_rotator_done_handler(struct kthread_work *work)
 {
 	struct sde_rot_entry *entry;
 	struct sde_rot_entry_container *request;
@@ -1606,8 +1637,8 @@
 	ATRACE_INT("sde_rot_done", 1);
 	sde_rotator_release_entry(mgr, entry);
 	atomic_dec(&request->pending_count);
-	if (request->retireq && request->retire_work)
-		queue_work(request->retireq, request->retire_work);
+	if (request->retire_kw && request->retire_work)
+		kthread_queue_work(request->retire_kw, request->retire_work);
 	if (entry->item.ts)
 		entry->item.ts[SDE_ROTATOR_TS_RETIRE] = ktime_get();
 	sde_rot_mgr_unlock(mgr);
@@ -1966,8 +1997,10 @@
 
 		entry->request = req;
 
-		INIT_WORK(&entry->commit_work, sde_rotator_commit_handler);
-		INIT_WORK(&entry->done_work, sde_rotator_done_handler);
+		kthread_init_work(&entry->commit_work,
+				sde_rotator_commit_handler);
+		kthread_init_work(&entry->done_work,
+				sde_rotator_done_handler);
 		SDEROT_DBG(
 			"Entry added. wbidx=%u, src{%u,%u,%u,%u}f=%x dst{%u,%u,%u,%u}f=%x session_id=%u\n",
 			item->wb_idx,
@@ -2016,8 +2049,8 @@
 		sde_rot_mgr_unlock(mgr);
 		for (i = req->count - 1; i >= 0; i--) {
 			entry = req->entries + i;
-			cancel_work_sync(&entry->commit_work);
-			cancel_work_sync(&entry->done_work);
+			kthread_cancel_work_sync(&entry->commit_work);
+			kthread_cancel_work_sync(&entry->done_work);
 		}
 		sde_rot_mgr_lock(mgr);
 		SDEROT_DBG("cancel work done\n");
@@ -2134,7 +2167,7 @@
 
 	sde_rot_mgr_unlock(mgr);
 	for (i = 0; i < req->count; i++)
-		flush_work(&req->entries[i].commit_work);
+		kthread_flush_work(&req->entries[i].commit_work);
 	sde_rot_mgr_lock(mgr);
 }
 
@@ -2925,7 +2958,7 @@
 	*pmgr = mgr;
 	ret = sde_rotator_footswitch_ctrl(mgr, true);
 	if (ret) {
-		SDEROT_ERR("res_init failed %d\n", ret);
+		SDEROT_INFO("res_init failed %d, use probe defer\n", ret);
 		ret = -EPROBE_DEFER;
 		goto error_fs_en_fail;
 	}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 7b8a066..731ff1e 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -21,7 +21,7 @@
 #include <linux/types.h>
 #include <linux/cdev.h>
 #include <linux/pm_runtime.h>
-#include <linux/completion.h>
+#include <linux/kthread.h>
 
 #include "sde_rotator_base.h"
 #include "sde_rotator_util.h"
@@ -230,7 +230,8 @@
 };
 
 struct sde_rot_queue {
-	struct workqueue_struct *rot_work_queue;
+	struct kthread_worker rot_kw;
+	struct task_struct *rot_thread;
 	struct sde_rot_timeline *timeline;
 	struct sde_rot_hw_resource *hw;
 };
@@ -253,8 +254,8 @@
 	u32 count;
 	atomic_t pending_count;
 	atomic_t failed_count;
-	struct workqueue_struct *retireq;
-	struct work_struct *retire_work;
+	struct kthread_worker *retire_kw;
+	struct kthread_work *retire_work;
 	bool finished;
 	struct sde_rot_entry *entries;
 };
@@ -284,8 +285,8 @@
  */
 struct sde_rot_entry {
 	struct sde_rotation_item item;
-	struct work_struct commit_work;
-	struct work_struct done_work;
+	struct kthread_work commit_work;
+	struct kthread_work done_work;
 	struct sde_rot_queue *commitq;
 	struct sde_rot_queue *fenceq;
 	struct sde_rot_queue *doneq;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index 2e91d54..d300de2 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -54,8 +54,8 @@
 #define SDE_ROTATOR_DEGREE_180		180
 #define SDE_ROTATOR_DEGREE_90		90
 
-static void sde_rotator_submit_handler(struct work_struct *work);
-static void sde_rotator_retire_handler(struct work_struct *work);
+static void sde_rotator_submit_handler(struct kthread_work *work);
+static void sde_rotator_retire_handler(struct kthread_work *work);
 #ifdef CONFIG_COMPAT
 static long sde_rotator_compat_ioctl32(struct file *file,
 	unsigned int cmd, unsigned long arg);
@@ -467,8 +467,8 @@
 			SDEDEV_DBG(rot_dev->dev, "cancel request s:%d\n",
 					ctx->session_id);
 			mutex_unlock(q->lock);
-			cancel_work_sync(&request->submit_work);
-			cancel_work_sync(&request->retire_work);
+			kthread_cancel_work_sync(&request->submit_work);
+			kthread_cancel_work_sync(&request->retire_work);
 			mutex_lock(q->lock);
 			spin_lock(&ctx->list_lock);
 			list_del_init(&request->list);
@@ -926,9 +926,9 @@
 	for (i = 0 ; i < ARRAY_SIZE(ctx->requests); i++) {
 		struct sde_rotator_request *request = &ctx->requests[i];
 
-		INIT_WORK(&request->submit_work,
+		kthread_init_work(&request->submit_work,
 				sde_rotator_submit_handler);
-		INIT_WORK(&request->retire_work,
+		kthread_init_work(&request->retire_work,
 				sde_rotator_retire_handler);
 		request->ctx = ctx;
 		INIT_LIST_HEAD(&request->list);
@@ -965,14 +965,16 @@
 
 	snprintf(name, sizeof(name), "rot_fenceq_%d_%d", rot_dev->dev->id,
 			ctx->session_id);
-	ctx->work_queue.rot_work_queue = alloc_ordered_workqueue("%s",
-			WQ_MEM_RECLAIM | WQ_HIGHPRI, name);
-	if (!ctx->work_queue.rot_work_queue) {
-		SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate workqueue\n");
+	kthread_init_worker(&ctx->work_queue.rot_kw);
+	ctx->work_queue.rot_thread = kthread_run(kthread_worker_fn,
+			&ctx->work_queue.rot_kw, name);
+	if (IS_ERR(ctx->work_queue.rot_thread)) {
+		SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate kthread\n");
 		ret = -EPERM;
+		ctx->work_queue.rot_thread = NULL;
 		goto error_alloc_workqueue;
 	}
-	SDEDEV_DBG(ctx->rot_dev->dev, "work queue name=%s\n", name);
+	SDEDEV_DBG(ctx->rot_dev->dev, "kthread name=%s\n", name);
 
 	snprintf(name, sizeof(name), "%d_%d", rot_dev->dev->id,
 			ctx->session_id);
@@ -1022,7 +1024,8 @@
 error_open_session:
 	sde_rot_mgr_unlock(rot_dev->mgr);
 	sde_rotator_destroy_timeline(ctx->work_queue.timeline);
-	destroy_workqueue(ctx->work_queue.rot_work_queue);
+	kthread_flush_worker(&ctx->work_queue.rot_kw);
+	kthread_stop(ctx->work_queue.rot_thread);
 error_alloc_workqueue:
 	sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group);
 error_create_sysfs:
@@ -1072,7 +1075,7 @@
 
 		SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n",
 				session_id);
-		cancel_work_sync(&request->submit_work);
+		kthread_cancel_work_sync(&request->submit_work);
 	}
 	SDEDEV_DBG(rot_dev->dev, "release session s:%d\n", session_id);
 	sde_rot_mgr_lock(rot_dev->mgr);
@@ -1085,12 +1088,13 @@
 
 		SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n",
 				session_id);
-		cancel_work_sync(&request->retire_work);
+		kthread_cancel_work_sync(&request->retire_work);
 	}
 	mutex_lock(&rot_dev->lock);
 	SDEDEV_DBG(rot_dev->dev, "release context s:%d\n", session_id);
 	sde_rotator_destroy_timeline(ctx->work_queue.timeline);
-	destroy_workqueue(ctx->work_queue.rot_work_queue);
+	kthread_flush_worker(&ctx->work_queue.rot_kw);
+	kthread_stop(ctx->work_queue.rot_thread);
 	sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group);
 	kobject_put(&ctx->kobj);
 	if (ctx->file) {
@@ -1609,7 +1613,7 @@
 		} else {
 			SDEROT_ERR("invalid stats timestamp\n");
 		}
-		req->retireq = ctx->work_queue.rot_work_queue;
+		req->retire_kw = &ctx->work_queue.rot_kw;
 		req->retire_work = &request->retire_work;
 
 		trace_rot_entry_fence(
@@ -2719,7 +2723,7 @@
  *
  * This function is scheduled in work queue context.
  */
-static void sde_rotator_retire_handler(struct work_struct *work)
+static void sde_rotator_retire_handler(struct kthread_work *work)
 {
 	struct vb2_v4l2_buffer *src_buf;
 	struct vb2_v4l2_buffer *dst_buf;
@@ -2909,7 +2913,7 @@
 		goto error_init_request;
 	}
 
-	req->retireq = ctx->work_queue.rot_work_queue;
+	req->retire_kw = &ctx->work_queue.rot_kw;
 	req->retire_work = &request->retire_work;
 
 	ret = sde_rotator_handle_request_common(
@@ -2938,7 +2942,7 @@
  *
  * This function is scheduled in work queue context.
  */
-static void sde_rotator_submit_handler(struct work_struct *work)
+static void sde_rotator_submit_handler(struct kthread_work *work)
 {
 	struct sde_rotator_ctx *ctx;
 	struct sde_rotator_device *rot_dev;
@@ -3203,7 +3207,7 @@
 			list_del_init(&request->list);
 			list_add_tail(&request->list, &ctx->pending_list);
 			spin_unlock(&ctx->list_lock);
-			queue_work(ctx->work_queue.rot_work_queue,
+			kthread_queue_work(&ctx->work_queue.rot_kw,
 					&request->submit_work);
 		}
 	} else if (request && !atomic_read(&request->req->pending_count)) {
@@ -3287,7 +3291,10 @@
 
 	ret = sde_rotator_core_init(&rot_dev->mgr, pdev);
 	if (ret < 0) {
-		SDEDEV_ERR(&pdev->dev, "fail init core %d\n", ret);
+		if (ret == -EPROBE_DEFER)
+			SDEDEV_INFO(&pdev->dev, "probe defer for core init\n");
+		else
+			SDEDEV_ERR(&pdev->dev, "fail init core %d\n", ret);
 		goto error_rotator_core_init;
 	}
 
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
index 100ce27..627ea86 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
@@ -23,6 +23,7 @@
 #include <linux/msm-bus.h>
 #include <linux/platform_device.h>
 #include <linux/soc/qcom/llcc-qcom.h>
+#include <linux/kthread.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-ctrls.h>
@@ -95,8 +96,8 @@
  */
 struct sde_rotator_request {
 	struct list_head list;
-	struct work_struct submit_work;
-	struct work_struct retire_work;
+	struct kthread_work submit_work;
+	struct kthread_work retire_work;
 	struct sde_rot_entry_container *req;
 	struct sde_rotator_ctx *ctx;
 	bool committed;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index b582934..743d2f7 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -57,6 +57,9 @@
 
 #define DEFAULT_MAXLINEWIDTH	4096
 
+/* stride alignment requirement for avoiding partial writes */
+#define PARTIAL_WRITE_ALIGNMENT	0x1F
+
 /* Macro for constructing the REGDMA command */
 #define SDE_REGDMA_WRITE(p, off, data) \
 	do { \
@@ -869,6 +872,8 @@
 	SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_SIZE, 0x00010001);
 	SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_IMG_SIZE, 0x00010001);
 	SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_XY, 0);
+	SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_WRITE_CONFIG,
+			(ctx->rot->highest_bank & 0x3) << 8);
 	SDE_REGDMA_WRITE(wrptr, ROTTOP_DNSC, 0);
 	SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, 1);
 	SDE_REGDMA_MODIFY(wrptr, REGDMA_TIMESTAMP_REG, mask, swts);
@@ -1270,7 +1275,7 @@
 	u32 *wrptr;
 	u32 pack = 0;
 	u32 dst_format = 0;
-	u32 partial_write = 0;
+	u32 no_partial_writes = 0;
 	int i;
 
 	wrptr = sde_hw_rotator_get_regdma_segment(ctx);
@@ -1355,12 +1360,34 @@
 			(cfg->h_downscale_factor << 16));
 
 	/* partial write check */
-	if (test_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map) &&
-			!sde_mdp_is_ubwc_format(fmt))
-		partial_write = BIT(10);
+	if (test_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map)) {
+		no_partial_writes = BIT(10);
+
+		/*
+		 * For simplicity, don't disable partial writes if
+		 * the ROI does not span the entire width of the
+		 * output image, and require the total stride to
+		 * also be properly aligned.
+		 *
+		 * This avoids having to determine the memory access
+		 * alignment of the actual horizontal ROI on a per
+		 * color format basis.
+		 */
+		if (sde_mdp_is_ubwc_format(fmt)) {
+			no_partial_writes = 0x0;
+		} else if (cfg->dst_rect->x ||
+				cfg->dst_rect->w != cfg->img_width) {
+			no_partial_writes = 0x0;
+		} else {
+			for (i = 0; i < SDE_ROT_MAX_PLANES; i++)
+				if (cfg->dst_plane.ystride[i] &
+						PARTIAL_WRITE_ALIGNMENT)
+					no_partial_writes = 0x0;
+		}
+	}
 
 	/* write config setup for bank configuration */
-	SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_WRITE_CONFIG, partial_write |
+	SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_WRITE_CONFIG, no_partial_writes |
 			(ctx->rot->highest_bank & 0x3) << 8);
 
 	if (test_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map))
@@ -2677,9 +2704,9 @@
 static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr)
 {
 	struct sde_hw_rotator *rot = ptr;
-	struct sde_hw_rotator_context *ctx;
+	struct sde_hw_rotator_context *ctx, *tmp;
 	irqreturn_t ret = IRQ_NONE;
-	u32 isr;
+	u32 isr, isr_tmp;
 	u32 ts;
 	u32 q_id;
 
@@ -2716,18 +2743,28 @@
 		 * Timestamp packet is not available in sbuf mode.
 		 * Simulate timestamp update in the handler instead.
 		 */
-		if (!list_empty(&rot->sbuf_ctx[q_id])) {
-			ctx = list_first_entry_or_null(&rot->sbuf_ctx[q_id],
-					struct sde_hw_rotator_context, list);
-			if (ctx) {
+		if (list_empty(&rot->sbuf_ctx[q_id]))
+			goto skip_sbuf;
+
+		ctx = NULL;
+		isr_tmp = isr;
+		list_for_each_entry(tmp, &rot->sbuf_ctx[q_id], list) {
+			u32 mask;
+
+			mask = tmp->timestamp & 0x1 ? REGDMA_INT_1_MASK :
+				REGDMA_INT_0_MASK;
+			if (isr_tmp & mask) {
+				isr_tmp &= ~mask;
+				ctx = tmp;
 				ts = ctx->timestamp;
 				sde_hw_rotator_update_swts(rot, ctx, ts);
 				SDEROT_DBG("update swts:0x%X\n", ts);
-			} else {
-				SDEROT_ERR("invalid swts ctx\n");
 			}
+			SDEROT_EVTLOG(isr, tmp->timestamp);
 		}
-
+		if (ctx == NULL)
+			SDEROT_ERR("invalid swts ctx\n");
+skip_sbuf:
 		ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK];
 
 		/*
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
index d2b81d5..2afd032 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
@@ -297,4 +297,8 @@
 #define REGDMA_TIMESTAMP_REG            ROT_SSPP_TPG_PATTERN_GEN_INIT_VAL
 #define REGDMA_RESET_STATUS_REG         ROT_SSPP_TPG_RGB_MAPPING
 
+#define REGDMA_INT_0_MASK               0x101
+#define REGDMA_INT_1_MASK               0x202
+#define REGDMA_INT_2_MASK               0x404
+
 #endif /*_SDE_ROTATOR_R3_HWIO_H */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
index e209192..9e47187 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
@@ -519,7 +519,8 @@
 	char name[MAX_CLIENT_NAME_LEN];
 
 	if (!mdata) {
-		SDEROT_ERR("probe failed as mdata is not initialized\n");
+		SDEROT_INFO(
+			"probe failed as mdata is not initializedi, probe defer\n");
 		return -EPROBE_DEFER;
 	}
 
diff --git a/drivers/media/platform/msm/vidc/Makefile b/drivers/media/platform/msm/vidc/Makefile
index 7bad081..e33eaa8 100644
--- a/drivers/media/platform/msm/vidc/Makefile
+++ b/drivers/media/platform/msm/vidc/Makefile
@@ -1,6 +1,7 @@
 ccflags-y += -I$(srctree)/drivers/media/platform/msm/vidc/
 
 msm-vidc-objs := msm_v4l2_vidc.o \
+				msm_vidc_platform.o \
                                 msm_vidc_common.o \
                                 msm_vidc.o \
                                 msm_vdec.o \
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
index f7ce757..9daf053 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
@@ -16,6 +16,7 @@
 #include "msm_vidc_internal.h"
 #include "msm_vidc_debug.h"
 #include "vidc_hfi_api.h"
+#define COMPRESSION_RATIO_MAX 5
 
 static bool debug;
 module_param(debug, bool, 0644);
@@ -30,13 +31,6 @@
 	struct devfreq_governor devfreq_gov;
 };
 
-enum scenario {
-	SCENARIO_WORST,
-	SCENARIO_SUSTAINED_WORST,
-	SCENARIO_AVERAGE,
-	SCENARIO_MAX,
-};
-
 /*
  * Minimum dimensions that the governor is willing to calculate
  * bandwidth for.  This means that anything bandwidth(0, 0) ==
@@ -62,15 +56,9 @@
 #define kbps(__mbps) ((__mbps) * 1000)
 #define bps(__mbps) (kbps(__mbps) * 1000)
 
-#define GENERATE_SCENARIO_PROFILE(__average, __worst) {                        \
-	[SCENARIO_AVERAGE] = (__average),                                      \
-	[SCENARIO_WORST] =  (__worst),                                         \
-	[SCENARIO_SUSTAINED_WORST] = (__worst),                                \
-}
-
-#define GENERATE_COMPRESSION_PROFILE(__bpp, __average, __worst) {              \
+#define GENERATE_COMPRESSION_PROFILE(__bpp, __worst) {              \
 	.bpp = __bpp,                                                          \
-	.ratio = GENERATE_SCENARIO_PROFILE(__average, __worst),                \
+	.ratio = __worst,                \
 }
 
 /*
@@ -85,109 +73,168 @@
  *  4096   2160|     44   88|     2.2       1.26      1.97        1.22|
  *  4096   2304|     48   96|     2.2       1.26      1.97        1.22|
  */
-#define COMPRESSION_RATIO_MAX 2
 static struct lut {
 	int frame_size; /* width x height */
-	unsigned long bitrate[SCENARIO_MAX];
+	int frame_rate;
+	unsigned long bitrate;
 	struct {
 		int bpp;
-		fp_t ratio[SCENARIO_MAX];
+		fp_t ratio;
 	} compression_ratio[COMPRESSION_RATIO_MAX];
 } const LUT[] = {
 	{
 		.frame_size = 1280 * 720,
-		.bitrate = GENERATE_SCENARIO_PROFILE(7, 14),
+		.frame_rate = 30,
+		.bitrate = 14,
 		.compression_ratio = {
 			GENERATE_COMPRESSION_PROFILE(8,
-					FP(1, 69, 100),
 					FP(1, 28, 100)),
 			GENERATE_COMPRESSION_PROFILE(10,
-					FP(1, 49, 100),
+					FP(1, 23, 100)),
+		}
+	},
+	{
+		.frame_size = 1280 * 720,
+		.frame_rate = 60,
+		.bitrate = 22,
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 28, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
 					FP(1, 23, 100)),
 		}
 	},
 	{
 		.frame_size = 1920 * 1088,
-		.bitrate = GENERATE_SCENARIO_PROFILE(20, 40),
+		.frame_rate = 30,
+		.bitrate = 40,
 		.compression_ratio = {
 			GENERATE_COMPRESSION_PROFILE(8,
-					FP(1, 69, 100),
 					FP(1, 28, 100)),
 			GENERATE_COMPRESSION_PROFILE(10,
-					FP(1, 49, 100),
+					FP(1, 23, 100)),
+		}
+	},
+	{
+		.frame_size = 1920 * 1088,
+		.frame_rate = 60,
+		.bitrate = 64,
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 28, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
 					FP(1, 23, 100)),
 		}
 	},
 	{
 		.frame_size = 2560 * 1440,
-		.bitrate = GENERATE_SCENARIO_PROFILE(32, 64),
+		.frame_rate = 30,
+		.bitrate = 64,
 		.compression_ratio = {
 			GENERATE_COMPRESSION_PROFILE(8,
-					FP(2, 20, 100),
 					FP(1, 26, 100)),
 			GENERATE_COMPRESSION_PROFILE(10,
-					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 2560 * 1440,
+		.frame_rate = 60,
+		.bitrate = 102,
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
 					FP(1, 22, 100)),
 		}
 	},
 	{
 		.frame_size = 3840 * 2160,
-		.bitrate = GENERATE_SCENARIO_PROFILE(42, 84),
+		.frame_rate = 30,
+		.bitrate = 84,
 		.compression_ratio = {
 			GENERATE_COMPRESSION_PROFILE(8,
-					FP(2, 20, 100),
 					FP(1, 26, 100)),
 			GENERATE_COMPRESSION_PROFILE(10,
-					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 3840 * 2160,
+		.frame_rate = 60,
+		.bitrate = 134,
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
 					FP(1, 22, 100)),
 		}
 	},
 	{
 		.frame_size = 4096 * 2160,
-		.bitrate = GENERATE_SCENARIO_PROFILE(44, 88),
+		.frame_rate = 30,
+		.bitrate = 88,
 		.compression_ratio = {
 			GENERATE_COMPRESSION_PROFILE(8,
-					FP(2, 20, 100),
 					FP(1, 26, 100)),
 			GENERATE_COMPRESSION_PROFILE(10,
-					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 4096 * 2160,
+		.frame_rate = 60,
+		.bitrate = 141,
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
 					FP(1, 22, 100)),
 		}
 	},
 	{
 		.frame_size = 4096 * 2304,
-		.bitrate = GENERATE_SCENARIO_PROFILE(48, 96),
+		.frame_rate = 30,
+		.bitrate = 96,
 		.compression_ratio = {
 			GENERATE_COMPRESSION_PROFILE(8,
-					FP(2, 20, 100),
 					FP(1, 26, 100)),
 			GENERATE_COMPRESSION_PROFILE(10,
-					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 4096 * 2304,
+		.frame_rate = 60,
+		.bitrate = 154,
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
 					FP(1, 22, 100)),
 		}
 	},
 };
 
-static struct lut const *__lut(int width, int height)
+static struct lut const *__lut(int width, int height, int fps)
 {
 	int frame_size = height * width, c = 0;
 
 	do {
-		if (LUT[c].frame_size >= frame_size)
+		if (LUT[c].frame_size >= frame_size && LUT[c].frame_rate >= fps)
 			return &LUT[c];
 	} while (++c < ARRAY_SIZE(LUT));
 
 	return &LUT[ARRAY_SIZE(LUT) - 1];
 }
 
-static fp_t __compression_ratio(struct lut const *entry, int bpp,
-		enum scenario s)
+static fp_t __compression_ratio(struct lut const *entry, int bpp)
 {
 	int c = 0;
 
 	for (c = 0; c < COMPRESSION_RATIO_MAX; ++c) {
 		if (entry->compression_ratio[c].bpp == bpp)
-			return entry->compression_ratio[c].ratio[s];
+			return entry->compression_ratio[c].ratio;
 	}
 
 	WARN(true, "Shouldn't be here, LUT possibly corrupted?\n");
@@ -282,23 +329,20 @@
 	 * measured heuristics and hardcoded numbers taken from the firmware.
 	 */
 	/* Decoder parameters */
-	enum scenario scenario;
-	int width, height, lcu_size, dpb_bpp, opb_bpp, fps;
+	int width, height, lcu_size, dpb_bpp, opb_bpp, fps, opb_factor;
 	bool unified_dpb_opb, dpb_compression_enabled, opb_compression_enabled;
-	fp_t dpb_opb_scaling_ratio, dpb_compression_factor,
-		opb_compression_factor, qsmmu_bw_overhead_factor;
-	int vmem_size; /* in kB */
+	fp_t dpb_opb_scaling_ratio, dpb_read_compression_factor,
+		dpb_write_compression_factor, opb_compression_factor,
+		qsmmu_bw_overhead_factor, height_ratio;
 
 	/* Derived parameters */
-	int lcu_per_frame, tnbr_per_lcu_10bpc, tnbr_per_lcu_8bpc, tnbr_per_lcu,
-		colocated_bytes_per_lcu, vmem_line_buffer, vmem_chroma_cache,
-		vmem_luma_cache, vmem_chroma_luma_cache;
+	int lcu_per_frame, tnbr_per_lcu, colocated_bytes_per_lcu;
 	unsigned long bitrate;
+
 	fp_t bins_to_bit_factor, dpb_write_factor, ten_bpc_packing_factor,
 		ten_bpc_bpp_factor, vsp_read_factor, vsp_write_factor,
-		ocmem_usage_lcu_factor, ref_ocmem_bw_factor_read,
-		ref_ocmem_bw_factor_write, bw_for_1x_8bpc, dpb_bw_for_1x,
-		motion_vector_complexity, row_cache_penalty, opb_bw;
+		bw_for_1x_8bpc, dpb_bw_for_1x,
+		motion_vector_complexity = 0, row_cache_penalty = 0, opb_bw = 0;
 
 	/* Output parameters */
 	struct {
@@ -306,17 +350,15 @@
 			line_buffer_read, line_buffer_write, recon_read,
 			recon_write, opb_read, opb_write, dpb_read, dpb_write,
 			total;
-	} ddr, vmem;
+	} ddr = {0};
 
 	unsigned long ret = 0;
+	unsigned int integer_part, frac_part;
 
-	/* Decoder parameters setup */
-	scenario = SCENARIO_WORST;
+	width = max(d->input_width, BASELINE_DIMENSIONS.width);
+	height = max(d->input_height, BASELINE_DIMENSIONS.height);
 
-	width = max(d->width, BASELINE_DIMENSIONS.width);
-	height = max(d->height, BASELINE_DIMENSIONS.height);
-
-	lcu_size = 32;
+	lcu_size = d->lcu_size;
 
 	dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
 	opb_bpp = d->num_formats >= 2 ?  __bpp(d->color_formats[1]) : dpb_bpp;
@@ -325,134 +367,71 @@
 
 	unified_dpb_opb = d->num_formats == 1;
 
-	dpb_opb_scaling_ratio = FP_ONE;
+	dpb_opb_scaling_ratio = fp_div(FP_INT(d->input_width * d->input_height),
+		FP_INT(d->output_width * d->output_height));
+	height_ratio = fp_div(d->input_height, d->output_height);
 
 	dpb_compression_enabled = d->num_formats >= 1 &&
 		__ubwc(d->color_formats[0]);
 	opb_compression_enabled = d->num_formats >= 2 &&
 		__ubwc(d->color_formats[1]);
 
-	dpb_compression_factor = !dpb_compression_enabled ? FP_ONE :
-		__compression_ratio(__lut(width, height), dpb_bpp, scenario);
+	/*
+	 * Convert Q16 number into Integer and Fractional part upto 2 places.
+	 * Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752;
+	 * Integer part =  105752 / 65536 = 1;
+	 * Reminder = 105752 - 1 * 65536 = 40216;
+	 * Fractional part = 40216 * 100 / 65536 = 61;
+	 * Now converto to FP(1, 61, 100) for below code.
+	 */
+
+	integer_part = d->compression_ratio >> 16;
+	frac_part =
+		((d->compression_ratio - (integer_part << 16)) * 100) >> 16;
+
+	dpb_read_compression_factor = FP(integer_part, frac_part, 100);
+
+	integer_part = d->complexity_factor >> 16;
+	frac_part =
+		((d->complexity_factor - (integer_part << 16)) * 100) >> 16;
+
+	motion_vector_complexity = FP(integer_part, frac_part, 100);
+
+	dpb_write_compression_factor = !dpb_compression_enabled ? FP_ONE :
+		__compression_ratio(__lut(width, height, fps), opb_bpp);
+
+	dpb_write_compression_factor = d->use_dpb_read ?
+		dpb_read_compression_factor :
+		dpb_write_compression_factor;
 
 	opb_compression_factor = !opb_compression_enabled ? FP_ONE :
-		__compression_ratio(__lut(width, height), opb_bpp, scenario);
+		__compression_ratio(__lut(width, height, fps), opb_bpp);
 
-	vmem_size = 512; /* in kB */
 
 	/* Derived parameters setup */
 	lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
 		DIV_ROUND_UP(height, lcu_size);
 
-	bitrate = __lut(width, height)->bitrate[scenario];
+	bitrate = __lut(width, height, fps)->bitrate;
 
-	bins_to_bit_factor = FP(1, 60, 100);
+	bins_to_bit_factor = d->work_mode == VIDC_WORK_MODE_1 ?
+		FP_INT(0) : FP_INT(4);
 
-	dpb_write_factor = scenario == SCENARIO_AVERAGE ?
-		FP_ONE : FP(1, 5, 100);
+	vsp_read_factor = bins_to_bit_factor + FP_INT(2);
+
+	dpb_write_factor = FP(1, 5, 100);
 
 	ten_bpc_packing_factor = FP(1, 67, 1000);
 	ten_bpc_bpp_factor = FP(1, 1, 4);
 
-	vsp_read_factor = bins_to_bit_factor + FP_INT(2);
 	vsp_write_factor = bins_to_bit_factor;
 
-	tnbr_per_lcu_10bpc = lcu_size == 16 ? 384 + 192 :
-				lcu_size == 32 ? 640 + 256 :
-						1280 + 384;
-	tnbr_per_lcu_8bpc = lcu_size == 16 ? 256 + 192 :
-				lcu_size == 32 ? 512 + 256 :
-						1024 + 384;
-	tnbr_per_lcu = dpb_bpp == 10 ? tnbr_per_lcu_10bpc : tnbr_per_lcu_8bpc;
+	tnbr_per_lcu = lcu_size == 16 ? 128 :
+		lcu_size == 32 ? 64 : 128;
 
 	colocated_bytes_per_lcu = lcu_size == 16 ? 16 :
 				lcu_size == 32 ? 64 : 256;
 
-	ocmem_usage_lcu_factor = lcu_size == 16 ? FP(1, 8, 10) :
-				lcu_size == 32 ? FP(1, 2, 10) :
-						FP_ONE;
-	ref_ocmem_bw_factor_read = vmem_size < 296 ? FP_ZERO :
-				vmem_size < 648 ? FP(0, 1, 4) :
-						FP(0, 55, 100);
-	ref_ocmem_bw_factor_write = vmem_size < 296 ? FP_ZERO :
-				vmem_size < 648 ? FP(0, 7, 10) :
-						FP(1, 4, 10);
-
-	/* Prelim b/w calculation */
-	bw_for_1x_8bpc = fp_mult(FP_INT(width * height * fps),
-			fp_mult(FP(1, 50, 100), dpb_write_factor));
-	bw_for_1x_8bpc = fp_div(bw_for_1x_8bpc, FP_INT(bps(1)));
-
-	dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc :
-		fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor,
-					ten_bpc_bpp_factor));
-	/* VMEM adjustments */
-	vmem_line_buffer = tnbr_per_lcu * DIV_ROUND_UP(width, lcu_size) / 1024;
-	vmem_chroma_cache = dpb_bpp == 10 ? 176 : 128;
-	vmem_luma_cache = dpb_bpp == 10 ? 353 : 256;
-	vmem_chroma_luma_cache = vmem_chroma_cache + vmem_luma_cache;
-
-	motion_vector_complexity = scenario == SCENARIO_AVERAGE ?
-		FP(2, 66, 100) : FP_INT(4);
-
-	row_cache_penalty = FP_ZERO;
-	if (vmem_size < vmem_line_buffer + vmem_chroma_cache)
-		row_cache_penalty = fp_mult(FP(0, 5, 100),
-				motion_vector_complexity);
-	else if (vmem_size < vmem_line_buffer + vmem_luma_cache)
-		row_cache_penalty = fp_mult(FP(0, 7, 100),
-				motion_vector_complexity);
-	else if (vmem_size < vmem_line_buffer + vmem_chroma_cache
-			+ vmem_luma_cache)
-		row_cache_penalty = fp_mult(FP(0, 3, 100),
-				motion_vector_complexity);
-	else
-		row_cache_penalty = FP_ZERO;
-
-
-	opb_bw = unified_dpb_opb ? FP_ZERO :
-		fp_div(fp_div(bw_for_1x_8bpc, dpb_opb_scaling_ratio),
-				opb_compression_factor);
-
-	/* B/W breakdown on a per buffer type basis for VMEM */
-	vmem.vsp_read = FP_ZERO;
-	vmem.vsp_write = FP_ZERO;
-
-	vmem.collocated_read = FP_ZERO;
-	vmem.collocated_write = FP_ZERO;
-
-	vmem.line_buffer_read = FP_INT(tnbr_per_lcu *
-			lcu_per_frame * fps / bps(1));
-	vmem.line_buffer_write = vmem.line_buffer_read;
-
-	vmem.recon_read = FP_ZERO;
-	vmem.recon_write = FP_ZERO;
-
-	vmem.opb_read = FP_ZERO;
-	vmem.opb_write = FP_ZERO;
-
-	vmem.dpb_read = fp_mult(ocmem_usage_lcu_factor, fp_mult(
-					ref_ocmem_bw_factor_read,
-					dpb_bw_for_1x));
-	vmem.dpb_write = fp_mult(ocmem_usage_lcu_factor, fp_mult(
-					ref_ocmem_bw_factor_write,
-					dpb_bw_for_1x));
-
-	vmem.total = vmem.vsp_read + vmem.vsp_write +
-		vmem.collocated_read + vmem.collocated_write +
-		vmem.line_buffer_read + vmem.line_buffer_write +
-		vmem.recon_read + vmem.recon_write +
-		vmem.opb_read + vmem.opb_write +
-		vmem.dpb_read + vmem.dpb_write;
-
-	/*
-	 * Attempt to force VMEM to a certain frequency for 4K
-	 */
-	if (width * height * fps >= 3840 * 2160 * 60)
-		vmem.total = FP_INT(NOMINAL_BW_MBPS);
-	else if (width * height * fps >= 3840 * 2160 * 30)
-		vmem.total = FP_INT(SVS_BW_MBPS);
-
 	/* ........................................ for DDR */
 	ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate),
 				vsp_read_factor), FP_INT(8));
@@ -464,35 +443,49 @@
 	ddr.collocated_write = FP_INT(lcu_per_frame *
 			colocated_bytes_per_lcu * fps / bps(1));
 
-	ddr.line_buffer_read = vmem_size ? FP_ZERO : vmem.line_buffer_read;
-	ddr.line_buffer_write = vmem_size ? FP_ZERO : vmem.line_buffer_write;
+	ddr.line_buffer_read = FP_INT(tnbr_per_lcu *
+			lcu_per_frame * fps / bps(1));
+	ddr.line_buffer_write = ddr.line_buffer_read;
 
-	ddr.recon_read = FP_ZERO;
-	ddr.recon_write = fp_div(dpb_bw_for_1x, dpb_compression_factor);
+	bw_for_1x_8bpc = fp_div(FP_INT(width * height), FP_INT(32 * 8));
 
-	ddr.opb_read = FP_ZERO;
-	ddr.opb_write = opb_bw;
+	bw_for_1x_8bpc = fp_mult(bw_for_1x_8bpc,
+		fp_div(FP_INT(256 * 30), FP_INT(1000 * 1000)));
 
-	ddr.dpb_read = fp_div(fp_mult(dpb_bw_for_1x,
-				motion_vector_complexity + row_cache_penalty),
-			dpb_compression_factor);
-	ddr.dpb_write = FP_ZERO;
+	dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc :
+		fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor,
+				ten_bpc_bpp_factor));
+
+	ddr.dpb_read = fp_div(fp_mult(fp_mult(dpb_bw_for_1x,
+			motion_vector_complexity), dpb_write_factor),
+			dpb_read_compression_factor);
+
+	ddr.dpb_write = fp_div(fp_mult(dpb_bw_for_1x, dpb_write_factor),
+		dpb_write_compression_factor);
+
+	opb_factor = dpb_bpp == 8 ? 8 : 4;
+
+	ddr.opb_read = unified_dpb_opb ? 0 : opb_compression_enabled ?
+		fp_div(fp_mult(fp_div(dpb_bw_for_1x, dpb_opb_scaling_ratio),
+		FP_INT(opb_factor)), height_ratio) : 0;
+	ddr.opb_write = unified_dpb_opb ? 0 : opb_compression_enabled ?
+		ddr.dpb_read : fp_div(fp_div(fp_mult(dpb_bw_for_1x,
+		FP(1, 50, 100)), dpb_opb_scaling_ratio),
+			opb_compression_factor);
 
 	ddr.total = ddr.vsp_read + ddr.vsp_write +
 		ddr.collocated_read + ddr.collocated_write +
-		ddr.line_buffer_read + ddr.line_buffer_write +
-		ddr.recon_read + ddr.recon_write +
 		ddr.opb_read + ddr.opb_write +
 		ddr.dpb_read + ddr.dpb_write;
 
 	qsmmu_bw_overhead_factor = FP(1, 3, 100);
+
 	ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
 
 	/* Dump all the variables for easier debugging */
 	if (debug) {
 		struct dump dump[] = {
 		{"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC},
-		{"content", "%d", scenario},
 		{"LCU size", "%d", lcu_size},
 		{"DPB bitdepth", "%d", dpb_bpp},
 		{"frame rate", "%d", fps},
@@ -501,11 +494,12 @@
 			dpb_opb_scaling_ratio},
 		{"DPB compression", "%d", dpb_compression_enabled},
 		{"OPB compression", "%d", opb_compression_enabled},
-		{"DPB compression factor", DUMP_FP_FMT,
-			dpb_compression_factor},
+		{"DPB Read compression factor", DUMP_FP_FMT,
+			dpb_read_compression_factor},
+		{"DPB Write compression factor", DUMP_FP_FMT,
+			dpb_write_compression_factor},
 		{"OPB compression factor", DUMP_FP_FMT,
 			opb_compression_factor},
-		{"VMEM size", "%dkB", vmem_size},
 		{"frame width", "%d", width},
 		{"frame height", "%d", height},
 
@@ -519,25 +513,11 @@
 		{"10bpc,BPP factor", DUMP_FP_FMT, ten_bpc_bpp_factor},
 		{"VSP read factor", DUMP_FP_FMT, vsp_read_factor},
 		{"VSP write factor", DUMP_FP_FMT, vsp_write_factor},
-		{"TNBR/LCU_10bpc", "%d", tnbr_per_lcu_10bpc},
-		{"TNBR/LCU_8bpc", "%d", tnbr_per_lcu_8bpc},
 		{"TNBR/LCU", "%d", tnbr_per_lcu},
 		{"colocated bytes/LCU", "%d", colocated_bytes_per_lcu},
-		{"OCMEM usage LCU factor", DUMP_FP_FMT,
-			ocmem_usage_lcu_factor},
-		{"ref OCMEM b/w factor (read)", DUMP_FP_FMT,
-			ref_ocmem_bw_factor_read},
-		{"ref OCMEM b/w factor (write)", DUMP_FP_FMT,
-			ref_ocmem_bw_factor_write},
 		{"B/W for 1x (NV12 8bpc)", DUMP_FP_FMT, bw_for_1x_8bpc},
 		{"DPB B/W For 1x (NV12)", DUMP_FP_FMT, dpb_bw_for_1x},
 
-		{"VMEM", "", DUMP_HEADER_MAGIC},
-		{"line buffer", "%d", vmem_line_buffer},
-		{"chroma cache", "%d", vmem_chroma_cache},
-		{"luma cache", "%d", vmem_luma_cache},
-		{"luma & chroma cache", "%d", vmem_chroma_luma_cache},
-
 		{"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC},
 		{"MV complexity", DUMP_FP_FMT, motion_vector_complexity},
 		{"row cache penalty", DUMP_FP_FMT, row_cache_penalty},
@@ -557,19 +537,6 @@
 		{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
 		{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
 
-		{"INTERMEDIATE VMEM B/W", "", DUMP_HEADER_MAGIC},
-		{"VSP read", "%d", vmem.vsp_read},
-		{"VSP write", DUMP_FP_FMT, vmem.vsp_write},
-		{"collocated read", DUMP_FP_FMT, vmem.collocated_read},
-		{"collocated write", DUMP_FP_FMT, vmem.collocated_write},
-		{"line buffer read", DUMP_FP_FMT, vmem.line_buffer_read},
-		{"line buffer write", DUMP_FP_FMT, vmem.line_buffer_write},
-		{"recon read", DUMP_FP_FMT, vmem.recon_read},
-		{"recon write", DUMP_FP_FMT, vmem.recon_write},
-		{"OPB read", DUMP_FP_FMT, vmem.opb_read},
-		{"OPB write", DUMP_FP_FMT, vmem.opb_write},
-		{"DPB read", DUMP_FP_FMT, vmem.dpb_read},
-		{"DPB write", DUMP_FP_FMT, vmem.dpb_write},
 		};
 		__dump(dump, ARRAY_SIZE(dump));
 	}
@@ -579,7 +546,7 @@
 		ret = kbps(fp_round(ddr.total));
 		break;
 	case GOVERNOR_LLCC:
-		ret = kbps(fp_round(vmem.total));
+		dprintk(VIDC_PROF, "LLCC Voting not supported yet\n");
 		break;
 	default:
 		dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
@@ -597,9 +564,9 @@
 	 * measured heuristics and hardcoded numbers taken from the firmware.
 	 */
 	/* Encoder Parameters */
-	enum scenario scenario, bitrate_scenario;
+
 	enum hal_video_codec standard;
-	int width, height, fps, vmem_size;
+	int width, height, fps;
 	enum hal_uncompressed_format dpb_color_format;
 	enum hal_uncompressed_format original_color_format;
 	bool dpb_compression_enabled, original_compression_enabled,
@@ -618,35 +585,34 @@
 	fp_t bins_to_bit_factor, chroma_luma_factor_dpb, one_frame_bw_dpb,
 		 chroma_luma_factor_original, one_frame_bw_original,
 		 line_buffer_size_per_lcu, line_buffer_size, line_buffer_bw,
-		 original_vmem_requirement, bw_increase_p, bw_increase_b;
+		 bw_increase_p, bw_increase_b;
 	int collocated_mv_per_lcu, max_transaction_size,
 		search_window_size_vertical_p, search_window_factor_p,
-		search_window_factor_bw_p, vmem_size_p, available_vmem_p,
+		search_window_factor_bw_p,
 		search_window_size_vertical_b, search_window_factor_b,
-		search_window_factor_bw_b, vmem_size_b, available_vmem_b;
+		search_window_factor_bw_b;
 
 	/* Output paramaters */
 	struct {
 		fp_t vsp_read, vsp_write, collocated_read, collocated_write,
 			line_buffer_read, line_buffer_write, original_read,
 			original_write, dpb_read, dpb_write, total;
-	} ddr, vmem;
+	} ddr = {0};
 
 	unsigned long ret = 0;
+	fp_t integer_part, frac_part;
 
 	/* Encoder Parameters setup */
-	scenario = SCENARIO_WORST;
 
 	standard = d->codec;
-	width = max(d->width, BASELINE_DIMENSIONS.width);
-	height = max(d->height, BASELINE_DIMENSIONS.height);
+	width = max(d->input_width, BASELINE_DIMENSIONS.width);
+	height = max(d->input_height, BASELINE_DIMENSIONS.height);
 
 	dpb_color_format = HAL_COLOR_FORMAT_NV12_UBWC;
 	original_color_format = d->num_formats >= 1 ?
 		d->color_formats[0] : HAL_UNUSED_COLOR;
 
 	fps = d->fps;
-	bitrate_scenario = SCENARIO_WORST;
 
 	dpb_compression_enabled = __ubwc(dpb_color_format);
 	original_compression_enabled = __ubwc(original_color_format);
@@ -655,21 +621,30 @@
 	low_power = d->power_mode == VIDC_POWER_LOW;
 	b_frames_enabled = false;
 
-	dpb_compression_factor = !dpb_compression_enabled ? FP_ONE :
-		__compression_ratio(__lut(width, height),
-				__bpp(dpb_color_format), scenario);
-	original_compression_factor = !original_compression_enabled ? FP_ONE :
-		__compression_ratio(__lut(width, height),
-				__bpp(original_color_format), scenario);
+	/*
+	 * Convert Q16 number into Integer and Fractional part upto 2 places.
+	 * Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752;
+	 * Integer part =  105752 / 65536 = 1;
+	 * Reminder = 105752 - 1 * 65536 = 40216;
+	 * Fractional part = 40216 * 100 / 65536 = 61;
+	 * Now converto to FP(1, 61, 100) for below code.
+	 */
+
+	integer_part = d->compression_ratio >> 16;
+	frac_part =
+		((d->compression_ratio - (integer_part * 65536)) * 100) >> 16;
+
+	dpb_compression_factor = FP(integer_part, frac_part, 100);
+
+	original_compression_factor = dpb_compression_factor;
 
 	rotation = false;
 	cropping_or_scaling = false;
-	vmem_size = 512; /* in kB */
 
 	/* Derived Parameters */
 	lcu_size = 16;
 	gop = b_frames_enabled ? GOP_IBBP : GOP_IPPP;
-	bitrate = __lut(width, height)->bitrate[bitrate_scenario];
+	bitrate = __lut(width, height, fps)->bitrate;
 	bins_to_bit_factor = FP(1, 6, 10);
 
 	/*
@@ -713,16 +688,6 @@
 	collocated_mv_per_lcu = lcu_size == 16 ? 16 : 64;
 	max_transaction_size = 256;
 
-	original_vmem_requirement = FP_INT(3 *
-			(two_stage_encoding ? 2 : 1) * lcu_size);
-	original_vmem_requirement = fp_mult(original_vmem_requirement,
-			(FP_ONE + chroma_luma_factor_original));
-	original_vmem_requirement += FP_INT((cropping_or_scaling ? 3 : 0) * 2);
-	original_vmem_requirement = fp_mult(original_vmem_requirement,
-			FP_INT(max_transaction_size));
-	original_vmem_requirement = fp_div(original_vmem_requirement,
-			FP_INT(1024));
-
 	search_window_size_vertical_p = low_power ? 32 :
 					b_frames_enabled ? 80 :
 					width > 2048 ? 64 : 48;
@@ -730,24 +695,16 @@
 	search_window_factor_bw_p = !two_stage_encoding ?
 		search_window_size_vertical_p * 2 / lcu_size + 1 :
 		(search_window_size_vertical_p * 2 / lcu_size + 2) / 2;
-	vmem_size_p = (search_window_factor_p * width + 128 * 2) *
-		lcu_size / 2 / 1024; /* XXX: CF hack */
 	bw_increase_p = fp_mult(one_frame_bw_dpb,
 			FP_INT(search_window_factor_bw_p - 1) / 3);
-	available_vmem_p = min_t(int, 3, (vmem_size - fp_int(line_buffer_size) -
-			fp_int(original_vmem_requirement)) / vmem_size_p);
 
 	search_window_size_vertical_b = 48;
 	search_window_factor_b = search_window_size_vertical_b * 2 / lcu_size;
 	search_window_factor_bw_b = !two_stage_encoding ?
 		search_window_size_vertical_b * 2 / lcu_size + 1 :
 		(search_window_size_vertical_b * 2 / lcu_size + 2) / 2;
-	vmem_size_b = (search_window_factor_b * width + 128 * 2) * lcu_size /
-		2 / 1024;
 	bw_increase_b = fp_mult(one_frame_bw_dpb,
 			FP_INT((search_window_factor_bw_b - 1) / 3));
-	available_vmem_b = min_t(int, 6, (vmem_size - fp_int(line_buffer_size) -
-			fp_int(original_vmem_requirement)) / vmem_size_b);
 
 	/* Output parameters for DDR */
 	ddr.vsp_read = fp_mult(fp_div(FP_INT(bitrate), FP_INT(8)),
@@ -759,8 +716,6 @@
 			collocated_mv_per_lcu * fps), FP_INT(1000 * 1000));
 	ddr.collocated_write = ddr.collocated_read;
 
-	ddr.line_buffer_read = (FP_INT(vmem_size) >= line_buffer_size +
-		original_vmem_requirement) ? FP_ZERO : line_buffer_bw;
 	ddr.line_buffer_write = ddr.line_buffer_read;
 
 	ddr.original_read = fp_div(one_frame_bw_original,
@@ -768,27 +723,6 @@
 	ddr.original_write = FP_ZERO;
 
 	ddr.dpb_read = FP_ZERO;
-	if (gop == GOP_IPPP) {
-		ddr.dpb_read = one_frame_bw_dpb + fp_mult(bw_increase_p,
-			FP_INT(3 - available_vmem_p));
-	} else if (scenario == SCENARIO_WORST ||
-			scenario == SCENARIO_SUSTAINED_WORST) {
-		ddr.dpb_read = fp_mult(one_frame_bw_dpb, FP_INT(2));
-		ddr.dpb_read += fp_mult(FP_INT(6 - available_vmem_b),
-				bw_increase_b);
-	} else {
-		fp_t part_p, part_b;
-
-		part_p = one_frame_bw_dpb + fp_mult(bw_increase_p,
-				FP_INT(3 - available_vmem_p));
-		part_p = fp_div(part_p, FP_INT(3));
-
-		part_b = fp_mult(one_frame_bw_dpb, 2) +
-			fp_mult(FP_INT(6 - available_vmem_b), bw_increase_b);
-		part_b = fp_mult(part_b, FP(0, 2, 3));
-
-		ddr.dpb_read = part_p + part_b;
-	}
 
 	ddr.dpb_read = fp_div(ddr.dpb_read, dpb_compression_factor);
 	ddr.dpb_write = fp_div(one_frame_bw_dpb, dpb_compression_factor);
@@ -802,103 +736,15 @@
 	qsmmu_bw_overhead_factor = FP(1, 3, 100);
 	ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
 
-	/* ................. for VMEM */
-	vmem.vsp_read = FP_ZERO;
-	vmem.vsp_write = FP_ZERO;
-
-	vmem.collocated_read = FP_ZERO;
-	vmem.collocated_write = FP_ZERO;
-
-	vmem.line_buffer_read = line_buffer_bw - ddr.line_buffer_read;
-	vmem.line_buffer_write = vmem.line_buffer_read;
-
-	vmem.original_read = FP_INT(vmem_size) >= original_vmem_requirement ?
-		ddr.original_read : FP_ZERO;
-	vmem.original_write = vmem.original_read;
-
-	vmem.dpb_read = FP_ZERO;
-	if (gop == GOP_IPPP) {
-		fp_t temp = fp_mult(one_frame_bw_dpb,
-			FP_INT(search_window_factor_bw_p * available_vmem_p));
-		temp = fp_div(temp, FP_INT(3));
-
-		vmem.dpb_read = temp;
-	} else if (scenario != SCENARIO_AVERAGE) {
-		fp_t temp = fp_mult(one_frame_bw_dpb, FP_INT(2));
-
-		temp = fp_mult(temp, FP_INT(search_window_factor_bw_b *
-					available_vmem_b));
-		temp = fp_div(temp, FP_INT(6));
-
-		vmem.dpb_read = temp;
-	} else {
-		fp_t part_p, part_b;
-
-		part_p = fp_mult(one_frame_bw_dpb, FP_INT(
-					search_window_factor_bw_p *
-					available_vmem_p));
-		part_p = fp_div(part_p, FP_INT(3 * 3));
-
-		part_b = fp_mult(one_frame_bw_dpb, FP_INT(2 *
-					search_window_factor_bw_b *
-					available_vmem_b));
-		part_b = fp_div(part_b, FP_INT(6));
-		part_b = fp_mult(part_b, FP(0, 2, 3));
-
-		vmem.dpb_read = part_p + part_b;
-	}
-
-	vmem.dpb_write = FP_ZERO;
-	if (gop == GOP_IPPP) {
-		fp_t temp = fp_mult(one_frame_bw_dpb,
-				FP_INT(available_vmem_p));
-		temp = fp_div(temp, FP_INT(3));
-
-		vmem.dpb_write = temp;
-	} else if (scenario != SCENARIO_AVERAGE) {
-		fp_t temp = fp_mult(one_frame_bw_dpb,
-				FP_INT(2 * available_vmem_b));
-		temp = fp_div(temp, FP_INT(6));
-
-		vmem.dpb_write = temp;
-	} else {
-		fp_t part_b, part_p;
-
-		part_b = fp_mult(one_frame_bw_dpb, FP_INT(available_vmem_p));
-		part_b = fp_div(part_b, FP_INT(9));
-
-		part_p = fp_mult(one_frame_bw_dpb, FP_INT(
-					2 * available_vmem_b));
-		part_p = fp_div(part_p, FP_INT(6));
-		part_b = fp_mult(part_b, FP(0, 2, 3));
-
-		vmem.dpb_write = part_p + part_b;
-	}
-
-	vmem.total = vmem.vsp_read + vmem.vsp_write +
-		vmem.collocated_read + vmem.collocated_write +
-		vmem.line_buffer_read + vmem.line_buffer_write +
-		vmem.original_read + vmem.original_write +
-		vmem.dpb_read + vmem.dpb_write;
-
-	/*
-	 * When in low power mode, attempt to force the VMEM clocks a certain
-	 * frequency that DCVS would prefer
-	 */
-	if (width * height >= 3840 * 2160 && low_power)
-		vmem.total = FP_INT(NOMINAL_BW_MBPS);
-
 	if (debug) {
 		struct dump dump[] = {
 		{"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC},
-		{"scenario", "%d", scenario},
 		{"standard", "%#x", standard},
 		{"width", "%d", width},
 		{"height", "%d", height},
 		{"DPB format", "%#x", dpb_color_format},
 		{"original frame format", "%#x", original_color_format},
 		{"fps", "%d", fps},
-		{"target bitrate", "%d", bitrate_scenario},
 		{"DPB compression enable", "%d", dpb_compression_enabled},
 		{"original compression enable", "%d",
 			original_compression_enabled},
@@ -910,7 +756,6 @@
 			original_compression_factor},
 		{"rotation", "%d", rotation},
 		{"cropping or scaling", "%d", cropping_or_scaling},
-		{"VMEM size (KB)", "%d", vmem_size},
 
 		{"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC},
 		{"LCU size", "%d", lcu_size},
@@ -923,17 +768,13 @@
 		{"search window factor (B)", "%d", search_window_factor_b},
 		{"search window factor BW (B)", "%d",
 			search_window_factor_bw_b},
-		{"VMEM size (B)", "%d", vmem_size_b},
 		{"bw increase (MB/s) (B)", DUMP_FP_FMT, bw_increase_b},
-		{"available VMEM (B)", "%d", available_vmem_b},
 		{"search window size vertical (P)", "%d",
 			search_window_size_vertical_p},
 		{"search window factor (P)", "%d", search_window_factor_p},
 		{"search window factor BW (P)", "%d",
 			search_window_factor_bw_p},
-		{"VMEM size (P)", "%d", vmem_size_p},
 		{"bw increase (MB/s) (P)", DUMP_FP_FMT, bw_increase_p},
-		{"available VMEM (P)", "%d", available_vmem_p},
 		{"chroma/luma factor DPB", DUMP_FP_FMT,
 			chroma_luma_factor_dpb},
 		{"one frame BW DPB (MB/s)", DUMP_FP_FMT, one_frame_bw_dpb},
@@ -946,8 +787,6 @@
 		{"line buffer size (KB)", DUMP_FP_FMT, line_buffer_size},
 		{"line buffer BW (MB/s)", DUMP_FP_FMT, line_buffer_bw},
 		{"collocated MVs per LCU", "%d", collocated_mv_per_lcu},
-		{"original VMEM requirement (KB)", DUMP_FP_FMT,
-			original_vmem_requirement},
 
 		{"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC},
 		{"VSP read", DUMP_FP_FMT, ddr.vsp_read},
@@ -960,18 +799,6 @@
 		{"original read", DUMP_FP_FMT, ddr.original_write},
 		{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
 		{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
-
-		{"INTERMEDIATE B/W VMEM", "", DUMP_HEADER_MAGIC},
-		{"VSP read", DUMP_FP_FMT, vmem.vsp_read},
-		{"VSP read", DUMP_FP_FMT, vmem.vsp_write},
-		{"collocated read", DUMP_FP_FMT, vmem.collocated_read},
-		{"collocated read", DUMP_FP_FMT, vmem.collocated_write},
-		{"line buffer read", DUMP_FP_FMT, vmem.line_buffer_read},
-		{"line buffer read", DUMP_FP_FMT, vmem.line_buffer_write},
-		{"original read", DUMP_FP_FMT, vmem.original_read},
-		{"original read", DUMP_FP_FMT, vmem.original_write},
-		{"DPB read", DUMP_FP_FMT, vmem.dpb_read},
-		{"DPB write", DUMP_FP_FMT, vmem.dpb_write},
 		};
 		__dump(dump, ARRAY_SIZE(dump));
 	}
@@ -981,7 +808,7 @@
 		ret = kbps(fp_round(ddr.total));
 		break;
 	case GOVERNOR_LLCC:
-		ret = kbps(fp_round(vmem.total));
+		dprintk(VIDC_PROF, "LLCC Voting not supported yet\n");
 		break;
 	default:
 		dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
@@ -1023,18 +850,21 @@
 	dev->profile->get_dev_status(dev->dev.parent, &stats);
 	vidc_data = (struct msm_vidc_gov_data *)stats.private_data;
 
+	if (!vidc_data || !vidc_data->data_count)
+		goto exit;
+
 	for (c = 0; c < vidc_data->data_count; ++c) {
 		if (vidc_data->data->power_mode == VIDC_POWER_TURBO) {
-			*freq = INT_MAX;
 			goto exit;
 		}
 	}
 
+	ab_kbps = 0;
 	for (c = 0; c < vidc_data->data_count; ++c)
 		ab_kbps += __calculate(&vidc_data->data[c], gov->mode);
 
-	*freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX);
 exit:
+	*freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX);
 	return 0;
 }
 
@@ -1049,6 +879,7 @@
 	switch (event) {
 	case DEVFREQ_GOV_START:
 	case DEVFREQ_GOV_RESUME:
+	case DEVFREQ_GOV_SUSPEND:
 		mutex_lock(&devfreq->lock);
 		rc = update_devfreq(devfreq);
 		mutex_unlock(&devfreq->lock);
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 8d54e20..1991a34 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -10,9 +10,6 @@
  * GNU General Public License for more details.
  *
  */
-#include <linux/errno.h>
-#include <linux/log2.h>
-#include <linux/hash.h>
 #include "hfi_packetization.h"
 #include "msm_vidc_debug.h"
 
@@ -619,6 +616,9 @@
 	case HAL_EXTRADATA_VPX_COLORSPACE:
 		ret = HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA;
 		break;
+	case HAL_EXTRADATA_UBWC_CR_STATS_INFO:
+		ret = HFI_PROPERTY_PARAM_VDEC_UBWC_CR_STAT_INFO_EXTRADATA;
+		break;
 	default:
 		dprintk(VIDC_WARN, "Extradata index not found: %d\n", index);
 		break;
@@ -868,8 +868,6 @@
 		output_frame->device_addr, output_frame->timestamp,
 		output_frame->alloc_len, output_frame->filled_len,
 		output_frame->offset);
-	dprintk(VIDC_DBG, "### Q OUTPUT BUFFER ###: %d, %d, %d\n",
-			pkt->alloc_len, pkt->filled_len, pkt->offset);
 
 	return rc;
 }
@@ -1295,7 +1293,7 @@
 		struct hal_quantization *hal_quant =
 			(struct hal_quantization *) pdata;
 		pkt->rg_property_data[0] =
-			HFI_PROPERTY_CONFIG_VENC_SESSION_QP;
+			HFI_PROPERTY_CONFIG_VENC_FRAME_QP;
 		hfi = (struct hfi_quantization *) &pkt->rg_property_data[1];
 		hfi->qp_packed = hal_quant->qpi | hal_quant->qpp << 8 |
 			hal_quant->qpb << 16;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index f678f56..c2a93a96 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1074,15 +1074,6 @@
 	}
 
 	while (req_bytes) {
-		if (hfi_buf_req->buffer_size &&
-			hfi_buf_req->buffer_count_min > hfi_buf_req->
-			buffer_count_actual)
-			dprintk(VIDC_WARN,
-				"Bad buffer requirements for %#x: min %d, actual %d\n",
-				hfi_buf_req->buffer_type,
-				hfi_buf_req->buffer_count_min,
-				hfi_buf_req->buffer_count_actual);
-
 		dprintk(VIDC_DBG, "got buffer requirements for: %d\n",
 					hfi_buf_req->buffer_type);
 		switch (hfi_buf_req->buffer_type) {
@@ -1320,12 +1311,17 @@
 	data_done.status = hfi_map_err_status(pkt->error_type);
 	data_done.size = sizeof(struct msm_vidc_cb_data_done);
 	data_done.clnt_data = pkt->input_tag;
+	data_done.input_done.recon_stats.buffer_index =
+		pkt->ubwc_cr_stats.frame_index;
+	memcpy(&data_done.input_done.recon_stats.ubwc_stats_info,
+		&pkt->ubwc_cr_stats.ubwc_stats_info,
+		sizeof(data_done.input_done.recon_stats.ubwc_stats_info));
+	data_done.input_done.recon_stats.complexity_number =
+		pkt->ubwc_cr_stats.complexity_number;
 	data_done.input_done.offset = pkt->offset;
 	data_done.input_done.filled_len = pkt->filled_len;
-	data_done.input_done.packet_buffer =
-		(ion_phys_addr_t)pkt->packet_buffer;
-	data_done.input_done.extra_data_buffer =
-		(ion_phys_addr_t)pkt->extra_data_buffer;
+	data_done.input_done.packet_buffer = pkt->packet_buffer;
+	data_done.input_done.extra_data_buffer = pkt->extra_data_buffer;
 	data_done.input_done.status =
 		hfi_map_err_status(pkt->error_type);
 	hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[0];
@@ -1406,10 +1402,9 @@
 		data_done.output_done.alloc_len1 = pkt->alloc_len;
 		data_done.output_done.filled_len1 = pkt->filled_len;
 		data_done.output_done.picture_type = pkt->picture_type;
-		data_done.output_done.packet_buffer1 =
-			(ion_phys_addr_t)pkt->packet_buffer;
+		data_done.output_done.packet_buffer1 = pkt->packet_buffer;
 		data_done.output_done.extra_data_buffer =
-			(ion_phys_addr_t)pkt->extra_data_buffer;
+			pkt->extra_data_buffer;
 		data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
 	} else /* if (is_decoder) */ {
 		struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt =
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index b116622..9b23376 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -30,7 +30,7 @@
 	enum session_type session_type;
 };
 
-static int get_device_address(struct smem_client *smem_client,
+static int msm_ion_get_device_address(struct smem_client *smem_client,
 		struct ion_handle *hndl, unsigned long align,
 		ion_phys_addr_t *iova, unsigned long *buffer_size,
 		unsigned long flags, enum hal_buffer buffer_type,
@@ -122,12 +122,6 @@
 			goto mem_map_sg_failed;
 		}
 		if (table->sgl) {
-			dprintk(VIDC_DBG,
-				"%s: CB : %s, DMA buf: %pK, device: %pK, attach: %pK, table: %pK, table sgl: %pK, rc: %d, dma_address: %pa\n",
-				__func__, cb->name, buf, cb->dev, attach,
-				table, table->sgl, rc,
-				&table->sgl->dma_address);
-
 			*iova = table->sgl->dma_address;
 			*buffer_size = table->sgl->dma_length;
 		} else {
@@ -153,7 +147,6 @@
 		}
 	}
 
-	dprintk(VIDC_DBG, "mapped ion handle %pK to %pa\n", hndl, iova);
 	return 0;
 mem_map_sg_failed:
 	dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
@@ -166,38 +159,26 @@
 	return rc;
 }
 
-static void put_device_address(struct smem_client *smem_client,
+static int msm_ion_put_device_address(struct smem_client *smem_client,
 	struct ion_handle *hndl, u32 flags,
 	struct dma_mapping_info *mapping_info,
 	enum hal_buffer buffer_type)
 {
-	struct ion_client *clnt = NULL;
+	int rc = 0;
 
 	if (!hndl || !smem_client || !mapping_info) {
 		dprintk(VIDC_WARN, "Invalid params: %pK, %pK\n",
 				smem_client, hndl);
-		return;
+		return -EINVAL;
 	}
 
 	if (!mapping_info->dev || !mapping_info->table ||
 		!mapping_info->buf || !mapping_info->attach) {
 		dprintk(VIDC_WARN, "Invalid params:\n");
-		return;
+		return -EINVAL;
 	}
 
-	clnt = smem_client->clnt;
-	if (!clnt) {
-		dprintk(VIDC_WARN, "Invalid client\n");
-		return;
-	}
 	if (is_iommu_present(smem_client->res)) {
-		dprintk(VIDC_DBG,
-			"Calling dma_unmap_sg - device: %pK, address: %pa, buf: %pK, table: %pK, attach: %pK\n",
-			mapping_info->dev,
-			&mapping_info->table->sgl->dma_address,
-			mapping_info->buf, mapping_info->table,
-			mapping_info->attach);
-
 		trace_msm_smem_buffer_iommu_op_start("UNMAP", 0, 0, 0, 0, 0);
 		msm_dma_unmap_sg(mapping_info->dev, mapping_info->table->sgl,
 			mapping_info->table->nents, DMA_BIDIRECTIONAL,
@@ -207,68 +188,257 @@
 		dma_buf_detach(mapping_info->buf, mapping_info->attach);
 		dma_buf_put(mapping_info->buf);
 		trace_msm_smem_buffer_iommu_op_end("UNMAP", 0, 0, 0, 0, 0);
+
+		mapping_info->dev = NULL;
+		mapping_info->mapping = NULL;
+		mapping_info->table = NULL;
+		mapping_info->attach = NULL;
+		mapping_info->buf = NULL;
 	}
+
+	return rc;
 }
 
-static int ion_user_to_kernel(struct smem_client *client, int fd, u32 size,
-		struct msm_smem *mem, enum hal_buffer buffer_type)
+static void *msm_ion_get_dma_buf(int fd)
 {
-	struct ion_handle *hndl = NULL;
-	ion_phys_addr_t iova = 0;
-	unsigned long buffer_size = size;
+	struct dma_buf *dma_buf;
+
+	dma_buf = dma_buf_get(fd);
+	if (IS_ERR_OR_NULL(dma_buf)) {
+		dprintk(VIDC_ERR, "Failed to get dma_buf for %d, error %ld\n",
+				fd, PTR_ERR(dma_buf));
+		dma_buf = NULL;
+	}
+
+	return dma_buf;
+}
+
+void *msm_smem_get_dma_buf(int fd)
+{
+	return (void *)msm_ion_get_dma_buf(fd);
+}
+
+static void msm_ion_put_dma_buf(struct dma_buf *dma_buf)
+{
+	if (!dma_buf) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK\n",
+				__func__, dma_buf);
+		return;
+	}
+
+	dma_buf_put(dma_buf);
+}
+
+void msm_smem_put_dma_buf(void *dma_buf)
+{
+	return msm_ion_put_dma_buf((struct dma_buf *)dma_buf);
+}
+
+static struct ion_handle *msm_ion_get_handle(void *ion_client,
+		struct dma_buf *dma_buf)
+{
+	struct ion_handle *handle;
+
+	if (!ion_client || !dma_buf) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+				__func__, ion_client, dma_buf);
+		return NULL;
+	}
+
+	handle = ion_import_dma_buf(ion_client, dma_buf);
+	if (IS_ERR_OR_NULL(handle)) {
+		dprintk(VIDC_ERR, "Failed to get ion_handle: %pK, %pK, %ld\n",
+				ion_client, dma_buf, PTR_ERR(handle));
+		handle = NULL;
+	}
+
+	return handle;
+}
+
+void *msm_smem_get_handle(struct smem_client *client, void *dma_buf)
+{
+	if (!client)
+		return NULL;
+
+	return (void *)msm_ion_get_handle(client->clnt,
+			(struct dma_buf *)dma_buf);
+}
+
+static void msm_ion_put_handle(struct ion_client *ion_client,
+		struct ion_handle *ion_handle)
+{
+	if (!ion_client || !ion_handle) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+				__func__, ion_client, ion_handle);
+		return;
+	}
+
+	ion_free(ion_client, ion_handle);
+}
+
+void msm_smem_put_handle(struct smem_client *client, void *handle)
+{
+	if (!client) {
+		dprintk(VIDC_ERR, "%s: Invalid params %pK %pK\n",
+				__func__, client, handle);
+		return;
+	}
+	return msm_ion_put_handle(client->clnt, (struct ion_handle *)handle);
+}
+
+static int msm_ion_map_dma_buf(struct msm_vidc_inst *inst,
+		struct msm_smem *smem)
+{
 	int rc = 0;
+	ion_phys_addr_t iova = 0;
+	u32 temp = 0;
+	unsigned long buffer_size = 0;
 	unsigned long align = SZ_4K;
 	unsigned long ion_flags = 0;
+	struct ion_client *ion_client;
+	struct ion_handle *ion_handle;
+	struct dma_buf *dma_buf;
 
-#ifdef CONFIG_ION
-	hndl = ion_import_dma_buf_fd(client->clnt, fd);
-#endif
-	dprintk(VIDC_DBG, "%s ion handle: %pK\n", __func__, hndl);
-	if (IS_ERR_OR_NULL(hndl)) {
-		dprintk(VIDC_ERR, "Failed to get handle: %pK, %d, %d, %pK\n",
-				client, fd, size, hndl);
-		rc = -ENOMEM;
-		goto fail_import_fd;
+	if (!inst || !inst->mem_client || !inst->mem_client->clnt) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+				__func__, inst, smem);
+		return -EINVAL;
 	}
 
-	mem->kvaddr = NULL;
-	rc = ion_handle_get_flags(client->clnt, hndl, &ion_flags);
+	ion_client = inst->mem_client->clnt;
+	dma_buf = msm_ion_get_dma_buf(smem->fd);
+	if (!dma_buf)
+		return -EINVAL;
+	ion_handle = msm_ion_get_handle(ion_client, dma_buf);
+	if (!ion_handle)
+		return -EINVAL;
+
+	smem->dma_buf = dma_buf;
+	smem->handle = ion_handle;
+	rc = ion_handle_get_flags(ion_client, ion_handle, &ion_flags);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
-		goto fail_device_address;
+		goto exit;
 	}
 
-	mem->buffer_type = buffer_type;
 	if (ion_flags & ION_FLAG_CACHED)
-		mem->flags |= SMEM_CACHED;
+		smem->flags |= SMEM_CACHED;
 
 	if (ion_flags & ION_FLAG_SECURE)
-		mem->flags |= SMEM_SECURE;
+		smem->flags |= SMEM_SECURE;
 
-	rc = get_device_address(client, hndl, align, &iova, &buffer_size,
-				mem->flags, buffer_type, &mem->mapping_info);
+	rc = msm_ion_get_device_address(inst->mem_client, ion_handle,
+			align, &iova, &buffer_size, smem->flags,
+			smem->buffer_type, &smem->mapping_info);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
-		goto fail_device_address;
+		goto exit;
+	}
+	temp = (u32)iova;
+	if ((ion_phys_addr_t)temp != iova) {
+		dprintk(VIDC_ERR, "iova(%pa) truncated to %#x", &iova, temp);
+		rc = -EINVAL;
+		goto exit;
 	}
 
-	mem->mem_type = client->mem_type;
-	mem->smem_priv = hndl;
-	mem->device_addr = iova;
-	mem->size = buffer_size;
-	if ((u32)mem->device_addr != iova) {
-		dprintk(VIDC_ERR, "iova(%pa) truncated to %#x",
-			&iova, (u32)mem->device_addr);
-		goto fail_device_address;
-	}
-	dprintk(VIDC_DBG,
-		"%s: ion_handle = %pK, fd = %d, device_addr = %pa, size = %zx, kvaddr = %pK, buffer_type = %d, flags = %#lx\n",
-		__func__, mem->smem_priv, fd, &mem->device_addr, mem->size,
-		mem->kvaddr, mem->buffer_type, mem->flags);
+	smem->device_addr = (u32)iova + smem->offset;
+
+exit:
 	return rc;
-fail_device_address:
-	ion_free(client->clnt, hndl);
-fail_import_fd:
+}
+
+int msm_smem_map_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem)
+{
+	int rc = 0;
+
+	if (!inst || !smem) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+				__func__, inst, smem);
+		return -EINVAL;
+	}
+
+	if (smem->refcount) {
+		smem->refcount++;
+		return rc;
+	}
+
+	switch (inst->mem_client->mem_type) {
+	case SMEM_ION:
+		rc = msm_ion_map_dma_buf(inst, smem);
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s: Unknown mem_type %d\n",
+			__func__, inst->mem_client->mem_type);
+		rc = -EINVAL;
+		break;
+	}
+	if (!rc)
+		smem->refcount++;
+
+	return rc;
+}
+
+static int msm_ion_unmap_dma_buf(struct msm_vidc_inst *inst,
+		struct msm_smem *smem)
+{
+	int rc = 0;
+
+	if (!inst || !inst->mem_client || !smem) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+				__func__, inst, smem);
+		return -EINVAL;
+	}
+
+	rc = msm_ion_put_device_address(inst->mem_client, smem->handle,
+			smem->flags, &smem->mapping_info, smem->buffer_type);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to put device address: %d\n", rc);
+		goto exit;
+	}
+
+	msm_ion_put_handle(inst->mem_client->clnt, smem->handle);
+	msm_ion_put_dma_buf(smem->dma_buf);
+
+	smem->device_addr = 0x0;
+	smem->handle = NULL;
+	smem->dma_buf = NULL;
+
+exit:
+	return rc;
+}
+
+int msm_smem_unmap_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem)
+{
+	int rc = 0;
+
+	if (!inst || !smem) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+				__func__, inst, smem);
+		return -EINVAL;
+	}
+
+	if (smem->refcount) {
+		smem->refcount--;
+	} else {
+		dprintk(VIDC_WARN,
+			"unmap called while refcount is zero already\n");
+		return -EINVAL;
+	}
+
+	if (smem->refcount)
+		return rc;
+
+	switch (inst->mem_client->mem_type) {
+	case SMEM_ION:
+		rc = msm_ion_unmap_dma_buf(inst, smem);
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s: Unknown mem_type %d\n",
+			__func__, inst->mem_client->mem_type);
+		rc = -EINVAL;
+		break;
+	}
+
 	return rc;
 }
 
@@ -321,6 +491,12 @@
 	int rc = 0;
 	int ion_flags = 0;
 
+	if (!client || !mem) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+				__func__, client, mem);
+		return -EINVAL;
+	}
+
 	align = ALIGN(align, SZ_4K);
 	size = ALIGN(size, SZ_4K);
 
@@ -366,10 +542,13 @@
 	}
 	trace_msm_smem_buffer_ion_op_end("ALLOC", (u32)buffer_type,
 		heap_mask, size, align, flags, map_kernel);
-	mem->mem_type = client->mem_type;
-	mem->smem_priv = hndl;
+
+	mem->handle = hndl;
 	mem->flags = flags;
 	mem->buffer_type = buffer_type;
+	mem->offset = 0;
+	mem->size = size;
+
 	if (map_kernel) {
 		mem->kvaddr = ion_map_kernel(client->clnt, hndl);
 		if (IS_ERR_OR_NULL(mem->kvaddr)) {
@@ -382,24 +561,23 @@
 		mem->kvaddr = NULL;
 	}
 
-	rc = get_device_address(client, hndl, align, &iova, &buffer_size,
-				flags, buffer_type, &mem->mapping_info);
+	rc = msm_ion_get_device_address(client, hndl, align, &iova,
+			&buffer_size, flags, buffer_type, &mem->mapping_info);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to get device address: %d\n",
 			rc);
 		goto fail_device_address;
 	}
-	mem->device_addr = iova;
-	if ((u32)mem->device_addr != iova) {
+	mem->device_addr = (u32)iova;
+	if ((ion_phys_addr_t)mem->device_addr != iova) {
 		dprintk(VIDC_ERR, "iova(%pa) truncated to %#x",
-			&iova, (u32)mem->device_addr);
+			&iova, mem->device_addr);
 		goto fail_device_address;
 	}
-	mem->size = size;
 	dprintk(VIDC_DBG,
-		"%s: ion_handle = %pK, device_addr = %pa, size = %#zx, kvaddr = %pK, buffer_type = %#x, flags = %#lx\n",
-		__func__, mem->smem_priv, &mem->device_addr,
-		mem->size, mem->kvaddr, mem->buffer_type, mem->flags);
+		"%s: ion_handle = %pK, device_addr = %x, size = %d, kvaddr = %pK, buffer_type = %#x, flags = %#lx\n",
+		__func__, mem->handle, mem->device_addr, mem->size,
+		mem->kvaddr, mem->buffer_type, mem->flags);
 	return rc;
 fail_device_address:
 	if (mem->kvaddr)
@@ -410,30 +588,40 @@
 	return rc;
 }
 
-static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
+static int free_ion_mem(struct smem_client *client, struct msm_smem *mem)
 {
+	int rc = 0;
+
+	if (!client || !mem) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+				__func__, client, mem);
+		return -EINVAL;
+	}
+
 	dprintk(VIDC_DBG,
-		"%s: ion_handle = %pK, device_addr = %pa, size = %#zx, kvaddr = %pK, buffer_type = %#x\n",
-		__func__, mem->smem_priv, &mem->device_addr,
-		mem->size, mem->kvaddr, mem->buffer_type);
+		"%s: ion_handle = %pK, device_addr = %x, size = %d, kvaddr = %pK, buffer_type = %#x\n",
+		__func__, mem->handle, mem->device_addr, mem->size,
+		mem->kvaddr, mem->buffer_type);
 
 	if (mem->device_addr)
-		put_device_address(client, mem->smem_priv, mem->flags,
+		msm_ion_put_device_address(client, mem->handle, mem->flags,
 			&mem->mapping_info, mem->buffer_type);
 
 	if (mem->kvaddr)
-		ion_unmap_kernel(client->clnt, mem->smem_priv);
-	if (mem->smem_priv) {
+		ion_unmap_kernel(client->clnt, mem->handle);
+
+	if (mem->handle) {
 		trace_msm_smem_buffer_ion_op_start("FREE",
 				(u32)mem->buffer_type, -1, mem->size, -1,
 				mem->flags, -1);
-		dprintk(VIDC_DBG,
-			"%s: Freeing handle %pK, client: %pK\n",
-			__func__, mem->smem_priv, client->clnt);
-		ion_free(client->clnt, mem->smem_priv);
+		ion_free(client->clnt, mem->handle);
 		trace_msm_smem_buffer_ion_op_end("FREE", (u32)mem->buffer_type,
 			-1, mem->size, -1, mem->flags, -1);
+	} else {
+		dprintk(VIDC_ERR, "%s: invalid ion_handle\n", __func__);
 	}
+
+	return rc;
 }
 
 static void *ion_new_client(void)
@@ -443,135 +631,105 @@
 	client = msm_ion_client_create("video_client");
 	if (!client)
 		dprintk(VIDC_ERR, "Failed to create smem client\n");
+
+	dprintk(VIDC_DBG, "%s: client %pK\n", __func__, client);
+
 	return client;
 };
 
 static void ion_delete_client(struct smem_client *client)
 {
+	if (!client) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK\n",
+				__func__, client);
+		return;
+	}
+
+	dprintk(VIDC_DBG, "%s: client %pK\n", __func__, client->clnt);
 	ion_client_destroy(client->clnt);
+	client->clnt = NULL;
 }
 
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 size,
-		enum hal_buffer buffer_type)
+static int msm_ion_cache_operations(void *ion_client, void *ion_handle,
+		unsigned long offset, unsigned long size,
+		enum smem_cache_ops cache_op)
 {
-	struct smem_client *client = clt;
 	int rc = 0;
-	struct msm_smem *mem;
-
-	if (fd < 0) {
-		dprintk(VIDC_ERR, "Invalid fd: %d\n", fd);
-		return NULL;
-	}
-	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
-	if (!mem) {
-		dprintk(VIDC_ERR, "Failed to allocate shared mem\n");
-		return NULL;
-	}
-	switch (client->mem_type) {
-	case SMEM_ION:
-		rc = ion_user_to_kernel(clt, fd, size, mem, buffer_type);
-		break;
-	default:
-		dprintk(VIDC_ERR, "Mem type not supported\n");
-		rc = -EINVAL;
-		break;
-	}
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
-		kfree(mem);
-		mem = NULL;
-	}
-	return mem;
-}
-
-bool msm_smem_compare_buffers(void *clt, int fd, void *priv)
-{
-	struct smem_client *client = clt;
-	struct ion_handle *handle = NULL;
-	bool ret = false;
-
-	if (!clt || !priv) {
-		dprintk(VIDC_ERR, "Invalid params: %pK, %pK\n",
-			clt, priv);
-		return false;
-	}
-#ifdef CONFIG_ION
-	handle = ion_import_dma_buf_fd(client->clnt, fd);
-#endif
-	ret = handle == priv;
-	(!IS_ERR_OR_NULL(handle)) ? ion_free(client->clnt, handle) : 0;
-	return ret;
-}
-
-static int ion_cache_operations(struct smem_client *client,
-	struct msm_smem *mem, enum smem_cache_ops cache_op)
-{
-	unsigned long ionflag = 0;
-	int rc = 0;
+	unsigned long flags = 0;
 	int msm_cache_ops = 0;
 
-	if (!mem || !client) {
-		dprintk(VIDC_ERR, "Invalid params: %pK, %pK\n",
-			mem, client);
+	if (!ion_client || !ion_handle) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+			__func__, ion_client, ion_handle);
 		return -EINVAL;
 	}
-	rc = ion_handle_get_flags(client->clnt,	mem->smem_priv,
-		&ionflag);
+
+	rc = ion_handle_get_flags(ion_client, ion_handle, &flags);
 	if (rc) {
 		dprintk(VIDC_ERR,
-			"ion_handle_get_flags failed: %d\n", rc);
-		goto cache_op_failed;
+			"%s: ion_handle_get_flags failed: %d, ion client %pK, ion handle %pK\n",
+			__func__, rc, ion_client, ion_handle);
+		goto exit;
 	}
-	if (ION_IS_CACHED(ionflag)) {
-		switch (cache_op) {
-		case SMEM_CACHE_CLEAN:
-			msm_cache_ops = ION_IOC_CLEAN_CACHES;
-			break;
-		case SMEM_CACHE_INVALIDATE:
-			msm_cache_ops = ION_IOC_INV_CACHES;
-			break;
-		case SMEM_CACHE_CLEAN_INVALIDATE:
-			msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
-			break;
-		default:
-			dprintk(VIDC_ERR, "cache operation not supported\n");
-			rc = -EINVAL;
-			goto cache_op_failed;
-		}
-		rc = msm_ion_do_cache_op(client->clnt,
-			(struct ion_handle *)mem->smem_priv,
-			0, (unsigned long)mem->size,
-			msm_cache_ops);
-		if (rc) {
-			dprintk(VIDC_ERR,
-					"cache operation failed %d\n", rc);
-			goto cache_op_failed;
-		}
+
+	if (!ION_IS_CACHED(flags))
+		goto exit;
+
+	switch (cache_op) {
+	case SMEM_CACHE_CLEAN:
+		msm_cache_ops = ION_IOC_CLEAN_CACHES;
+		break;
+	case SMEM_CACHE_INVALIDATE:
+		msm_cache_ops = ION_IOC_INV_CACHES;
+		break;
+	case SMEM_CACHE_CLEAN_INVALIDATE:
+		msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s: cache (%d) operation not supported\n",
+			__func__, cache_op);
+		rc = -EINVAL;
+		goto exit;
 	}
-cache_op_failed:
+
+	rc = msm_ion_do_cache_offset_op(ion_client, ion_handle, NULL,
+			offset, size, msm_cache_ops);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: cache operation failed %d, ion client %pK, ion handle %pK, offset %lu, size %lu, msm_cache_ops %u\n",
+			__func__, rc, ion_client, ion_handle, offset,
+			size, msm_cache_ops);
+		goto exit;
+	}
+
+exit:
 	return rc;
 }
 
-int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+int msm_smem_cache_operations(struct smem_client *client,
+		void *handle, unsigned long offset, unsigned long size,
 		enum smem_cache_ops cache_op)
 {
-	struct smem_client *client = clt;
 	int rc = 0;
 
-	if (!client) {
-		dprintk(VIDC_ERR, "Invalid params: %pK\n",
-			client);
+	if (!client || !handle) {
+		dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
+			__func__, client, handle);
 		return -EINVAL;
 	}
+
 	switch (client->mem_type) {
 	case SMEM_ION:
-		rc = ion_cache_operations(client, mem, cache_op);
+		rc = msm_ion_cache_operations(client->clnt, handle,
+				offset, size, cache_op);
 		if (rc)
 			dprintk(VIDC_ERR,
-			"Failed cache operations: %d\n", rc);
+			"%s: Failed cache operations: %d\n", __func__, rc);
 		break;
 	default:
-		dprintk(VIDC_ERR, "Mem type not supported\n");
+		dprintk(VIDC_ERR, "%s: Mem type (%d) not supported\n",
+			__func__, client->mem_type);
+		rc = -EINVAL;
 		break;
 	}
 	return rc;
@@ -607,32 +765,22 @@
 	return client;
 }
 
-struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
-		enum hal_buffer buffer_type, int map_kernel)
+int msm_smem_alloc(struct smem_client *client, size_t size,
+		u32 align, u32 flags, enum hal_buffer buffer_type,
+		int map_kernel, struct msm_smem *smem)
 {
-	struct smem_client *client;
 	int rc = 0;
-	struct msm_smem *mem;
 
-	client = clt;
-	if (!client) {
-		dprintk(VIDC_ERR, "Invalid  client passed\n");
-		return NULL;
+	if (!client || !smem || !size) {
+		dprintk(VIDC_ERR, "%s: Invalid params %pK %pK %d\n",
+				__func__, client, smem, (u32)size);
+		return -EINVAL;
 	}
-	if (!size) {
-		dprintk(VIDC_ERR, "No need to allocate memory of size: %zx\n",
-			size);
-		return NULL;
-	}
-	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
-	if (!mem) {
-		dprintk(VIDC_ERR, "Failed to allocate shared mem\n");
-		return NULL;
-	}
+
 	switch (client->mem_type) {
 	case SMEM_ION:
 		rc = alloc_ion_mem(client, size, align, flags, buffer_type,
-					mem, map_kernel);
+					smem, map_kernel);
 		break;
 	default:
 		dprintk(VIDC_ERR, "Mem type not supported\n");
@@ -640,30 +788,34 @@
 		break;
 	}
 	if (rc) {
-		dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
-		kfree(mem);
-		mem = NULL;
+		dprintk(VIDC_ERR, "Failed to allocate memory\n");
 	}
-	return mem;
+
+	return rc;
 }
 
-void msm_smem_free(void *clt, struct msm_smem *mem)
+int msm_smem_free(void *clt, struct msm_smem *smem)
 {
+	int rc = 0;
 	struct smem_client *client = clt;
 
-	if (!client || !mem) {
+	if (!client || !smem) {
 		dprintk(VIDC_ERR, "Invalid  client/handle passed\n");
-		return;
+		return -EINVAL;
 	}
 	switch (client->mem_type) {
 	case SMEM_ION:
-		free_ion_mem(client, mem);
+		rc = free_ion_mem(client, smem);
 		break;
 	default:
 		dprintk(VIDC_ERR, "Mem type not supported\n");
+		rc = -EINVAL;
 		break;
 	}
-	kfree(mem);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to free memory\n");
+
+	return rc;
 };
 
 void msm_smem_delete_client(void *clt)
@@ -692,7 +844,7 @@
 	struct context_bank_info *cb = NULL, *match = NULL;
 
 	if (!clt) {
-		dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+		dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
 		return NULL;
 	}
 
@@ -713,12 +865,13 @@
 		if (cb->is_secure == is_secure &&
 				cb->buffer_type & buffer_type) {
 			match = cb;
-			dprintk(VIDC_DBG,
-				"context bank found for CB : %s, device: %pK mapping: %pK\n",
-				match->name, match->dev, match->mapping);
 			break;
 		}
 	}
+	if (!match)
+		dprintk(VIDC_ERR,
+			"%s: cb not found for buffer_type %x, is_secure %d\n",
+			__func__, buffer_type, is_secure);
 
 	return match;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 5c34f28..8c63469 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -36,7 +36,6 @@
 
 struct msm_vidc_drv *vidc_driver;
 
-uint32_t msm_vidc_pwr_collapse_delay = 3000;
 
 static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
 {
@@ -315,6 +314,7 @@
 	core->resources.pdev = pdev;
 	if (pdev->dev.of_node) {
 		/* Target supports DT, parse from it */
+		rc = read_platform_resources_from_drv_data(core);
 		rc = read_platform_resources_from_dt(&core->resources);
 	} else {
 		dprintk(VIDC_ERR, "pdev node is NULL\n");
@@ -375,13 +375,18 @@
 {
 	unsigned long val = 0;
 	int rc = 0;
+	struct msm_vidc_core *core = NULL;
 
 	rc = kstrtoul(buf, 0, &val);
 	if (rc)
 		return rc;
 	else if (!val)
 		return -EINVAL;
-	msm_vidc_pwr_collapse_delay = val;
+
+	core = get_vidc_core(MSM_VIDC_CORE_VENUS);
+	if (!core)
+		return -EINVAL;
+	core->resources.msm_vidc_pwr_collapse_delay = val;
 	return count;
 }
 
@@ -389,7 +394,14 @@
 		struct device_attribute *attr,
 		char *buf)
 {
-	return snprintf(buf, PAGE_SIZE, "%u\n", msm_vidc_pwr_collapse_delay);
+	struct msm_vidc_core *core = NULL;
+
+	core = get_vidc_core(MSM_VIDC_CORE_VENUS);
+	if (!core)
+		return -EINVAL;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		core->resources.msm_vidc_pwr_collapse_delay);
 }
 
 static DEVICE_ATTR(pwr_collapse_delay, 0644, show_pwr_collapse_delay,
@@ -481,6 +493,7 @@
 		goto err_no_mem;
 	}
 
+	core->platform_data = vidc_get_drv_data(&pdev->dev);
 	dev_set_drvdata(&pdev->dev, core);
 	rc = msm_vidc_initialize_core(pdev, core);
 	if (rc) {
@@ -710,6 +723,7 @@
 	v4l2_device_unregister(&core->v4l2_dev);
 
 	msm_vidc_free_platform_resources(&core->resources);
+	kfree(core->vote_data);
 	sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
 	dev_set_drvdata(&pdev->dev, NULL);
 	mutex_destroy(&core->lock);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 053d748..acca9f4 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -20,7 +20,10 @@
 #include "msm_vidc_clocks.h"
 
 #define MSM_VDEC_DVC_NAME "msm_vdec_8974"
+#define MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS MIN_NUM_OUTPUT_BUFFERS
 #define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS MIN_NUM_CAPTURE_BUFFERS
+#define MIN_NUM_DEC_OUTPUT_BUFFERS 4
+#define MIN_NUM_DEC_CAPTURE_BUFFERS 4
 #define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
 #define MB_SIZE_IN_PIXEL (16 * 16)
 #define OPERATING_FRAME_RATE_STEP (1 << 16)
@@ -149,7 +152,7 @@
 		.name = "Extradata Type",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
-		.maximum = V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE,
+		.maximum = V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO,
 		.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
 		.menu_skip_mask = ~(
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
@@ -176,7 +179,8 @@
 			(1 <<
 			V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY) |
-			(1 << V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE)
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO)
 			),
 		.qmenu = mpeg_video_vidc_extradata,
 	},
@@ -513,6 +517,7 @@
 				msm_comm_get_hal_output_buffer(inst),
 				f->fmt.pix_mp.pixelformat);
 
+		inst->clk_data.opb_fourcc = f->fmt.pix_mp.pixelformat;
 		if (msm_comm_get_stream_output_mode(inst) ==
 			HAL_VIDEO_DECODER_SECONDARY) {
 			frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
@@ -544,7 +549,6 @@
 				f->fmt.pix_mp.plane_fmt[i].sizeimage;
 		}
 
-		rc = msm_comm_try_get_bufreqs(inst);
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 
 		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
@@ -598,8 +602,6 @@
 			inst->bufq[OUTPUT_PORT].plane_sizes[i] =
 				f->fmt.pix_mp.plane_fmt[i].sizeimage;
 		}
-
-		rc = msm_comm_try_get_bufreqs(inst);
 	}
 err_invalid_fmt:
 	return rc;
@@ -675,6 +677,19 @@
 	memcpy(&inst->fmts[fmt->type], fmt,
 			sizeof(struct msm_vidc_format));
 
+	inst->buff_req.buffer[1].buffer_type = HAL_BUFFER_INPUT;
+	inst->buff_req.buffer[1].buffer_count_min_host =
+	inst->buff_req.buffer[1].buffer_count_actual =
+		MIN_NUM_DEC_OUTPUT_BUFFERS;
+	inst->buff_req.buffer[2].buffer_type = HAL_BUFFER_OUTPUT;
+	inst->buff_req.buffer[2].buffer_count_min_host =
+	inst->buff_req.buffer[2].buffer_count_actual =
+		MIN_NUM_DEC_CAPTURE_BUFFERS;
+	inst->buff_req.buffer[3].buffer_type = HAL_BUFFER_OUTPUT2;
+	inst->buff_req.buffer[3].buffer_count_min_host =
+	inst->buff_req.buffer[3].buffer_count_actual =
+		MIN_NUM_DEC_CAPTURE_BUFFERS;
+
 	/* By default, initialize OUTPUT port to H264 decoder */
 	fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
 		ARRAY_SIZE(vdec_formats), V4L2_PIX_FMT_H264,
@@ -716,6 +731,7 @@
 	struct v4l2_ctrl *temp_ctrl = NULL;
 	struct hal_profile_level profile_level;
 	struct hal_frame_size frame_sz;
+	struct hal_buffer_requirements *bufreq;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
@@ -777,6 +793,59 @@
 		hal_property.enable = ctrl->val;
 		pdata = &hal_property;
 		msm_dcvs_try_enable(inst);
+
+		bufreq = get_buff_req_buffer(inst,
+				HAL_BUFFER_INPUT);
+		if (!bufreq) {
+			dprintk(VIDC_ERR,
+					"Failed : No buffer requirements : %x\n",
+					HAL_BUFFER_OUTPUT);
+			return -EINVAL;
+		}
+		bufreq->buffer_count_min =
+			MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS;
+
+		if (msm_comm_get_stream_output_mode(inst) ==
+				HAL_VIDEO_DECODER_SECONDARY) {
+
+			bufreq = get_buff_req_buffer(inst,
+					HAL_BUFFER_OUTPUT);
+			if (!bufreq) {
+				dprintk(VIDC_ERR,
+					"Failed : No buffer requirements: %x\n",
+						HAL_BUFFER_OUTPUT);
+				return -EINVAL;
+			}
+
+			bufreq->buffer_count_min =
+				MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS;
+
+			bufreq = get_buff_req_buffer(inst,
+					HAL_BUFFER_OUTPUT2);
+			if (!bufreq) {
+				dprintk(VIDC_ERR,
+					"Failed : No buffer requirements: %x\n",
+						HAL_BUFFER_OUTPUT2);
+				return -EINVAL;
+			}
+
+			bufreq->buffer_count_min =
+				MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS;
+		} else {
+
+			bufreq = get_buff_req_buffer(inst,
+					HAL_BUFFER_OUTPUT);
+			if (!bufreq) {
+				dprintk(VIDC_ERR,
+					"Failed : No buffer requirements: %x\n",
+						HAL_BUFFER_OUTPUT);
+				return -EINVAL;
+			}
+			bufreq->buffer_count_min =
+				MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS;
+
+		}
+
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
 		property_id = HAL_PARAM_SECURE;
@@ -809,6 +878,7 @@
 		case V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI:
 		case V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY:
 		case V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE:
+		case V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO:
 			inst->bufq[CAPTURE_PORT].num_planes = 2;
 			inst->bufq[CAPTURE_PORT].plane_sizes[EXTRADATA_IDX(2)] =
 				VENUS_EXTRADATA_SIZE(
@@ -896,7 +966,6 @@
 					"Failed setting OUTPUT2 size : %d\n",
 					rc);
 
-			rc = msm_comm_try_get_bufreqs(inst);
 			break;
 		default:
 			dprintk(VIDC_ERR,
@@ -920,7 +989,6 @@
 				V4L2_CID_MPEG_VIDEO_H264_LEVEL,
 				temp_ctrl->val);
 		pdata = &profile_level;
-		rc = msm_comm_try_get_bufreqs(inst);
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
 		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
@@ -932,7 +1000,6 @@
 				V4L2_CID_MPEG_VIDEO_H264_PROFILE,
 				temp_ctrl->val);
 		pdata = &profile_level;
-		rc = msm_comm_try_get_bufreqs(inst);
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT:
 		dprintk(VIDC_DBG,
@@ -1051,11 +1118,14 @@
 						break;
 					}
 					rc = msm_comm_try_get_bufreqs(inst);
-					if (rc)
+					if (rc) {
 						dprintk(VIDC_ERR,
 							"%s Failed to get buffer requirements : %d\n",
 							__func__, rc);
+						break;
+					}
 				}
+				inst->clk_data.dpb_fourcc = fourcc;
 				break;
 			default:
 				dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index d44684e..e2ea2bc 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -39,6 +39,8 @@
 #define MIN_TIME_RESOLUTION 1
 #define MAX_TIME_RESOLUTION 0xFFFFFF
 #define DEFAULT_TIME_RESOLUTION 0x7530
+#define MIN_NUM_ENC_OUTPUT_BUFFERS 4
+#define MIN_NUM_ENC_CAPTURE_BUFFERS 5
 
 /*
  * Default 601 to 709 conversion coefficients for resolution: 176x144 negative
@@ -955,7 +957,7 @@
 		.name = "Set Color space transfer characterstics",
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.minimum = MSM_VIDC_TRANSFER_BT709_5,
-		.maximum = MSM_VIDC_TRANSFER_BT_2020_12,
+		.maximum = MSM_VIDC_TRANSFER_HLG,
 		.default_value = MSM_VIDC_TRANSFER_601_6_625,
 		.step = 1,
 		.qmenu = NULL,
@@ -2124,6 +2126,15 @@
 	inst->bufq[CAPTURE_PORT].num_planes = 1;
 	inst->clk_data.operating_rate = 0;
 
+	inst->buff_req.buffer[1].buffer_type = HAL_BUFFER_INPUT;
+	inst->buff_req.buffer[1].buffer_count_min_host =
+	inst->buff_req.buffer[1].buffer_count_actual =
+		MIN_NUM_ENC_OUTPUT_BUFFERS;
+	inst->buff_req.buffer[2].buffer_type = HAL_BUFFER_OUTPUT;
+	inst->buff_req.buffer[2].buffer_count_min_host =
+	inst->buff_req.buffer[2].buffer_count_actual =
+		MIN_NUM_ENC_CAPTURE_BUFFERS;
+
 	/* By default, initialize OUTPUT port to UBWC YUV format */
 	fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
 		ARRAY_SIZE(venc_formats), V4L2_PIX_FMT_NV12_UBWC,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 2e952a3..21ad17a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include "vidc_hfi_api.h"
 #include "msm_vidc_clocks.h"
+#include <linux/dma-buf.h>
 
 #define MAX_EVENTS 30
 
@@ -383,507 +384,6 @@
 }
 EXPORT_SYMBOL(msm_vidc_reqbufs);
 
-struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst,
-		struct v4l2_buffer *b, int idx, int *plane)
-{
-	struct buffer_info *temp;
-	struct buffer_info *ret = NULL;
-	int i;
-	int fd = b->m.planes[idx].reserved[0];
-	u32 buff_off = b->m.planes[idx].reserved[1];
-	u32 size = b->m.planes[idx].length;
-	ion_phys_addr_t device_addr = b->m.planes[idx].m.userptr;
-
-	if (fd < 0 || !plane) {
-		dprintk(VIDC_ERR, "Invalid input\n");
-		goto err_invalid_input;
-	}
-
-	WARN(!mutex_is_locked(&inst->registeredbufs.lock),
-		"Registered buf lock is not acquired for %s", __func__);
-
-	*plane = 0;
-	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
-		for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
-			bool ion_hndl_matches = temp->handle[i] ?
-				msm_smem_compare_buffers(inst->mem_client, fd,
-				temp->handle[i]->smem_priv) : false;
-			bool device_addr_matches = device_addr ==
-						temp->device_addr[i];
-			bool contains_within = CONTAINS(temp->buff_off[i],
-					temp->size[i], buff_off) ||
-				CONTAINS(buff_off, size, temp->buff_off[i]);
-			bool overlaps = OVERLAPS(buff_off, size,
-					temp->buff_off[i], temp->size[i]);
-
-			if (!temp->inactive &&
-				(ion_hndl_matches || device_addr_matches) &&
-				(contains_within || overlaps)) {
-				dprintk(VIDC_DBG,
-						"This memory region is already mapped\n");
-				ret = temp;
-				*plane = i;
-				break;
-			}
-		}
-		if (ret)
-			break;
-	}
-
-err_invalid_input:
-	return ret;
-}
-
-static struct msm_smem *get_same_fd_buffer(struct msm_vidc_inst *inst, int fd)
-{
-	struct buffer_info *temp;
-	struct msm_smem *same_fd_handle = NULL;
-	int i;
-
-	if (!fd)
-		return NULL;
-
-	if (!inst || fd < 0) {
-		dprintk(VIDC_ERR, "%s: Invalid input\n", __func__);
-		goto err_invalid_input;
-	}
-
-	mutex_lock(&inst->registeredbufs.lock);
-	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
-		for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
-			bool ion_hndl_matches = temp->handle[i] ?
-				msm_smem_compare_buffers(inst->mem_client, fd,
-				temp->handle[i]->smem_priv) : false;
-			if (ion_hndl_matches && temp->mapped[i])  {
-				temp->same_fd_ref[i]++;
-				dprintk(VIDC_INFO,
-				"Found same fd buffer\n");
-				same_fd_handle = temp->handle[i];
-				break;
-			}
-		}
-		if (same_fd_handle)
-			break;
-	}
-	mutex_unlock(&inst->registeredbufs.lock);
-
-err_invalid_input:
-	return same_fd_handle;
-}
-
-struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list,
-				ion_phys_addr_t device_addr)
-{
-	struct buffer_info *temp = NULL;
-	bool found = false;
-	int i;
-
-	if (!buf_list || !device_addr) {
-		dprintk(VIDC_ERR,
-			"Invalid input- device_addr: %pa buf_list: %pK\n",
-			&device_addr, buf_list);
-		goto err_invalid_input;
-	}
-
-	mutex_lock(&buf_list->lock);
-	list_for_each_entry(temp, &buf_list->list, list) {
-		for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
-			if (!temp->inactive &&
-				temp->device_addr[i] == device_addr)  {
-				dprintk(VIDC_INFO,
-				"Found same fd buffer\n");
-				found = true;
-				break;
-			}
-		}
-
-		if (found)
-			break;
-	}
-	mutex_unlock(&buf_list->lock);
-
-err_invalid_input:
-	return temp;
-}
-
-static inline void populate_buf_info(struct buffer_info *binfo,
-			struct v4l2_buffer *b, u32 i)
-{
-	if (i >= VIDEO_MAX_PLANES) {
-		dprintk(VIDC_ERR, "%s: Invalid input\n", __func__);
-		return;
-	}
-	binfo->type = b->type;
-	binfo->fd[i] = b->m.planes[i].reserved[0];
-	binfo->buff_off[i] = b->m.planes[i].reserved[1];
-	binfo->size[i] = b->m.planes[i].length;
-	binfo->uvaddr[i] = b->m.planes[i].m.userptr;
-	binfo->num_planes = b->length;
-	binfo->memory = b->memory;
-	binfo->v4l2_index = b->index;
-	binfo->timestamp.tv_sec = b->timestamp.tv_sec;
-	binfo->timestamp.tv_usec = b->timestamp.tv_usec;
-	dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d",
-			__func__, i, binfo->fd[i], b->index);
-}
-
-static inline void repopulate_v4l2_buffer(struct v4l2_buffer *b,
-					struct buffer_info *binfo)
-{
-	int i = 0;
-
-	b->type = binfo->type;
-	b->length = binfo->num_planes;
-	b->memory = binfo->memory;
-	b->index = binfo->v4l2_index;
-	b->timestamp.tv_sec = binfo->timestamp.tv_sec;
-	b->timestamp.tv_usec = binfo->timestamp.tv_usec;
-	binfo->dequeued = false;
-	for (i = 0; i < binfo->num_planes; ++i) {
-		b->m.planes[i].reserved[0] = binfo->fd[i];
-		b->m.planes[i].reserved[1] = binfo->buff_off[i];
-		b->m.planes[i].length = binfo->size[i];
-		b->m.planes[i].m.userptr = binfo->device_addr[i];
-		dprintk(VIDC_DBG, "%s %d %d %d %pa\n", __func__, binfo->fd[i],
-				binfo->buff_off[i], binfo->size[i],
-				&binfo->device_addr[i]);
-	}
-}
-
-static struct msm_smem *map_buffer(struct msm_vidc_inst *inst,
-		struct v4l2_plane *p, enum hal_buffer buffer_type)
-{
-	struct msm_smem *handle = NULL;
-
-	handle = msm_comm_smem_user_to_kernel(inst,
-				p->reserved[0],
-				p->length,
-				buffer_type);
-	if (!handle) {
-		dprintk(VIDC_ERR,
-			"%s: Failed to get device buffer address\n", __func__);
-		return NULL;
-	}
-	return handle;
-}
-
-static inline enum hal_buffer get_hal_buffer_type(
-		struct msm_vidc_inst *inst, struct v4l2_buffer *b)
-{
-	if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-		return HAL_BUFFER_INPUT;
-	else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-		return HAL_BUFFER_OUTPUT;
-	else
-		return -EINVAL;
-}
-
-static inline bool is_dynamic_buffer_mode(struct v4l2_buffer *b,
-				struct msm_vidc_inst *inst)
-{
-	enum vidc_ports port = b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
-		OUTPUT_PORT : CAPTURE_PORT;
-	return inst->buffer_mode_set[port] == HAL_BUFFER_MODE_DYNAMIC;
-}
-
-
-static inline void save_v4l2_buffer(struct v4l2_buffer *b,
-						struct buffer_info *binfo)
-{
-	int i = 0;
-
-	for (i = 0; i < b->length; ++i) {
-		if (EXTRADATA_IDX(b->length) &&
-			(i == EXTRADATA_IDX(b->length)) &&
-			!b->m.planes[i].length) {
-			continue;
-		}
-		populate_buf_info(binfo, b, i);
-	}
-}
-
-int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
-{
-	struct buffer_info *binfo = NULL;
-	struct buffer_info *temp = NULL, *iterator = NULL;
-	int plane = 0;
-	int i = 0, rc = 0;
-	struct msm_smem *same_fd_handle = NULL;
-
-	if (!b || !inst) {
-		dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
-		return -EINVAL;
-	}
-
-	binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
-	if (!binfo) {
-		dprintk(VIDC_ERR, "Out of memory\n");
-		rc = -ENOMEM;
-		goto exit;
-	}
-	if (b->length > VIDEO_MAX_PLANES) {
-		dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
-			b->length, VIDEO_MAX_PLANES);
-		rc = -EINVAL;
-		goto exit;
-	}
-
-	dprintk(VIDC_DBG,
-		"[MAP] Create binfo = %pK fd = %d size = %d type = %d\n",
-		binfo, b->m.planes[0].reserved[0],
-		b->m.planes[0].length, b->type);
-
-	for (i = 0; i < b->length; ++i) {
-		rc = 0;
-		if (EXTRADATA_IDX(b->length) &&
-			(i == EXTRADATA_IDX(b->length)) &&
-			!b->m.planes[i].length) {
-			continue;
-		}
-		mutex_lock(&inst->registeredbufs.lock);
-		temp = get_registered_buf(inst, b, i, &plane);
-		if (temp && !is_dynamic_buffer_mode(b, inst)) {
-			dprintk(VIDC_DBG,
-				"This memory region has already been prepared\n");
-			rc = 0;
-			mutex_unlock(&inst->registeredbufs.lock);
-			goto exit;
-		}
-
-		if (temp && is_dynamic_buffer_mode(b, inst) && !i) {
-			/*
-			 * Buffer is already present in registered list
-			 * increment ref_count, populate new values of v4l2
-			 * buffer in existing buffer_info struct.
-			 *
-			 * We will use the saved buffer info and queue it when
-			 * we receive RELEASE_BUFFER_REFERENCE EVENT from f/w.
-			 */
-			dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
-			temp->inactive = false;
-			list_for_each_entry(iterator,
-				&inst->registeredbufs.list, list) {
-				if (iterator == temp) {
-					rc = buf_ref_get(inst, temp);
-					save_v4l2_buffer(b, temp);
-					break;
-				}
-			}
-		}
-		mutex_unlock(&inst->registeredbufs.lock);
-		/*
-		 * rc == 1,
-		 * buffer is mapped, fw has released all reference, so skip
-		 * mapping and queue it immediately.
-		 *
-		 * rc == 2,
-		 * buffer is mapped and fw is holding a reference, hold it in
-		 * the driver and queue it later when fw has released
-		 */
-		if (rc == 1) {
-			rc = 0;
-			goto exit;
-		} else if (rc >= 2) {
-			rc = -EEXIST;
-			goto exit;
-		}
-
-		same_fd_handle = get_same_fd_buffer(
-				inst, b->m.planes[i].reserved[0]);
-
-		populate_buf_info(binfo, b, i);
-		if (same_fd_handle) {
-			binfo->device_addr[i] =
-			same_fd_handle->device_addr + binfo->buff_off[i];
-			b->m.planes[i].m.userptr = binfo->device_addr[i];
-			binfo->mapped[i] = false;
-			binfo->handle[i] = same_fd_handle;
-		} else {
-			binfo->handle[i] = map_buffer(inst, &b->m.planes[i],
-					get_hal_buffer_type(inst, b));
-			if (!binfo->handle[i]) {
-				rc = -EINVAL;
-				goto exit;
-			}
-
-			binfo->mapped[i] = true;
-			binfo->device_addr[i] = binfo->handle[i]->device_addr +
-				binfo->buff_off[i];
-			b->m.planes[i].m.userptr = binfo->device_addr[i];
-		}
-
-		/* We maintain one ref count for all planes*/
-		if (!i && is_dynamic_buffer_mode(b, inst)) {
-			rc = buf_ref_get(inst, binfo);
-			if (rc < 0)
-				goto exit;
-		}
-		dprintk(VIDC_DBG,
-			"%s: [MAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
-			__func__, binfo, i, binfo->handle[i],
-			&binfo->device_addr[i], binfo->fd[i],
-			binfo->buff_off[i], binfo->mapped[i]);
-	}
-
-	mutex_lock(&inst->registeredbufs.lock);
-	list_add_tail(&binfo->list, &inst->registeredbufs.list);
-	mutex_unlock(&inst->registeredbufs.lock);
-	return 0;
-
-exit:
-	kfree(binfo);
-	return rc;
-}
-int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
-			struct buffer_info *binfo)
-{
-	int i = 0;
-	struct buffer_info *temp = NULL;
-	bool found = false, keep_node = false;
-
-	if (!inst || !binfo) {
-		dprintk(VIDC_ERR, "%s invalid param: %pK %pK\n",
-			__func__, inst, binfo);
-		return -EINVAL;
-	}
-
-	WARN(!mutex_is_locked(&inst->registeredbufs.lock),
-		"Registered buf lock is not acquired for %s", __func__);
-
-	/*
-	 * Make sure the buffer to be unmapped and deleted
-	 * from the registered list is present in the list.
-	 */
-	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
-		if (temp == binfo) {
-			found = true;
-			break;
-		}
-	}
-
-	/*
-	 * Free the buffer info only if
-	 * - buffer info has not been deleted from registered list
-	 * - vidc client has called dqbuf on the buffer
-	 * - no references are held on the buffer
-	 */
-	if (!found || !temp || !temp->pending_deletion || !temp->dequeued)
-		goto exit;
-
-	for (i = 0; i < temp->num_planes; i++) {
-		dprintk(VIDC_DBG,
-			"%s: [UNMAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
-			__func__, temp, i, temp->handle[i],
-			&temp->device_addr[i], temp->fd[i],
-			temp->buff_off[i], temp->mapped[i]);
-		/*
-		 * Unmap the handle only if the buffer has been mapped and no
-		 * other buffer has a reference to this buffer.
-		 * In case of buffers with same fd, we will map the buffer only
-		 * once and subsequent buffers will refer to the mapped buffer's
-		 * device address.
-		 * For buffers which share the same fd, do not unmap and keep
-		 * the buffer info in registered list.
-		 */
-		if (temp->handle[i] && temp->mapped[i] &&
-			!temp->same_fd_ref[i]) {
-			msm_comm_smem_free(inst,
-				temp->handle[i]);
-		}
-
-		if (temp->same_fd_ref[i])
-			keep_node = true;
-		else {
-			temp->fd[i] = 0;
-			temp->handle[i] = 0;
-			temp->device_addr[i] = 0;
-			temp->uvaddr[i] = 0;
-		}
-	}
-	if (!keep_node) {
-		dprintk(VIDC_DBG, "[UNMAP] AND-FREED binfo: %pK\n", temp);
-		list_del(&temp->list);
-		kfree(temp);
-	} else {
-		temp->inactive = true;
-		dprintk(VIDC_DBG, "[UNMAP] NOT-FREED binfo: %pK\n", temp);
-	}
-exit:
-	return 0;
-}
-
-
-int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
-			struct buffer_info *binfo)
-{
-	struct v4l2_buffer b = {0};
-	struct v4l2_plane plane[VIDEO_MAX_PLANES] = { {0} };
-	struct buf_queue *q = NULL;
-	int rc = 0;
-
-	if (!binfo) {
-		dprintk(VIDC_ERR, "%s invalid param: %pK\n", __func__, binfo);
-		return -EINVAL;
-	}
-	dprintk(VIDC_DBG, "%s fd[0] = %d\n", __func__, binfo->fd[0]);
-
-	b.m.planes = plane;
-	repopulate_v4l2_buffer(&b, binfo);
-
-	q = msm_comm_get_vb2q(inst, (&b)->type);
-	if (!q) {
-		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
-				, (&b)->type);
-		return -EINVAL;
-	}
-
-	mutex_lock(&q->lock);
-	rc = vb2_qbuf(&q->vb2_bufq, &b);
-	mutex_unlock(&q->lock);
-
-	if (rc)
-		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
-	return rc;
-}
-
-int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
-				struct buffer_info *binfo)
-{
-	int i = 0;
-	int rc = 0;
-
-	if (!inst) {
-		dprintk(VIDC_ERR, "%s: invalid inst: %pK\n", __func__, inst);
-		return -EINVAL;
-	}
-
-	if (!binfo) {
-		dprintk(VIDC_ERR, "%s: invalid buffer info: %pK\n",
-			__func__, inst);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < binfo->num_planes; i++) {
-		if (binfo->handle[i]) {
-			struct msm_smem smem = *binfo->handle[i];
-
-			smem.offset = (unsigned int)(binfo->buff_off[i]);
-			smem.size   = binfo->size[i];
-			rc = msm_comm_smem_cache_operations(inst,
-				&smem, SMEM_CACHE_INVALIDATE);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"%s: Failed to clean caches: %d\n",
-					__func__, rc);
-				return -EINVAL;
-			}
-		} else
-			dprintk(VIDC_DBG, "%s: NULL handle for plane %d\n",
-					__func__, i);
-	}
-	return 0;
-}
-
 static bool valid_v4l2_buffer(struct v4l2_buffer *b,
 		struct msm_vidc_inst *inst) {
 	enum vidc_ports port =
@@ -896,17 +396,16 @@
 		inst->bufq[port].num_planes == b->length;
 }
 
-int msm_vidc_release_buffer(void *instance, int buffer_type,
-		unsigned int buffer_index)
+int msm_vidc_release_buffer(void *instance, int type, unsigned int index)
 {
+	int rc = 0;
 	struct msm_vidc_inst *inst = instance;
-	struct buffer_info *bi, *dummy;
-	int i, rc = 0;
-	int found_buf = 0;
-	struct vb2_buf_entry *temp, *next;
+	struct msm_vidc_buffer *mbuf, *dummy;
 
-	if (!inst)
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid inst\n", __func__);
 		return -EINVAL;
+	}
 
 	if (!inst->in_reconfig &&
 		inst->state > MSM_VIDC_LOAD_RESOURCES &&
@@ -914,64 +413,26 @@
 		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
 		if (rc) {
 			dprintk(VIDC_ERR,
-					"Failed to move inst: %pK to release res done\n",
-					inst);
+					"%s: Failed to move inst: %pK to release res done\n",
+					__func__, inst);
 		}
 	}
 
 	mutex_lock(&inst->registeredbufs.lock);
-	list_for_each_entry_safe(bi, dummy, &inst->registeredbufs.list, list) {
-		if (bi->type == buffer_type && bi->v4l2_index == buffer_index) {
-			found_buf = 1;
-			list_del(&bi->list);
-			for (i = 0; i < bi->num_planes; i++) {
-				if (bi->handle[i] && bi->mapped[i]) {
-					dprintk(VIDC_DBG,
-						"%s: [UNMAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
-						__func__, bi, i, bi->handle[i],
-						&bi->device_addr[i], bi->fd[i],
-						bi->buff_off[i], bi->mapped[i]);
-					msm_comm_smem_free(inst,
-							bi->handle[i]);
-					found_buf = 2;
-				}
-			}
-			kfree(bi);
-			break;
-		}
+	list_for_each_entry_safe(mbuf, dummy, &inst->registeredbufs.list,
+			list) {
+		struct vb2_buffer *vb2 = &mbuf->vvb.vb2_buf;
+
+		if (vb2->type != type || vb2->index != index)
+			continue;
+
+		print_vidc_buffer(VIDC_DBG, "release buf", inst, mbuf);
+		msm_comm_unmap_vidc_buffer(inst, mbuf);
+		list_del(&mbuf->list);
+		kfree(mbuf);
 	}
 	mutex_unlock(&inst->registeredbufs.lock);
 
-	switch (found_buf) {
-	case 0:
-		dprintk(VIDC_DBG,
-			"%s: No buffer(type: %d) found for index %d\n",
-			__func__, buffer_type, buffer_index);
-		break;
-	case 1:
-		dprintk(VIDC_WARN,
-			"%s: Buffer(type: %d) found for index %d.",
-			__func__, buffer_type, buffer_index);
-		dprintk(VIDC_WARN, "zero planes mapped.\n");
-		break;
-	case 2:
-		dprintk(VIDC_DBG,
-			"%s: Released buffer(type: %d) for index %d\n",
-			__func__, buffer_type, buffer_index);
-		break;
-	default:
-		break;
-	}
-
-	mutex_lock(&inst->pendingq.lock);
-	list_for_each_entry_safe(temp, next, &inst->pendingq.list, list) {
-		if (temp->vb->type == buffer_type) {
-			list_del(&temp->list);
-			kfree(temp);
-		}
-	}
-	mutex_unlock(&inst->pendingq.lock);
-
 	return rc;
 }
 EXPORT_SYMBOL(msm_vidc_release_buffer);
@@ -979,65 +440,20 @@
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
-	struct buffer_info *binfo;
-	int plane = 0;
-	int rc = 0;
-	int i;
+	int rc = 0, i = 0;
 	struct buf_queue *q = NULL;
 
-	if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst))
+	if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst)) {
+		dprintk(VIDC_ERR, "%s: invalid params, inst %pK\n",
+			__func__, inst);
 		return -EINVAL;
-
-	if (inst->state == MSM_VIDC_CORE_INVALID ||
-		inst->core->state == VIDC_CORE_INVALID)
-		return -EINVAL;
-
-	rc = map_and_register_buf(inst, b);
-	if (rc == -EEXIST) {
-		if (atomic_read(&inst->in_flush) &&
-			is_dynamic_buffer_mode(b, inst)) {
-			dprintk(VIDC_ERR,
-				"Flush in progress, do not hold any buffers in driver\n");
-			msm_comm_flush_dynamic_buffers(inst);
-		}
-		return 0;
 	}
-	if (rc)
-		return rc;
 
-	for (i = 0; i < b->length; ++i) {
-		if (EXTRADATA_IDX(b->length) &&
-			(i == EXTRADATA_IDX(b->length)) &&
-			!b->m.planes[i].length) {
-			b->m.planes[i].m.userptr = 0;
-			continue;
-		}
-		mutex_lock(&inst->registeredbufs.lock);
-		binfo = get_registered_buf(inst, b, i, &plane);
-		mutex_unlock(&inst->registeredbufs.lock);
-		if (!binfo) {
-			dprintk(VIDC_ERR,
-				"This buffer is not registered: %d, %d, %d\n",
-				b->m.planes[i].reserved[0],
-				b->m.planes[i].reserved[1],
-				b->m.planes[i].length);
-			goto err_invalid_buff;
-		}
-		b->m.planes[i].m.userptr = binfo->device_addr[i];
-		dprintk(VIDC_DBG, "Queueing device address = %pa\n",
-				&binfo->device_addr[i]);
-
-		if (binfo->handle[i] &&
-			(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
-			rc = msm_comm_smem_cache_operations(inst,
-					binfo->handle[i], SMEM_CACHE_CLEAN);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"Failed to clean caches: %d\n", rc);
-				goto err_invalid_buff;
-			}
-		}
+	for (i = 0; i < b->length; i++) {
+		b->m.planes[i].m.fd = b->m.planes[i].reserved[0];
+		b->m.planes[i].data_offset = b->m.planes[i].reserved[1];
 	}
+	msm_comm_qbuf_cache_operations(inst, b);
 
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
@@ -1045,27 +461,28 @@
 			"Failed to find buffer queue for type = %d\n", b->type);
 		return -EINVAL;
 	}
+
 	mutex_lock(&q->lock);
 	rc = vb2_qbuf(&q->vb2_bufq, b);
 	mutex_unlock(&q->lock);
 	if (rc)
 		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
-	return rc;
 
-err_invalid_buff:
-	return -EINVAL;
+	return rc;
 }
 EXPORT_SYMBOL(msm_vidc_qbuf);
 
 int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
-	struct buffer_info *buffer_info = NULL;
-	int i = 0, rc = 0;
+	int rc = 0, i = 0;
 	struct buf_queue *q = NULL;
 
-	if (!inst || !b || !valid_v4l2_buffer(b, inst))
+	if (!inst || !b || !valid_v4l2_buffer(b, inst)) {
+		dprintk(VIDC_ERR, "%s: invalid params, inst %pK\n",
+			__func__, inst);
 		return -EINVAL;
+	}
 
 	q = msm_comm_get_vb2q(inst, b->type);
 	if (!q) {
@@ -1073,54 +490,21 @@
 			"Failed to find buffer queue for type = %d\n", b->type);
 		return -EINVAL;
 	}
+
 	mutex_lock(&q->lock);
 	rc = vb2_dqbuf(&q->vb2_bufq, b, true);
 	mutex_unlock(&q->lock);
-	if (rc) {
-		dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
+	if (rc == -EAGAIN) {
+		return rc;
+	} else if (rc) {
+		dprintk(VIDC_ERR, "Failed to dqbuf, %d\n", rc);
 		return rc;
 	}
 
+	msm_comm_dqbuf_cache_operations(inst, b);
 	for (i = 0; i < b->length; i++) {
-		if (EXTRADATA_IDX(b->length) &&
-			i == EXTRADATA_IDX(b->length)) {
-			continue;
-		}
-		buffer_info = device_to_uvaddr(&inst->registeredbufs,
-			b->m.planes[i].m.userptr);
-
-		if (!buffer_info) {
-			dprintk(VIDC_ERR,
-				"%s no buffer info registered for buffer addr: %#lx\n",
-				__func__, b->m.planes[i].m.userptr);
-			return -EINVAL;
-		}
-
-		b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
-		b->m.planes[i].reserved[0] = buffer_info->fd[i];
-		b->m.planes[i].reserved[1] = buffer_info->buff_off[i];
-	}
-
-	if (!buffer_info) {
-		dprintk(VIDC_ERR,
-			"%s: error - no buffer info found in registered list\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	rc = output_buffer_cache_invalidate(inst, buffer_info);
-	if (rc)
-		return rc;
-
-
-	if (is_dynamic_buffer_mode(b, inst)) {
-		buffer_info->dequeued = true;
-
-		dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n",
-			buffer_info->fd[0]);
-		mutex_lock(&inst->registeredbufs.lock);
-		rc = unmap_and_deregister_buf(inst, buffer_info);
-		mutex_unlock(&inst->registeredbufs.lock);
+		b->m.planes[i].reserved[0] = b->m.planes[i].m.fd;
+		b->m.planes[i].reserved[1] = b->m.planes[i].data_offset;
 	}
 
 	return rc;
@@ -1325,8 +709,8 @@
 			sizes[i] = inst->bufq[OUTPUT_PORT].plane_sizes[i];
 
 		bufreq->buffer_count_actual = *num_buffers;
-		rc = set_buffer_count(inst, bufreq->buffer_count_actual,
-			*num_buffers, HAL_BUFFER_INPUT);
+		rc = set_buffer_count(inst, bufreq->buffer_count_min_host,
+			bufreq->buffer_count_actual, HAL_BUFFER_INPUT);
 		}
 
 		break;
@@ -1359,8 +743,8 @@
 			sizes[i] = inst->bufq[CAPTURE_PORT].plane_sizes[i];
 
 		bufreq->buffer_count_actual = *num_buffers;
-		rc = set_buffer_count(inst, bufreq->buffer_count_actual,
-			*num_buffers, buffer_type);
+		rc = set_buffer_count(inst, bufreq->buffer_count_min_host,
+			bufreq->buffer_count_actual, buffer_type);
 		}
 		break;
 	default:
@@ -1419,7 +803,6 @@
 	int rc = 0;
 	struct hfi_device *hdev;
 	struct hal_buffer_size_minimum b;
-	struct vb2_buf_entry *temp, *next;
 
 	hdev = inst->core->device;
 
@@ -1454,13 +837,13 @@
 		b.buffer_type = HAL_BUFFER_OUTPUT;
 	}
 
+	rc = msm_comm_try_get_bufreqs(inst);
+
 	b.buffer_size = inst->bufq[CAPTURE_PORT].plane_sizes[0];
 	rc = call_hfi_op(hdev, session_set_property,
 			inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM,
 			&b);
 
-	rc = msm_comm_try_get_bufreqs(inst);
-
 	/* Verify if buffer counts are correct */
 	rc = msm_vidc_verify_buffer_counts(inst);
 	if (rc) {
@@ -1482,6 +865,13 @@
 		goto fail_start;
 	}
 
+	rc = msm_comm_set_recon_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to set recon buffers: %d\n", rc);
+		goto fail_start;
+	}
+
 	if (msm_comm_get_stream_output_mode(inst) ==
 			HAL_VIDEO_DECODER_SECONDARY) {
 		rc = msm_comm_set_output_buffers(inst);
@@ -1528,17 +918,6 @@
 	}
 
 fail_start:
-	if (rc) {
-		mutex_lock(&inst->pendingq.lock);
-		list_for_each_entry_safe(temp, next, &inst->pendingq.list,
-				list) {
-			vb2_buffer_done(temp->vb,
-					VB2_BUF_STATE_QUEUED);
-			list_del(&temp->list);
-			kfree(temp);
-		}
-		mutex_unlock(&inst->pendingq.lock);
-	}
 	return rc;
 }
 
@@ -1590,6 +969,35 @@
 	}
 
 stream_start_failed:
+	if (rc) {
+		struct msm_vidc_buffer *temp, *next;
+		struct vb2_buffer *vb;
+
+		mutex_lock(&inst->registeredbufs.lock);
+		list_for_each_entry_safe(temp, next, &inst->registeredbufs.list,
+					list) {
+			if (temp->vvb.vb2_buf.type != q->type)
+				continue;
+			/*
+			 * queued_list lock is already acquired before
+			 * vb2_stream so no need to acquire it again.
+			 */
+			list_for_each_entry(vb, &q->queued_list, queued_entry) {
+				if (msm_comm_compare_vb2_planes(inst, temp,
+						vb)) {
+					print_vb2_buffer(VIDC_ERR, "return vb",
+						inst, vb);
+					vb2_buffer_done(vb,
+						VB2_BUF_STATE_QUEUED);
+					break;
+				}
+			}
+			msm_comm_unmap_vidc_buffer(inst, temp);
+			list_del(&temp->list);
+			kfree(temp);
+		}
+		mutex_unlock(&inst->registeredbufs.lock);
+	}
 	return rc;
 }
 
@@ -1644,12 +1052,29 @@
 			inst, q->type);
 }
 
-static void msm_vidc_buf_queue(struct vb2_buffer *vb)
+static void msm_vidc_buf_queue(struct vb2_buffer *vb2)
 {
-	int rc = msm_comm_qbuf(vb2_get_drv_priv(vb->vb2_queue), vb);
+	int rc = 0;
+	struct msm_vidc_inst *inst = NULL;
+	struct msm_vidc_buffer *mbuf = NULL;
 
+	inst = vb2_get_drv_priv(vb2->vb2_queue);
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid inst\n", __func__);
+		return;
+	}
+
+	mbuf = msm_comm_get_vidc_buffer(inst, vb2);
+	if (IS_ERR_OR_NULL(mbuf)) {
+		if (PTR_ERR(mbuf) != -EEXIST)
+			print_vb2_buffer(VIDC_ERR, "failed to get vidc-buf",
+				inst, vb2);
+		return;
+	}
+
+	rc = msm_comm_qbuf(inst, mbuf);
 	if (rc)
-		dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
+		print_vidc_buffer(VIDC_ERR, "failed qbuf", inst, mbuf);
 }
 
 static const struct vb2_ops msm_vidc_vb2q_ops = {
@@ -1809,34 +1234,11 @@
 	return rc;
 }
 
-static int set_actual_buffer_count(struct msm_vidc_inst *inst,
-	int count, enum hal_buffer type)
-{
-	int rc = 0;
-	struct hfi_device *hdev;
-	struct hal_buffer_count_actual buf_count;
-
-	hdev = inst->core->device;
-
-	buf_count.buffer_type = type;
-	buf_count.buffer_count_min_host = count;
-	buf_count.buffer_count_actual = count;
-	rc = call_hfi_op(hdev, session_set_property,
-		inst->session, HAL_PARAM_BUFFER_COUNT_ACTUAL,
-		&buf_count);
-	if (rc)
-		dprintk(VIDC_ERR,
-			"Failed to set actual count %d for buffer type %d\n",
-			count, type);
-	return rc;
-}
-
-
 static int msm_vidc_get_count(struct msm_vidc_inst *inst,
 	struct v4l2_ctrl *ctrl)
 {
 	int rc = 0;
-	struct hal_buffer_requirements *bufreq, *newreq;
+	struct hal_buffer_requirements *bufreq;
 	enum hal_buffer buffer_type;
 
 	if (ctrl->id == V4L2_CID_MIN_BUFFERS_FOR_OUTPUT) {
@@ -1856,13 +1258,20 @@
 				"Buffer count Host changed from %d to %d\n",
 					bufreq->buffer_count_min_host,
 					ctrl->val);
-			bufreq->buffer_count_min_host = ctrl->val;
+			bufreq->buffer_count_actual =
+			bufreq->buffer_count_min =
+			bufreq->buffer_count_min_host =
+				ctrl->val;
 		} else {
 			ctrl->val = bufreq->buffer_count_min_host;
 		}
-		rc = set_actual_buffer_count(inst,
-				bufreq->buffer_count_min_host,
+		rc = set_buffer_count(inst,
+			bufreq->buffer_count_min_host,
+			bufreq->buffer_count_actual,
 			HAL_BUFFER_INPUT);
+
+		msm_vidc_update_host_buff_counts(inst);
+		ctrl->val = bufreq->buffer_count_min_host;
 		return rc;
 
 	} else if (ctrl->id == V4L2_CID_MIN_BUFFERS_FOR_CAPTURE) {
@@ -1883,40 +1292,37 @@
 				return 0;
 		}
 
-
-		if (inst->in_reconfig) {
-			rc = msm_comm_try_get_bufreqs(inst);
-			newreq = get_buff_req_buffer(inst,
-				buffer_type);
-			if (!newreq) {
-				dprintk(VIDC_ERR,
-					"Failed to find new bufreqs = %d\n",
-					buffer_type);
-				return 0;
-			}
-			ctrl->val = newreq->buffer_count_min;
-		}
 		if (inst->session_type == MSM_VIDC_DECODER &&
 				!inst->in_reconfig &&
 			inst->state < MSM_VIDC_LOAD_RESOURCES_DONE) {
 			dprintk(VIDC_DBG,
 				"Clients updates Buffer count from %d to %d\n",
 				bufreq->buffer_count_min_host, ctrl->val);
-			bufreq->buffer_count_min_host = ctrl->val;
+			bufreq->buffer_count_actual =
+			bufreq->buffer_count_min =
+			bufreq->buffer_count_min_host =
+				ctrl->val;
 		}
 		if (ctrl->val > bufreq->buffer_count_min_host) {
 			dprintk(VIDC_DBG,
 				"Buffer count Host changed from %d to %d\n",
 				bufreq->buffer_count_min_host,
 				ctrl->val);
-			bufreq->buffer_count_min_host = ctrl->val;
+			bufreq->buffer_count_actual =
+			bufreq->buffer_count_min =
+			bufreq->buffer_count_min_host =
+				ctrl->val;
 		} else {
 			ctrl->val = bufreq->buffer_count_min_host;
 		}
-		rc = set_actual_buffer_count(inst,
-				bufreq->buffer_count_min_host,
+		rc = set_buffer_count(inst,
+			bufreq->buffer_count_min_host,
+			bufreq->buffer_count_actual,
 			HAL_BUFFER_OUTPUT);
 
+		msm_vidc_update_host_buff_counts(inst);
+		ctrl->val = bufreq->buffer_count_min_host;
+
 		return rc;
 	}
 	return -EINVAL;
@@ -1963,8 +1369,7 @@
 
 	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
 		if (inst->in_reconfig)
-			msm_comm_try_get_bufreqs(inst);
-
+			msm_vidc_update_host_buff_counts(inst);
 		buffer_type = msm_comm_get_hal_output_buffer(inst);
 		bufreq = get_buff_req_buffer(inst,
 			buffer_type);
@@ -1977,7 +1382,6 @@
 		ctrl->val = bufreq->buffer_count_min_host;
 		break;
 	case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
-		msm_comm_try_get_bufreqs(inst);
 		bufreq = get_buff_req_buffer(inst, HAL_BUFFER_INPUT);
 		if (!bufreq) {
 			dprintk(VIDC_ERR,
@@ -2078,13 +1482,13 @@
 	mutex_init(&inst->bufq[OUTPUT_PORT].lock);
 	mutex_init(&inst->lock);
 
-	INIT_MSM_VIDC_LIST(&inst->pendingq);
 	INIT_MSM_VIDC_LIST(&inst->scratchbufs);
 	INIT_MSM_VIDC_LIST(&inst->freqs);
 	INIT_MSM_VIDC_LIST(&inst->persistbufs);
 	INIT_MSM_VIDC_LIST(&inst->pending_getpropq);
 	INIT_MSM_VIDC_LIST(&inst->outputbufs);
 	INIT_MSM_VIDC_LIST(&inst->registeredbufs);
+	INIT_MSM_VIDC_LIST(&inst->reconbufs);
 
 	kref_init(&inst->kref);
 
@@ -2184,7 +1588,6 @@
 	mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
 	mutex_destroy(&inst->lock);
 
-	DEINIT_MSM_VIDC_LIST(&inst->pendingq);
 	DEINIT_MSM_VIDC_LIST(&inst->scratchbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->persistbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq);
@@ -2200,50 +1603,43 @@
 
 static void cleanup_instance(struct msm_vidc_inst *inst)
 {
-	struct vb2_buf_entry *entry, *dummy;
-
-	if (inst) {
-
-		mutex_lock(&inst->pendingq.lock);
-		list_for_each_entry_safe(entry, dummy, &inst->pendingq.list,
-				list) {
-			list_del(&entry->list);
-			kfree(entry);
-		}
-		mutex_unlock(&inst->pendingq.lock);
-
-		msm_comm_free_freq_table(inst);
-
-		if (msm_comm_release_scratch_buffers(inst, false)) {
-			dprintk(VIDC_ERR,
-				"Failed to release scratch buffers\n");
-		}
-
-		if (msm_comm_release_persist_buffers(inst)) {
-			dprintk(VIDC_ERR,
-				"Failed to release persist buffers\n");
-		}
-
-		/*
-		 * At this point all buffes should be with driver
-		 * irrespective of scenario
-		 */
-		msm_comm_validate_output_buffers(inst);
-
-		if (msm_comm_release_output_buffers(inst, true)) {
-			dprintk(VIDC_ERR,
-				"Failed to release output buffers\n");
-		}
-
-		if (inst->extradata_handle)
-			msm_comm_smem_free(inst, inst->extradata_handle);
-
-		debugfs_remove_recursive(inst->debugfs_root);
-
-		mutex_lock(&inst->pending_getpropq.lock);
-		WARN_ON(!list_empty(&inst->pending_getpropq.list));
-		mutex_unlock(&inst->pending_getpropq.lock);
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
+		return;
 	}
+
+	msm_comm_free_freq_table(inst);
+
+	if (msm_comm_release_scratch_buffers(inst, false))
+		dprintk(VIDC_ERR,
+			"Failed to release scratch buffers\n");
+
+	if (msm_comm_release_recon_buffers(inst))
+		dprintk(VIDC_ERR,
+			"Failed to release recon buffers\n");
+
+	if (msm_comm_release_persist_buffers(inst))
+		dprintk(VIDC_ERR,
+			"Failed to release persist buffers\n");
+
+	/*
+	 * At this point all buffes should be with driver
+	 * irrespective of scenario
+	 */
+	msm_comm_validate_output_buffers(inst);
+
+	if (msm_comm_release_output_buffers(inst, true))
+		dprintk(VIDC_ERR,
+			"Failed to release output buffers\n");
+
+	if (inst->extradata_handle)
+		msm_comm_smem_free(inst, inst->extradata_handle);
+
+	debugfs_remove_recursive(inst->debugfs_root);
+
+	mutex_lock(&inst->pending_getpropq.lock);
+	WARN_ON(!list_empty(&inst->pending_getpropq.list));
+	mutex_unlock(&inst->pending_getpropq.lock);
 }
 
 int msm_vidc_destroy(struct msm_vidc_inst *inst)
@@ -2251,8 +1647,10 @@
 	struct msm_vidc_core *core;
 	int i = 0;
 
-	if (!inst || !inst->core)
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
 		return -EINVAL;
+	}
 
 	core = inst->core;
 
@@ -2263,7 +1661,6 @@
 
 	msm_comm_ctrl_deinit(inst);
 
-	DEINIT_MSM_VIDC_LIST(&inst->pendingq);
 	DEINIT_MSM_VIDC_LIST(&inst->scratchbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->persistbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq);
@@ -2287,22 +1684,24 @@
 	return 0;
 }
 
+static void close_helper(struct kref *kref)
+{
+	struct msm_vidc_inst *inst = container_of(kref,
+			struct msm_vidc_inst, kref);
+
+	msm_vidc_destroy(inst);
+}
+
 int msm_vidc_close(void *instance)
 {
-	void close_helper(struct kref *kref)
-	{
-		struct msm_vidc_inst *inst = container_of(kref,
-				struct msm_vidc_inst, kref);
-
-		msm_vidc_destroy(inst);
-	}
-
 	struct msm_vidc_inst *inst = instance;
-	struct buffer_info *bi, *dummy;
+	struct msm_vidc_buffer *temp, *dummy;
 	int rc = 0;
 
-	if (!inst || !inst->core)
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
 		return -EINVAL;
+	}
 
 	/*
 	 * Make sure that HW stop working on these buffers that
@@ -2314,19 +1713,13 @@
 				MSM_VIDC_RELEASE_RESOURCES_DONE);
 
 	mutex_lock(&inst->registeredbufs.lock);
-	list_for_each_entry_safe(bi, dummy, &inst->registeredbufs.list, list) {
-			int i = 0;
-
-			list_del(&bi->list);
-
-			for (i = 0; i < min(bi->num_planes, VIDEO_MAX_PLANES);
-					i++) {
-				if (bi->handle[i] && bi->mapped[i])
-					msm_comm_smem_free(inst, bi->handle[i]);
-			}
-
-			kfree(bi);
-		}
+	list_for_each_entry_safe(temp, dummy, &inst->registeredbufs.list,
+			list) {
+		print_vidc_buffer(VIDC_ERR, "undequeud buf", inst, temp);
+		msm_comm_unmap_vidc_buffer(inst, temp);
+		list_del(&temp->list);
+		kfree(temp);
+	}
 	mutex_unlock(&inst->registeredbufs.lock);
 
 	cleanup_instance(inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 05af186..cb3c526 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -16,6 +16,111 @@
 #include "msm_vidc_debug.h"
 #include "msm_vidc_clocks.h"
 
+#define MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR 1
+#define MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR 4
+
+static inline unsigned long int get_ubwc_compression_ratio(
+	struct ubwc_cr_stats_info_type ubwc_stats_info)
+{
+	unsigned long int sum = 0, weighted_sum = 0;
+	unsigned long int compression_ratio = 1 << 16;
+
+	weighted_sum =
+		32  * ubwc_stats_info.cr_stats_info0 +
+		64  * ubwc_stats_info.cr_stats_info1 +
+		96  * ubwc_stats_info.cr_stats_info2 +
+		128 * ubwc_stats_info.cr_stats_info3 +
+		160 * ubwc_stats_info.cr_stats_info4 +
+		192 * ubwc_stats_info.cr_stats_info5 +
+		256 * ubwc_stats_info.cr_stats_info6;
+
+	sum =
+		ubwc_stats_info.cr_stats_info0 +
+		ubwc_stats_info.cr_stats_info1 +
+		ubwc_stats_info.cr_stats_info2 +
+		ubwc_stats_info.cr_stats_info3 +
+		ubwc_stats_info.cr_stats_info4 +
+		ubwc_stats_info.cr_stats_info5 +
+		ubwc_stats_info.cr_stats_info6;
+
+	compression_ratio = (weighted_sum && sum) ?
+		((256 * sum) << 16) / weighted_sum : compression_ratio;
+
+	return compression_ratio;
+}
+
+static inline int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst)
+{
+	int height, width;
+
+	if (!inst->in_reconfig) {
+		height = max(inst->prop.height[CAPTURE_PORT],
+			inst->prop.height[OUTPUT_PORT]);
+		width = max(inst->prop.width[CAPTURE_PORT],
+			inst->prop.width[OUTPUT_PORT]);
+	} else {
+		height = inst->reconfig_height;
+		width = inst->reconfig_width;
+	}
+
+	return NUM_MBS_PER_FRAME(height, width);
+}
+
+void update_recon_stats(struct msm_vidc_inst *inst,
+	struct recon_stats_type *recon_stats)
+{
+	struct recon_buf *binfo;
+	u32 CR = 0, CF = 0;
+	u32 frame_size;
+
+	CR = get_ubwc_compression_ratio(recon_stats->ubwc_stats_info);
+
+	frame_size = (msm_vidc_get_mbs_per_frame(inst) / (32 * 8) * 3) / 2;
+
+	CF = recon_stats->complexity_number / frame_size;
+
+	mutex_lock(&inst->reconbufs.lock);
+	list_for_each_entry(binfo, &inst->reconbufs.list, list) {
+		if (binfo->buffer_index ==
+				recon_stats->buffer_index) {
+			binfo->CR = CR;
+			binfo->CF = CF;
+		}
+	}
+	mutex_unlock(&inst->reconbufs.lock);
+}
+
+static int fill_recon_stats(struct msm_vidc_inst *inst,
+	struct vidc_bus_vote_data *vote_data)
+{
+	struct recon_buf *binfo;
+	u32 CR = 0, min_cf = MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR,
+		max_cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR;
+
+	mutex_lock(&inst->reconbufs.lock);
+	list_for_each_entry(binfo, &inst->reconbufs.list, list) {
+		CR = max(CR, binfo->CR);
+		min_cf = min(min_cf, binfo->CF);
+		max_cf = max(max_cf, binfo->CF);
+	}
+	mutex_unlock(&inst->reconbufs.lock);
+	vote_data->compression_ratio = CR;
+
+	vote_data->complexity_factor = max_cf;
+	vote_data->use_dpb_read = false;
+	if (inst->clk_data.load <= inst->clk_data.load_norm) {
+		vote_data->complexity_factor = min_cf;
+		vote_data->use_dpb_read = true;
+	}
+
+	dprintk(VIDC_DBG,
+		"Complression Ratio = %d Complexity Factor = %d\n",
+			vote_data->compression_ratio,
+			vote_data->complexity_factor);
+
+	return 0;
+}
+
 int msm_comm_vote_bus(struct msm_vidc_core *core)
 {
 	int rc = 0, vote_data_count = 0, i = 0;
@@ -30,35 +135,62 @@
 
 	hdev = core->device;
 
-	mutex_lock(&core->lock);
-	list_for_each_entry(inst, &core->instances, list)
-		++vote_data_count;
-
-	vote_data = kcalloc(vote_data_count, sizeof(*vote_data),
-			GFP_TEMPORARY);
+	vote_data = core->vote_data;
 	if (!vote_data) {
-		dprintk(VIDC_ERR, "%s: failed to allocate memory\n", __func__);
-		rc = -ENOMEM;
-		goto fail_alloc;
+		dprintk(VIDC_PROF,
+			"Failed to get vote_data for inst %pK\n",
+				inst);
+		return -EINVAL;
 	}
 
+	mutex_lock(&core->lock);
 	list_for_each_entry(inst, &core->instances, list) {
-		int codec = 0, yuv = 0;
+		int codec = 0;
+		struct msm_vidc_buffer *temp, *next;
+		u32 filled_len = 0;
+		u32 device_addr = 0;
+
+		if (!inst) {
+			dprintk(VIDC_ERR, "%s Invalid args\n",
+				__func__);
+			return -EINVAL;
+		}
+
+		mutex_lock(&inst->registeredbufs.lock);
+		list_for_each_entry_safe(temp, next,
+				&inst->registeredbufs.list, list) {
+			if (temp->vvb.vb2_buf.type ==
+				V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+				filled_len = max(filled_len,
+					temp->vvb.vb2_buf.planes[0].bytesused);
+				device_addr = temp->smem[0].device_addr;
+			}
+		}
+		mutex_unlock(&inst->registeredbufs.lock);
+
+		if (!filled_len || !device_addr) {
+			dprintk(VIDC_DBG, "%s No ETBs\n", __func__);
+			continue;
+		}
+
+		++vote_data_count;
 
 		codec = inst->session_type == MSM_VIDC_DECODER ?
 			inst->fmts[OUTPUT_PORT].fourcc :
 			inst->fmts[CAPTURE_PORT].fourcc;
 
-		yuv = inst->session_type == MSM_VIDC_DECODER ?
-			inst->fmts[CAPTURE_PORT].fourcc :
-			inst->fmts[OUTPUT_PORT].fourcc;
-
 		vote_data[i].domain = get_hal_domain(inst->session_type);
 		vote_data[i].codec = get_hal_codec(codec);
-		vote_data[i].width =  max(inst->prop.width[CAPTURE_PORT],
+		vote_data[i].input_width =  max(inst->prop.width[OUTPUT_PORT],
 				inst->prop.width[OUTPUT_PORT]);
-		vote_data[i].height = max(inst->prop.height[CAPTURE_PORT],
+		vote_data[i].input_height = max(inst->prop.height[OUTPUT_PORT],
 				inst->prop.height[OUTPUT_PORT]);
+		vote_data[i].output_width =  max(inst->prop.width[CAPTURE_PORT],
+				inst->prop.width[OUTPUT_PORT]);
+		vote_data[i].output_height =
+				max(inst->prop.height[CAPTURE_PORT],
+				inst->prop.height[OUTPUT_PORT]);
+		vote_data[i].lcu_size = codec == V4L2_PIX_FMT_HEVC ? 32 : 16;
 
 		if (inst->clk_data.operating_rate)
 			vote_data[i].fps =
@@ -67,38 +199,45 @@
 		else
 			vote_data[i].fps = inst->prop.fps;
 
+		vote_data[i].power_mode = 0;
 		if (!msm_vidc_clock_scaling ||
 			inst->clk_data.buffer_counter < DCVS_FTB_WINDOW)
 			vote_data[i].power_mode = VIDC_POWER_TURBO;
 
-		/*
-		 * TODO: support for OBP-DBP split mode hasn't been yet
-		 * implemented, once it is, this part of code needs to be
-		 * revisited since passing in accurate information to the bus
-		 * governor will drastically reduce bandwidth
-		 */
-		//vote_data[i].color_formats[0] = get_hal_uncompressed(yuv);
-		vote_data[i].num_formats = 1;
+		if (msm_comm_get_stream_output_mode(inst) ==
+				HAL_VIDEO_DECODER_PRIMARY) {
+			vote_data[i].color_formats[0] =
+				msm_comm_get_hal_uncompressed(
+				inst->clk_data.opb_fourcc);
+			vote_data[i].num_formats = 1;
+		} else {
+			vote_data[i].color_formats[0] =
+				msm_comm_get_hal_uncompressed(
+				inst->clk_data.dpb_fourcc);
+			vote_data[i].color_formats[1] =
+				msm_comm_get_hal_uncompressed(
+				inst->clk_data.opb_fourcc);
+			vote_data[i].num_formats = 2;
+		}
+		vote_data[i].work_mode = inst->clk_data.work_mode;
+		fill_recon_stats(inst, &vote_data[i]);
+
+		if (core->resources.sys_cache_enabled)
+			vote_data[i].use_sys_cache = true;
+
 		i++;
 	}
 	mutex_unlock(&core->lock);
+	if (vote_data_count)
+		rc = call_hfi_op(hdev, vote_bus, hdev->hfi_device_data,
+			vote_data, vote_data_count);
 
-	rc = call_hfi_op(hdev, vote_bus, hdev->hfi_device_data, vote_data,
-			vote_data_count);
-	if (rc)
-		dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
-
-	kfree(vote_data);
-	return rc;
-
-fail_alloc:
-	mutex_unlock(&core->lock);
 	return rc;
 }
 
 static inline int get_pending_bufs_fw(struct msm_vidc_inst *inst)
 {
-	int fw_out_qsize = 0, buffers_in_driver = 0;
+	int fw_out_qsize = 0;
 
 	/*
 	 * DCVS always operates on Uncompressed buffers.
@@ -111,11 +250,9 @@
 			fw_out_qsize = inst->count.ftb - inst->count.fbd;
 		else
 			fw_out_qsize = inst->count.etb - inst->count.ebd;
-
-		buffers_in_driver = inst->buffers_held_in_driver;
 	}
 
-	return fw_out_qsize + buffers_in_driver;
+	return fw_out_qsize;
 }
 
 static int msm_dcvs_scale_clocks(struct msm_vidc_inst *inst)
@@ -159,22 +296,22 @@
 
 	/* Buffers outside FW are with display */
 	buffers_outside_fw = total_output_buf - fw_pending_bufs;
-	dprintk(VIDC_DBG,
+	dprintk(VIDC_PROF,
 		"Counts : total_output_buf = %d fw_pending_bufs = %d buffers_outside_fw = %d\n",
 		total_output_buf, fw_pending_bufs, buffers_outside_fw);
 
-	if (buffers_outside_fw >=  dcvs->min_threshold &&
-			dcvs->load > dcvs->load_low) {
+	if (buffers_outside_fw >=  dcvs->min_threshold)
 		dcvs->load = dcvs->load_low;
-	} else if (buffers_outside_fw < dcvs->min_threshold &&
-			dcvs->load == dcvs->load_low) {
+	else if (buffers_outside_fw <= dcvs->max_threshold)
 		dcvs->load = dcvs->load_high;
-	}
+	else
+		dcvs->load = dcvs->load_norm;
+
 	return rc;
 }
 
 static void msm_vidc_update_freq_entry(struct msm_vidc_inst *inst,
-	unsigned long freq, ion_phys_addr_t device_addr)
+	unsigned long freq, u32 device_addr)
 {
 	struct vidc_freq_data *temp, *next;
 	bool found = false;
@@ -197,10 +334,8 @@
 	mutex_unlock(&inst->freqs.lock);
 }
 
-// TODO this needs to be removed later and use queued_list
-
 void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
-	ion_phys_addr_t device_addr)
+	u32 device_addr)
 {
 	struct vidc_freq_data *temp, *next;
 
@@ -228,9 +363,8 @@
 
 	/* If current requirement is within DCVS limits, try DCVS. */
 
-	if (freq < inst->clk_data.load_high) {
+	if (freq < inst->clk_data.load_norm) {
 		dprintk(VIDC_DBG, "Calling DCVS now\n");
-		// TODO calling DCVS here may reduce the residency. Re-visit.
 		msm_dcvs_scale_clocks(inst);
 		freq = inst->clk_data.load;
 	}
@@ -252,22 +386,16 @@
 	mutex_unlock(&inst->freqs.lock);
 }
 
-
-static inline int msm_dcvs_get_mbs_per_frame(struct msm_vidc_inst *inst)
+static unsigned long msm_vidc_max_freq(struct msm_vidc_core *core)
 {
-	int height, width;
+	struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
+	unsigned long freq = 0;
 
-	if (!inst->in_reconfig) {
-		height = max(inst->prop.height[CAPTURE_PORT],
-			inst->prop.height[OUTPUT_PORT]);
-		width = max(inst->prop.width[CAPTURE_PORT],
-			inst->prop.width[OUTPUT_PORT]);
-	} else {
-		height = inst->reconfig_height;
-		width = inst->reconfig_width;
-	}
+	allowed_clks_tbl = core->resources.allowed_clks_tbl;
+	freq = allowed_clks_tbl[0].clock_rate;
+	dprintk(VIDC_PROF, "Max rate = %lu", freq);
 
-	return NUM_MBS_PER_FRAME(height, width);
+	return freq;
 }
 
 static unsigned long msm_vidc_calc_freq(struct msm_vidc_inst *inst,
@@ -301,17 +429,17 @@
 
 		vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
 		/* 10 / 7 is overhead factor */
-		vsp_cycles += (inst->prop.fps * filled_len * 8 * 10) / 7;
+		vsp_cycles += ((inst->prop.fps * filled_len * 8) / 7) * 10;
 
 	} else {
-		// TODO return Min or Max ?
 		dprintk(VIDC_ERR, "Unknown session type = %s\n", __func__);
-		return freq;
+		return msm_vidc_max_freq(inst->core);
 	}
 
 	freq = max(vpp_cycles, vsp_cycles);
 
-	dprintk(VIDC_PROF, "%s Inst %pK : Freq = %lu\n", __func__, inst, freq);
+	dprintk(VIDC_PROF, "%s Inst %pK : Filled Len = %d Freq = %lu\n",
+		__func__, inst, filled_len, freq);
 
 	return freq;
 }
@@ -353,18 +481,6 @@
 	return rc;
 }
 
-static unsigned long msm_vidc_max_freq(struct msm_vidc_core *core)
-{
-	struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
-	unsigned long freq = 0;
-
-	allowed_clks_tbl = core->resources.allowed_clks_tbl;
-	freq = allowed_clks_tbl[0].clock_rate;
-	dprintk(VIDC_PROF, "Max rate = %lu", freq);
-
-	return freq;
-}
-
 int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst)
 {
 	struct v4l2_ctrl *ctrl = NULL;
@@ -441,10 +557,10 @@
 
 int msm_comm_scale_clocks(struct msm_vidc_inst *inst)
 {
-	struct vb2_buf_entry *temp, *next;
+	struct msm_vidc_buffer *temp, *next;
 	unsigned long freq = 0;
 	u32 filled_len = 0;
-	ion_phys_addr_t device_addr = 0;
+	u32 device_addr = 0;
 
 	if (!inst || !inst->core) {
 		dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n",
@@ -452,19 +568,20 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&inst->pendingq.lock);
-	list_for_each_entry_safe(temp, next, &inst->pendingq.list, list) {
-		if (temp->vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) {
+		if (temp->vvb.vb2_buf.type ==
+				V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 			filled_len = max(filled_len,
-				temp->vb->planes[0].bytesused);
-			device_addr = temp->vb->planes[0].m.userptr;
+				temp->vvb.vb2_buf.planes[0].bytesused);
+			device_addr = temp->smem[0].device_addr;
 		}
 	}
-	mutex_unlock(&inst->pendingq.lock);
+	mutex_unlock(&inst->registeredbufs.lock);
 
 	if (!filled_len || !device_addr) {
-		dprintk(VIDC_PROF, "No Change in frequency\n");
-		goto decision_done;
+		dprintk(VIDC_DBG, "%s No ETBs\n", __func__);
+		goto no_clock_change;
 	}
 
 	freq = msm_vidc_calc_freq(inst, filled_len);
@@ -481,8 +598,9 @@
 	else
 		inst->clk_data.curr_freq = freq;
 
-decision_done:
 	msm_vidc_set_clocks(inst->core);
+
+no_clock_change:
 	return 0;
 }
 
@@ -529,7 +647,6 @@
 	}
 	inst->clk_data.dcvs_mode = true;
 
-	// TODO : Update with proper number based on on-target tuning.
 	inst->clk_data.extra_capture_buffer_count =
 		DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
 	inst->clk_data.extra_output_buffer_count =
@@ -537,84 +654,43 @@
 	return true;
 }
 
-static bool msm_dcvs_check_codec_supported(int fourcc,
-		unsigned long codecs_supported, enum session_type type)
-{
-	int codec_bit, session_type_bit;
-	bool codec_type, session_type;
-	unsigned long session;
-
-	session = VIDC_VOTE_DATA_SESSION_VAL(get_hal_codec(fourcc),
-		get_hal_domain(type));
-
-	if (!codecs_supported || !session)
-		return false;
-
-	/* ffs returns a 1 indexed, test_bit takes a 0 indexed...index */
-	codec_bit = ffs(session) - 1;
-	session_type_bit = codec_bit + 1;
-
-	codec_type =
-		test_bit(codec_bit, &codecs_supported) ==
-		test_bit(codec_bit, &session);
-	session_type =
-		test_bit(session_type_bit, &codecs_supported) ==
-		test_bit(session_type_bit, &session);
-
-	return codec_type && session_type;
-}
-
 int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst)
 {
 	int rc = 0, j = 0;
-	struct clock_freq_table *clk_freq_tbl = NULL;
-	struct clock_profile_entry *entry = NULL;
-	int fourcc;
+	int fourcc, count;
 
 	if (!inst || !inst->core) {
 		dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n",
-			__func__, inst);
+				__func__, inst);
 		return -EINVAL;
 	}
-
-	clk_freq_tbl = &inst->core->resources.clock_freq_tbl;
+	count = inst->core->resources.codec_data_count;
 	fourcc = inst->session_type == MSM_VIDC_DECODER ?
 		inst->fmts[OUTPUT_PORT].fourcc :
 		inst->fmts[CAPTURE_PORT].fourcc;
 
-	for (j = 0; j < clk_freq_tbl->count; j++) {
-		bool matched = false;
-
-		entry = &clk_freq_tbl->clk_prof_entries[j];
-
-		matched = msm_dcvs_check_codec_supported(
-				fourcc,
-				entry->codec_mask,
-				inst->session_type);
-
-		if (matched) {
-			inst->clk_data.entry = entry;
+	for (j = 0; j < count; j++) {
+		if (inst->core->resources.codec_data[j].session_type ==
+				inst->session_type &&
+				inst->core->resources.codec_data[j].fourcc ==
+				fourcc) {
+			inst->clk_data.entry =
+				&inst->core->resources.codec_data[j];
 			break;
 		}
 	}
-
-	if (j == clk_freq_tbl->count) {
-		dprintk(VIDC_ERR,
-			"Failed : No matching clock entry found\n");
-		rc = -EINVAL;
-	}
-
 	return rc;
 }
 
 static inline void msm_dcvs_print_dcvs_stats(struct clock_data *dcvs)
 {
-	dprintk(VIDC_DBG,
-		"DCVS: Load_Low %d, Load High %d\n",
+	dprintk(VIDC_PROF,
+		"DCVS: Load_Low %d, Load Norm %d, Load High %d\n",
 		dcvs->load_low,
+		dcvs->load_norm,
 		dcvs->load_high);
 
-	dprintk(VIDC_DBG,
+	dprintk(VIDC_PROF,
 		"DCVS: min_threshold %d, max_threshold %d\n",
 		dcvs->min_threshold, dcvs->max_threshold);
 }
@@ -627,6 +703,7 @@
 	u64 total_freq = 0, rate = 0, load;
 	int cycles;
 	struct clock_data *dcvs;
+	struct hal_buffer_requirements *output_buf_req;
 
 	dprintk(VIDC_DBG, "Init DCVS Load\n");
 
@@ -647,12 +724,22 @@
 			cycles;
 
 		dcvs->buffer_type = HAL_BUFFER_INPUT;
-		// TODO : Update with proper no based on Buffer counts change.
-		dcvs->min_threshold = 7;
+		dcvs->min_threshold =
+			msm_vidc_get_extra_buff_count(inst, HAL_BUFFER_INPUT);
 	} else if (inst->session_type == MSM_VIDC_DECODER) {
 		dcvs->buffer_type = msm_comm_get_hal_output_buffer(inst);
-		// TODO : Update with proper no based on Buffer counts change.
-		dcvs->min_threshold = 4;
+		output_buf_req = get_buff_req_buffer(inst,
+				dcvs->buffer_type);
+		if (!output_buf_req) {
+			dprintk(VIDC_ERR,
+				"%s: No bufer req for buffer type %x\n",
+				__func__, dcvs->buffer_type);
+			return;
+		}
+		dcvs->max_threshold = output_buf_req->buffer_count_actual -
+			output_buf_req->buffer_count_min_host + 1;
+		dcvs->min_threshold =
+			msm_vidc_get_extra_buff_count(inst, dcvs->buffer_type);
 	} else {
 		return;
 	}
@@ -665,8 +752,12 @@
 			break;
 	}
 
-	dcvs->load = dcvs->load_high = rate;
-	dcvs->load_low = allowed_clks_tbl[i+1].clock_rate;
+	dcvs->load = dcvs->load_norm = rate;
+
+	dcvs->load_low = i < (core->resources.allowed_clks_tbl_size - 1) ?
+		allowed_clks_tbl[i+1].clock_rate : dcvs->load_norm;
+	dcvs->load_high = i > 0 ? allowed_clks_tbl[i-1].clock_rate :
+		dcvs->load_norm;
 
 	inst->clk_data.buffer_counter = 0;
 
@@ -783,7 +874,7 @@
 				__func__);
 		return 0;
 	}
-	mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+	mbs_per_frame = msm_vidc_get_mbs_per_frame(inst);
 	if (mbs_per_frame >= inst->core->resources.max_hq_mbs_per_frame ||
 		inst->prop.fps >= inst->core->resources.max_hq_fps) {
 		enable = true;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index fe4822b..705cb7c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -15,21 +15,11 @@
 #define _MSM_VIDC_CLOCKS_H_
 #include "msm_vidc_internal.h"
 
-/* Low threshold for encoder dcvs */
-#define DCVS_ENC_LOW_THR 4
-/* High threshold for encoder dcvs */
-#define DCVS_ENC_HIGH_THR 9
 /* extra o/p buffers in case of encoder dcvs */
 #define DCVS_ENC_EXTRA_OUTPUT_BUFFERS 2
+
 /* extra o/p buffers in case of decoder dcvs */
 #define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4
-/* Default threshold to reduce the core frequency */
-#define DCVS_NOMINAL_THRESHOLD 8
-/* Default threshold to increase the core frequency */
-#define DCVS_TURBO_THRESHOLD 4
-
-/* Considering one safeguard buffer */
-#define DCVS_BUFFER_SAFEGUARD (DCVS_DEC_EXTRA_OUTPUT_BUFFERS - 1)
 
 void msm_clock_data_reset(struct msm_vidc_inst *inst);
 int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst);
@@ -42,6 +32,7 @@
 int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst);
 int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst);
 void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
-	ion_phys_addr_t device_addr);
-
+	u32 device_addr);
+void update_recon_stats(struct msm_vidc_inst *inst,
+	struct recon_stats_type *recon_stats);
 #endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index fe61e6f..b103d73 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -69,6 +69,7 @@
 	"Extradata PQ Info",
 	"Extradata display VUI",
 	"Extradata vpx color space",
+	"Extradata UBWC CR stats info",
 };
 
 struct getprop_buf {
@@ -817,7 +818,7 @@
 	return codec;
 }
 
-static enum hal_uncompressed_format get_hal_uncompressed(int fourcc)
+enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc)
 {
 	enum hal_uncompressed_format format = HAL_UNUSED_COLOR;
 
@@ -976,6 +977,11 @@
 		__func__, core->codec_count, core->enc_codec_supported,
 		core->dec_codec_supported);
 
+	core->vote_data = kcalloc(MAX_SUPPORTED_INSTANCES,
+		sizeof(core->vote_data), GFP_KERNEL);
+	if (!core->vote_data)
+		dprintk(VIDC_ERR, "%s: failed to allocate memory\n", __func__);
+
 	complete(&(core->completions[index]));
 }
 
@@ -1063,9 +1069,9 @@
 	mutex_lock(&inst->scratchbufs.lock);
 	list_for_each_safe(ptr, next, &inst->scratchbufs.list) {
 		buf = list_entry(ptr, struct internal_buf, list);
-		if (address == (u32)buf->handle->device_addr) {
-			dprintk(VIDC_DBG, "releasing scratch: %pa\n",
-					&buf->handle->device_addr);
+		if (address == buf->smem.device_addr) {
+			dprintk(VIDC_DBG, "releasing scratch: %x\n",
+					buf->smem.device_addr);
 			buf_found = true;
 		}
 	}
@@ -1074,9 +1080,9 @@
 	mutex_lock(&inst->persistbufs.lock);
 	list_for_each_safe(ptr, next, &inst->persistbufs.list) {
 		buf = list_entry(ptr, struct internal_buf, list);
-		if (address == (u32)buf->handle->device_addr) {
-			dprintk(VIDC_DBG, "releasing persist: %pa\n",
-					&buf->handle->device_addr);
+		if (address == buf->smem.device_addr) {
+			dprintk(VIDC_DBG, "releasing persist: %x\n",
+					buf->smem.device_addr);
 			buf_found = true;
 		}
 	}
@@ -1162,7 +1168,8 @@
 	hdev = (struct hfi_device *)(inst->core->device);
 	rc = wait_for_completion_timeout(
 		&inst->completions[SESSION_MSG_INDEX(cmd)],
-		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+		msecs_to_jiffies(
+			inst->core->resources.msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR, "Wait interrupted or timed out: %d\n",
 				SESSION_MSG_INDEX(cmd));
@@ -1441,6 +1448,20 @@
 	put_inst(inst);
 }
 
+static void msm_vidc_queue_rbr_event(struct msm_vidc_inst *inst,
+		int fd, u32 offset)
+{
+	struct v4l2_event buf_event = {0};
+	u32 *ptr;
+
+	buf_event.type = V4L2_EVENT_RELEASE_BUFFER_REFERENCE;
+	ptr = (u32 *)buf_event.u.data;
+	ptr[0] = fd;
+	ptr[1] = offset;
+
+	v4l2_event_queue_fh(&inst->event_handler, &buf_event);
+}
+
 static void handle_event_change(enum hal_command_response cmd, void *data)
 {
 	struct msm_vidc_inst *inst = NULL;
@@ -1450,6 +1471,7 @@
 	int rc = 0;
 	struct hfi_device *hdev;
 	u32 *ptr = NULL;
+	struct hal_buffer_requirements *bufreq;
 
 	if (!event_notify) {
 		dprintk(VIDC_WARN, "Got an empty event from hfi\n");
@@ -1473,65 +1495,17 @@
 		break;
 	case HAL_EVENT_RELEASE_BUFFER_REFERENCE:
 	{
-		struct v4l2_event buf_event = {0};
-		struct buffer_info *binfo = NULL, *temp = NULL;
-		u32 *ptr = NULL;
-
-		dprintk(VIDC_DBG, "%s - inst: %pK buffer: %pa extra: %pa\n",
-				__func__, inst, &event_notify->packet_buffer,
-				&event_notify->extra_data_buffer);
-
-		if (inst->state == MSM_VIDC_CORE_INVALID ||
-				inst->core->state == VIDC_CORE_INVALID) {
-			dprintk(VIDC_DBG,
-					"Event release buf ref received in invalid state - discard\n");
-			goto err_bad_event;
-		}
-
-		/*
-		 * Get the buffer_info entry for the
-		 * device address.
-		 */
-		binfo = device_to_uvaddr(&inst->registeredbufs,
-				event_notify->packet_buffer);
-		if (!binfo) {
-			dprintk(VIDC_ERR,
-					"%s buffer not found in registered list\n",
-					__func__);
-			goto err_bad_event;
-		}
-
-		/* Fill event data to be sent to client*/
-		buf_event.type = V4L2_EVENT_RELEASE_BUFFER_REFERENCE;
-		ptr = (u32 *)buf_event.u.data;
-		ptr[0] = binfo->fd[0];
-		ptr[1] = binfo->buff_off[0];
+		u32 planes[VIDEO_MAX_PLANES] = {0};
 
 		dprintk(VIDC_DBG,
-				"RELEASE REFERENCE EVENT FROM F/W - fd = %d offset = %d\n",
-				ptr[0], ptr[1]);
+			"%s: inst: %pK data_buffer: %x extradata_buffer: %x\n",
+			__func__, inst, event_notify->packet_buffer,
+			event_notify->extra_data_buffer);
 
-		/* Decrement buffer reference count*/
-		mutex_lock(&inst->registeredbufs.lock);
-		list_for_each_entry(temp, &inst->registeredbufs.list,
-				list) {
-			if (temp == binfo) {
-				buf_ref_put(inst, binfo);
-				break;
-			}
-		}
+		planes[0] = event_notify->packet_buffer;
+		planes[1] = event_notify->extra_data_buffer;
+		handle_release_buffer_reference(inst, planes);
 
-		/*
-		 * Release buffer and remove from list
-		 * if reference goes to zero.
-		 */
-		if (unmap_and_deregister_buf(inst, binfo))
-			dprintk(VIDC_ERR,
-					"%s: buffer unmap failed\n", __func__);
-		mutex_unlock(&inst->registeredbufs.lock);
-
-		/*send event to client*/
-		v4l2_event_queue_fh(&inst->event_handler, &buf_event);
 		goto err_bad_event;
 	}
 	default:
@@ -1594,6 +1568,44 @@
 	inst->in_reconfig = true;
 	inst->reconfig_height = event_notify->height;
 	inst->reconfig_width = event_notify->width;
+
+	if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+
+		bufreq = get_buff_req_buffer(inst,
+				HAL_BUFFER_OUTPUT);
+		if (!bufreq) {
+			dprintk(VIDC_ERR,
+				"Failed : No buffer requirements : %x\n",
+					HAL_BUFFER_OUTPUT);
+			return;
+		}
+
+		bufreq->buffer_count_min = event_notify->capture_buf_count;
+
+		bufreq = get_buff_req_buffer(inst,
+				HAL_BUFFER_OUTPUT2);
+		if (!bufreq) {
+			dprintk(VIDC_ERR,
+				"Failed : No buffer requirements : %x\n",
+					HAL_BUFFER_OUTPUT2);
+			return;
+		}
+
+		bufreq->buffer_count_min = event_notify->capture_buf_count;
+	} else {
+
+		bufreq = get_buff_req_buffer(inst,
+				HAL_BUFFER_OUTPUT);
+		if (!bufreq) {
+			dprintk(VIDC_ERR,
+				"Failed : No buffer requirements : %x\n",
+					HAL_BUFFER_OUTPUT);
+			return;
+		}
+		bufreq->buffer_count_min = event_notify->capture_buf_count;
+	}
+
 	mutex_unlock(&inst->lock);
 
 	if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) {
@@ -1604,8 +1616,6 @@
 				"event_notify->height = %d event_notify->width = %d\n",
 				event_notify->height,
 				event_notify->width);
-		inst->prop.height[OUTPUT_PORT] = event_notify->height;
-		inst->prop.width[OUTPUT_PORT] = event_notify->width;
 	}
 
 	rc = msm_vidc_check_session_supported(inst);
@@ -1776,8 +1786,8 @@
 	list_for_each_entry(binfo, &inst->outputbufs.list, list) {
 		if (binfo->buffer_ownership != DRIVER) {
 			dprintk(VIDC_DBG,
-				"This buffer is with FW %pa\n",
-				&binfo->handle->device_addr);
+				"This buffer is with FW %x\n",
+				binfo->smem.device_addr);
 			continue;
 		}
 		buffers_owned_by_driver++;
@@ -1797,7 +1807,6 @@
 {
 	struct internal_buf *binfo;
 	struct hfi_device *hdev;
-	struct msm_smem *handle;
 	struct vidc_frame_data frame_data = {0};
 	struct hal_buffer_requirements *output_buf, *extra_buf;
 	int rc = 0;
@@ -1827,13 +1836,12 @@
 	list_for_each_entry(binfo, &inst->outputbufs.list, list) {
 		if (binfo->buffer_ownership != DRIVER)
 			continue;
-		handle = binfo->handle;
 		frame_data.alloc_len = output_buf->buffer_size;
 		frame_data.filled_len = 0;
 		frame_data.offset = 0;
-		frame_data.device_addr = handle->device_addr;
+		frame_data.device_addr = binfo->smem.device_addr;
 		frame_data.flags = 0;
-		frame_data.extradata_addr = handle->device_addr +
+		frame_data.extradata_addr = binfo->smem.device_addr +
 		output_buf->buffer_size;
 		frame_data.buffer_type = HAL_BUFFER_OUTPUT;
 		frame_data.extradata_size = extra_buf ?
@@ -1884,7 +1892,7 @@
 			}
 		}
 	}
-	atomic_dec(&inst->in_flush);
+	inst->in_flush = false;
 	flush_event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
 	ptr = (u32 *)flush_event.u.data;
 
@@ -2107,82 +2115,84 @@
 	put_inst(inst);
 }
 
-static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq,
-		unsigned long dev_addr)
+struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer(
+		struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf)
 {
+	u32 port = 0;
 	struct vb2_buffer *vb = NULL;
 	struct vb2_queue *q = NULL;
-	int found = 0;
+	bool found = false;
 
-	if (!bufq) {
-		dprintk(VIDC_ERR, "Invalid parameter\n");
+	if (mbuf->vvb.vb2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		port = CAPTURE_PORT;
+	} else if (mbuf->vvb.vb2_buf.type ==
+			V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		port = OUTPUT_PORT;
+	} else {
+		dprintk(VIDC_ERR, "%s: invalid type %d\n",
+			__func__, mbuf->vvb.vb2_buf.type);
 		return NULL;
 	}
-	q = &bufq->vb2_bufq;
-	mutex_lock(&bufq->lock);
+
+	q = &inst->bufq[port].vb2_bufq;
+	mutex_lock(&inst->bufq[port].lock);
+	found = false;
 	list_for_each_entry(vb, &q->queued_list, queued_entry) {
-		if (vb->planes[0].m.userptr == dev_addr &&
-			vb->state == VB2_BUF_STATE_ACTIVE) {
-			found = 1;
-			dprintk(VIDC_DBG, "Found v4l2_buf index : %d\n",
-					vb->index);
+		if (msm_comm_compare_vb2_planes(inst, mbuf, vb)) {
+			found = true;
 			break;
 		}
 	}
-	mutex_unlock(&bufq->lock);
+	mutex_unlock(&inst->bufq[port].lock);
 	if (!found) {
-		dprintk(VIDC_DBG,
-			"Failed to find buffer in queued list: %#lx, qtype = %d\n",
-			dev_addr, q->type);
-		vb = NULL;
+		print_vidc_buffer(VIDC_ERR, "vb2 not found for", inst, mbuf);
+		return NULL;
 	}
+
 	return vb;
 }
 
-static void handle_dynamic_buffer(struct msm_vidc_inst *inst,
-		ion_phys_addr_t device_addr, u32 flags)
+int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst,
+		struct vb2_buffer *vb)
 {
-	struct buffer_info *binfo = NULL, *temp = NULL;
+	u32 port;
 
-	/*
-	 * Update reference count and release OR queue back the buffer,
-	 * only when firmware is not holding a reference.
-	 */
-	binfo = device_to_uvaddr(&inst->registeredbufs, device_addr);
-	if (!binfo) {
-		dprintk(VIDC_ERR,
-			"%s buffer not found in registered list\n",
-			__func__);
-		return;
+	if (!inst || !vb) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n",
+			__func__, inst, vb);
+		return -EINVAL;
 	}
-	if (flags & HAL_BUFFERFLAG_READONLY) {
-		dprintk(VIDC_DBG,
-			"FBD fd[0] = %d -> Reference with f/w, addr: %pa\n",
-			binfo->fd[0], &device_addr);
+
+	if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		port = CAPTURE_PORT;
+	} else if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		port = OUTPUT_PORT;
 	} else {
-		dprintk(VIDC_DBG,
-			"FBD fd[0] = %d -> FBD_ref_released, addr: %pa\n",
-			binfo->fd[0], &device_addr);
-
-		mutex_lock(&inst->registeredbufs.lock);
-		list_for_each_entry(temp, &inst->registeredbufs.list,
-				list) {
-			if (temp == binfo) {
-				buf_ref_put(inst, binfo);
-				break;
-			}
-		}
-		mutex_unlock(&inst->registeredbufs.lock);
+		dprintk(VIDC_ERR, "%s: invalid type %d\n",
+			__func__, vb->type);
+		return -EINVAL;
 	}
+	msm_vidc_debugfs_update(inst, port == CAPTURE_PORT ?
+			MSM_VIDC_DEBUGFS_EVENT_FBD :
+			MSM_VIDC_DEBUGFS_EVENT_EBD);
+
+	mutex_lock(&inst->bufq[port].lock);
+	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	mutex_unlock(&inst->bufq[port].lock);
+
+	return 0;
 }
 
 static void handle_ebd(enum hal_command_response cmd, void *data)
 {
 	struct msm_vidc_cb_data_done *response = data;
+	struct msm_vidc_buffer *mbuf;
 	struct vb2_buffer *vb;
 	struct msm_vidc_inst *inst;
 	struct vidc_hal_ebd *empty_buf_done;
-	struct vb2_v4l2_buffer *vbuf = NULL;
+	struct vb2_v4l2_buffer *vbuf;
+	u32 planes[VIDEO_MAX_PLANES] = {0};
+	u32 extra_idx = 0, i;
 
 	if (!response) {
 		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
@@ -2195,137 +2205,79 @@
 		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
 		return;
 	}
-	if (inst->buffer_mode_set[OUTPUT_PORT] == HAL_BUFFER_MODE_DYNAMIC)
-		handle_dynamic_buffer(inst,
-			response->input_done.packet_buffer, 0);
 
-	vb = get_vb_from_device_addr(&inst->bufq[OUTPUT_PORT],
-			response->input_done.packet_buffer);
+	empty_buf_done = (struct vidc_hal_ebd *)&response->input_done;
+	planes[0] = empty_buf_done->packet_buffer;
+	planes[1] = empty_buf_done->extra_data_buffer;
+
+	mbuf = msm_comm_get_buffer_using_device_planes(inst, planes);
+	if (!mbuf) {
+		dprintk(VIDC_ERR,
+			"%s: data_addr %x, extradata_addr %x not found\n",
+			__func__, planes[0], planes[1]);
+		goto exit;
+	}
+	vb = &mbuf->vvb.vb2_buf;
+
+	vb->planes[0].bytesused = response->input_done.filled_len;
+	if (vb->planes[0].bytesused > vb->planes[0].length)
+		dprintk(VIDC_INFO, "bytesused overflow length\n");
+
+	if (empty_buf_done->status == VIDC_ERR_NOT_SUPPORTED) {
+		dprintk(VIDC_INFO, "Failed : Unsupported input stream\n");
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_INPUT_UNSUPPORTED;
+	}
+	if (empty_buf_done->status == VIDC_ERR_BITSTREAM_ERR) {
+		dprintk(VIDC_INFO, "Failed : Corrupted input stream\n");
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
+	}
+	if (empty_buf_done->flags & HAL_BUFFERFLAG_SYNCFRAME)
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME |
+			V4L2_BUF_FLAG_KEYFRAME;
+
+	extra_idx = EXTRADATA_IDX(inst->bufq[OUTPUT_PORT].num_planes);
+	if (extra_idx && extra_idx < VIDEO_MAX_PLANES)
+		vb->planes[extra_idx].bytesused = vb->planes[extra_idx].length;
+
+	update_recon_stats(inst, &empty_buf_done->recon_stats);
+	msm_vidc_clear_freq_entry(inst, mbuf->smem[0].device_addr);
+
+	vb = msm_comm_get_vb_using_vidc_buffer(inst, mbuf);
 	if (vb) {
 		vbuf = to_vb2_v4l2_buffer(vb);
-		vb->planes[0].bytesused = response->input_done.filled_len;
-		vb->planes[0].data_offset = response->input_done.offset;
-		if (vb->planes[0].data_offset > vb->planes[0].length)
-			dprintk(VIDC_INFO, "data_offset overflow length\n");
-		if (vb->planes[0].bytesused > vb->planes[0].length)
-			dprintk(VIDC_INFO, "bytesused overflow length\n");
-		if (vb->planes[0].m.userptr !=
-			response->clnt_data)
-			dprintk(VIDC_INFO, "Client data != bufaddr\n");
-		empty_buf_done = (struct vidc_hal_ebd *)&response->input_done;
-		if (empty_buf_done) {
-			if (empty_buf_done->status == VIDC_ERR_NOT_SUPPORTED) {
-				dprintk(VIDC_INFO,
-					"Failed : Unsupported input stream\n");
-				vbuf->flags |=
-					V4L2_QCOM_BUF_INPUT_UNSUPPORTED;
-			}
-			if (empty_buf_done->status == VIDC_ERR_BITSTREAM_ERR) {
-				dprintk(VIDC_INFO,
-					"Failed : Corrupted input stream\n");
-				vbuf->flags |=
-					V4L2_QCOM_BUF_DATA_CORRUPT;
-			}
-			if (empty_buf_done->flags & HAL_BUFFERFLAG_SYNCFRAME)
-				vbuf->flags |=
-					V4L2_QCOM_BUF_FLAG_IDRFRAME |
-					V4L2_BUF_FLAG_KEYFRAME;
-		}
-		dprintk(VIDC_DBG,
-			"Got ebd from hal: device_addr: %pa, alloc: %d, status: %#x, pic_type: %#x, flags: %#x\n",
-			&empty_buf_done->packet_buffer,
-			empty_buf_done->alloc_len, empty_buf_done->status,
-			empty_buf_done->picture_type, empty_buf_done->flags);
-
-		msm_vidc_clear_freq_entry(inst, empty_buf_done->packet_buffer);
-
-		mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
-		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-		mutex_unlock(&inst->bufq[OUTPUT_PORT].lock);
-		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_EBD);
+		vbuf->flags |= mbuf->vvb.flags;
+		for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++)
+			vb->planes[i].bytesused =
+				mbuf->vvb.vb2_buf.planes[i].bytesused;
 	}
+	/*
+	 * put_buffer should be done before vb2_buffer_done else
+	 * client might queue the same buffer before it is unmapped
+	 * in put_buffer. also don't use mbuf after put_buffer
+	 * as it may be freed in put_buffer.
+	 */
+	msm_comm_put_vidc_buffer(inst, mbuf);
+	msm_comm_vb2_buffer_done(inst, vb);
 
+exit:
 	put_inst(inst);
 }
 
-int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo)
-{
-	int cnt = 0;
-
-	if (!inst || !binfo)
-		return -EINVAL;
-
-	atomic_inc(&binfo->ref_count);
-	cnt = atomic_read(&binfo->ref_count);
-	if (cnt >= 2)
-		inst->buffers_held_in_driver++;
-
-	dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
-
-	return cnt;
-}
-
-int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo)
-{
-	int rc = 0;
-	int cnt;
-	bool release_buf = false;
-	bool qbuf_again = false;
-
-	if (!inst || !binfo)
-		return -EINVAL;
-
-	atomic_dec(&binfo->ref_count);
-	cnt = atomic_read(&binfo->ref_count);
-	dprintk(VIDC_DBG, "REF_PUT[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
-	if (!cnt)
-		release_buf = true;
-	else if (cnt >= 1)
-		qbuf_again = true;
-	else {
-		dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
-		cnt = -EINVAL;
-	}
-
-	if (cnt < 0)
-		return cnt;
-
-	if (release_buf) {
-		/*
-		 * We can not delete binfo here as we need to set the user
-		 * virtual address saved in binfo->uvaddr to the dequeued v4l2
-		 * buffer.
-		 *
-		 * We will set the pending_deletion flag to true here and delete
-		 * binfo from registered list in dqbuf after setting the uvaddr.
-		 */
-		dprintk(VIDC_DBG, "fd[0] = %d -> pending_deletion = true\n",
-			binfo->fd[0]);
-		binfo->pending_deletion = true;
-	} else if (qbuf_again) {
-		inst->buffers_held_in_driver--;
-		rc = qbuf_dynamic_buf(inst, binfo);
-		if (!rc)
-			return rc;
-	}
-	return cnt;
-}
-
 static int handle_multi_stream_buffers(struct msm_vidc_inst *inst,
-		ion_phys_addr_t dev_addr)
+		u32 dev_addr)
 {
 	struct internal_buf *binfo;
-	struct msm_smem *handle;
+	struct msm_smem *smem;
 	bool found = false;
 
 	mutex_lock(&inst->outputbufs.lock);
 	list_for_each_entry(binfo, &inst->outputbufs.list, list) {
-		handle = binfo->handle;
-		if (handle && dev_addr == handle->device_addr) {
+		smem = &binfo->smem;
+		if (smem && dev_addr == smem->device_addr) {
 			if (binfo->buffer_ownership == DRIVER) {
 				dprintk(VIDC_ERR,
-					"FW returned same buffer: %pa\n",
-					&dev_addr);
+					"FW returned same buffer: %x\n",
+					dev_addr);
 				break;
 			}
 			binfo->buffer_ownership = DRIVER;
@@ -2337,8 +2289,8 @@
 
 	if (!found) {
 		dprintk(VIDC_ERR,
-			"Failed to find output buffer in queued list: %pa\n",
-			&dev_addr);
+			"Failed to find output buffer in queued list: %x\n",
+			dev_addr);
 	}
 
 	return 0;
@@ -2356,13 +2308,15 @@
 static void handle_fbd(enum hal_command_response cmd, void *data)
 {
 	struct msm_vidc_cb_data_done *response = data;
+	struct msm_vidc_buffer *mbuf;
 	struct msm_vidc_inst *inst;
 	struct vb2_buffer *vb = NULL;
 	struct vidc_hal_fbd *fill_buf_done;
+	struct vb2_v4l2_buffer *vbuf;
 	enum hal_buffer buffer_type;
-	int extra_idx = 0;
 	u64 time_usec = 0;
-	struct vb2_v4l2_buffer *vbuf = NULL;
+	u32 planes[VIDEO_MAX_PLANES] = {0};
+	u32 extra_idx, i;
 
 	if (!response) {
 		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
@@ -2377,132 +2331,117 @@
 	}
 
 	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+	planes[0] = fill_buf_done->packet_buffer1;
+	planes[1] = fill_buf_done->extra_data_buffer;
+
 	buffer_type = msm_comm_get_hal_output_buffer(inst);
 	if (fill_buf_done->buffer_type == buffer_type) {
-		vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
-				fill_buf_done->packet_buffer1);
+		mbuf = msm_comm_get_buffer_using_device_planes(inst, planes);
+		if (!mbuf) {
+			dprintk(VIDC_ERR,
+				"%s: data_addr %x, extradata_addr %x not found\n",
+				__func__, planes[0], planes[1]);
+			goto exit;
+		}
 	} else {
 		if (handle_multi_stream_buffers(inst,
 				fill_buf_done->packet_buffer1))
 			dprintk(VIDC_ERR,
 				"Failed : Output buffer not found %pa\n",
 				&fill_buf_done->packet_buffer1);
-		goto err_handle_fbd;
+		goto exit;
+	}
+	vb = &mbuf->vvb.vb2_buf;
+
+	if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME ||
+		fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
+		fill_buf_done->filled_len1 = 0;
+	vb->planes[0].bytesused = fill_buf_done->filled_len1;
+	if (vb->planes[0].bytesused > vb->planes[0].length)
+		dprintk(VIDC_INFO,
+			"fbd:Overflow bytesused = %d; length = %d\n",
+			vb->planes[0].bytesused,
+			vb->planes[0].length);
+	if (vb->planes[0].data_offset != fill_buf_done->offset1)
+		dprintk(VIDC_ERR, "%s: data_offset %d vs %d\n",
+			__func__, vb->planes[0].data_offset,
+			fill_buf_done->offset1);
+	if (!(fill_buf_done->flags1 & HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
+		time_usec = fill_buf_done->timestamp_hi;
+		time_usec = (time_usec << 32) | fill_buf_done->timestamp_lo;
+	} else {
+		time_usec = 0;
+		dprintk(VIDC_DBG,
+				"Set zero timestamp for buffer %pa, filled: %d, (hi:%u, lo:%u)\n",
+				&fill_buf_done->packet_buffer1,
+				fill_buf_done->filled_len1,
+				fill_buf_done->timestamp_hi,
+				fill_buf_done->timestamp_lo);
+	}
+	vb->timestamp = (time_usec * NSEC_PER_USEC);
+
+	extra_idx = EXTRADATA_IDX(inst->bufq[CAPTURE_PORT].num_planes);
+	if (extra_idx && extra_idx < VIDEO_MAX_PLANES)
+		vb->planes[extra_idx].bytesused = vb->planes[extra_idx].length;
+
+	mbuf->vvb.flags = 0;
+	if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY)
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_READONLY;
+	if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_EOS;
+	if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+	if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+	if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
+	if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY ||
+		fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME)
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
+	if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
+	switch (fill_buf_done->picture_type) {
+	case HAL_PICTURE_IDR:
+		mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+		mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+		break;
+	case HAL_PICTURE_I:
+		mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+		break;
+	case HAL_PICTURE_P:
+		mbuf->vvb.flags |= V4L2_BUF_FLAG_PFRAME;
+		break;
+	case HAL_PICTURE_B:
+		mbuf->vvb.flags |= V4L2_BUF_FLAG_BFRAME;
+		break;
+	case HAL_FRAME_NOTCODED:
+	case HAL_UNUSED_PICT:
+		/* Do we need to care about these? */
+	case HAL_FRAME_YUV:
+		break;
+	default:
+		break;
 	}
 
+	vb = msm_comm_get_vb_using_vidc_buffer(inst, mbuf);
 	if (vb) {
 		vbuf = to_vb2_v4l2_buffer(vb);
-		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME ||
-			fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
-			fill_buf_done->filled_len1 = 0;
-		vb->planes[0].bytesused = fill_buf_done->filled_len1;
-		vb->planes[0].data_offset = fill_buf_done->offset1;
-		if (vb->planes[0].data_offset > vb->planes[0].length)
-			dprintk(VIDC_INFO,
-				"fbd:Overflow data_offset = %d; length = %d\n",
-				vb->planes[0].data_offset,
-				vb->planes[0].length);
-		if (vb->planes[0].bytesused > vb->planes[0].length)
-			dprintk(VIDC_INFO,
-				"fbd:Overflow bytesused = %d; length = %d\n",
-				vb->planes[0].bytesused,
-				vb->planes[0].length);
-		if (!(fill_buf_done->flags1 &
-			HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
-			time_usec = fill_buf_done->timestamp_hi;
-			time_usec = (time_usec << 32) |
-				fill_buf_done->timestamp_lo;
-		} else {
-			time_usec = 0;
-			dprintk(VIDC_DBG,
-					"Set zero timestamp for buffer %pa, filled: %d, (hi:%u, lo:%u)\n",
-					&fill_buf_done->packet_buffer1,
-					fill_buf_done->filled_len1,
-					fill_buf_done->timestamp_hi,
-					fill_buf_done->timestamp_lo);
-		}
-		vbuf->flags = 0;
-		vb->timestamp = (time_usec * NSEC_PER_USEC);
-
-		extra_idx =
-			EXTRADATA_IDX(inst->bufq[CAPTURE_PORT].num_planes);
-		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
-			vb->planes[extra_idx].m.userptr =
-				(unsigned long)fill_buf_done->extra_data_buffer;
-			vb->planes[extra_idx].bytesused =
-				vb->planes[extra_idx].length;
-			vb->planes[extra_idx].data_offset = 0;
-		}
-
-		if (inst->buffer_mode_set[CAPTURE_PORT] ==
-			HAL_BUFFER_MODE_DYNAMIC)
-		handle_dynamic_buffer(inst, fill_buf_done->packet_buffer1,
-					fill_buf_done->flags1);
-		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY)
-			vbuf->flags |= V4L2_QCOM_BUF_FLAG_READONLY;
-		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
-			vbuf->flags |= V4L2_QCOM_BUF_FLAG_EOS;
-		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
-			vbuf->flags |= V4L2_QCOM_BUF_FLAG_CODECCONFIG;
-		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
-			vbuf->flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
-		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
-			vbuf->flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
-		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY ||
-			fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME)
-			vbuf->flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
-		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
-			vbuf->flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
-
-		switch (fill_buf_done->picture_type) {
-		case HAL_PICTURE_IDR:
-			vbuf->flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
-			vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
-			break;
-		case HAL_PICTURE_I:
-			vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
-			break;
-		case HAL_PICTURE_P:
-			vbuf->flags |= V4L2_BUF_FLAG_PFRAME;
-			break;
-		case HAL_PICTURE_B:
-			vbuf->flags |= V4L2_BUF_FLAG_BFRAME;
-			break;
-		case HAL_FRAME_NOTCODED:
-		case HAL_UNUSED_PICT:
-			/* Do we need to care about these? */
-		case HAL_FRAME_YUV:
-			break;
-		default:
-			break;
-		}
-
-		inst->count.fbd++;
-
-		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
-			dprintk(VIDC_DBG,
-				"extradata: userptr = %pK;"
-				" bytesused = %d; length = %d\n",
-				(u8 *)vb->planes[extra_idx].m.userptr,
-				vb->planes[extra_idx].bytesused,
-				vb->planes[extra_idx].length);
-		}
-		dprintk(VIDC_DBG,
-		"Got fbd from hal: device_addr: %pa, alloc: %d, filled: %d, offset: %d, ts: %lld, flags: %#x, crop: %d %d %d %d, pic_type: %#x, mark_data: %#x\n",
-		&fill_buf_done->packet_buffer1, fill_buf_done->alloc_len1,
-		fill_buf_done->filled_len1, fill_buf_done->offset1, time_usec,
-		fill_buf_done->flags1, fill_buf_done->start_x_coord,
-		fill_buf_done->start_y_coord, fill_buf_done->frame_width,
-		fill_buf_done->frame_height, fill_buf_done->picture_type,
-		fill_buf_done->mark_data);
-
-		mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
-		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-		mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
-		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FBD);
+		vbuf->flags = mbuf->vvb.flags;
+		vb->timestamp = mbuf->vvb.vb2_buf.timestamp;
+		for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++)
+			vb->planes[i].bytesused =
+				mbuf->vvb.vb2_buf.planes[i].bytesused;
 	}
+	/*
+	 * put_buffer should be done before vb2_buffer_done else
+	 * client might queue the same buffer before it is unmapped
+	 * in put_buffer. also don't use mbuf after put_buffer
+	 * as it may be freed in put_buffer.
+	 */
+	msm_comm_put_vidc_buffer(inst, mbuf);
+	msm_comm_vb2_buffer_done(inst, vb);
 
-err_handle_fbd:
+exit:
 	put_inst(inst);
 }
 
@@ -2647,7 +2586,8 @@
 	}
 	rc = wait_for_completion_timeout(
 			&inst->completions[abort_completion],
-			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+			msecs_to_jiffies(
+				inst->core->resources.msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR,
 				"%s: Wait interrupted or timed out [%pK]: %d\n",
@@ -2739,7 +2679,7 @@
 	hdev = (struct hfi_device *)core->device;
 	rc = wait_for_completion_timeout(
 		&core->completions[SYS_MSG_INDEX(HAL_SYS_INIT_DONE)],
-		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+		msecs_to_jiffies(core->resources.msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR, "%s: Wait interrupted or timed out: %d\n",
 				__func__, SYS_MSG_INDEX(HAL_SYS_INIT_DONE));
@@ -2878,11 +2818,12 @@
 		 */
 		schedule_delayed_work(&core->fw_unload_work,
 			msecs_to_jiffies(core->state == VIDC_CORE_INVALID ?
-					0 : msm_vidc_firmware_unload_delay));
+					0 :
+			core->resources.msm_vidc_firmware_unload_delay));
 
 		dprintk(VIDC_DBG, "firmware unload delayed by %u ms\n",
 			core->state == VIDC_CORE_INVALID ?
-			0 : msm_vidc_firmware_unload_delay);
+			0 : core->resources.msm_vidc_firmware_unload_delay);
 	}
 
 core_already_uninited:
@@ -3236,7 +3177,6 @@
 	enum hal_buffer buffer_type)
 {
 	int rc = 0;
-	struct msm_smem *handle;
 	struct internal_buf *binfo;
 	u32 smem_flags = 0, buffer_size;
 	struct hal_buffer_requirements *output_buf, *extradata_buf;
@@ -3284,33 +3224,30 @@
 	if (output_buf->buffer_size) {
 		for (i = 0; i < output_buf->buffer_count_actual;
 				i++) {
-			handle = msm_comm_smem_alloc(inst,
-					buffer_size, 1, smem_flags,
-					buffer_type, 0);
-			if (!handle) {
-				dprintk(VIDC_ERR,
-					"Failed to allocate output memory\n");
-				rc = -ENOMEM;
-				goto err_no_mem;
-			}
-			rc = msm_comm_smem_cache_operations(inst,
-					handle, SMEM_CACHE_CLEAN);
-			if (rc) {
-				dprintk(VIDC_WARN,
-					"Failed to clean cache may cause undefined behavior\n");
-			}
 			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
 			if (!binfo) {
 				dprintk(VIDC_ERR, "Out of memory\n");
 				rc = -ENOMEM;
 				goto fail_kzalloc;
 			}
-
-			binfo->handle = handle;
+			rc = msm_comm_smem_alloc(inst,
+					buffer_size, 1, smem_flags,
+					buffer_type, 0, &binfo->smem);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to allocate output memory\n");
+				goto err_no_mem;
+			}
+			rc = msm_comm_smem_cache_operations(inst,
+					&binfo->smem, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Failed to clean cache may cause undefined behavior\n");
+			}
 			binfo->buffer_type = buffer_type;
 			binfo->buffer_ownership = DRIVER;
-			dprintk(VIDC_DBG, "Output buffer address: %pa\n",
-					&handle->device_addr);
+			dprintk(VIDC_DBG, "Output buffer address: %#x\n",
+					binfo->smem.device_addr);
 
 			if (inst->buffer_mode_set[CAPTURE_PORT] ==
 				HAL_BUFFER_MODE_STATIC) {
@@ -3321,9 +3258,9 @@
 				buffer_info.buffer_type = buffer_type;
 				buffer_info.num_buffers = 1;
 				buffer_info.align_device_addr =
-					handle->device_addr;
+					binfo->smem.device_addr;
 				buffer_info.extradata_addr =
-					handle->device_addr +
+					binfo->smem.device_addr +
 					output_buf->buffer_size;
 				if (extradata_buf)
 					buffer_info.extradata_size =
@@ -3346,7 +3283,7 @@
 fail_set_buffers:
 	kfree(binfo);
 fail_kzalloc:
-	msm_comm_smem_free(inst, handle);
+	msm_comm_smem_free(inst, &binfo->smem);
 err_no_mem:
 	return rc;
 }
@@ -3396,10 +3333,10 @@
 	buffer_info.buffer_type = buffer_type;
 	buffer_info.num_buffers = 1;
 	buffer_info.align_device_addr = handle->device_addr;
-	dprintk(VIDC_DBG, "%s %s buffer : %pa\n",
+	dprintk(VIDC_DBG, "%s %s buffer : %x\n",
 				reuse ? "Reusing" : "Allocated",
 				get_buffer_name(buffer_type),
-				&buffer_info.align_device_addr);
+				buffer_info.align_device_addr);
 
 	rc = call_hfi_op(hdev, session_set_buffers,
 		(void *) inst->session, &buffer_info);
@@ -3425,11 +3362,6 @@
 
 	mutex_lock(&buf_list->lock);
 	list_for_each_entry(buf, &buf_list->list, list) {
-		if (!buf->handle) {
-			reused = false;
-			break;
-		}
-
 		if (buf->buffer_type != buffer_type)
 			continue;
 
@@ -3445,7 +3377,7 @@
 			&& buffer_type != HAL_BUFFER_INTERNAL_PERSIST_1) {
 
 			rc = set_internal_buf_on_fw(inst, buffer_type,
-					buf->handle, true);
+					&buf->smem, true);
 			if (rc) {
 				dprintk(VIDC_ERR,
 					"%s: session_set_buffers failed\n",
@@ -3466,7 +3398,6 @@
 			struct hal_buffer_requirements *internal_bufreq,
 			struct msm_vidc_list *buf_list)
 {
-	struct msm_smem *handle;
 	struct internal_buf *binfo;
 	u32 smem_flags = 0;
 	int rc = 0;
@@ -3482,27 +3413,25 @@
 		smem_flags |= SMEM_SECURE;
 
 	for (i = 0; i < internal_bufreq->buffer_count_actual; i++) {
-		handle = msm_comm_smem_alloc(inst, internal_bufreq->buffer_size,
-				1, smem_flags, internal_bufreq->buffer_type, 0);
-		if (!handle) {
-			dprintk(VIDC_ERR,
-				"Failed to allocate scratch memory\n");
-			rc = -ENOMEM;
-			goto err_no_mem;
-		}
-
 		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
 		if (!binfo) {
 			dprintk(VIDC_ERR, "Out of memory\n");
 			rc = -ENOMEM;
 			goto fail_kzalloc;
 		}
+		rc = msm_comm_smem_alloc(inst, internal_bufreq->buffer_size,
+				1, smem_flags, internal_bufreq->buffer_type,
+				0, &binfo->smem);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to allocate scratch memory\n");
+			goto err_no_mem;
+		}
 
-		binfo->handle = handle;
 		binfo->buffer_type = internal_bufreq->buffer_type;
 
 		rc = set_internal_buf_on_fw(inst, internal_bufreq->buffer_type,
-				handle, false);
+				&binfo->smem, false);
 		if (rc)
 			goto fail_set_buffers;
 
@@ -3513,10 +3442,10 @@
 	return rc;
 
 fail_set_buffers:
+	msm_comm_smem_free(inst, &binfo->smem);
+err_no_mem:
 	kfree(binfo);
 fail_kzalloc:
-	msm_comm_smem_free(inst, handle);
-err_no_mem:
 	return rc;
 
 }
@@ -3755,25 +3684,32 @@
 }
 
 static void populate_frame_data(struct vidc_frame_data *data,
-		const struct vb2_buffer *vb, struct msm_vidc_inst *inst)
+		struct msm_vidc_buffer *mbuf, struct msm_vidc_inst *inst)
 {
 	u64 time_usec;
 	int extra_idx;
-	enum v4l2_buf_type type = vb->type;
-	enum vidc_ports port = type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
-		OUTPUT_PORT : CAPTURE_PORT;
-	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct vb2_buffer *vb;
+	struct vb2_v4l2_buffer *vbuf;
+
+	if (!inst || !mbuf || !data) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK %pK %pK\n",
+			__func__, inst, mbuf, data);
+		return;
+	}
+
+	vb = &mbuf->vvb.vb2_buf;
+	vbuf = to_vb2_v4l2_buffer(vb);
 
 	time_usec = vb->timestamp;
 	do_div(time_usec, NSEC_PER_USEC);
 
 	data->alloc_len = vb->planes[0].length;
-	data->device_addr = vb->planes[0].m.userptr;
+	data->device_addr = mbuf->smem[0].device_addr;
 	data->timestamp = time_usec;
 	data->flags = 0;
 	data->clnt_data = data->device_addr;
 
-	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		bool pic_decoding_mode = msm_comm_g_ctrl_for_id(inst,
 				V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE);
 
@@ -3801,59 +3737,64 @@
 		data->mark_data = data->mark_target =
 			pic_decoding_mode ? 0xdeadbeef : 0;
 
-	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+	} else if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		data->buffer_type = msm_comm_get_hal_output_buffer(inst);
 	}
 
-	extra_idx = EXTRADATA_IDX(inst->bufq[port].num_planes);
-	if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
-			vb->planes[extra_idx].m.userptr) {
-		data->extradata_addr = vb->planes[extra_idx].m.userptr;
+	extra_idx = EXTRADATA_IDX(vb->num_planes);
+	if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+		data->extradata_addr = mbuf->smem[extra_idx].device_addr;
 		data->extradata_size = vb->planes[extra_idx].length;
 		data->flags |= HAL_BUFFERFLAG_EXTRADATA;
 	}
 }
 
-static unsigned int count_single_batch(struct msm_vidc_list *list,
+static unsigned int count_single_batch(struct msm_vidc_inst *inst,
 		enum v4l2_buf_type type)
 {
-	struct vb2_buf_entry *buf;
 	int count = 0;
-	struct vb2_v4l2_buffer *vbuf = NULL;
+	struct msm_vidc_buffer *mbuf = NULL;
 
-	mutex_lock(&list->lock);
-	list_for_each_entry(buf, &list->list, list) {
-		if (buf->vb->type != type)
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry(mbuf, &inst->registeredbufs.list, list) {
+		if (mbuf->vvb.vb2_buf.type != type)
+			continue;
+
+		/* count only deferred buffers */
+		if (!mbuf->deferred)
 			continue;
 
 		++count;
 
-		vbuf = to_vb2_v4l2_buffer(buf->vb);
-		if (!(vbuf->flags & V4L2_MSM_BUF_FLAG_DEFER))
+		if (!(mbuf->vvb.flags & V4L2_MSM_BUF_FLAG_DEFER))
 			goto found_batch;
 	}
-	 /* don't have a full batch */
+	/* don't have a full batch */
 	count = 0;
 
 found_batch:
-	mutex_unlock(&list->lock);
+	mutex_unlock(&inst->registeredbufs.lock);
 	return count;
 }
 
-static unsigned int count_buffers(struct msm_vidc_list *list,
+static unsigned int count_buffers(struct msm_vidc_inst *inst,
 		enum v4l2_buf_type type)
 {
-	struct vb2_buf_entry *buf;
+	struct msm_vidc_buffer *mbuf;
 	int count = 0;
 
-	mutex_lock(&list->lock);
-	list_for_each_entry(buf, &list->list, list) {
-		if (buf->vb->type != type)
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry(mbuf, &inst->registeredbufs.list, list) {
+		if (mbuf->vvb.vb2_buf.type != type)
+			continue;
+
+		/* count only deferred buffers */
+		if (!mbuf->deferred)
 			continue;
 
 		++count;
 	}
-	mutex_unlock(&list->lock);
+	mutex_unlock(&inst->registeredbufs.lock);
 
 	return count;
 }
@@ -3864,27 +3805,45 @@
 
 	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		dprintk(VIDC_DBG,
-			"Sending etb (%pa) to hal: filled: %d, ts: %lld, flags = %#x\n",
-			&data->device_addr, data->filled_len,
+			"Sending etb (%x) to hal: filled: %d, ts: %lld, flags = %#x\n",
+			data->device_addr, data->filled_len,
 			data->timestamp, data->flags);
 		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_ETB);
 
 	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		dprintk(VIDC_DBG,
-			"Sending ftb (%pa) to hal: size: %d, ts: %lld, flags = %#x\n",
-			&data->device_addr, data->alloc_len,
+			"Sending ftb (%x) to hal: size: %d, ts: %lld, flags = %#x\n",
+			data->device_addr, data->alloc_len,
 			data->timestamp, data->flags);
 		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FTB);
 	}
 }
 
+enum hal_buffer get_hal_buffer_type(unsigned int type,
+		unsigned int plane_num)
+{
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		if (plane_num == 0)
+			return HAL_BUFFER_INPUT;
+		else
+			return HAL_BUFFER_EXTRADATA_INPUT;
+	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (plane_num == 0)
+			return HAL_BUFFER_OUTPUT;
+		else
+			return HAL_BUFFER_EXTRADATA_OUTPUT;
+	} else {
+		return -EINVAL;
+	}
+}
+
 /*
  * Attempts to queue `vb` to hardware.  If, for various reasons, the buffer
  * cannot be queued to hardware, the buffer will be staged for commit in the
  * pending queue.  Once the hardware reaches a good state (or if `vb` is NULL,
  * the subsequent *_qbuf will commit the previously staged buffers to hardware.
  */
-int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb)
+int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf)
 {
 	int rc = 0, capture_count, output_count;
 	struct msm_vidc_core *core;
@@ -3894,8 +3853,7 @@
 		int count;
 	} etbs, ftbs;
 	bool defer = false, batch_mode;
-	struct vb2_buf_entry *temp, *next;
-	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct msm_vidc_buffer *temp = NULL, *next = NULL;
 
 	if (!inst) {
 		dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__);
@@ -3905,36 +3863,21 @@
 	core = inst->core;
 	hdev = core->device;
 
-	if (inst->state == MSM_VIDC_CORE_INVALID ||
-		core->state == VIDC_CORE_INVALID ||
-		core->state == VIDC_CORE_UNINIT) {
-		dprintk(VIDC_ERR, "Core is in bad state. Can't Queue\n");
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR, "%s: inst is in bad state\n", __func__);
 		return -EINVAL;
 	}
 
-	/*
-	 * Stick the buffer into the pendinq, we'll pop it out later on
-	 * if we want to commit it to hardware
-	 */
-	if (vb) {
-		temp = kzalloc(sizeof(*temp), GFP_KERNEL);
-		if (!temp) {
-			dprintk(VIDC_ERR, "Out of memory\n");
-			goto err_no_mem;
-		}
-
-		temp->vb = vb;
-		mutex_lock(&inst->pendingq.lock);
-		list_add_tail(&temp->list, &inst->pendingq.list);
-		mutex_unlock(&inst->pendingq.lock);
-	}
+	/* initially assume every buffer is going to be deferred */
+	if (mbuf)
+		mbuf->deferred = true;
 
 	batch_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_VIDC_QBUF_MODE)
 		== V4L2_VIDC_QBUF_BATCHED;
 	capture_count = (batch_mode ? &count_single_batch : &count_buffers)
-		(&inst->pendingq, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+		(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	output_count = (batch_mode ? &count_single_batch : &count_buffers)
-		(&inst->pendingq, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+		(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
 
 	/*
 	 * Somewhat complicated logic to prevent queuing the buffer to hardware.
@@ -3948,13 +3891,18 @@
 	 * buffer to be batched with future frames.  The batch size (on both
 	 * capabilities) is completely determined by the client.
 	 */
-	defer = defer ? defer : (vbuf && vbuf->flags & V4L2_MSM_BUF_FLAG_DEFER);
+	defer = defer ? defer :
+		(mbuf && mbuf->vvb.flags & V4L2_MSM_BUF_FLAG_DEFER);
 
 	/* 3) If we're in batch mode, we must have full batches of both types */
 	defer = defer ? defer:(batch_mode && (!output_count || !capture_count));
 
 	if (defer) {
-		dprintk(VIDC_DBG, "Deferring queue of %pK\n", vb);
+		if (mbuf) {
+			mbuf->deferred = true;
+			print_vidc_buffer(VIDC_DBG, "deferred qbuf",
+				inst, mbuf);
+		}
 		return 0;
 	}
 
@@ -3984,15 +3932,18 @@
 	etbs.count = ftbs.count = 0;
 
 	/*
-	 * Try to collect all pending buffers into 2 batches of ftb and etb
+	 * Try to collect all deferred buffers into 2 batches of ftb and etb
 	 * Note that these "batches" might be empty if we're no in batching mode
-	 * and the pendingq is empty
+	 * and the deferred is not set for buffers.
 	 */
-	mutex_lock(&inst->pendingq.lock);
-	list_for_each_entry_safe(temp, next, &inst->pendingq.list, list) {
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) {
 		struct vidc_frame_data *frame_data = NULL;
 
-		switch (temp->vb->type) {
+		if (!temp->deferred)
+			continue;
+
+		switch (temp->vvb.vb2_buf.type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 			if (ftbs.count < capture_count && ftbs.data)
 				frame_data = &ftbs.data[ftbs.count++];
@@ -4008,12 +3959,14 @@
 		if (!frame_data)
 			continue;
 
-		populate_frame_data(frame_data, temp->vb, inst);
+		populate_frame_data(frame_data, temp, inst);
 
-		list_del(&temp->list);
-		kfree(temp);
+		/* this buffer going to be queued (not deferred) */
+		temp->deferred = false;
+
+		print_vidc_buffer(VIDC_DBG, "qbuf", inst, temp);
 	}
-	mutex_unlock(&inst->pendingq.lock);
+	mutex_unlock(&inst->registeredbufs.lock);
 
 	/* Finally commit all our frame(s) to H/W */
 	if (batch_mode) {
@@ -4089,7 +4042,7 @@
 	return rc;
 }
 
-static int msm_vidc_update_host_buff_counts(struct msm_vidc_inst *inst)
+int msm_vidc_update_host_buff_counts(struct msm_vidc_inst *inst)
 {
 	int extra_buffers;
 	struct hal_buffer_requirements *bufreq;
@@ -4120,8 +4073,7 @@
 		}
 
 		/* For DPB buffers, no need to add Extra buffers */
-
-		bufreq->buffer_count_actual = bufreq->buffer_count_min_host =
+		bufreq->buffer_count_min_host =	bufreq->buffer_count_actual =
 			bufreq->buffer_count_min;
 
 		bufreq = get_buff_req_buffer(inst,
@@ -4136,8 +4088,22 @@
 		extra_buffers = msm_vidc_get_extra_buff_count(inst,
 			HAL_BUFFER_OUTPUT);
 
-		bufreq->buffer_count_min_host =
+		bufreq->buffer_count_min_host =	bufreq->buffer_count_actual =
 			bufreq->buffer_count_min + extra_buffers;
+
+		bufreq = get_buff_req_buffer(inst,
+				HAL_BUFFER_EXTRADATA_OUTPUT2);
+		if (!bufreq) {
+			dprintk(VIDC_DBG,
+				"No buffer requirements : %x\n",
+					HAL_BUFFER_EXTRADATA_OUTPUT2);
+		} else {
+			if (bufreq->buffer_count_min) {
+				bufreq->buffer_count_min_host =
+				bufreq->buffer_count_actual =
+				bufreq->buffer_count_min + extra_buffers;
+			}
+		}
 	} else {
 
 		bufreq = get_buff_req_buffer(inst,
@@ -4152,8 +4118,22 @@
 		extra_buffers = msm_vidc_get_extra_buff_count(inst,
 			HAL_BUFFER_OUTPUT);
 
-		bufreq->buffer_count_actual = bufreq->buffer_count_min_host =
+		bufreq->buffer_count_min_host =	bufreq->buffer_count_actual =
 			bufreq->buffer_count_min + extra_buffers;
+
+		bufreq = get_buff_req_buffer(inst,
+				HAL_BUFFER_EXTRADATA_OUTPUT);
+		if (!bufreq) {
+			dprintk(VIDC_DBG,
+				"No buffer requirements : %x\n",
+				HAL_BUFFER_EXTRADATA_OUTPUT);
+		} else {
+			if (bufreq->buffer_count_min) {
+				bufreq->buffer_count_min_host =
+				bufreq->buffer_count_actual =
+				bufreq->buffer_count_min + extra_buffers;
+			}
+		}
 	}
 
 	return 0;
@@ -4188,8 +4168,8 @@
 				req.buffer_count_min, req.buffer_size);
 		}
 	}
-
-	rc = msm_vidc_update_host_buff_counts(inst);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		rc = msm_vidc_update_host_buff_counts(inst);
 
 	dprintk(VIDC_DBG, "Buffer requirements host adjusted:\n");
 	dprintk(VIDC_DBG, "%15s %8s %8s %8s %8s\n",
@@ -4257,7 +4237,8 @@
 
 	rc = wait_for_completion_timeout(&inst->completions[
 			SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)],
-		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+		msecs_to_jiffies(
+			inst->core->resources.msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR,
 			"%s: Wait interrupted or timed out [%pK]: %d\n",
@@ -4332,11 +4313,7 @@
 	}
 	mutex_lock(&inst->outputbufs.lock);
 	list_for_each_entry_safe(buf, dummy, &inst->outputbufs.list, list) {
-		handle = buf->handle;
-		if (!handle) {
-			dprintk(VIDC_ERR, "%s - invalid handle\n", __func__);
-			goto exit;
-		}
+		handle = &buf->smem;
 
 		if ((buf->buffer_ownership == FIRMWARE) && !force_release) {
 			dprintk(VIDC_INFO, "DPB is with f/w. Can't free it\n");
@@ -4356,18 +4333,17 @@
 				(void *)inst->session, &buffer_info);
 			if (rc) {
 				dprintk(VIDC_WARN,
-					"Rel output buf fail:%pa, %d\n",
-					&buffer_info.align_device_addr,
+					"Rel output buf fail:%x, %d\n",
+					buffer_info.align_device_addr,
 					buffer_info.buffer_size);
 			}
 		}
 
 		list_del(&buf->list);
-		msm_comm_smem_free(inst, buf->handle);
+		msm_comm_smem_free(inst, &buf->smem);
 		kfree(buf);
 	}
 
-exit:
 	mutex_unlock(&inst->outputbufs.lock);
 	return rc;
 }
@@ -4392,13 +4368,8 @@
 	mutex_lock(&inst->scratchbufs.lock);
 
 	list_for_each_entry(buf, &inst->scratchbufs.list, list) {
-		if (!buf->handle) {
-			dprintk(VIDC_ERR, "%s: invalid buf handle\n", __func__);
-			mutex_unlock(&inst->scratchbufs.lock);
-			goto not_sufficient;
-		}
 		if (buf->buffer_type == buffer_type &&
-			buf->handle->size >= bufreq->buffer_size)
+			buf->smem.size >= bufreq->buffer_size)
 			count++;
 	}
 	mutex_unlock(&inst->scratchbufs.lock);
@@ -4457,13 +4428,7 @@
 
 	mutex_lock(&inst->scratchbufs.lock);
 	list_for_each_entry_safe(buf, dummy, &inst->scratchbufs.list, list) {
-		if (!buf->handle) {
-			dprintk(VIDC_ERR, "%s - buf->handle NULL\n", __func__);
-			rc = -EINVAL;
-			goto exit;
-		}
-
-		handle = buf->handle;
+		handle = &buf->smem;
 		buffer_info.buffer_size = handle->size;
 		buffer_info.buffer_type = buf->buffer_type;
 		buffer_info.num_buffers = 1;
@@ -4475,8 +4440,8 @@
 				(void *)inst->session, &buffer_info);
 			if (rc) {
 				dprintk(VIDC_WARN,
-					"Rel scrtch buf fail:%pa, %d\n",
-					&buffer_info.align_device_addr,
+					"Rel scrtch buf fail:%x, %d\n",
+					buffer_info.align_device_addr,
 					buffer_info.buffer_size);
 			}
 			mutex_unlock(&inst->scratchbufs.lock);
@@ -4495,15 +4460,35 @@
 			continue;
 
 		list_del(&buf->list);
-		msm_comm_smem_free(inst, buf->handle);
+		msm_comm_smem_free(inst, handle);
 		kfree(buf);
 	}
 
-exit:
 	mutex_unlock(&inst->scratchbufs.lock);
 	return rc;
 }
 
+int msm_comm_release_recon_buffers(struct msm_vidc_inst *inst)
+{
+	struct recon_buf *buf, *next;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+			"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+
+	mutex_lock(&inst->reconbufs.lock);
+	list_for_each_entry_safe(buf, next, &inst->reconbufs.list, list) {
+		list_del(&buf->list);
+		kfree(buf);
+	}
+	INIT_LIST_HEAD(&inst->reconbufs.list);
+	mutex_unlock(&inst->reconbufs.lock);
+
+	return 0;
+}
+
 int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
 {
 	struct msm_smem *handle;
@@ -4534,7 +4519,7 @@
 	mutex_lock(&inst->persistbufs.lock);
 	list_for_each_safe(ptr, next, &inst->persistbufs.list) {
 		buf = list_entry(ptr, struct internal_buf, list);
-		handle = buf->handle;
+		handle = &buf->smem;
 		buffer_info.buffer_size = handle->size;
 		buffer_info.buffer_type = buf->buffer_type;
 		buffer_info.num_buffers = 1;
@@ -4546,8 +4531,8 @@
 				(void *)inst->session, &buffer_info);
 			if (rc) {
 				dprintk(VIDC_WARN,
-					"Rel prst buf fail:%pa, %d\n",
-					&buffer_info.align_device_addr,
+					"Rel prst buf fail:%x, %d\n",
+					buffer_info.align_device_addr,
 					buffer_info.buffer_size);
 			}
 			mutex_unlock(&inst->persistbufs.lock);
@@ -4560,7 +4545,7 @@
 			mutex_lock(&inst->persistbufs.lock);
 		}
 		list_del(&buf->list);
-		msm_comm_smem_free(inst, buf->handle);
+		msm_comm_smem_free(inst, handle);
 		kfree(buf);
 	}
 	mutex_unlock(&inst->persistbufs.lock);
@@ -4657,6 +4642,54 @@
 	return rc;
 }
 
+int msm_comm_set_recon_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0, i = 0;
+	struct hal_buffer_requirements *internal_buf;
+	struct recon_buf *binfo;
+	struct msm_vidc_list *buf_list = &inst->reconbufs;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		internal_buf = get_buff_req_buffer(inst,
+			HAL_BUFFER_INTERNAL_RECON);
+	else if (inst->session_type == MSM_VIDC_DECODER)
+		internal_buf = get_buff_req_buffer(inst,
+			msm_comm_get_hal_output_buffer(inst));
+	else
+		return -EINVAL;
+
+	if (!internal_buf || !internal_buf->buffer_count_actual) {
+		dprintk(VIDC_DBG, "Inst : %pK Recon buffers not required\n",
+			inst);
+		return 0;
+	}
+
+	if (!list_empty(&inst->reconbufs.list))
+		msm_comm_release_recon_buffers(inst);
+
+	for (i = 0; i < internal_buf->buffer_count_actual; i++) {
+		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+		if (!binfo) {
+			dprintk(VIDC_ERR, "Out of memory\n");
+			rc = -ENOMEM;
+			goto fail_kzalloc;
+		}
+
+		binfo->buffer_index = i;
+		mutex_lock(&buf_list->lock);
+		list_add_tail(&binfo->list, &buf_list->list);
+		mutex_unlock(&buf_list->lock);
+	}
+
+fail_kzalloc:
+	return rc;
+}
+
 int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
@@ -4690,116 +4723,20 @@
 	for (c = 0; c < ARRAY_SIZE(ports); ++c) {
 		enum vidc_ports port = ports[c];
 
-		dprintk(VIDC_DBG, "Flushing buffers of type %d in bad state\n",
-				port);
 		mutex_lock(&inst->bufq[port].lock);
-		list_for_each_safe(ptr, next, &inst->bufq[port].
-				vb2_bufq.queued_list) {
+		list_for_each_safe(ptr, next,
+				&inst->bufq[port].vb2_bufq.queued_list) {
 			struct vb2_buffer *vb = container_of(ptr,
 					struct vb2_buffer, queued_entry);
-
 			vb->planes[0].bytesused = 0;
-			vb->planes[0].data_offset = 0;
-
+			print_vb2_buffer(VIDC_ERR, "flush in invalid",
+				inst, vb);
 			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
 		}
 		mutex_unlock(&inst->bufq[port].lock);
 	}
-
 	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
-}
-
-void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst)
-{
-	struct buffer_info *binfo = NULL;
-
-	if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
-		return;
-
-	/*
-	 * dynamic buffer mode:- if flush is called during seek
-	 * driver should not queue any new buffer it has been holding.
-	 *
-	 * Each dynamic o/p buffer can have one of following ref_count:
-	 * ref_count : 0   - f/w has released reference and sent dynamic
-	 *                   buffer back. The buffer has been returned
-	 *                   back to client.
-	 *
-	 * ref_count : 1   - f/w is holding reference. f/w may have released
-	 *                   dynamic buffer as read_only OR dynamic buffer is
-	 *                   pending. f/w will release reference before sending
-	 *                   flush_done.
-	 *
-	 * ref_count : >=2 - f/w is holding reference, f/w has released dynamic
-	 *                   buffer as read_only, which client has queued back
-	 *                   to driver. Driver holds this buffer and will queue
-	 *                   back only when f/w releases the reference. During
-	 *                   flush_done, f/w will release the reference but
-	 *                   driver should not queue back the buffer to f/w.
-	 *                   Flush all buffers with ref_count >= 2.
-	 */
-	mutex_lock(&inst->registeredbufs.lock);
-	if (!list_empty(&inst->registeredbufs.list)) {
-		struct v4l2_event buf_event = {0};
-		u32 *ptr = NULL;
-
-		list_for_each_entry(binfo, &inst->registeredbufs.list, list) {
-			if (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
-				atomic_read(&binfo->ref_count) >= 2) {
-
-				atomic_dec(&binfo->ref_count);
-				buf_event.type =
-				V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER;
-				ptr = (u32 *)buf_event.u.data;
-				ptr[0] = binfo->fd[0];
-				ptr[1] = binfo->buff_off[0];
-				ptr[2] = binfo->uvaddr[0];
-				ptr[3] = (u32) binfo->timestamp.tv_sec;
-				ptr[4] = (u32) binfo->timestamp.tv_usec;
-				ptr[5] = binfo->v4l2_index;
-				dprintk(VIDC_DBG,
-					"released buffer held in driver before issuing flush: %pa fd[0]: %d\n",
-					&binfo->device_addr[0], binfo->fd[0]);
-				/*send event to client*/
-				v4l2_event_queue_fh(&inst->event_handler,
-					&buf_event);
-			}
-		}
-	}
-	mutex_unlock(&inst->registeredbufs.lock);
-}
-
-void msm_comm_flush_pending_dynamic_buffers(struct msm_vidc_inst *inst)
-{
-	struct buffer_info *binfo = NULL;
-
-	if (!inst)
-		return;
-
-	if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
-		return;
-
-	if (list_empty(&inst->pendingq.list) ||
-		list_empty(&inst->registeredbufs.list))
-		return;
-
-	/*
-	 * Dynamic Buffer mode - Since pendingq is not empty
-	 * no output buffers have been sent to firmware yet.
-	 * Hence remove reference to all pendingq o/p buffers
-	 * before flushing them.
-	 */
-
-	mutex_lock(&inst->registeredbufs.lock);
-	list_for_each_entry(binfo, &inst->registeredbufs.list, list) {
-		if (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-			dprintk(VIDC_DBG,
-				"%s: binfo = %pK device_addr = %pa\n",
-				__func__, binfo, &binfo->device_addr[0]);
-			buf_ref_put(inst, binfo);
-		}
-	}
-	mutex_unlock(&inst->registeredbufs.lock);
+	return;
 }
 
 int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
@@ -4807,33 +4744,25 @@
 	int rc =  0;
 	bool ip_flush = false;
 	bool op_flush = false;
-	struct vb2_buf_entry *temp, *next;
-	struct mutex *lock;
+	struct msm_vidc_buffer *mbuf, *next;
 	struct msm_vidc_core *core;
 	struct hfi_device *hdev;
 
-	if (!inst) {
+	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR,
-				"Invalid instance pointer = %pK\n", inst);
+				"Invalid params, inst %pK\n", inst);
 		return -EINVAL;
 	}
 	core = inst->core;
-	if (!core) {
-		dprintk(VIDC_ERR,
-				"Invalid core pointer = %pK\n", core);
-		return -EINVAL;
-	}
 	hdev = core->device;
-	if (!hdev) {
-		dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev);
-		return -EINVAL;
-	}
 
 	ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT;
 	op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
 
 	if (ip_flush && !op_flush) {
-		dprintk(VIDC_INFO, "Input only flush not supported\n");
+		dprintk(VIDC_WARN,
+			"Input only flush not supported, making it flush all\n");
+		op_flush = true;
 		return 0;
 	}
 
@@ -4841,11 +4770,7 @@
 
 	msm_clock_data_reset(inst);
 
-	msm_comm_flush_dynamic_buffers(inst);
-
-	if (inst->state == MSM_VIDC_CORE_INVALID ||
-			core->state == VIDC_CORE_INVALID ||
-			core->state == VIDC_CORE_UNINIT) {
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
 		dprintk(VIDC_ERR,
 				"Core %pK and inst %pK are in bad state\n",
 					core, inst);
@@ -4853,68 +4778,52 @@
 		return 0;
 	}
 
-	if (inst->in_reconfig && !ip_flush && op_flush) {
-		mutex_lock(&inst->pendingq.lock);
-		if (!list_empty(&inst->pendingq.list)) {
-			/*
-			 * Execution can never reach here since port reconfig
-			 * wont happen unless pendingq is emptied out
-			 * (both pendingq and flush being secured with same
-			 * lock). Printing a message here incase this breaks.
-			 */
-			dprintk(VIDC_WARN,
-			"FLUSH BUG: Pending q not empty! It should be empty\n");
-		}
-		mutex_unlock(&inst->pendingq.lock);
-		atomic_inc(&inst->in_flush);
-		dprintk(VIDC_DBG, "Send flush Output to firmware\n");
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry_safe(mbuf, next, &inst->registeredbufs.list, list) {
+		/* flush only deferred buffers (which are not queued yet) */
+		if (!mbuf->deferred)
+			continue;
+
+		/* don't flush input buffers if flush not requested on it */
+		if (!ip_flush && mbuf->vvb.vb2_buf.type ==
+				V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+			continue;
+
+		print_vidc_buffer(VIDC_DBG, "flush buf", inst, mbuf);
+		msm_comm_flush_vidc_buffer(inst, mbuf);
+		msm_comm_unmap_vidc_buffer(inst, mbuf);
+
+		/* remove from list */
+		list_del(&mbuf->list);
+		kfree(mbuf);
+		mbuf = NULL;
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+
+	/* enable in flush */
+	inst->in_flush = true;
+
+	hdev = inst->core->device;
+	if (ip_flush) {
+		dprintk(VIDC_DBG, "Send flush on all ports to firmware\n");
 		rc = call_hfi_op(hdev, session_flush, inst->session,
-				HAL_FLUSH_OUTPUT);
+			HAL_FLUSH_ALL);
 	} else {
-		msm_comm_flush_pending_dynamic_buffers(inst);
-		/*
-		 * If flush is called after queueing buffers but before
-		 * streamon driver should flush the pending queue
-		 */
-		mutex_lock(&inst->pendingq.lock);
-		list_for_each_entry_safe(temp, next,
-				&inst->pendingq.list, list) {
-			enum v4l2_buf_type type = temp->vb->type;
-
-			if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-				lock = &inst->bufq[CAPTURE_PORT].lock;
-			else
-				lock = &inst->bufq[OUTPUT_PORT].lock;
-
-			temp->vb->planes[0].bytesused = 0;
-
-			mutex_lock(lock);
-			vb2_buffer_done(temp->vb, VB2_BUF_STATE_DONE);
-			msm_vidc_debugfs_update(inst,
-				type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
-					MSM_VIDC_DEBUGFS_EVENT_FBD :
-					MSM_VIDC_DEBUGFS_EVENT_EBD);
-			list_del(&temp->list);
-			mutex_unlock(lock);
-
-			kfree(temp);
-		}
-		mutex_unlock(&inst->pendingq.lock);
-
-		/*Do not send flush in case of session_error */
-		if (!(inst->state == MSM_VIDC_CORE_INVALID &&
-			  core->state != VIDC_CORE_INVALID)) {
-			atomic_inc(&inst->in_flush);
-			dprintk(VIDC_DBG, "Send flush all to firmware\n");
-			rc = call_hfi_op(hdev, session_flush, inst->session,
-				HAL_FLUSH_ALL);
-		}
+		dprintk(VIDC_DBG, "Send flush on output port to firmware\n");
+		rc = call_hfi_op(hdev, session_flush, inst->session,
+			HAL_FLUSH_OUTPUT);
+	}
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Sending flush to firmware failed, flush out all buffers\n");
+		msm_comm_flush_in_invalid_state(inst);
+		/* disable in_flush */
+		inst->in_flush = false;
 	}
 
 	return rc;
 }
 
-
 enum hal_extradata_id msm_comm_get_hal_extradata_index(
 	enum v4l2_mpeg_vidc_extradata index)
 {
@@ -5009,6 +4918,9 @@
 	case V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE:
 		ret = HAL_EXTRADATA_VPX_COLORSPACE;
 		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO:
+		ret = HAL_EXTRADATA_UBWC_CR_STATS_INFO;
+		break;
 	default:
 		dprintk(VIDC_WARN, "Extradata not found: %d\n", index);
 		break;
@@ -5117,30 +5029,30 @@
 	if (input_height > output_height) {
 		if (input_height > x_min * output_height) {
 			dprintk(VIDC_ERR,
-				"Unsupported height downscale ratio %d vs %d\n",
-				input_height/output_height, x_min);
+				"Unsupported height min height %d vs %d\n",
+				input_height / x_min, output_height);
 			return -ENOTSUPP;
 		}
 	} else {
 		if (output_height > x_max * input_height) {
 			dprintk(VIDC_ERR,
-				"Unsupported height upscale ratio %d vs %d\n",
-				input_height/output_height, x_max);
+				"Unsupported height max height %d vs %d\n",
+				x_max * input_height, output_height);
 			return -ENOTSUPP;
 		}
 	}
 	if (input_width > output_width) {
 		if (input_width > y_min * output_width) {
 			dprintk(VIDC_ERR,
-				"Unsupported width downscale ratio %d vs %d\n",
-				input_width/output_width, y_min);
+				"Unsupported width min width %d vs %d\n",
+				input_width / y_min, output_width);
 			return -ENOTSUPP;
 		}
 	} else {
 		if (output_width > y_max * input_width) {
 			dprintk(VIDC_ERR,
-				"Unsupported width upscale ratio %d vs %d\n",
-				input_width/output_width, y_max);
+				"Unsupported width max width %d vs %d\n",
+				y_max * input_width, output_width);
 			return -ENOTSUPP;
 		}
 	}
@@ -5207,6 +5119,10 @@
 			capability->width.max, capability->height.max);
 			rc = -ENOTSUPP;
 		}
+
+		if (!rc && msm_vidc_check_scaling_supported(inst)) {
+			rc = -ENOTSUPP;
+		}
 	}
 	if (rc) {
 		change_inst_state(inst, MSM_VIDC_CORE_INVALID);
@@ -5286,19 +5202,19 @@
 	return rc;
 }
 
-struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
-			size_t size, u32 align, u32 flags,
-			enum hal_buffer buffer_type, int map_kernel)
+int msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+		size_t size, u32 align, u32 flags, enum hal_buffer buffer_type,
+		int map_kernel, struct msm_smem *smem)
 {
-	struct msm_smem *m = NULL;
+	int rc = 0;
 
 	if (!inst || !inst->core) {
 		dprintk(VIDC_ERR, "%s: invalid inst: %pK\n", __func__, inst);
-		return NULL;
+		return -EINVAL;
 	}
-	m = msm_smem_alloc(inst->mem_client, size, align,
-				flags, buffer_type, map_kernel);
-	return m;
+	rc = msm_smem_alloc(inst->mem_client, size, align,
+			flags, buffer_type, map_kernel, smem);
+	return rc;
 }
 
 void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem)
@@ -5319,28 +5235,138 @@
 			"%s: invalid params: %pK %pK\n", __func__, inst, mem);
 		return -EINVAL;
 	}
-	return msm_smem_cache_operations(inst->mem_client, mem, cache_ops);
+	return msm_smem_cache_operations(inst->mem_client, mem->handle,
+			mem->offset, mem->size, cache_ops);
 }
 
-struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
-			int fd, u32 offset, enum hal_buffer buffer_type)
+int msm_comm_qbuf_cache_operations(struct msm_vidc_inst *inst,
+		struct v4l2_buffer *b)
 {
-	struct msm_smem *m = NULL;
+	int rc = 0, i;
+	void *dma_buf;
+	void *handle;
+	bool skip;
 
-	if (!inst || !inst->core) {
-		dprintk(VIDC_ERR, "%s: invalid inst: %pK\n", __func__, inst);
-		return NULL;
+	if (!inst || !b) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n",
+			__func__, inst, b);
+		return -EINVAL;
 	}
 
-	if (inst->state == MSM_VIDC_CORE_INVALID) {
-		dprintk(VIDC_ERR, "Core in Invalid state, returning from %s\n",
-			__func__);
-		return NULL;
+	for (i = 0; i < b->length; i++) {
+		unsigned long offset, size;
+		enum smem_cache_ops cache_ops;
+
+		dma_buf = msm_smem_get_dma_buf(b->m.planes[i].m.fd);
+		handle = msm_smem_get_handle(inst->mem_client, dma_buf);
+
+		offset = b->m.planes[i].data_offset;
+		size = b->m.planes[i].length;
+		cache_ops = SMEM_CACHE_INVALIDATE;
+		skip = false;
+
+		if (inst->session_type == MSM_VIDC_DECODER) {
+			if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+				if (!i) { /* bitstream */
+					size = b->m.planes[i].bytesused;
+					cache_ops = SMEM_CACHE_CLEAN_INVALIDATE;
+				}
+			} else if (b->type ==
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+				if (!i) { /* yuv */
+					/* all values are correct */
+				}
+			}
+		} else if (inst->session_type == MSM_VIDC_ENCODER) {
+			if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+				if (!i) { /* yuv */
+					size = b->m.planes[i].bytesused;
+					cache_ops = SMEM_CACHE_CLEAN_INVALIDATE;
+				} else { /* extradata */
+					cache_ops = SMEM_CACHE_CLEAN_INVALIDATE;
+				}
+			} else if (b->type ==
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+				if (!i) { /* bitstream */
+					/* all values are correct */
+				}
+			}
+		}
+
+		if (!skip) {
+			rc = msm_smem_cache_operations(inst->mem_client, handle,
+					offset, size, cache_ops);
+			if (rc)
+				print_v4l2_buffer(VIDC_ERR,
+					"qbuf cache ops failed", inst, b);
+		}
+
+		msm_smem_put_handle(inst->mem_client, handle);
+		msm_smem_put_dma_buf(dma_buf);
 	}
 
-	m = msm_smem_user_to_kernel(inst->mem_client,
-			fd, offset, buffer_type);
-	return m;
+	return rc;
+}
+
+int msm_comm_dqbuf_cache_operations(struct msm_vidc_inst *inst,
+		struct v4l2_buffer *b)
+{
+	int rc = 0, i;
+	void *dma_buf;
+	void *handle;
+	bool skip;
+
+	if (!inst || !b) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n",
+			__func__, inst, b);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < b->length; i++) {
+		unsigned long offset, size;
+		enum smem_cache_ops cache_ops;
+
+		dma_buf = msm_smem_get_dma_buf(b->m.planes[i].m.fd);
+		handle = msm_smem_get_handle(inst->mem_client, dma_buf);
+
+		offset = b->m.planes[i].data_offset;
+		size = b->m.planes[i].length;
+		cache_ops = SMEM_CACHE_INVALIDATE;
+		skip = false;
+
+		if (inst->session_type == MSM_VIDC_DECODER) {
+			if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+				if (!i) /* bitstream */
+					skip = true;
+			} else if (b->type ==
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+				if (!i) /* yuv */
+					skip = true;
+			}
+		} else if (inst->session_type == MSM_VIDC_ENCODER) {
+			if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+				if (!i) /* yuv */
+					skip = true;
+			} else if (b->type ==
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+				if (!i) /* bitstream */
+					skip = true;
+			}
+		}
+
+		if (!skip) {
+			rc = msm_smem_cache_operations(inst->mem_client, handle,
+					offset, size, cache_ops);
+			if (rc)
+				print_v4l2_buffer(VIDC_ERR,
+					"dqbuf cache ops failed", inst, b);
+		}
+
+		msm_smem_put_handle(inst->mem_client, handle);
+		msm_smem_put_dma_buf(dma_buf);
+	}
+
+	return rc;
 }
 
 void msm_vidc_fw_unload_handler(struct work_struct *work)
@@ -5395,7 +5421,7 @@
 
 	hdev = inst->core->device;
 
-	format = get_hal_uncompressed(fourcc);
+	format = msm_comm_get_hal_uncompressed(fourcc);
 	if (format == HAL_UNUSED_COLOR) {
 		dprintk(VIDC_ERR, "Using unsupported colorformat %#x\n",
 				fourcc);
@@ -5497,9 +5523,8 @@
 
 void msm_comm_print_inst_info(struct msm_vidc_inst *inst)
 {
-	struct buffer_info *temp;
+	struct msm_vidc_buffer *mbuf;
 	struct internal_buf *buf;
-	int i = 0;
 	bool is_decode = false;
 	enum vidc_ports port;
 	bool is_secure = false;
@@ -5527,37 +5552,32 @@
 			inst, inst->session_type);
 	mutex_lock(&inst->registeredbufs.lock);
 	dprintk(VIDC_ERR, "registered buffer list:\n");
-	list_for_each_entry(temp, &inst->registeredbufs.list, list)
-		for (i = 0; i < temp->num_planes; i++)
-			dprintk(VIDC_ERR,
-					"type: %d plane: %d addr: %pa size: %d\n",
-					temp->type, i, &temp->device_addr[i],
-					temp->size[i]);
-
+	list_for_each_entry(mbuf, &inst->registeredbufs.list, list)
+		print_vidc_buffer(VIDC_ERR, "buf", inst, mbuf);
 	mutex_unlock(&inst->registeredbufs.lock);
 
 	mutex_lock(&inst->scratchbufs.lock);
 	dprintk(VIDC_ERR, "scratch buffer list:\n");
 	list_for_each_entry(buf, &inst->scratchbufs.list, list)
-		dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n",
-				buf->buffer_type, &buf->handle->device_addr,
-				buf->handle->size);
+		dprintk(VIDC_ERR, "type: %d addr: %x size: %u\n",
+				buf->buffer_type, buf->smem.device_addr,
+				buf->smem.size);
 	mutex_unlock(&inst->scratchbufs.lock);
 
 	mutex_lock(&inst->persistbufs.lock);
 	dprintk(VIDC_ERR, "persist buffer list:\n");
 	list_for_each_entry(buf, &inst->persistbufs.list, list)
-		dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n",
-				buf->buffer_type, &buf->handle->device_addr,
-				buf->handle->size);
+		dprintk(VIDC_ERR, "type: %d addr: %x size: %u\n",
+				buf->buffer_type, buf->smem.device_addr,
+				buf->smem.size);
 	mutex_unlock(&inst->persistbufs.lock);
 
 	mutex_lock(&inst->outputbufs.lock);
 	dprintk(VIDC_ERR, "dpb buffer list:\n");
 	list_for_each_entry(buf, &inst->outputbufs.list, list)
-		dprintk(VIDC_ERR, "type: %d addr: %pa size: %zu\n",
-				buf->buffer_type, &buf->handle->device_addr,
-				buf->handle->size);
+		dprintk(VIDC_ERR, "type: %d addr: %x size: %u\n",
+				buf->buffer_type, buf->smem.device_addr,
+				buf->smem.size);
 	mutex_unlock(&inst->outputbufs.lock);
 }
 
@@ -5654,3 +5674,540 @@
 	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
 }
 
+
+void print_vidc_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf)
+{
+	struct vb2_buffer *vb2 = NULL;
+
+	if (!(tag & msm_vidc_debug) || !inst || !mbuf)
+		return;
+
+	vb2 = &mbuf->vvb.vb2_buf;
+
+	if (vb2->num_planes == 1)
+		dprintk(tag,
+			"%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d\n",
+			str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
+			vb2->index, vb2->planes[0].m.fd,
+			vb2->planes[0].data_offset, mbuf->smem[0].device_addr,
+			vb2->planes[0].length, vb2->planes[0].bytesused,
+			mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp,
+			mbuf->smem[0].refcount);
+	else
+		dprintk(tag,
+			"%s: %s: %x : idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d, extradata: fd %d off %d daddr %x size %d filled %d refcnt %d\n",
+			str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
+			vb2->index, vb2->planes[0].m.fd,
+			vb2->planes[0].data_offset, mbuf->smem[0].device_addr,
+			vb2->planes[0].length, vb2->planes[0].bytesused,
+			mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp,
+			mbuf->smem[0].refcount, vb2->planes[1].m.fd,
+			vb2->planes[1].data_offset, mbuf->smem[1].device_addr,
+			vb2->planes[1].length, vb2->planes[1].bytesused,
+			mbuf->smem[1].refcount);
+}
+
+void print_vb2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
+		struct vb2_buffer *vb2)
+{
+	if (!(tag & msm_vidc_debug) || !inst || !vb2)
+		return;
+
+	if (vb2->num_planes == 1)
+		dprintk(tag,
+			"%s: %s: %x : idx %2d fd %d off %d size %d filled %d\n",
+			str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
+			vb2->index, vb2->planes[0].m.fd,
+			vb2->planes[0].data_offset, vb2->planes[0].length,
+			vb2->planes[0].bytesused);
+	else
+		dprintk(tag,
+			"%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d\n",
+			str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
+			vb2->index, vb2->planes[0].m.fd,
+			vb2->planes[0].data_offset, vb2->planes[0].length,
+			vb2->planes[0].bytesused, vb2->planes[1].m.fd,
+			vb2->planes[1].data_offset, vb2->planes[1].length);
+}
+
+void print_v4l2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
+		struct v4l2_buffer *v4l2)
+{
+	if (!(tag & msm_vidc_debug) || !inst || !v4l2)
+		return;
+
+	if (v4l2->length == 1)
+		dprintk(tag,
+			"%s: %s: %x : idx %2d fd %d off %d size %d filled %d\n",
+			str, v4l2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
+			v4l2->index, v4l2->m.planes[0].m.fd,
+			v4l2->m.planes[0].data_offset,
+			v4l2->m.planes[0].length,
+			v4l2->m.planes[0].bytesused);
+	else
+		dprintk(tag,
+			"%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d\n",
+			str, v4l2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+			"OUTPUT" : "CAPTURE", hash32_ptr(inst->session),
+			v4l2->index, v4l2->m.planes[0].m.fd,
+			v4l2->m.planes[0].data_offset,
+			v4l2->m.planes[0].length,
+			v4l2->m.planes[0].bytesused,
+			v4l2->m.planes[1].m.fd,
+			v4l2->m.planes[1].data_offset,
+			v4l2->m.planes[1].length);
+}
+
+bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2, u32 i)
+{
+	struct vb2_buffer *vb;
+
+	if (!inst || !mbuf || !vb2) {
+		dprintk(VIDC_ERR, "%s: invalid params, %pK %pK %pK\n",
+			__func__, inst, mbuf, vb2);
+		return false;
+	}
+
+	vb = &mbuf->vvb.vb2_buf;
+	if (vb->planes[i].m.fd == vb2->planes[i].m.fd &&
+		vb->planes[i].data_offset == vb2->planes[i].data_offset &&
+		vb->planes[i].length == vb2->planes[i].length) {
+		return true;
+	}
+
+	return false;
+}
+
+bool msm_comm_compare_vb2_planes(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2)
+{
+	int i = 0;
+	struct vb2_buffer *vb;
+
+	if (!inst || !mbuf || !vb2) {
+		dprintk(VIDC_ERR, "%s: invalid params, %pK %pK %pK\n",
+			__func__, inst, mbuf, vb2);
+		return false;
+	}
+
+	vb = &mbuf->vvb.vb2_buf;
+
+	if (vb->num_planes != vb2->num_planes)
+		return false;
+
+	for (i = 0; i < vb->num_planes; i++) {
+		if (!msm_comm_compare_vb2_plane(inst, mbuf, vb2, i))
+			return false;
+	}
+
+	return true;
+}
+
+bool msm_comm_compare_dma_plane(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf, unsigned long *dma_planes, u32 i)
+{
+	if (!inst || !mbuf || !dma_planes) {
+		dprintk(VIDC_ERR, "%s: invalid params, %pK %pK %pK\n",
+			__func__, inst, mbuf, dma_planes);
+		return false;
+	}
+
+	if ((unsigned long)mbuf->smem[i].dma_buf == dma_planes[i])
+		return true;
+
+	return false;
+}
+
+bool msm_comm_compare_dma_planes(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf, unsigned long *dma_planes)
+{
+	int i = 0;
+	struct vb2_buffer *vb;
+
+	if (!inst || !mbuf || !dma_planes) {
+		dprintk(VIDC_ERR, "%s: invalid params, %pK %pK %pK\n",
+			__func__, inst, mbuf, dma_planes);
+		return false;
+	}
+
+	vb = &mbuf->vvb.vb2_buf;
+	for (i = 0; i < vb->num_planes; i++) {
+		if (!msm_comm_compare_dma_plane(inst, mbuf, dma_planes, i))
+			return false;
+	}
+
+	return true;
+}
+
+
+bool msm_comm_compare_device_plane(struct msm_vidc_buffer *mbuf,
+		u32 *planes, u32 i)
+{
+	if (!mbuf || !planes) {
+		dprintk(VIDC_ERR, "%s: invalid params, %pK %pK\n",
+			__func__, mbuf, planes);
+		return false;
+	}
+
+	if (mbuf->smem[i].device_addr == planes[i])
+		return true;
+
+	return false;
+}
+
+bool msm_comm_compare_device_planes(struct msm_vidc_buffer *mbuf,
+		u32 *planes)
+{
+	int i = 0;
+
+	if (!mbuf || !planes)
+		return false;
+
+	for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
+		if (!msm_comm_compare_device_plane(mbuf, planes, i))
+			return false;
+	}
+
+	return true;
+}
+
+struct msm_vidc_buffer *msm_comm_get_buffer_using_device_planes(
+		struct msm_vidc_inst *inst, u32 *planes)
+{
+	struct msm_vidc_buffer *mbuf;
+	bool found = false;
+
+	mutex_lock(&inst->registeredbufs.lock);
+	found = false;
+	list_for_each_entry(mbuf, &inst->registeredbufs.list, list) {
+		if (msm_comm_compare_device_planes(mbuf, planes)) {
+			found = true;
+			break;
+		}
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+	if (!found) {
+		dprintk(VIDC_ERR,
+			"%s: data_addr %x, extradata_addr %x not found\n",
+			__func__, planes[0], planes[1]);
+		mbuf = NULL;
+	}
+
+	return mbuf;
+}
+
+int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf)
+{
+	int rc;
+	struct vb2_buffer *vb;
+
+	if (!inst || !mbuf) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n",
+			__func__, inst, mbuf);
+		return -EINVAL;
+	}
+
+	vb = msm_comm_get_vb_using_vidc_buffer(inst, mbuf);
+	if (!vb) {
+		print_vidc_buffer(VIDC_ERR,
+			"vb not found for buf", inst, mbuf);
+		return -EINVAL;
+	}
+
+	vb->planes[0].bytesused = 0;
+	rc = msm_comm_vb2_buffer_done(inst, vb);
+	if (rc)
+		print_vidc_buffer(VIDC_ERR,
+			"vb2_buffer_done failed for", inst, mbuf);
+
+	return rc;
+}
+
+struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst,
+		struct vb2_buffer *vb2)
+{
+	int rc = 0;
+	struct vb2_v4l2_buffer *vbuf;
+	struct vb2_buffer *vb;
+	unsigned long dma_planes[VB2_MAX_PLANES] = {0};
+	struct msm_vidc_buffer *mbuf;
+	bool found = false;
+	int i;
+
+	if (!inst || !vb2) {
+		dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
+		return NULL;
+	}
+
+	for (i = 0; i < vb2->num_planes; i++) {
+		/*
+		 * always compare dma_buf addresses which is guaranteed
+		 * to be same across the processes (duplicate fds).
+		 */
+		dma_planes[i] = (unsigned long)dma_buf_get(vb2->planes[i].m.fd);
+		dma_buf_put((struct dma_buf *)dma_planes[i]);
+	}
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry(mbuf, &inst->registeredbufs.list, list) {
+		if (msm_comm_compare_dma_planes(inst, mbuf, dma_planes)) {
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		/* this is new vb2_buffer */
+		mbuf = kzalloc(sizeof(struct msm_vidc_buffer), GFP_KERNEL);
+		if (!mbuf) {
+			dprintk(VIDC_ERR, "%s: alloc msm_vidc_buffer failed\n",
+				__func__);
+			rc = -ENOMEM;
+			goto exit;
+		}
+	}
+
+	vbuf = to_vb2_v4l2_buffer(vb2);
+	memcpy(&mbuf->vvb, vbuf, sizeof(struct vb2_v4l2_buffer));
+	vb = &mbuf->vvb.vb2_buf;
+
+	for (i = 0; i < vb->num_planes; i++) {
+		mbuf->smem[i].buffer_type = get_hal_buffer_type(vb->type, i);
+		mbuf->smem[i].fd = vb->planes[i].m.fd;
+		mbuf->smem[i].offset = vb->planes[i].data_offset;
+		mbuf->smem[i].size = vb->planes[i].length;
+		rc = msm_smem_map_dma_buf(inst, &mbuf->smem[i]);
+		if (rc) {
+			dprintk(VIDC_ERR, "%s: map failed.\n", __func__);
+			goto exit;
+		}
+		/* increase refcount as we get both fbd and rbr */
+		rc = msm_smem_map_dma_buf(inst, &mbuf->smem[i]);
+		if (rc) {
+			dprintk(VIDC_ERR, "%s: map failed..\n", __func__);
+			goto exit;
+		}
+	}
+
+	/* special handling for decoder */
+	if (inst->session_type == MSM_VIDC_DECODER) {
+		if (found) {
+			rc = -EEXIST;
+		} else {
+			bool found_plane0 = false;
+			struct msm_vidc_buffer *temp;
+			/*
+			 * client might have queued same plane[0] but different
+			 * plane[1] search plane[0] and if found don't queue the
+			 * buffer, the buffer will be queued when rbr event
+			 * arrived.
+			 */
+			list_for_each_entry(temp, &inst->registeredbufs.list,
+						list) {
+				if (msm_comm_compare_dma_plane(inst, temp,
+						dma_planes, 0)) {
+					found_plane0 = true;
+					break;
+				}
+			}
+			if (found_plane0)
+				rc = -EEXIST;
+		}
+	}
+
+	/* add the new buffer to list */
+	if (!found)
+		list_add_tail(&mbuf->list, &inst->registeredbufs.list);
+
+	mutex_unlock(&inst->registeredbufs.lock);
+	if (rc == -EEXIST) {
+		print_vidc_buffer(VIDC_DBG, "qbuf upon rbr", inst, mbuf);
+		return ERR_PTR(rc);
+	}
+
+	return mbuf;
+
+exit:
+	mutex_unlock(&inst->registeredbufs.lock);
+	dprintk(VIDC_ERR, "%s: rc %d\n", __func__, rc);
+	msm_comm_unmap_vidc_buffer(inst, mbuf);
+	if (!found)
+		kfree(mbuf);
+
+	return ERR_PTR(rc);
+}
+
+void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf)
+{
+	struct msm_vidc_buffer *temp;
+	bool found = false;
+	int i = 0;
+
+	if (!inst || !mbuf) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n",
+			__func__, inst, mbuf);
+		return;
+	}
+
+	mutex_lock(&inst->registeredbufs.lock);
+	/* check if mbuf was not removed by any chance */
+	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+		if (msm_comm_compare_vb2_planes(inst, mbuf,
+				&temp->vvb.vb2_buf)) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		print_vidc_buffer(VIDC_ERR, "buf was removed", inst, mbuf);
+		goto unlock;
+	}
+
+	print_vidc_buffer(VIDC_DBG, "dqbuf", inst, mbuf);
+	for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
+		if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+			print_vidc_buffer(VIDC_ERR,
+				"dqbuf: unmap failed.", inst, mbuf);
+
+		if (!(mbuf->vvb.flags & V4L2_QCOM_BUF_FLAG_READONLY)) {
+			/* rbr won't come for this buffer */
+			if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+				print_vidc_buffer(VIDC_ERR,
+					"dqbuf: unmap failed..", inst, mbuf);
+		} /* else RBR event expected */
+	}
+	/*
+	 * remove the entry if plane[0].refcount is zero else
+	 * don't remove as client queued same buffer that's why
+	 * plane[0].refcount is not zero
+	 */
+	if (!mbuf->smem[0].refcount) {
+		list_del(&mbuf->list);
+		kfree(mbuf);
+		mbuf = NULL;
+	}
+unlock:
+	mutex_unlock(&inst->registeredbufs.lock);
+}
+
+void handle_release_buffer_reference(struct msm_vidc_inst *inst, u32 *planes)
+{
+	int rc = 0;
+	struct msm_vidc_buffer *mbuf = NULL;
+	bool found = false;
+	int i = 0;
+
+	mutex_lock(&inst->registeredbufs.lock);
+	found = false;
+	list_for_each_entry(mbuf, &inst->registeredbufs.list, list) {
+		if (msm_comm_compare_device_planes(mbuf, planes)) {
+			found = true;
+			break;
+		}
+	}
+	if (found) {
+		msm_vidc_queue_rbr_event(inst,
+			mbuf->vvb.vb2_buf.planes[0].m.fd,
+			mbuf->vvb.vb2_buf.planes[0].data_offset);
+
+		for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
+			if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+				print_vidc_buffer(VIDC_ERR,
+					"rbr unmap failed.", inst, mbuf);
+		}
+		/* refcount is not zero if client queued the same buffer */
+		if (!mbuf->smem[0].refcount) {
+			list_del(&mbuf->list);
+			kfree(mbuf);
+			mbuf = NULL;
+		}
+	} else {
+		dprintk(VIDC_ERR,
+			"%s: data_addr %x extradata_addr %x not found\n",
+			__func__, planes[0], planes[1]);
+		goto unlock;
+	}
+
+	/*
+	 * 1. client might have pushed same planes in which case mbuf will be
+	 *    same and refcounts are positive and buffer wouldn't have been
+	 *    removed from the registeredbufs list.
+	 * 2. client might have pushed same planes[0] but different planes[1]
+	 *    in which case mbuf will be different.
+	 * 3. in either case we can search mbuf->smem[0].device_addr in the list
+	 *    and if found queue it to video hw (if not flushing).
+	 */
+	found = false;
+	list_for_each_entry(mbuf, &inst->registeredbufs.list, list) {
+		if (msm_comm_compare_device_plane(mbuf, planes, 0)) {
+			found = true;
+			break;
+		}
+	}
+	if (!found)
+		goto unlock;
+
+	/* found means client queued the buffer already */
+	if (inst->in_reconfig || inst->in_flush) {
+		print_vidc_buffer(VIDC_DBG, "rbr flush buf", inst, mbuf);
+		msm_comm_flush_vidc_buffer(inst, mbuf);
+		msm_comm_unmap_vidc_buffer(inst, mbuf);
+		/* remove from list */
+		list_del(&mbuf->list);
+		kfree(mbuf);
+		mbuf = NULL;
+
+		/* don't queue the buffer */
+		found = false;
+	}
+unlock:
+	mutex_unlock(&inst->registeredbufs.lock);
+
+	if (found) {
+		print_vidc_buffer(VIDC_DBG, "rbr qbuf", inst, mbuf);
+		rc = msm_comm_qbuf(inst, mbuf);
+		if (rc)
+			print_vidc_buffer(VIDC_ERR,
+				"rbr qbuf failed", inst, mbuf);
+	}
+}
+
+int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf)
+{
+	int rc = 0, i;
+
+	if (!inst || !mbuf) {
+		dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n",
+			__func__, inst, mbuf);
+		return -EINVAL;
+	}
+	if (mbuf->vvb.vb2_buf.num_planes > VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "%s: invalid num_planes %d\n", __func__,
+			mbuf->vvb.vb2_buf.num_planes);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) {
+		u32 refcount = mbuf->smem[i].refcount;
+
+		while (refcount) {
+			if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i]))
+				print_vidc_buffer(VIDC_ERR,
+					"unmap failed for buf", inst, mbuf);
+			refcount--;
+		}
+	}
+
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 7534593..bc881a0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -14,6 +14,7 @@
 #ifndef _MSM_VIDC_COMMON_H_
 #define _MSM_VIDC_COMMON_H_
 #include "msm_vidc_internal.h"
+
 struct vb2_buf_entry {
 	struct list_head list;
 	struct vb2_buffer *vb;
@@ -28,6 +29,8 @@
 	LOAD_CALC_IGNORE_NON_REALTIME_LOAD = 1 << 2,
 };
 
+enum hal_buffer get_hal_buffer_type(unsigned int type,
+		unsigned int plane_num);
 struct msm_vidc_core *get_vidc_core(int core_id);
 const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
 	const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
@@ -41,21 +44,24 @@
 	enum hal_property ptype, void *pdata);
 int msm_comm_try_get_prop(struct msm_vidc_inst *inst,
 	enum hal_property ptype, union hal_get_property *hprop);
+int msm_comm_set_recon_buffers(struct msm_vidc_inst *inst);
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
 int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
 int msm_comm_set_output_buffers(struct msm_vidc_inst *inst);
 int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst);
-int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb);
+int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf);
 void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst);
 int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
 int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
 					bool check_for_reuse);
 int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_recon_buffers(struct msm_vidc_inst *inst);
 int msm_comm_release_output_buffers(struct msm_vidc_inst *inst,
 	bool force_release);
 void msm_comm_validate_output_buffers(struct msm_vidc_inst *inst);
 int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
 int msm_comm_suspend(int core_id);
+int msm_vidc_update_host_buff_counts(struct msm_vidc_inst *inst);
 enum hal_extradata_id msm_comm_get_hal_extradata_index(
 	enum v4l2_mpeg_vidc_extradata index);
 struct hal_buffer_requirements *get_buff_req_buffer(
@@ -67,14 +73,12 @@
 int msm_comm_kill_session(struct msm_vidc_inst *inst);
 enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
 enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
-struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
-			size_t size, u32 align, u32 flags,
-			enum hal_buffer buffer_type, int map_kernel);
-void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem);
+int msm_comm_smem_alloc(struct msm_vidc_inst *inst, size_t size, u32 align,
+		u32 flags, enum hal_buffer buffer_type, int map_kernel,
+		struct msm_smem *smem);
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *smem);
 int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
 		struct msm_smem *mem, enum smem_cache_ops cache_ops);
-struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
-			int fd, u32 offset, enum hal_buffer buffer_type);
 enum hal_video_codec get_hal_codec(int fourcc);
 enum hal_domain get_hal_domain(int session_type);
 int msm_comm_check_core_init(struct msm_vidc_core *core);
@@ -98,10 +102,47 @@
 int msm_comm_v4l2_to_hal(int id, int value);
 int msm_comm_hal_to_v4l2(int id, int value);
 int msm_comm_session_continue(void *instance);
+enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc);
 u32 get_frame_size_nv12(int plane, u32 height, u32 width);
 u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width);
 u32 get_frame_size_rgba(int plane, u32 height, u32 width);
 u32 get_frame_size_nv21(int plane, u32 height, u32 width);
 u32 get_frame_size_tp10_ubwc(int plane, u32 height, u32 width);
-void msm_comm_set_use_sys_cache(struct msm_vidc_inst *inst);
+struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer(
+		struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf);
+struct msm_vidc_buffer *msm_comm_get_buffer_using_device_planes(
+		struct msm_vidc_inst *inst, u32 *planes);
+struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst,
+		struct vb2_buffer *vb2);
+void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf);
+void handle_release_buffer_reference(struct msm_vidc_inst *inst, u32 *planes);
+int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst,
+		struct vb2_buffer *vb);
+int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf);
+int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf);
+bool msm_comm_compare_dma_plane(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf, unsigned long *dma_planes, u32 i);
+bool msm_comm_compare_dma_planes(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf, unsigned long *dma_planes);
+bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2, u32 i);
+bool msm_comm_compare_vb2_planes(struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2);
+bool msm_comm_compare_device_plane(struct msm_vidc_buffer *mbuf,
+		u32 *planes, u32 i);
+bool msm_comm_compare_device_planes(struct msm_vidc_buffer *mbuf,
+		u32 *planes);
+int msm_comm_qbuf_cache_operations(struct msm_vidc_inst *inst,
+		struct v4l2_buffer *b);
+int msm_comm_dqbuf_cache_operations(struct msm_vidc_inst *inst,
+			struct v4l2_buffer *b);
+void print_vidc_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
+		struct msm_vidc_buffer *mbuf);
+void print_vb2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
+		struct vb2_buffer *vb2);
+void print_v4l2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
+		struct v4l2_buffer *v4l2);
 #endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index c197776..58c3b0f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -25,10 +25,8 @@
 int msm_vidc_fw_debug = 0x18;
 int msm_vidc_fw_debug_mode = 1;
 int msm_vidc_fw_low_power_mode = 1;
-int msm_vidc_hw_rsp_timeout = 2000;
 bool msm_vidc_fw_coverage = !true;
 bool msm_vidc_sys_idle_indicator = !true;
-int msm_vidc_firmware_unload_delay = 15000;
 bool msm_vidc_thermal_mitigation_disabled = !true;
 bool msm_vidc_clock_scaling = true;
 bool msm_vidc_debug_timeout = !true;
@@ -204,11 +202,8 @@
 	__debugfs_create(u32, "fw_low_power_mode",
 			&msm_vidc_fw_low_power_mode) &&
 	__debugfs_create(u32, "debug_output", &msm_vidc_debug_out) &&
-	__debugfs_create(u32, "hw_rsp_timeout", &msm_vidc_hw_rsp_timeout) &&
 	__debugfs_create(bool, "sys_idle_indicator",
 			&msm_vidc_sys_idle_indicator) &&
-	__debugfs_create(u32, "firmware_unload_delay",
-			&msm_vidc_firmware_unload_delay) &&
 	__debugfs_create(bool, "disable_thermal_mitigation",
 			&msm_vidc_thermal_mitigation_disabled) &&
 	__debugfs_create(bool, "clock_scaling",
@@ -270,7 +265,7 @@
 
 static int publish_unreleased_reference(struct msm_vidc_inst *inst)
 {
-	struct buffer_info *temp = NULL;
+	struct msm_vidc_buffer *temp = NULL;
 
 	if (!inst) {
 		dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
@@ -282,14 +277,15 @@
 
 		mutex_lock(&inst->registeredbufs.lock);
 		list_for_each_entry(temp, &inst->registeredbufs.list, list) {
-			if (temp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
-			!temp->inactive && atomic_read(&temp->ref_count)) {
+			struct vb2_buffer *vb2 = &temp->vvb.vb2_buf;
+
+			if (vb2->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 				write_str(&dbg_buf,
-				"\tpending buffer: %#lx fd[0] = %d ref_count = %d held by: %s\n",
-				temp->device_addr[0],
-				temp->fd[0],
-				atomic_read(&temp->ref_count),
-				DYNAMIC_BUF_OWNER(temp));
+				"\tbuffer: %#x fd[0] = %d size %d refcount = %d\n",
+				temp->smem[0].device_addr,
+				vb2->planes[0].m.fd,
+				vb2->planes[0].length,
+				temp->smem[0].refcount);
 			}
 		}
 		mutex_unlock(&inst->registeredbufs.lock);
@@ -408,18 +404,14 @@
 
 	switch (e) {
 	case MSM_VIDC_DEBUGFS_EVENT_ETB:
-		mutex_lock(&inst->lock);
 		inst->count.etb++;
-		mutex_unlock(&inst->lock);
 		if (inst->count.ebd && inst->count.ftb > inst->count.fbd) {
 			d->pdata[FRAME_PROCESSING].name[0] = '\0';
 			tic(inst, FRAME_PROCESSING, a);
 		}
 	break;
 	case MSM_VIDC_DEBUGFS_EVENT_EBD:
-		mutex_lock(&inst->lock);
 		inst->count.ebd++;
-		mutex_unlock(&inst->lock);
 		if (inst->count.ebd && inst->count.ebd == inst->count.etb) {
 			toc(inst, FRAME_PROCESSING);
 			dprintk(VIDC_PROF, "EBD: FW needs input buffers\n");
@@ -436,6 +428,7 @@
 	}
 	break;
 	case MSM_VIDC_DEBUGFS_EVENT_FBD:
+		inst->count.fbd++;
 		inst->debug.samples++;
 		if (inst->count.ebd && inst->count.fbd == inst->count.ftb) {
 			toc(inst, FRAME_PROCESSING);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index f4c851a..9a798b5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -57,10 +57,8 @@
 extern int msm_vidc_fw_debug;
 extern int msm_vidc_fw_debug_mode;
 extern int msm_vidc_fw_low_power_mode;
-extern int msm_vidc_hw_rsp_timeout;
 extern bool msm_vidc_fw_coverage;
 extern bool msm_vidc_sys_idle_indicator;
-extern int msm_vidc_firmware_unload_delay;
 extern bool msm_vidc_thermal_mitigation_disabled;
 extern bool msm_vidc_clock_scaling;
 extern bool msm_vidc_debug_timeout;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 5edd3d5..373dbba 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -33,7 +33,6 @@
 #include <media/videobuf2-v4l2.h>
 #include <media/msm_vidc.h>
 #include <media/msm_media_info.h>
-
 #include "vidc_hfi_api.h"
 
 #define MSM_VIDC_DRV_NAME "msm_vidc_driver"
@@ -141,17 +140,44 @@
 
 struct vidc_freq_data {
 	struct list_head list;
-	ion_phys_addr_t device_addr;
+	u32 device_addr;
 	unsigned long freq;
 };
 
+struct recon_buf {
+	struct list_head list;
+	u32 buffer_index;
+	u32 CR;
+	u32 CF;
+};
+
 struct internal_buf {
 	struct list_head list;
 	enum hal_buffer buffer_type;
-	struct msm_smem *handle;
+	struct msm_smem smem;
 	enum buffer_owner buffer_ownership;
 };
 
+struct msm_vidc_common_data {
+	char key[128];
+	int value;
+};
+
+struct msm_vidc_codec_data {
+	u32 fourcc;
+	enum session_type session_type;
+	int vpp_cycles;
+	int vsp_cycles;
+	int low_power_cycles;
+};
+
+struct msm_vidc_platform_data {
+	struct msm_vidc_common_data *common_data;
+	unsigned int common_data_length;
+	struct msm_vidc_codec_data *codec_data;
+	unsigned int codec_data_length;
+};
+
 struct msm_vidc_format {
 	char name[MAX_NAME_LENGTH];
 	u8 description[32];
@@ -217,6 +243,7 @@
 	int buffer_counter;
 	int load;
 	int load_low;
+	int load_norm;
 	int load_high;
 	int min_threshold;
 	int max_threshold;
@@ -228,10 +255,13 @@
 	unsigned long min_freq;
 	unsigned long curr_freq;
 	u32 operating_rate;
-	struct clock_profile_entry *entry;
+	struct msm_vidc_codec_data *entry;
 	u32 core_id;
+	u32 dpb_fourcc;
+	u32 opb_fourcc;
 	enum hal_work_mode work_mode;
 	bool low_latency_mode;
+	bool use_sys_cache;
 };
 
 struct profile_data {
@@ -262,6 +292,7 @@
 	struct mutex lock;
 	int id;
 	struct hfi_device *device;
+	struct msm_vidc_platform_data *platform_data;
 	struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
 	struct v4l2_device v4l2_dev;
 	struct list_head instances;
@@ -278,6 +309,7 @@
 	bool smmu_fault_handled;
 	unsigned long min_freq;
 	unsigned long curr_freq;
+	struct vidc_bus_vote_data *vote_data;
 };
 
 struct msm_vidc_inst {
@@ -290,15 +322,15 @@
 	enum instance_state state;
 	struct msm_vidc_format fmts[MAX_PORT_NUM];
 	struct buf_queue bufq[MAX_PORT_NUM];
-	struct msm_vidc_list pendingq;
 	struct msm_vidc_list freqs;
 	struct msm_vidc_list scratchbufs;
 	struct msm_vidc_list persistbufs;
 	struct msm_vidc_list pending_getpropq;
 	struct msm_vidc_list outputbufs;
+	struct msm_vidc_list reconbufs;
 	struct msm_vidc_list registeredbufs;
 	struct buffer_requirements buff_req;
-	void *mem_client;
+	struct smem_client *mem_client;
 	struct v4l2_ctrl_handler ctrl_handler;
 	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
 	struct v4l2_ctrl **cluster;
@@ -319,13 +351,13 @@
 	struct v4l2_ctrl **ctrls;
 	enum msm_vidc_pixel_depth bit_depth;
 	struct kref kref;
-	u32 buffers_held_in_driver;
-	atomic_t in_flush;
+	bool in_flush;
 	u32 pic_struct;
 	u32 colour_space;
 	u32 profile;
 	u32 level;
 	u32 entropy_mode;
+	struct msm_vidc_codec_data *codec_data;
 };
 
 extern struct msm_vidc_drv *vidc_driver;
@@ -355,56 +387,37 @@
 int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
 void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
 
-struct buffer_info {
+struct msm_vidc_buffer {
 	struct list_head list;
-	int type;
-	int num_planes;
-	int fd[VIDEO_MAX_PLANES];
-	int buff_off[VIDEO_MAX_PLANES];
-	int size[VIDEO_MAX_PLANES];
-	unsigned long uvaddr[VIDEO_MAX_PLANES];
-	ion_phys_addr_t device_addr[VIDEO_MAX_PLANES];
-	struct msm_smem *handle[VIDEO_MAX_PLANES];
-	enum v4l2_memory memory;
-	u32 v4l2_index;
-	bool pending_deletion;
-	atomic_t ref_count;
-	bool dequeued;
-	bool inactive;
-	bool mapped[VIDEO_MAX_PLANES];
-	int same_fd_ref[VIDEO_MAX_PLANES];
-	struct timeval timestamp;
+	struct msm_smem smem[VIDEO_MAX_PLANES];
+	struct vb2_v4l2_buffer vvb;
+	bool deferred;
 };
 
-struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list,
-				ion_phys_addr_t device_addr);
-int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo);
-int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo);
-int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
-				struct buffer_info *binfo);
-int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
-			struct buffer_info *binfo);
-int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
-			struct buffer_info *binfo);
-
 void msm_comm_handle_thermal_event(void);
 void *msm_smem_new_client(enum smem_type mtype,
 		void *platform_resources, enum session_type stype);
-struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
-		enum hal_buffer buffer_type, int map_kernel);
-void msm_smem_free(void *clt, struct msm_smem *mem);
+int msm_smem_alloc(struct smem_client *client,
+		size_t size, u32 align, u32 flags, enum hal_buffer buffer_type,
+		int map_kernel, struct msm_smem *smem);
+int msm_smem_free(void *clt, struct msm_smem *mem);
 void msm_smem_delete_client(void *clt);
-int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
-		enum smem_cache_ops);
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
-				enum hal_buffer buffer_type);
 struct context_bank_info *msm_smem_get_context_bank(void *clt,
 		bool is_secure, enum hal_buffer buffer_type);
+int msm_smem_map_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem);
+int msm_smem_unmap_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem);
+void *msm_smem_get_dma_buf(int fd);
+void msm_smem_put_dma_buf(void *dma_buf);
+void *msm_smem_get_handle(struct smem_client *client, void *dma_buf);
+void msm_smem_put_handle(struct smem_client *client, void *handle);
+int msm_smem_cache_operations(struct smem_client *client,
+		void *handle, unsigned long offset, unsigned long size,
+		enum smem_cache_ops cache_op);
 void msm_vidc_fw_unload_handler(struct work_struct *work);
-bool msm_smem_compare_buffers(void *clt, int fd, void *priv);
 /*
  * XXX: normally should be in msm_vidc.h, but that's meant for public APIs,
  * whereas this is private
  */
 int msm_vidc_destroy(struct msm_vidc_inst *inst);
+void *vidc_get_drv_data(struct device *dev);
 #endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
new file mode 100644
index 0000000..8a701cb
--- /dev/null
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -0,0 +1,146 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/io.h>
+#include "msm_vidc_internal.h"
+
+
+#define CODEC_ENTRY(n, p, vsp, vpp, lp) \
+{	\
+	.fourcc = n,		\
+	.session_type = p,	\
+	.vsp_cycles = vsp,	\
+	.vpp_cycles = vpp,	\
+	.low_power_cycles = lp	\
+}
+
+static struct msm_vidc_codec_data default_codec_data[] =  {
+	CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
+	CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 125, 675, 320),
+};
+
+static struct msm_vidc_codec_data sdm845_codec_data[] =  {
+	CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
+	CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320),
+	CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320),
+	CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200),
+	CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200),
+	CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200),
+	CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 50, 200, 200),
+	CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 50, 200, 200),
+};
+
+static struct msm_vidc_common_data default_common_data[] = {
+	{
+		.key = "qcom,never-unload-fw",
+		.value = 1,
+	},
+};
+
+static struct msm_vidc_common_data sdm845_common_data[] = {
+	{
+		.key = "qcom,never-unload-fw",
+		.value = 1,
+	},
+	{
+		.key = "qcom,sw-power-collapse",
+		.value = 1,
+	},
+	{
+		.key = "qcom,max-secure-instances",
+		.value = 5,
+	},
+	{
+		.key = "qcom,max-hw-load",
+		.value = 2563200,
+	},
+	{
+		.key = "qcom,max-hq-mbs-per-frame",
+		.value = 8160,
+	},
+	{
+		.key = "qcom,max-hq-frames-per-sec",
+		.value = 60,
+	},
+	{
+		.key = "qcom,max-b-frame-size",
+		.value = 8160,
+	},
+	{
+		.key = "qcom,max-b-frames-per-sec",
+		.value = 60,
+	},
+	{
+		.key = "qcom,power-collapse-delay",
+		.value = 500,
+	},
+	{
+		.key = "qcom,hw-resp-timeout",
+		.value = 250,
+	},
+};
+
+
+static struct msm_vidc_platform_data default_data = {
+	.codec_data = default_codec_data,
+	.codec_data_length =  ARRAY_SIZE(default_codec_data),
+	.common_data = default_common_data,
+	.common_data_length =  ARRAY_SIZE(default_common_data),
+};
+
+static struct msm_vidc_platform_data sdm845_data = {
+	.codec_data = sdm845_codec_data,
+	.codec_data_length =  ARRAY_SIZE(sdm845_codec_data),
+	.common_data = sdm845_common_data,
+	.common_data_length =  ARRAY_SIZE(sdm845_common_data),
+};
+
+static const struct of_device_id msm_vidc_dt_match[] = {
+	{
+		.compatible = "qcom,sdm845-vidc",
+		.data = &sdm845_data,
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
+void *vidc_get_drv_data(struct device *dev)
+{
+	struct msm_vidc_platform_data *driver_data = NULL;
+	const struct of_device_id *match;
+
+	if (!IS_ENABLED(CONFIG_OF) || !dev->of_node) {
+		driver_data = &default_data;
+		goto exit;
+	}
+
+	match = of_match_node(msm_vidc_dt_match, dev->of_node);
+
+	if (match)
+		driver_data = (struct msm_vidc_platform_data *)match->data;
+
+exit:
+	return driver_data;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 19ca561..afb8893 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -27,6 +27,8 @@
 	CLOCK_PROP_HAS_MEM_RETENTION    = 1 << 1,
 };
 
+#define PERF_GOV "performance"
+
 static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
 {
 	return NULL;
@@ -132,7 +134,6 @@
 	msm_vidc_free_clock_table(res);
 	msm_vidc_free_regulator_table(res);
 	msm_vidc_free_platform_version_table(res);
-	msm_vidc_free_cycles_per_mb_table(res);
 	msm_vidc_free_allowed_clocks_table(res);
 	msm_vidc_free_reg_table(res);
 	msm_vidc_free_qdss_addr_table(res);
@@ -275,12 +276,12 @@
 			"cache-slice-names", c, &vsc->name);
 	}
 
-	res->sys_cache_present = true;
+	res->sys_cache_enabled = true;
 
 	return 0;
 
 err_load_subcache_table_fail:
-	res->sys_cache_present = false;
+	res->sys_cache_enabled = false;
 	subcaches->count = 0;
 	subcaches->subcache_tbl = NULL;
 
@@ -407,118 +408,6 @@
 	return 0;
 }
 
-static int msm_vidc_load_cycles_per_mb_table(
-		struct msm_vidc_platform_resources *res)
-{
-	int rc = 0, i = 0;
-	struct clock_freq_table *clock_freq_tbl = &res->clock_freq_tbl;
-	struct clock_profile_entry *entry = NULL;
-	struct device_node *parent_node = NULL;
-	struct device_node *child_node = NULL;
-	struct platform_device *pdev = res->pdev;
-
-	parent_node = of_find_node_by_name(pdev->dev.of_node,
-			"qcom,clock-freq-tbl");
-	if (!parent_node) {
-		dprintk(VIDC_DBG, "Node qcom,clock-freq-tbl not found.\n");
-		return 0;
-	}
-
-	clock_freq_tbl->count = 0;
-	for_each_child_of_node(parent_node, child_node)
-		clock_freq_tbl->count++;
-
-	if (!clock_freq_tbl->count) {
-		dprintk(VIDC_DBG, "No child nodes in qcom,clock-freq-tbl\n");
-		return 0;
-	}
-
-	clock_freq_tbl->clk_prof_entries = devm_kzalloc(&pdev->dev,
-		sizeof(*clock_freq_tbl->clk_prof_entries) *
-		clock_freq_tbl->count, GFP_KERNEL);
-	if (!clock_freq_tbl->clk_prof_entries) {
-		dprintk(VIDC_DBG, "no memory to allocate clk_prof_entries\n");
-		return -ENOMEM;
-	}
-
-	for_each_child_of_node(parent_node, child_node) {
-
-		if (i >= clock_freq_tbl->count) {
-			dprintk(VIDC_ERR,
-				"qcom,clock-freq-tbl: invalid child node %d, max is %d\n",
-				i, clock_freq_tbl->count);
-			break;
-		}
-
-		entry = &clock_freq_tbl->clk_prof_entries[i];
-		dprintk(VIDC_DBG, "qcom,clock-freq-tbl: profile[%d]\n", i);
-
-		if (of_find_property(child_node, "qcom,codec-mask", NULL)) {
-			rc = of_property_read_u32(child_node,
-					"qcom,codec-mask", &entry->codec_mask);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"qcom,codec-mask not found\n");
-				goto error;
-			}
-		} else {
-			entry->codec_mask = 0;
-		}
-		dprintk(VIDC_DBG, "codec_mask %#x\n", entry->codec_mask);
-
-		if (of_find_property(child_node,
-				"qcom,vsp-cycles-per-mb", NULL)) {
-			rc = of_property_read_u32(child_node,
-					"qcom,vsp-cycles-per-mb",
-					&entry->vsp_cycles);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"qcom,vsp-cycles-per-mb not found\n");
-				goto error;
-			}
-		} else {
-			entry->vsp_cycles = 0;
-		}
-		dprintk(VIDC_DBG, "vsp cycles_per_mb %d\n", entry->vsp_cycles);
-
-		if (of_find_property(child_node,
-				"qcom,vpp-cycles-per-mb", NULL)) {
-			rc = of_property_read_u32(child_node,
-					"qcom,vpp-cycles-per-mb",
-					&entry->vpp_cycles);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"qcom,vpp-cycles-per-mb not found\n");
-				goto error;
-			}
-		} else {
-			entry->vpp_cycles = 0;
-		}
-		dprintk(VIDC_DBG, "vpp cycles_per_mb %d\n", entry->vpp_cycles);
-
-		if (of_find_property(child_node,
-				"qcom,low-power-cycles-per-mb", NULL)) {
-			rc = of_property_read_u32(child_node,
-					"qcom,low-power-cycles-per-mb",
-					&entry->low_power_cycles);
-			if (rc) {
-				dprintk(VIDC_ERR,
-					"qcom,low-power-cycles-per-mb not found\n");
-				goto error;
-			}
-		} else {
-			entry->low_power_cycles = 0;
-		}
-		dprintk(VIDC_DBG, "low_power_factor %d\n",
-				entry->low_power_cycles);
-
-		i++;
-	}
-
-error:
-	return rc;
-}
-
 static int msm_vidc_populate_bus(struct device *dev,
 		struct msm_vidc_platform_resources *res)
 {
@@ -539,6 +428,8 @@
 	buses->bus_tbl = temp_table;
 	bus = &buses->bus_tbl[buses->count];
 
+	memset(bus, 0x0, sizeof(struct bus_info));
+
 	rc = of_property_read_string(dev->of_node, "label", &temp_name);
 	if (rc) {
 		dprintk(VIDC_ERR, "'label' not found in node\n");
@@ -570,9 +461,12 @@
 		rc = 0;
 		dprintk(VIDC_DBG,
 				"'qcom,bus-governor' not found, default to performance governor\n");
-		bus->governor = "performance";
+		bus->governor = PERF_GOV;
 	}
 
+	if (!strcmp(bus->governor, PERF_GOV))
+		bus->is_prfm_gov_used = true;
+
 	rc = of_property_read_u32_array(dev->of_node, "qcom,bus-range-kbps",
 			range, ARRAY_SIZE(range));
 	if (rc) {
@@ -818,6 +712,83 @@
 	return rc;
 }
 
+static int find_key_value(struct msm_vidc_platform_data *platform_data,
+	const char *key)
+{
+	int i = 0;
+	struct msm_vidc_common_data *common_data = platform_data->common_data;
+	int size = platform_data->common_data_length;
+
+	for (i = 0; i < size; i++) {
+		if (!strcmp(common_data[i].key, key))
+			return common_data[i].value;
+	}
+	return 0;
+}
+
+int read_platform_resources_from_drv_data(
+		struct msm_vidc_core *core)
+{
+	struct msm_vidc_platform_data *platform_data;
+	struct msm_vidc_platform_resources *res;
+	int rc = 0;
+
+	if (!core || !core->platform_data) {
+		dprintk(VIDC_ERR, "%s Invalid data\n", __func__);
+		return -ENOENT;
+	}
+	platform_data = core->platform_data;
+	res = &core->resources;
+
+	res->codec_data_count = platform_data->codec_data_length;
+	res->codec_data = platform_data->codec_data;
+
+	res->fw_name = "venus";
+
+	dprintk(VIDC_DBG, "Firmware filename: %s\n", res->fw_name);
+
+	res->max_load = find_key_value(platform_data,
+			"qcom,max-hw-load");
+
+	res->max_hq_mbs_per_frame = find_key_value(platform_data,
+			"qcom,max-hq-mbs-per-frame");
+
+	res->max_hq_fps = find_key_value(platform_data,
+			"qcom,max-hq-frames-per-sec");
+
+	res->sw_power_collapsible = find_key_value(platform_data,
+			"qcom,sw-power-collapse");
+
+	res->never_unload_fw =  find_key_value(platform_data,
+			"qcom,never-unload-fw");
+
+	res->debug_timeout = find_key_value(platform_data,
+			"qcom,debug-timeout");
+
+	res->debug_timeout |= msm_vidc_debug_timeout;
+
+	res->pm_qos_latency_us = find_key_value(platform_data,
+			"qcom,pm-qos-latency-us");
+
+	res->max_secure_inst_count = find_key_value(platform_data,
+			"qcom,max-secure-instances");
+
+	res->slave_side_cp = find_key_value(platform_data,
+			"qcom,slave-side-cp");
+	res->sys_idle_indicator = find_key_value(platform_data,
+			"qcom,enable-idle-indicator");
+	res->thermal_mitigable = find_key_value(platform_data,
+			"qcom,enable-thermal-mitigation");
+	res->msm_vidc_pwr_collapse_delay = find_key_value(platform_data,
+			"qcom,power-collapse-delay");
+	res->msm_vidc_firmware_unload_delay = find_key_value(platform_data,
+			"qcom,fw-unload-delay");
+	res->msm_vidc_hw_rsp_timeout = find_key_value(platform_data,
+			"qcom,hw-resp-timeout");
+	return rc;
+
+}
+
 int read_platform_resources_from_dt(
 		struct msm_vidc_platform_resources *res)
 {
@@ -842,26 +813,6 @@
 	kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	res->irq = kres ? kres->start : -1;
 
-	res->sys_idle_indicator = of_property_read_bool(pdev->dev.of_node,
-			"qcom,enable-idle-indicator");
-
-	res->thermal_mitigable =
-			of_property_read_bool(pdev->dev.of_node,
-			"qcom,enable-thermal-mitigation");
-
-	rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
-			&res->fw_name);
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to read firmware name: %d\n", rc);
-		goto err_load_reg_table;
-	}
-	dprintk(VIDC_DBG, "Firmware filename: %s\n", res->fw_name);
-
-	rc = of_property_read_string(pdev->dev.of_node, "qcom,hfi-version",
-			&res->hfi_version);
-	if (rc)
-		dprintk(VIDC_DBG, "HFI packetization will default to legacy\n");
-
 	rc = msm_vidc_load_platform_version_table(res);
 	if (rc)
 		dprintk(VIDC_ERR, "Failed to load pf version table: %d\n", rc);
@@ -900,13 +851,6 @@
 		goto err_load_clock_table;
 	}
 
-	rc = msm_vidc_load_cycles_per_mb_table(res);
-	if (rc) {
-		dprintk(VIDC_ERR,
-			"Failed to load cycles per mb table: %d\n", rc);
-		goto err_load_cycles_per_mb_table;
-	}
-
 	rc = msm_vidc_load_allowed_clocks_table(res);
 	if (rc) {
 		dprintk(VIDC_ERR,
@@ -914,32 +858,6 @@
 		goto err_load_allowed_clocks_table;
 	}
 
-	rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
-			&res->max_load);
-	if (rc) {
-		dprintk(VIDC_ERR,
-			"Failed to determine max load supported: %d\n", rc);
-		goto err_load_max_hw_load;
-	}
-
-	rc = of_property_read_u32(pdev->dev.of_node,
-		"qcom,max-hq-mbs-per-frame",
-			&res->max_hq_mbs_per_frame);
-	if (rc) {
-		dprintk(VIDC_ERR,
-			"Failed to determine Max HQ mbs per frame: %d\n", rc);
-		goto err_load_HQ_values;
-	}
-
-	rc = of_property_read_u32(pdev->dev.of_node,
-		"qcom,max-hq-frames-per-sec",
-			&res->max_hq_fps);
-	if (rc) {
-		dprintk(VIDC_ERR,
-			"Failed to determine Max HQ fps: %d\n", rc);
-		goto err_load_HQ_values;
-	}
-
 	rc = msm_vidc_populate_legacy_context_bank(res);
 	if (rc) {
 		dprintk(VIDC_ERR,
@@ -958,39 +876,11 @@
 				"Using fw-bias : %pa", &res->firmware_base);
 	}
 
-	res->sw_power_collapsible = of_property_read_bool(pdev->dev.of_node,
-					"qcom,sw-power-collapse");
-	dprintk(VIDC_DBG, "Power collapse supported = %s\n",
-		res->sw_power_collapsible ? "yes" : "no");
-
-	res->never_unload_fw = of_property_read_bool(pdev->dev.of_node,
-			"qcom,never-unload-fw");
-
-	res->debug_timeout = of_property_read_bool(pdev->dev.of_node,
-			"qcom,debug-timeout");
-
-	msm_vidc_debug_timeout |= res->debug_timeout;
-
-	of_property_read_u32(pdev->dev.of_node,
-			"qcom,pm-qos-latency-us", &res->pm_qos_latency_us);
-
-	res->slave_side_cp = of_property_read_bool(pdev->dev.of_node,
-					"qcom,slave-side-cp");
-	dprintk(VIDC_DBG, "Slave side cp = %s\n",
-				res->slave_side_cp ? "yes" : "no");
-
-	of_property_read_u32(pdev->dev.of_node,
-			"qcom,max-secure-instances",
-			&res->max_secure_inst_count);
-	return rc;
+return rc;
 
 err_setup_legacy_cb:
-err_load_HQ_values:
-err_load_max_hw_load:
 	msm_vidc_free_allowed_clocks_table(res);
 err_load_allowed_clocks_table:
-	msm_vidc_free_cycles_per_mb_table(res);
-err_load_cycles_per_mb_table:
 	msm_vidc_free_clock_table(res);
 err_load_clock_table:
 	msm_vidc_free_regulator_table(res);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h
index 4ba9057..a682282 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h
@@ -22,6 +22,8 @@
 
 int read_hfi_type(struct platform_device *pdev);
 
+int read_platform_resources_from_drv_data(
+		struct msm_vidc_core *core);
 int read_platform_resources_from_dt(
 		struct msm_vidc_platform_resources *res);
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index b07785a..755f0c86 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -112,6 +112,7 @@
 	struct devfreq_dev_profile devfreq_prof;
 	struct devfreq *devfreq;
 	struct msm_bus_client_handle *client;
+	bool is_prfm_gov_used;
 };
 
 struct bus_set {
@@ -185,6 +186,11 @@
 	uint32_t pm_qos_latency_us;
 	uint32_t max_inst_count;
 	uint32_t max_secure_inst_count;
+	int msm_vidc_hw_rsp_timeout;
+	int msm_vidc_firmware_unload_delay;
+	uint32_t msm_vidc_pwr_collapse_delay;
+	struct msm_vidc_codec_data *codec_data;
+	int codec_data_count;
 };
 
 static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)
@@ -192,7 +198,5 @@
 	return !list_empty(&res->context_banks);
 }
 
-extern uint32_t msm_vidc_pwr_collapse_delay;
-
 #endif
 
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 6139e46..dad4b60 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -560,7 +560,7 @@
 			struct vidc_mem_addr *mem, u32 size, u32 align,
 			u32 flags, u32 usage)
 {
-	struct msm_smem *alloc = NULL;
+	struct msm_smem *alloc = &mem->mem_data;
 	int rc = 0;
 
 	if (!dev || !dev->hal_client || !mem || !size) {
@@ -569,8 +569,9 @@
 	}
 
 	dprintk(VIDC_INFO, "start to alloc size: %d, flags: %d\n", size, flags);
-	alloc = msm_smem_alloc(dev->hal_client, size, align, flags, usage, 1);
-	if (!alloc) {
+	rc = msm_smem_alloc(dev->hal_client, size, align, flags,
+		usage, 1, alloc);
+	if (rc) {
 		dprintk(VIDC_ERR, "Alloc failed\n");
 		rc = -ENOMEM;
 		goto fail_smem_alloc;
@@ -578,17 +579,16 @@
 
 	dprintk(VIDC_DBG, "__smem_alloc: ptr = %pK, size = %d\n",
 			alloc->kvaddr, size);
-	rc = msm_smem_cache_operations(dev->hal_client, alloc,
-		SMEM_CACHE_CLEAN);
+	rc = msm_smem_cache_operations(dev->hal_client, alloc->handle, 0,
+			alloc->size, SMEM_CACHE_CLEAN);
 	if (rc) {
 		dprintk(VIDC_WARN, "Failed to clean cache\n");
-		dprintk(VIDC_WARN, "This may result in undefined behavior\n");
 	}
 
 	mem->mem_size = alloc->size;
-	mem->mem_data = alloc;
 	mem->align_virtual_addr = alloc->kvaddr;
 	mem->align_device_addr = alloc->device_addr;
+
 	return rc;
 fail_smem_alloc:
 	return rc;
@@ -723,35 +723,6 @@
 	}
 }
 
-static bool __is_session_supported(unsigned long sessions_supported,
-		enum vidc_vote_data_session session_type)
-{
-	bool same_codec, same_session_type;
-	int codec_bit, session_type_bit;
-	unsigned long session = session_type;
-
-	if (!sessions_supported || !session)
-		return false;
-
-	/* ffs returns a 1 indexed, test_bit takes a 0 indexed...index */
-	codec_bit = ffs(session) - 1;
-	session_type_bit = codec_bit + 1;
-
-	same_codec = test_bit(codec_bit, &sessions_supported) ==
-		test_bit(codec_bit, &session);
-	same_session_type = test_bit(session_type_bit, &sessions_supported) ==
-		test_bit(session_type_bit, &session);
-
-	return same_codec && same_session_type;
-}
-
-bool venus_hfi_is_session_supported(unsigned long sessions_supported,
-		enum vidc_vote_data_session session_type)
-{
-	return __is_session_supported(sessions_supported, session_type);
-}
-EXPORT_SYMBOL(venus_hfi_is_session_supported);
-
 static int __devfreq_target(struct device *devfreq_dev,
 		unsigned long *freq, u32 flags)
 {
@@ -838,21 +809,22 @@
 	int rc = 0;
 	struct bus_info *bus = NULL;
 
+	kfree(device->bus_vote.data);
+	device->bus_vote.data = NULL;
+	device->bus_vote.data_count = 0;
+
 	venus_hfi_for_each_bus(device, bus) {
-		int local_rc = 0;
 		unsigned long zero = 0;
 
-		rc = devfreq_suspend_device(bus->devfreq);
+		if (!bus->is_prfm_gov_used)
+			rc = devfreq_suspend_device(bus->devfreq);
+		else
+			rc = __devfreq_target(bus->dev, &zero, 0);
+
 		if (rc)
 			goto err_unknown_device;
-
-		local_rc = __devfreq_target(bus->dev, &zero, 0);
-		rc = rc ?: local_rc;
 	}
 
-	if (rc)
-		dprintk(VIDC_WARN, "Failed to unvote some buses\n");
-
 err_unknown_device:
 	return rc;
 }
@@ -886,15 +858,14 @@
 
 	venus_hfi_for_each_bus(device, bus) {
 		if (bus && bus->devfreq) {
-			/* NOP if already resume */
-			rc = devfreq_resume_device(bus->devfreq);
-			if (rc)
-				goto err_no_mem;
-
-			/* Kick devfreq awake incase _resume() didn't do it */
-
-			bus->devfreq->nb.notifier_call(
-				&bus->devfreq->nb, 0, NULL);
+			if (!bus->is_prfm_gov_used) {
+				rc = devfreq_resume_device(bus->devfreq);
+				if (rc)
+					goto err_no_mem;
+			} else {
+				bus->devfreq->nb.notifier_call(
+					&bus->devfreq->nb, 0, NULL);
+			}
 		}
 	}
 
@@ -1151,11 +1122,9 @@
 static int __scale_clocks(struct venus_hfi_device *device)
 {
 	int rc = 0;
-	struct clock_freq_table *clk_freq_tbl = NULL;
 	struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
 	u32 rate = 0;
 
-	clk_freq_tbl = &device->res->clock_freq_tbl;
 	allowed_clks_tbl = device->res->allowed_clks_tbl;
 
 	dprintk(VIDC_DBG, "%s: NULL scale data\n", __func__);
@@ -1214,7 +1183,7 @@
 			if (!queue_delayed_work(device->venus_pm_workq,
 				&venus_hfi_pm_work,
 				msecs_to_jiffies(
-				msm_vidc_pwr_collapse_delay))) {
+				device->res->msm_vidc_pwr_collapse_delay))) {
 				dprintk(VIDC_DBG,
 				"PM work already scheduled\n");
 			}
@@ -1343,7 +1312,7 @@
 	unsigned long mem_map_table_base_addr;
 	struct context_bank_info *cb;
 
-	if (device->qdss.mem_data) {
+	if (device->qdss.align_virtual_addr) {
 		qdss = (struct hfi_mem_map_table *)
 			device->qdss.align_virtual_addr;
 		qdss->mem_map_num_entries = num_entries;
@@ -1369,32 +1338,27 @@
 						mem_map[i].size);
 		}
 
-		__smem_free(device, device->qdss.mem_data);
+		__smem_free(device, &device->qdss.mem_data);
 	}
 
-	__smem_free(device, device->iface_q_table.mem_data);
-	__smem_free(device, device->sfr.mem_data);
+	__smem_free(device, &device->iface_q_table.mem_data);
+	__smem_free(device, &device->sfr.mem_data);
 
 	for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
 		device->iface_queues[i].q_hdr = NULL;
-		device->iface_queues[i].q_array.mem_data = NULL;
 		device->iface_queues[i].q_array.align_virtual_addr = NULL;
 		device->iface_queues[i].q_array.align_device_addr = 0;
 	}
 
-	device->iface_q_table.mem_data = NULL;
 	device->iface_q_table.align_virtual_addr = NULL;
 	device->iface_q_table.align_device_addr = 0;
 
-	device->qdss.mem_data = NULL;
 	device->qdss.align_virtual_addr = NULL;
 	device->qdss.align_device_addr = 0;
 
-	device->sfr.mem_data = NULL;
 	device->sfr.align_virtual_addr = NULL;
 	device->sfr.align_device_addr = 0;
 
-	device->mem_addr.mem_data = NULL;
 	device->mem_addr.align_virtual_addr = NULL;
 	device->mem_addr.align_device_addr = 0;
 
@@ -1483,7 +1447,6 @@
 	struct vidc_mem_addr *mem_addr;
 	int offset = 0;
 	int num_entries = dev->res->qdss_addr_set.count;
-	u32 value = 0;
 	phys_addr_t fw_bias = 0;
 	size_t q_size;
 	unsigned long mem_map_table_base_addr;
@@ -1514,7 +1477,6 @@
 		iface_q->q_array.align_virtual_addr =
 			mem_addr->align_virtual_addr + offset;
 		iface_q->q_array.mem_size = VIDC_IFACEQ_QUEUE_SIZE;
-		iface_q->q_array.mem_data = NULL;
 		offset += iface_q->q_array.mem_size;
 		iface_q->q_hdr = VIDC_IFACEQ_GET_QHDR_START_ADDR(
 				dev->iface_q_table.align_virtual_addr, i);
@@ -1566,65 +1528,34 @@
 
 	iface_q = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
 	q_hdr = iface_q->q_hdr;
-	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr;
 	q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q;
-	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
-		iface_q->q_array.align_device_addr) {
-		dprintk(VIDC_ERR, "Invalid CMDQ device address (%pa)",
-			&iface_q->q_array.align_device_addr);
-	}
 
 	iface_q = &dev->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
 	q_hdr = iface_q->q_hdr;
-	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr;
 	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q;
-	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
-		iface_q->q_array.align_device_addr) {
-		dprintk(VIDC_ERR, "Invalid MSGQ device address (%pa)",
-			&iface_q->q_array.align_device_addr);
-	}
 
 	iface_q = &dev->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
 	q_hdr = iface_q->q_hdr;
-	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr;
 	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
 	/*
 	 * Set receive request to zero on debug queue as there is no
 	 * need of interrupt from video hardware for debug messages
 	 */
 	q_hdr->qhdr_rx_req = 0;
-	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
-		iface_q->q_array.align_device_addr) {
-		dprintk(VIDC_ERR, "Invalid DBGQ device address (%pa)",
-			&iface_q->q_array.align_device_addr);
-	}
 
-	value = (u32)dev->iface_q_table.align_device_addr;
-	if ((ion_phys_addr_t)value !=
-		dev->iface_q_table.align_device_addr) {
-		dprintk(VIDC_ERR,
-			"Invalid iface_q_table device address (%pa)",
-			&dev->iface_q_table.align_device_addr);
-	}
-
-	if (dev->qdss.mem_data) {
+	if (dev->qdss.align_virtual_addr) {
 		qdss = (struct hfi_mem_map_table *)dev->qdss.align_virtual_addr;
 		qdss->mem_map_num_entries = num_entries;
 		mem_map_table_base_addr = dev->qdss.align_device_addr +
 			sizeof(struct hfi_mem_map_table);
-		qdss->mem_map_table_base_addr =
-			(u32)mem_map_table_base_addr;
-		if ((ion_phys_addr_t)qdss->mem_map_table_base_addr !=
-				mem_map_table_base_addr) {
-			dprintk(VIDC_ERR,
-					"Invalid mem_map_table_base_addr (%#lx)",
-					mem_map_table_base_addr);
-		}
+		qdss->mem_map_table_base_addr = mem_map_table_base_addr;
 
 		mem_map = (struct hfi_mem_map *)(qdss + 1);
 		cb = msm_smem_get_context_bank(dev->hal_client, false,
 				HAL_BUFFER_INTERNAL_CMD_QUEUE);
-
 		if (!cb) {
 			dprintk(VIDC_ERR,
 				"%s: failed to get context bank\n", __func__);
@@ -1635,28 +1566,14 @@
 		if (rc) {
 			dprintk(VIDC_ERR,
 				"IOMMU mapping failed, Freeing qdss memdata\n");
-			__smem_free(dev, dev->qdss.mem_data);
-			dev->qdss.mem_data = NULL;
+			__smem_free(dev, &dev->qdss.mem_data);
 			dev->qdss.align_virtual_addr = NULL;
 			dev->qdss.align_device_addr = 0;
 		}
-
-		value = (u32)dev->qdss.align_device_addr;
-		if ((ion_phys_addr_t)value !=
-				dev->qdss.align_device_addr) {
-			dprintk(VIDC_ERR, "Invalid qdss device address (%pa)",
-					&dev->qdss.align_device_addr);
-		}
 	}
 
 	vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr;
 	vsfr->bufSize = ALIGNED_SFR_SIZE;
-	value = (u32)dev->sfr.align_device_addr;
-	if ((ion_phys_addr_t)value !=
-		dev->sfr.align_device_addr) {
-		dprintk(VIDC_ERR, "Invalid sfr device address (%pa)",
-			&dev->sfr.align_device_addr);
-	}
 
 	__setup_ucregion_memory_map(dev);
 	return 0;
@@ -1942,7 +1859,6 @@
 
 	__write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR, 1);
 	__write_register(device, VIDC_WRAPPER_INTR_CLEAR, intr_status);
-	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt\n");
 }
 
 static int venus_hfi_core_ping(void *device)
@@ -2848,7 +2764,8 @@
 		device->skip_pc_count, wfi_status, idle_status, pc_ready);
 	queue_delayed_work(device->venus_pm_workq,
 			&venus_hfi_pm_work,
-			msecs_to_jiffies(msm_vidc_pwr_collapse_delay));
+			msecs_to_jiffies(
+			device->res->msm_vidc_pwr_collapse_delay));
 exit:
 	mutex_unlock(&device->lock);
 }
@@ -3097,7 +3014,8 @@
 		cancel_delayed_work(&venus_hfi_pm_work);
 		if (!queue_delayed_work(device->venus_pm_workq,
 			&venus_hfi_pm_work,
-			msecs_to_jiffies(msm_vidc_pwr_collapse_delay))) {
+			msecs_to_jiffies(
+				device->res->msm_vidc_pwr_collapse_delay))) {
 			dprintk(VIDC_ERR, "PM work already scheduled\n");
 		}
 	}
@@ -3117,7 +3035,7 @@
 
 	mutex_lock(&device->lock);
 
-	dprintk(VIDC_INFO, "Handling interrupt\n");
+	dprintk(VIDC_DBG, "Handling interrupt\n");
 
 	if (!__core_in_valid_state(device)) {
 		dprintk(VIDC_DBG, "%s - Core not in init state\n", __func__);
@@ -3152,7 +3070,8 @@
 	for (i = 0; !IS_ERR_OR_NULL(device->response_pkt) &&
 		i < num_responses; ++i) {
 		struct msm_vidc_cb_info *r = &device->response_pkt[i];
-
+		dprintk(VIDC_DBG, "Processing response %d of %d, type %d\n",
+			(i + 1), num_responses, r->response_type);
 		device->callback(r->response_type, &r->response);
 	}
 
@@ -3160,6 +3079,7 @@
 	if (!(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
 		enable_irq(device->hal_data->irq);
 
+	dprintk(VIDC_DBG, "Handling interrupt done\n");
 	/*
 	 * XXX: Don't add any code beyond here.  Reacquiring locks after release
 	 * it above doesn't guarantee the atomicity that we're aiming for.
@@ -4020,7 +3940,6 @@
 		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
 		return -EINVAL;
 	} else if (device->power_enabled) {
-		dprintk(VIDC_DBG, "Power is already enabled\n");
 		goto exit;
 	} else if (!__core_in_valid_state(device)) {
 		dprintk(VIDC_DBG, "venus_hfi_device in deinit state.");
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 925918c..4c4cb06 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -126,10 +126,10 @@
 };
 
 struct vidc_mem_addr {
-	ion_phys_addr_t align_device_addr;
+	u32 align_device_addr;
 	u8 *align_virtual_addr;
 	u32 mem_size;
-	struct msm_smem *mem_data;
+	struct msm_smem mem_data;
 };
 
 struct vidc_iface_q_info {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 5601f1b..8e9e51f 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -188,6 +188,12 @@
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001E)
 #define HFI_PROPERTY_PARAM_VDEC_CONTENT_LIGHT_LEVEL_SEI_EXTRADATA \
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001F)
+#define HFI_PROPERTY_PARAM_VDEC_COLOUR_REMAPPING_INFO_SEI_EXTRADATA	\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0020)
+#define HFI_PROPERTY_PARAM_VDEC_DOWN_SCALAR	\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0021)
+#define HFI_PROPERTY_PARAM_VDEC_UBWC_CR_STAT_INFO_EXTRADATA	\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0022)
 
 #define HFI_PROPERTY_CONFIG_VDEC_OX_START				\
 	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x4000)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 86e4f42..79ce858 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -17,6 +17,8 @@
 #include <linux/log2.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/hash.h>
 #include <media/msm_vidc.h>
 #include "msm_vidc_resources.h"
 
@@ -123,6 +125,7 @@
 	HAL_EXTRADATA_PQ_INFO,
 	HAL_EXTRADATA_VUI_DISPLAY_INFO,
 	HAL_EXTRADATA_VPX_COLORSPACE,
+	HAL_EXTRADATA_UBWC_CR_STATS_INFO,
 };
 
 enum hal_property {
@@ -882,8 +885,8 @@
 	enum hal_buffer buffer_type;
 	u32 buffer_size;
 	u32 num_buffers;
-	ion_phys_addr_t align_device_addr;
-	ion_phys_addr_t extradata_addr;
+	u32 align_device_addr;
+	u32 extradata_addr;
 	u32 extradata_size;
 	u32 response_required;
 };
@@ -910,8 +913,8 @@
 
 struct vidc_frame_data {
 	enum hal_buffer buffer_type;
-	ion_phys_addr_t device_addr;
-	ion_phys_addr_t extradata_addr;
+	u32 device_addr;
+	u32 extradata_addr;
 	int64_t timestamp;
 	u32 flags;
 	u32 offset;
@@ -1082,6 +1085,22 @@
 	HAL_RESPONSE_UNUSED = 0x10000000,
 };
 
+struct ubwc_cr_stats_info_type {
+	u32 cr_stats_info0;
+	u32 cr_stats_info1;
+	u32 cr_stats_info2;
+	u32 cr_stats_info3;
+	u32 cr_stats_info4;
+	u32 cr_stats_info5;
+	u32 cr_stats_info6;
+};
+
+struct recon_stats_type {
+	u32 buffer_index;
+	u32 complexity_number;
+	struct ubwc_cr_stats_info_type ubwc_stats_info;
+};
+
 struct vidc_hal_ebd {
 	u32 timestamp_hi;
 	u32 timestamp_lo;
@@ -1094,8 +1113,9 @@
 	u32 alloc_len;
 	u32 filled_len;
 	enum hal_picture picture_type;
-	ion_phys_addr_t packet_buffer;
-	ion_phys_addr_t extra_data_buffer;
+	struct recon_stats_type recon_stats;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
 };
 
 struct vidc_hal_fbd {
@@ -1117,18 +1137,18 @@
 	u32 input_tag;
 	u32 input_tag1;
 	enum hal_picture picture_type;
-	ion_phys_addr_t packet_buffer1;
-	ion_phys_addr_t extra_data_buffer;
+	u32 packet_buffer1;
+	u32 extra_data_buffer;
 	u32 flags2;
 	u32 alloc_len2;
 	u32 filled_len2;
 	u32 offset2;
-	ion_phys_addr_t packet_buffer2;
+	u32 packet_buffer2;
 	u32 flags3;
 	u32 alloc_len3;
 	u32 filled_len3;
 	u32 offset3;
-	ion_phys_addr_t packet_buffer3;
+	u32 packet_buffer3;
 	enum hal_buffer buffer_type;
 };
 
@@ -1230,8 +1250,8 @@
 	u32 width;
 	enum msm_vidc_pixel_depth bit_depth;
 	u32 hal_event_type;
-	ion_phys_addr_t packet_buffer;
-	ion_phys_addr_t extra_data_buffer;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
 	u32 pic_struct;
 	u32 colour_space;
 	u32 profile;
@@ -1315,8 +1335,15 @@
 	enum hal_video_codec codec;
 	enum hal_uncompressed_format color_formats[2];
 	int num_formats; /* 1 = DPB-OPB unified; 2 = split */
-	int height, width, fps;
+	int input_height, input_width, fps;
+	int output_height, output_width;
+	int compression_ratio;
+	int complexity_factor;
+	bool use_dpb_read;
+	unsigned int lcu_size;
 	enum msm_vidc_power_mode power_mode;
+	enum hal_work_mode work_mode;
+	bool use_sys_cache;
 };
 
 struct vidc_clk_scale_data {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 616fc09..8169a9b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -339,7 +339,7 @@
 	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00E)
 #define HFI_PROPERTY_CONFIG_VENC_BASELAYER_PRIORITYID		\
 	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00F)
-#define HFI_PROPERTY_CONFIG_VENC_SESSION_QP			\
+#define HFI_PROPERTY_CONFIG_VENC_FRAME_QP			\
 	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x012)
 
 #define HFI_PROPERTY_PARAM_VPE_COMMON_START				\
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
index e6e5e90..b3659448 100644
--- a/drivers/media/tuners/xc5000.c
+++ b/drivers/media/tuners/xc5000.c
@@ -931,7 +931,7 @@
 static int xc5000_set_tv_freq(struct dvb_frontend *fe)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
-	u16 pll_lock_status;
+	u16 pll_lock_status = 0;
 	int ret;
 
 tune_channel:
@@ -1040,7 +1040,6 @@
 
 	return 0;
 }
-
 static int xc5000_set_params(struct dvb_frontend *fe)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
@@ -1133,7 +1132,7 @@
 	const struct xc5000_fw_cfg *desired_fw = xc5000_assign_firmware(priv->chip_id);
 	const struct firmware *fw;
 	int ret, i;
-	u16 pll_lock_status;
+	u16 pll_lock_status = 0;
 	u16 fw_ck;
 
 	cancel_delayed_work(&priv->timer_sleep);
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 52ef883..a29ddca 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -330,6 +330,8 @@
 					b->m.planes[plane].m.userptr;
 				planes[plane].length =
 					b->m.planes[plane].length;
+				planes[plane].data_offset =
+					b->m.planes[plane].data_offset;
 			}
 		}
 		if (b->memory == VB2_MEMORY_DMABUF) {
@@ -338,6 +340,8 @@
 					b->m.planes[plane].m.fd;
 				planes[plane].length =
 					b->m.planes[plane].length;
+				planes[plane].data_offset =
+					b->m.planes[plane].data_offset;
 			}
 		}
 
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 1239e68..71341a7 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -8,7 +8,7 @@
 config MFD_CORE
 	tristate
 	select IRQ_DOMAIN
-	default n
+	default y
 
 config MFD_CS5535
 	tristate "AMD CS5535 and CS5536 southbridge core functions"
@@ -1636,61 +1636,19 @@
 	  power supply enable or disable. This driver acts as interface
 	  between codec and regulator framework.
 
-config WCD9XXX_CODEC_UTIL
-	tristate "WCD9XXX Codec Utils"
-	select MFD_CORE
-	help
-	  WCD9XXX Util driver provides APIs for WCD drivers to reset,
-	  suspend/resume, regmap bus callback functions and read/write
-	  functions. This driver also hides the underlying bus related
-	  functionalities.
-
-config WCD9330_CODEC
-	tristate "WCD9330 Codec"
-	select SLIMBUS
-	select MFD_CORE
-	select WCD9XXX_CODEC_UTIL
-	select MSM_CDC_SUPPLY
-	select REGMAP_ALLOW_WRITE_DEBUGFS
-	help
-	  Enables the WCD9xxx codec core driver. The core driver provides
-	  read/write capability to registers which are part of the
-	  WCD9330 core and gives the ability to use the WCD9330 codec.
-	  The WCD9330 codec support either I2C/I2S or Slimbus for
-	  control and data exchnage with master processor.
-
-config WCD9335_CODEC
-	tristate "WCD9335 Codec"
+config WCD9XXX_CODEC_CORE
+	tristate "WCD9XXX Codec Core"
 	select SLIMBUS
 	select SOUNDWIRE_WCD_CTRL
-	select MFD_CORE
-	select WCD9XXX_CODEC_UTIL
-	select MSM_CDC_SUPPLY
-	select MSM_CDC_PINCTRL
-	select REGMAP_ALLOW_WRITE_DEBUGFS
-	help
-	  Enables the WCD9xxx codec core driver. The core driver provides
-	  read/write capability to registers which are part of the
-	  WCD9335 core and gives the ability to use the WCD9335 codec.
-	  The WCD9335 codec support either I2C/I2S or Slimbus for
-	  control and data exchnage with master processor.
-
-config WCD934X_CODEC
-	tristate "WCD934X Codec"
-	depends on SLIMBUS
-	select SOUNDWIRE_WCD_CTRL
-	select MFD_CORE
-	select WCD9XXX_CODEC_UTIL
 	select MSM_CDC_SUPPLY
 	select MSM_CDC_PINCTRL
 	select REGMAP_ALLOW_WRITE_DEBUGFS
 	select PINCTRL_WCD
 	help
-	  Enables the WCD9xxx codec core driver. The core driver provides
-	  read/write capability to registers which are part of the
-	  WCD934X core and gives the ability to use the WCD934X codec.
-	  The WCD934X codec supports either I2C/I2S or Slimbus for
-	  control and data exchange with master processor.
+	  WCD9XXX Core driver provides APIs for WCD drivers to reset,
+	  suspend/resume, regmap bus callback functions and read/write
+	  functions. This driver also hides the underlying bus related
+	  functionalities.
 
 menu "Multimedia Capabilities Port drivers"
 	depends on ARCH_SA1100
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b2fe74b..0ce70f3 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -205,16 +205,13 @@
 obj-$(CONFIG_MFD_DLN2)		+= dln2.o
 obj-$(CONFIG_MFD_RT5033)	+= rt5033.o
 obj-$(CONFIG_MFD_SKY81452)	+= sky81452.o
-obj-$(CONFIG_MSM_CDC_PINCTRL)	+= msm-cdc-pinctrl.o
-obj-$(CONFIG_MSM_CDC_SUPPLY) += msm-cdc-supply.o
-obj-$(CONFIG_WCD9XXX_CODEC_UTIL) += wcd9xxx-utils.o
-obj-$(CONFIG_WCD9330_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\
-						wcd9330-regmap.o
-obj-$(CONFIG_WCD9335_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\
-					wcd9335-regmap.o wcd9335-tables.o
-obj-$(CONFIG_WCD934X_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\
-					wcd934x-regmap.o wcd934x-tables.o
-
+wcd-core-objs			:= wcd9xxx-rst.o wcd9xxx-core-init.o \
+				   wcd9xxx-core.o wcd9xxx-irq.o \
+				   wcd9xxx-slimslave.o wcd9xxx-utils.o \
+				   wcd934x-regmap.o wcd934x-tables.o \
+				   wcd9335-regmap.o wcd9335-tables.o \
+				   msm-cdc-pinctrl.o msm-cdc-supply.o
+obj-$(CONFIG_WCD9XXX_CODEC_CORE) += wcd-core.o
 intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
 intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC)	+= intel_soc_pmic_bxtwc.o
 obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
diff --git a/drivers/mfd/msm-cdc-pinctrl.c b/drivers/mfd/msm-cdc-pinctrl.c
index 9622256..859a75f 100644
--- a/drivers/mfd/msm-cdc-pinctrl.c
+++ b/drivers/mfd/msm-cdc-pinctrl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -239,7 +239,15 @@
 	.probe = msm_cdc_pinctrl_probe,
 	.remove = msm_cdc_pinctrl_remove,
 };
-module_platform_driver(msm_cdc_pinctrl_driver);
 
+int msm_cdc_pinctrl_drv_init(void)
+{
+	return platform_driver_register(&msm_cdc_pinctrl_driver);
+}
+
+void msm_cdc_pinctrl_drv_exit(void)
+{
+	platform_driver_unregister(&msm_cdc_pinctrl_driver);
+}
 MODULE_DESCRIPTION("MSM CODEC pin control platform driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9330-regmap.c b/drivers/mfd/wcd9330-regmap.c
deleted file mode 100644
index 878ea72..0000000
--- a/drivers/mfd/wcd9330-regmap.c
+++ /dev/null
@@ -1,990 +0,0 @@
-/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/wcd9330_registers.h>
-#include <linux/regmap.h>
-#include <linux/device.h>
-#include "wcd9xxx-regmap.h"
-
-static struct reg_default wcd9330_defaults[] = {
-	{ TOMTOM_A_CHIP_CTL, TOMTOM_A_CHIP_CTL__POR },
-	{ TOMTOM_A_CHIP_STATUS, TOMTOM_A_CHIP_STATUS__POR },
-	{ TOMTOM_A_CHIP_ID_BYTE_0, TOMTOM_A_CHIP_ID_BYTE_0__POR },
-	{ TOMTOM_A_CHIP_ID_BYTE_1, TOMTOM_A_CHIP_ID_BYTE_1__POR },
-	{ TOMTOM_A_CHIP_ID_BYTE_2, TOMTOM_A_CHIP_ID_BYTE_2__POR },
-	{ TOMTOM_A_CHIP_ID_BYTE_3, TOMTOM_A_CHIP_ID_BYTE_3__POR },
-	{ TOMTOM_A_CHIP_I2C_SLAVE_ID, TOMTOM_A_CHIP_I2C_SLAVE_ID__POR },
-	{ TOMTOM_A_SLAVE_ID_1, TOMTOM_A_SLAVE_ID_1__POR },
-	{ TOMTOM_A_SLAVE_ID_2, TOMTOM_A_SLAVE_ID_2__POR },
-	{ TOMTOM_A_SLAVE_ID_3, TOMTOM_A_SLAVE_ID_3__POR },
-	{ TOMTOM_A_PIN_CTL_OE0, TOMTOM_A_PIN_CTL_OE0__POR },
-	{ TOMTOM_A_PIN_CTL_OE1, TOMTOM_A_PIN_CTL_OE1__POR },
-	{ TOMTOM_A_PIN_CTL_OE2, TOMTOM_A_PIN_CTL_OE2__POR },
-	{ TOMTOM_A_PIN_CTL_DATA0, TOMTOM_A_PIN_CTL_DATA0__POR },
-	{ TOMTOM_A_PIN_CTL_DATA1, TOMTOM_A_PIN_CTL_DATA1__POR },
-	{ TOMTOM_A_PIN_CTL_DATA2, TOMTOM_A_PIN_CTL_DATA2__POR },
-	{ TOMTOM_A_HDRIVE_GENERIC, TOMTOM_A_HDRIVE_GENERIC__POR },
-	{ TOMTOM_A_HDRIVE_OVERRIDE, TOMTOM_A_HDRIVE_OVERRIDE__POR },
-	{ TOMTOM_A_ANA_CSR_WAIT_STATE, TOMTOM_A_ANA_CSR_WAIT_STATE__POR },
-	{ TOMTOM_A_PROCESS_MONITOR_CTL0, TOMTOM_A_PROCESS_MONITOR_CTL0__POR },
-	{ TOMTOM_A_PROCESS_MONITOR_CTL1, TOMTOM_A_PROCESS_MONITOR_CTL1__POR },
-	{ TOMTOM_A_PROCESS_MONITOR_CTL2, TOMTOM_A_PROCESS_MONITOR_CTL2__POR },
-	{ TOMTOM_A_PROCESS_MONITOR_CTL3, TOMTOM_A_PROCESS_MONITOR_CTL3__POR },
-	{ TOMTOM_A_QFUSE_CTL, TOMTOM_A_QFUSE_CTL__POR },
-	{ TOMTOM_A_QFUSE_STATUS, TOMTOM_A_QFUSE_STATUS__POR },
-	{ TOMTOM_A_QFUSE_DATA_OUT0, TOMTOM_A_QFUSE_DATA_OUT0__POR },
-	{ TOMTOM_A_QFUSE_DATA_OUT1, TOMTOM_A_QFUSE_DATA_OUT1__POR },
-	{ TOMTOM_A_QFUSE_DATA_OUT2, TOMTOM_A_QFUSE_DATA_OUT2__POR },
-	{ TOMTOM_A_QFUSE_DATA_OUT3, TOMTOM_A_QFUSE_DATA_OUT3__POR },
-	{ TOMTOM_A_QFUSE_DATA_OUT4, TOMTOM_A_QFUSE_DATA_OUT4__POR },
-	{ TOMTOM_A_QFUSE_DATA_OUT5, TOMTOM_A_QFUSE_DATA_OUT5__POR },
-	{ TOMTOM_A_QFUSE_DATA_OUT6, TOMTOM_A_QFUSE_DATA_OUT6__POR },
-	{ TOMTOM_A_QFUSE_DATA_OUT7, TOMTOM_A_QFUSE_DATA_OUT7__POR },
-	{ TOMTOM_A_CDC_CTL, TOMTOM_A_CDC_CTL__POR },
-	{ TOMTOM_A_LEAKAGE_CTL, TOMTOM_A_LEAKAGE_CTL__POR },
-	{ TOMTOM_A_SVASS_MEM_PTR0, TOMTOM_A_SVASS_MEM_PTR0__POR },
-	{ TOMTOM_A_SVASS_MEM_PTR1, TOMTOM_A_SVASS_MEM_PTR1__POR },
-	{ TOMTOM_A_SVASS_MEM_PTR2, TOMTOM_A_SVASS_MEM_PTR2__POR },
-	{ TOMTOM_A_SVASS_MEM_CTL, TOMTOM_A_SVASS_MEM_CTL__POR },
-	{ TOMTOM_A_SVASS_MEM_BANK, TOMTOM_A_SVASS_MEM_BANK__POR },
-	{ TOMTOM_A_DMIC_B1_CTL, TOMTOM_A_DMIC_B1_CTL__POR },
-	{ TOMTOM_A_DMIC_B2_CTL, TOMTOM_A_DMIC_B2_CTL__POR },
-	{ TOMTOM_A_SVASS_CLKRST_CTL, TOMTOM_A_SVASS_CLKRST_CTL__POR },
-	{ TOMTOM_A_SVASS_CPAR_CFG, TOMTOM_A_SVASS_CPAR_CFG__POR },
-	{ TOMTOM_A_SVASS_BUF_RDY_INT_PERIOD,
-				TOMTOM_A_SVASS_BUF_RDY_INT_PERIOD__POR },
-	{ TOMTOM_A_SVASS_CPAR_WDOG_CFG, TOMTOM_A_SVASS_CPAR_WDOG_CFG__POR },
-	{ TOMTOM_A_SVASS_CFG, TOMTOM_A_SVASS_CFG__POR },
-	{ TOMTOM_A_SVASS_SPE_CFG, TOMTOM_A_SVASS_SPE_CFG__POR },
-	{ TOMTOM_A_SVASS_STATUS, TOMTOM_A_SVASS_STATUS__POR },
-	{ TOMTOM_A_SVASS_INT_MASK, TOMTOM_A_SVASS_INT_MASK__POR },
-	{ TOMTOM_A_SVASS_INT_STATUS, TOMTOM_A_SVASS_INT_STATUS__POR },
-	{ TOMTOM_A_SVASS_INT_CLR, TOMTOM_A_SVASS_INT_CLR__POR },
-	{ TOMTOM_A_SVASS_DEBUG, TOMTOM_A_SVASS_DEBUG__POR },
-	{ TOMTOM_A_SVASS_SPE_BKUP_INT, TOMTOM_A_SVASS_SPE_BKUP_INT__POR },
-	{ TOMTOM_A_SVASS_MEM_ACC, TOMTOM_A_SVASS_MEM_ACC__POR },
-	{ TOMTOM_A_MEM_LEAKAGE_CTL, TOMTOM_A_MEM_LEAKAGE_CTL__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_TRG, TOMTOM_A_SVASS_SPE_INBOX_TRG__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_0, TOMTOM_A_SVASS_SPE_INBOX_0__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_1, TOMTOM_A_SVASS_SPE_INBOX_1__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_2, TOMTOM_A_SVASS_SPE_INBOX_2__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_3, TOMTOM_A_SVASS_SPE_INBOX_3__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_4, TOMTOM_A_SVASS_SPE_INBOX_4__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_5, TOMTOM_A_SVASS_SPE_INBOX_5__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_6, TOMTOM_A_SVASS_SPE_INBOX_6__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_7, TOMTOM_A_SVASS_SPE_INBOX_7__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_8, TOMTOM_A_SVASS_SPE_INBOX_8__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_9, TOMTOM_A_SVASS_SPE_INBOX_9__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_10, TOMTOM_A_SVASS_SPE_INBOX_10__POR },
-	{ TOMTOM_A_SVASS_SPE_INBOX_11, TOMTOM_A_SVASS_SPE_INBOX_11__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_0, TOMTOM_A_SVASS_SPE_OUTBOX_0__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_1, TOMTOM_A_SVASS_SPE_OUTBOX_1__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_2, TOMTOM_A_SVASS_SPE_OUTBOX_2__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_3, TOMTOM_A_SVASS_SPE_OUTBOX_3__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_4, TOMTOM_A_SVASS_SPE_OUTBOX_4__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_5, TOMTOM_A_SVASS_SPE_OUTBOX_5__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_6, TOMTOM_A_SVASS_SPE_OUTBOX_6__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_7, TOMTOM_A_SVASS_SPE_OUTBOX_7__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_8, TOMTOM_A_SVASS_SPE_OUTBOX_8__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_9, TOMTOM_A_SVASS_SPE_OUTBOX_9__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_10, TOMTOM_A_SVASS_SPE_OUTBOX_10__POR },
-	{ TOMTOM_A_SVASS_SPE_OUTBOX_11, TOMTOM_A_SVASS_SPE_OUTBOX_11__POR },
-	{ TOMTOM_A_INTR_MODE, TOMTOM_A_INTR_MODE__POR },
-	{ TOMTOM_A_INTR1_MASK0, TOMTOM_A_INTR1_MASK0__POR },
-	{ TOMTOM_A_INTR1_MASK1, TOMTOM_A_INTR1_MASK1__POR },
-	{ TOMTOM_A_INTR1_MASK2, TOMTOM_A_INTR1_MASK2__POR },
-	{ TOMTOM_A_INTR1_MASK3, TOMTOM_A_INTR1_MASK3__POR },
-	{ TOMTOM_A_INTR1_STATUS0, TOMTOM_A_INTR1_STATUS0__POR },
-	{ TOMTOM_A_INTR1_STATUS1, TOMTOM_A_INTR1_STATUS1__POR },
-	{ TOMTOM_A_INTR1_STATUS2, TOMTOM_A_INTR1_STATUS2__POR },
-	{ TOMTOM_A_INTR1_STATUS3, TOMTOM_A_INTR1_STATUS3__POR },
-	{ TOMTOM_A_INTR1_CLEAR0, TOMTOM_A_INTR1_CLEAR0__POR },
-	{ TOMTOM_A_INTR1_CLEAR1, TOMTOM_A_INTR1_CLEAR1__POR },
-	{ TOMTOM_A_INTR1_CLEAR2, TOMTOM_A_INTR1_CLEAR2__POR },
-	{ TOMTOM_A_INTR1_CLEAR3, TOMTOM_A_INTR1_CLEAR3__POR },
-	{ TOMTOM_A_INTR1_LEVEL0, TOMTOM_A_INTR1_LEVEL0__POR },
-	{ TOMTOM_A_INTR1_LEVEL1, TOMTOM_A_INTR1_LEVEL1__POR },
-	{ TOMTOM_A_INTR1_LEVEL2, TOMTOM_A_INTR1_LEVEL2__POR },
-	{ TOMTOM_A_INTR1_LEVEL3, TOMTOM_A_INTR1_LEVEL3__POR },
-	{ TOMTOM_A_INTR1_TEST0, TOMTOM_A_INTR1_TEST0__POR },
-	{ TOMTOM_A_INTR1_TEST1, TOMTOM_A_INTR1_TEST1__POR },
-	{ TOMTOM_A_INTR1_TEST2, TOMTOM_A_INTR1_TEST2__POR },
-	{ TOMTOM_A_INTR1_TEST3, TOMTOM_A_INTR1_TEST3__POR },
-	{ TOMTOM_A_INTR1_SET0, TOMTOM_A_INTR1_SET0__POR },
-	{ TOMTOM_A_INTR1_SET1, TOMTOM_A_INTR1_SET1__POR },
-	{ TOMTOM_A_INTR1_SET2, TOMTOM_A_INTR1_SET2__POR },
-	{ TOMTOM_A_INTR1_SET3, TOMTOM_A_INTR1_SET3__POR },
-	{ TOMTOM_A_INTR2_MASK0, TOMTOM_A_INTR2_MASK0__POR },
-	{ TOMTOM_A_INTR2_STATUS0, TOMTOM_A_INTR2_STATUS0__POR },
-	{ TOMTOM_A_INTR2_CLEAR0, TOMTOM_A_INTR2_CLEAR0__POR },
-	{ TOMTOM_A_INTR2_LEVEL0, TOMTOM_A_INTR2_LEVEL0__POR },
-	{ TOMTOM_A_INTR2_TEST0, TOMTOM_A_INTR2_TEST0__POR },
-	{ TOMTOM_A_INTR2_SET0, TOMTOM_A_INTR2_SET0__POR },
-	{ TOMTOM_A_CDC_TX_I2S_SCK_MODE, TOMTOM_A_CDC_TX_I2S_SCK_MODE__POR },
-	{ TOMTOM_A_CDC_TX_I2S_WS_MODE, TOMTOM_A_CDC_TX_I2S_WS_MODE__POR },
-	{ TOMTOM_A_CDC_DMIC_DATA0_MODE, TOMTOM_A_CDC_DMIC_DATA0_MODE__POR },
-	{ TOMTOM_A_CDC_DMIC_CLK0_MODE, TOMTOM_A_CDC_DMIC_CLK0_MODE__POR },
-	{ TOMTOM_A_CDC_DMIC_DATA1_MODE, TOMTOM_A_CDC_DMIC_DATA1_MODE__POR },
-	{ TOMTOM_A_CDC_DMIC_CLK1_MODE, TOMTOM_A_CDC_DMIC_CLK1_MODE__POR },
-	{ TOMTOM_A_CDC_RX_I2S_SCK_MODE, TOMTOM_A_CDC_RX_I2S_SCK_MODE__POR },
-	{ TOMTOM_A_CDC_RX_I2S_WS_MODE, TOMTOM_A_CDC_RX_I2S_WS_MODE__POR },
-	{ TOMTOM_A_CDC_DMIC_DATA2_MODE, TOMTOM_A_CDC_DMIC_DATA2_MODE__POR },
-	{ TOMTOM_A_CDC_DMIC_CLK2_MODE, TOMTOM_A_CDC_DMIC_CLK2_MODE__POR },
-	{ TOMTOM_A_CDC_INTR1_MODE, TOMTOM_A_CDC_INTR1_MODE__POR },
-	{ TOMTOM_A_CDC_SB_NRZ_SEL_MODE, TOMTOM_A_CDC_SB_NRZ_SEL_MODE__POR },
-	{ TOMTOM_A_CDC_INTR2_MODE, TOMTOM_A_CDC_INTR2_MODE__POR },
-	{ TOMTOM_A_CDC_RF_PA_ON_MODE, TOMTOM_A_CDC_RF_PA_ON_MODE__POR },
-	{ TOMTOM_A_CDC_BOOST_MODE, TOMTOM_A_CDC_BOOST_MODE__POR },
-	{ TOMTOM_A_CDC_JTCK_MODE, TOMTOM_A_CDC_JTCK_MODE__POR },
-	{ TOMTOM_A_CDC_JTDI_MODE, TOMTOM_A_CDC_JTDI_MODE__POR },
-	{ TOMTOM_A_CDC_JTMS_MODE, TOMTOM_A_CDC_JTMS_MODE__POR },
-	{ TOMTOM_A_CDC_JTDO_MODE, TOMTOM_A_CDC_JTDO_MODE__POR },
-	{ TOMTOM_A_CDC_JTRST_MODE, TOMTOM_A_CDC_JTRST_MODE__POR },
-	{ TOMTOM_A_CDC_BIST_MODE_MODE, TOMTOM_A_CDC_BIST_MODE_MODE__POR },
-	{ TOMTOM_A_CDC_MAD_MAIN_CTL_1, TOMTOM_A_CDC_MAD_MAIN_CTL_1__POR },
-	{ TOMTOM_A_CDC_MAD_MAIN_CTL_2, TOMTOM_A_CDC_MAD_MAIN_CTL_2__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_CTL_1, TOMTOM_A_CDC_MAD_AUDIO_CTL_1__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_CTL_2, TOMTOM_A_CDC_MAD_AUDIO_CTL_2__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_CTL_3, TOMTOM_A_CDC_MAD_AUDIO_CTL_3__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_CTL_4, TOMTOM_A_CDC_MAD_AUDIO_CTL_4__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_CTL_5, TOMTOM_A_CDC_MAD_AUDIO_CTL_5__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_CTL_6, TOMTOM_A_CDC_MAD_AUDIO_CTL_6__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_CTL_7, TOMTOM_A_CDC_MAD_AUDIO_CTL_7__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_CTL_8, TOMTOM_A_CDC_MAD_AUDIO_CTL_8__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_PTR,
-				TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_PTR__POR },
-	{ TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_VAL,
-				TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_VAL__POR },
-	{ TOMTOM_A_CDC_MAD_ULTR_CTL_1, TOMTOM_A_CDC_MAD_ULTR_CTL_1__POR },
-	{ TOMTOM_A_CDC_MAD_ULTR_CTL_2, TOMTOM_A_CDC_MAD_ULTR_CTL_2__POR },
-	{ TOMTOM_A_CDC_MAD_ULTR_CTL_3, TOMTOM_A_CDC_MAD_ULTR_CTL_3__POR },
-	{ TOMTOM_A_CDC_MAD_ULTR_CTL_4, TOMTOM_A_CDC_MAD_ULTR_CTL_4__POR },
-	{ TOMTOM_A_CDC_MAD_ULTR_CTL_5, TOMTOM_A_CDC_MAD_ULTR_CTL_5__POR },
-	{ TOMTOM_A_CDC_MAD_ULTR_CTL_6, TOMTOM_A_CDC_MAD_ULTR_CTL_6__POR },
-	{ TOMTOM_A_CDC_MAD_ULTR_CTL_7, TOMTOM_A_CDC_MAD_ULTR_CTL_7__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_CTL_1, TOMTOM_A_CDC_MAD_BEACON_CTL_1__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_CTL_2, TOMTOM_A_CDC_MAD_BEACON_CTL_2__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_CTL_3, TOMTOM_A_CDC_MAD_BEACON_CTL_3__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_CTL_4, TOMTOM_A_CDC_MAD_BEACON_CTL_4__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_CTL_5, TOMTOM_A_CDC_MAD_BEACON_CTL_5__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_CTL_6, TOMTOM_A_CDC_MAD_BEACON_CTL_6__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_CTL_7, TOMTOM_A_CDC_MAD_BEACON_CTL_7__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_CTL_8, TOMTOM_A_CDC_MAD_BEACON_CTL_8__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_PTR,
-				TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_PTR__POR },
-	{ TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_VAL,
-				TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_VAL__POR },
-	{ TOMTOM_A_CDC_MAD_INP_SEL, TOMTOM_A_CDC_MAD_INP_SEL__POR },
-	{ TOMTOM_A_BIAS_REF_CTL, TOMTOM_A_BIAS_REF_CTL__POR },
-	{ TOMTOM_A_BIAS_CENTRAL_BG_CTL, TOMTOM_A_BIAS_CENTRAL_BG_CTL__POR },
-	{ TOMTOM_A_BIAS_PRECHRG_CTL, TOMTOM_A_BIAS_PRECHRG_CTL__POR },
-	{ TOMTOM_A_BIAS_CURR_CTL_1, TOMTOM_A_BIAS_CURR_CTL_1__POR },
-	{ TOMTOM_A_BIAS_CURR_CTL_2, TOMTOM_A_BIAS_CURR_CTL_2__POR },
-	{ TOMTOM_A_BIAS_OSC_BG_CTL, TOMTOM_A_BIAS_OSC_BG_CTL__POR },
-	{ TOMTOM_A_CLK_BUFF_EN1, TOMTOM_A_CLK_BUFF_EN1__POR },
-	{ TOMTOM_A_CLK_BUFF_EN2, TOMTOM_A_CLK_BUFF_EN2__POR },
-	{ TOMTOM_A_LDO_L_MODE_1, TOMTOM_A_LDO_L_MODE_1__POR },
-	{ TOMTOM_A_LDO_L_MODE_2, TOMTOM_A_LDO_L_MODE_2__POR },
-	{ TOMTOM_A_LDO_L_CTRL_1, TOMTOM_A_LDO_L_CTRL_1__POR },
-	{ TOMTOM_A_LDO_L_CTRL_2, TOMTOM_A_LDO_L_CTRL_2__POR },
-	{ TOMTOM_A_LDO_L_CTRL_3, TOMTOM_A_LDO_L_CTRL_3__POR },
-	{ TOMTOM_A_LDO_L_CTRL_4, TOMTOM_A_LDO_L_CTRL_4__POR },
-	{ TOMTOM_A_LDO_H_MODE_1, TOMTOM_A_LDO_H_MODE_1__POR },
-	{ TOMTOM_A_LDO_H_MODE_2, TOMTOM_A_LDO_H_MODE_2__POR },
-	{ TOMTOM_A_LDO_H_LOOP_CTL, TOMTOM_A_LDO_H_LOOP_CTL__POR },
-	{ TOMTOM_A_LDO_H_COMP_1, TOMTOM_A_LDO_H_COMP_1__POR },
-	{ TOMTOM_A_LDO_H_COMP_2, TOMTOM_A_LDO_H_COMP_2__POR },
-	{ TOMTOM_A_LDO_H_BIAS_1, TOMTOM_A_LDO_H_BIAS_1__POR },
-	{ TOMTOM_A_LDO_H_BIAS_2, TOMTOM_A_LDO_H_BIAS_2__POR },
-	{ TOMTOM_A_LDO_H_BIAS_3, TOMTOM_A_LDO_H_BIAS_3__POR },
-	{ TOMTOM_A_VBAT_CLK, TOMTOM_A_VBAT_CLK__POR },
-	{ TOMTOM_A_VBAT_LOOP, TOMTOM_A_VBAT_LOOP__POR },
-	{ TOMTOM_A_VBAT_REF, TOMTOM_A_VBAT_REF__POR },
-	{ TOMTOM_A_VBAT_ADC_TEST, TOMTOM_A_VBAT_ADC_TEST__POR },
-	{ TOMTOM_A_VBAT_FE, TOMTOM_A_VBAT_FE__POR },
-	{ TOMTOM_A_VBAT_BIAS_1, TOMTOM_A_VBAT_BIAS_1__POR },
-	{ TOMTOM_A_VBAT_BIAS_2, TOMTOM_A_VBAT_BIAS_2__POR },
-	{ TOMTOM_A_VBAT_ADC_DATA_MSB, TOMTOM_A_VBAT_ADC_DATA_MSB__POR },
-	{ TOMTOM_A_VBAT_ADC_DATA_LSB, TOMTOM_A_VBAT_ADC_DATA_LSB__POR },
-	{ TOMTOM_A_FLL_NREF, TOMTOM_A_FLL_NREF__POR },
-	{ TOMTOM_A_FLL_KDCO_TUNE, TOMTOM_A_FLL_KDCO_TUNE__POR },
-	{ TOMTOM_A_FLL_LOCK_THRESH, TOMTOM_A_FLL_LOCK_THRESH__POR },
-	{ TOMTOM_A_FLL_LOCK_DET_COUNT, TOMTOM_A_FLL_LOCK_DET_COUNT__POR },
-	{ TOMTOM_A_FLL_DAC_THRESHOLD, TOMTOM_A_FLL_DAC_THRESHOLD__POR },
-	{ TOMTOM_A_FLL_TEST_DCO_FREERUN, TOMTOM_A_FLL_TEST_DCO_FREERUN__POR },
-	{ TOMTOM_A_FLL_TEST_ENABLE, TOMTOM_A_FLL_TEST_ENABLE__POR },
-	{ TOMTOM_A_MICB_CFILT_1_CTL, TOMTOM_A_MICB_CFILT_1_CTL__POR },
-	{ TOMTOM_A_MICB_CFILT_1_VAL, TOMTOM_A_MICB_CFILT_1_VAL__POR },
-	{ TOMTOM_A_MICB_CFILT_1_PRECHRG, TOMTOM_A_MICB_CFILT_1_PRECHRG__POR },
-	{ TOMTOM_A_MICB_1_CTL, TOMTOM_A_MICB_1_CTL__POR },
-	{ TOMTOM_A_MICB_1_INT_RBIAS, TOMTOM_A_MICB_1_INT_RBIAS__POR },
-	{ TOMTOM_A_MICB_1_MBHC, TOMTOM_A_MICB_1_MBHC__POR },
-	{ TOMTOM_A_MICB_CFILT_2_CTL, TOMTOM_A_MICB_CFILT_2_CTL__POR },
-	{ TOMTOM_A_MICB_CFILT_2_VAL, TOMTOM_A_MICB_CFILT_2_VAL__POR },
-	{ TOMTOM_A_MICB_CFILT_2_PRECHRG, TOMTOM_A_MICB_CFILT_2_PRECHRG__POR },
-	{ TOMTOM_A_MICB_2_CTL, TOMTOM_A_MICB_2_CTL__POR },
-	{ TOMTOM_A_MICB_2_INT_RBIAS, TOMTOM_A_MICB_2_INT_RBIAS__POR },
-	{ TOMTOM_A_MICB_2_MBHC, TOMTOM_A_MICB_2_MBHC__POR },
-	{ TOMTOM_A_MICB_CFILT_3_CTL, TOMTOM_A_MICB_CFILT_3_CTL__POR },
-	{ TOMTOM_A_MICB_CFILT_3_VAL, TOMTOM_A_MICB_CFILT_3_VAL__POR },
-	{ TOMTOM_A_MICB_CFILT_3_PRECHRG, TOMTOM_A_MICB_CFILT_3_PRECHRG__POR },
-	{ TOMTOM_A_MICB_3_CTL, TOMTOM_A_MICB_3_CTL__POR },
-	{ TOMTOM_A_MICB_3_INT_RBIAS, TOMTOM_A_MICB_3_INT_RBIAS__POR },
-	{ TOMTOM_A_MICB_3_MBHC, TOMTOM_A_MICB_3_MBHC__POR },
-	{ TOMTOM_A_MICB_4_CTL, TOMTOM_A_MICB_4_CTL__POR },
-	{ TOMTOM_A_MICB_4_INT_RBIAS, TOMTOM_A_MICB_4_INT_RBIAS__POR },
-	{ TOMTOM_A_MICB_4_MBHC, TOMTOM_A_MICB_4_MBHC__POR },
-	{ TOMTOM_A_SPKR_DRV2_EN, TOMTOM_A_SPKR_DRV2_EN__POR },
-	{ TOMTOM_A_SPKR_DRV2_GAIN, TOMTOM_A_SPKR_DRV2_GAIN__POR },
-	{ TOMTOM_A_SPKR_DRV2_DAC_CTL, TOMTOM_A_SPKR_DRV2_DAC_CTL__POR },
-	{ TOMTOM_A_SPKR_DRV2_OCP_CTL, TOMTOM_A_SPKR_DRV2_OCP_CTL__POR },
-	{ TOMTOM_A_SPKR_DRV2_CLIP_DET, TOMTOM_A_SPKR_DRV2_CLIP_DET__POR },
-	{ TOMTOM_A_SPKR_DRV2_DBG_DAC, TOMTOM_A_SPKR_DRV2_DBG_DAC__POR },
-	{ TOMTOM_A_SPKR_DRV2_DBG_PA, TOMTOM_A_SPKR_DRV2_DBG_PA__POR },
-	{ TOMTOM_A_SPKR_DRV2_DBG_PWRSTG, TOMTOM_A_SPKR_DRV2_DBG_PWRSTG__POR },
-	{ TOMTOM_A_SPKR_DRV2_BIAS_LDO, TOMTOM_A_SPKR_DRV2_BIAS_LDO__POR },
-	{ TOMTOM_A_SPKR_DRV2_BIAS_INT, TOMTOM_A_SPKR_DRV2_BIAS_INT__POR },
-	{ TOMTOM_A_SPKR_DRV2_BIAS_PA, TOMTOM_A_SPKR_DRV2_BIAS_PA__POR },
-	{ TOMTOM_A_SPKR_DRV2_STATUS_OCP, TOMTOM_A_SPKR_DRV2_STATUS_OCP__POR },
-	{ TOMTOM_A_SPKR_DRV2_STATUS_PA, TOMTOM_A_SPKR_DRV2_STATUS_PA__POR },
-	{ TOMTOM_A_MBHC_INSERT_DETECT, TOMTOM_A_MBHC_INSERT_DETECT__POR },
-	{ TOMTOM_A_MBHC_INSERT_DET_STATUS,
-				TOMTOM_A_MBHC_INSERT_DET_STATUS__POR },
-	{ TOMTOM_A_TX_COM_BIAS, TOMTOM_A_TX_COM_BIAS__POR },
-	{ TOMTOM_A_MBHC_INSERT_DETECT2, TOMTOM_A_MBHC_INSERT_DETECT2__POR },
-	{ TOMTOM_A_MBHC_SCALING_MUX_1, TOMTOM_A_MBHC_SCALING_MUX_1__POR },
-	{ TOMTOM_A_MBHC_SCALING_MUX_2, TOMTOM_A_MBHC_SCALING_MUX_2__POR },
-	{ TOMTOM_A_MAD_ANA_CTRL, TOMTOM_A_MAD_ANA_CTRL__POR },
-	{ TOMTOM_A_TX_SUP_SWITCH_CTRL_1, TOMTOM_A_TX_SUP_SWITCH_CTRL_1__POR },
-	{ TOMTOM_A_TX_SUP_SWITCH_CTRL_2, TOMTOM_A_TX_SUP_SWITCH_CTRL_2__POR },
-	{ TOMTOM_A_TX_1_GAIN, TOMTOM_A_TX_1_GAIN__POR },
-	{ TOMTOM_A_TX_1_2_TEST_EN, TOMTOM_A_TX_1_2_TEST_EN__POR },
-	{ TOMTOM_A_TX_2_GAIN, TOMTOM_A_TX_2_GAIN__POR },
-	{ TOMTOM_A_TX_1_2_ADC_IB, TOMTOM_A_TX_1_2_ADC_IB__POR },
-	{ TOMTOM_A_TX_1_2_ATEST_REFCTRL, TOMTOM_A_TX_1_2_ATEST_REFCTRL__POR },
-	{ TOMTOM_A_TX_1_2_TEST_CTL, TOMTOM_A_TX_1_2_TEST_CTL__POR },
-	{ TOMTOM_A_TX_1_2_TEST_BLOCK_EN, TOMTOM_A_TX_1_2_TEST_BLOCK_EN__POR },
-	{ TOMTOM_A_TX_1_2_TXFE_CLKDIV, TOMTOM_A_TX_1_2_TXFE_CLKDIV__POR },
-	{ TOMTOM_A_TX_1_2_SAR_ERR_CH1, TOMTOM_A_TX_1_2_SAR_ERR_CH1__POR },
-	{ TOMTOM_A_TX_1_2_SAR_ERR_CH2, TOMTOM_A_TX_1_2_SAR_ERR_CH2__POR },
-	{ TOMTOM_A_TX_3_GAIN, TOMTOM_A_TX_3_GAIN__POR },
-	{ TOMTOM_A_TX_3_4_TEST_EN, TOMTOM_A_TX_3_4_TEST_EN__POR },
-	{ TOMTOM_A_TX_4_GAIN, TOMTOM_A_TX_4_GAIN__POR },
-	{ TOMTOM_A_TX_3_4_ADC_IB, TOMTOM_A_TX_3_4_ADC_IB__POR },
-	{ TOMTOM_A_TX_3_4_ATEST_REFCTRL, TOMTOM_A_TX_3_4_ATEST_REFCTRL__POR },
-	{ TOMTOM_A_TX_3_4_TEST_CTL, TOMTOM_A_TX_3_4_TEST_CTL__POR },
-	{ TOMTOM_A_TX_3_4_TEST_BLOCK_EN, TOMTOM_A_TX_3_4_TEST_BLOCK_EN__POR },
-	{ TOMTOM_A_TX_3_4_TXFE_CKDIV, TOMTOM_A_TX_3_4_TXFE_CKDIV__POR },
-	{ TOMTOM_A_TX_3_4_SAR_ERR_CH3, TOMTOM_A_TX_3_4_SAR_ERR_CH3__POR },
-	{ TOMTOM_A_TX_3_4_SAR_ERR_CH4, TOMTOM_A_TX_3_4_SAR_ERR_CH4__POR },
-	{ TOMTOM_A_TX_5_GAIN, TOMTOM_A_TX_5_GAIN__POR },
-	{ TOMTOM_A_TX_5_6_TEST_EN, TOMTOM_A_TX_5_6_TEST_EN__POR },
-	{ TOMTOM_A_TX_6_GAIN, TOMTOM_A_TX_6_GAIN__POR },
-	{ TOMTOM_A_TX_5_6_ADC_IB, TOMTOM_A_TX_5_6_ADC_IB__POR },
-	{ TOMTOM_A_TX_5_6_ATEST_REFCTRL, TOMTOM_A_TX_5_6_ATEST_REFCTRL__POR },
-	{ TOMTOM_A_TX_5_6_TEST_CTL, TOMTOM_A_TX_5_6_TEST_CTL__POR },
-	{ TOMTOM_A_TX_5_6_TEST_BLOCK_EN, TOMTOM_A_TX_5_6_TEST_BLOCK_EN__POR },
-	{ TOMTOM_A_TX_5_6_TXFE_CKDIV, TOMTOM_A_TX_5_6_TXFE_CKDIV__POR },
-	{ TOMTOM_A_TX_5_6_SAR_ERR_CH5, TOMTOM_A_TX_5_6_SAR_ERR_CH5__POR },
-	{ TOMTOM_A_TX_5_6_SAR_ERR_CH6, TOMTOM_A_TX_5_6_SAR_ERR_CH6__POR },
-	{ TOMTOM_A_TX_7_MBHC_EN, TOMTOM_A_TX_7_MBHC_EN__POR },
-	{ TOMTOM_A_TX_7_MBHC_ATEST_REFCTRL,
-				TOMTOM_A_TX_7_MBHC_ATEST_REFCTRL__POR },
-	{ TOMTOM_A_TX_7_MBHC_ADC, TOMTOM_A_TX_7_MBHC_ADC__POR },
-	{ TOMTOM_A_TX_7_MBHC_TEST_CTL, TOMTOM_A_TX_7_MBHC_TEST_CTL__POR },
-	{ TOMTOM_A_TX_7_MBHC_SAR_ERR, TOMTOM_A_TX_7_MBHC_SAR_ERR__POR },
-	{ TOMTOM_A_TX_7_TXFE_CLKDIV, TOMTOM_A_TX_7_TXFE_CLKDIV__POR },
-	{ TOMTOM_A_RCO_CTRL, TOMTOM_A_RCO_CTRL__POR },
-	{ TOMTOM_A_RCO_CALIBRATION_CTRL1, TOMTOM_A_RCO_CALIBRATION_CTRL1__POR },
-	{ TOMTOM_A_RCO_CALIBRATION_CTRL2, TOMTOM_A_RCO_CALIBRATION_CTRL2__POR },
-	{ TOMTOM_A_RCO_CALIBRATION_CTRL3, TOMTOM_A_RCO_CALIBRATION_CTRL3__POR },
-	{ TOMTOM_A_RCO_TEST_CTRL, TOMTOM_A_RCO_TEST_CTRL__POR },
-	{ TOMTOM_A_RCO_CALIBRATION_RESULT1,
-				TOMTOM_A_RCO_CALIBRATION_RESULT1__POR },
-	{ TOMTOM_A_RCO_CALIBRATION_RESULT2,
-				TOMTOM_A_RCO_CALIBRATION_RESULT2__POR },
-	{ TOMTOM_A_BUCK_MODE_1, TOMTOM_A_BUCK_MODE_1__POR },
-	{ TOMTOM_A_BUCK_MODE_2, TOMTOM_A_BUCK_MODE_2__POR },
-	{ TOMTOM_A_BUCK_MODE_3, TOMTOM_A_BUCK_MODE_3__POR },
-	{ TOMTOM_A_BUCK_MODE_4, TOMTOM_A_BUCK_MODE_4__POR },
-	{ TOMTOM_A_BUCK_MODE_5, TOMTOM_A_BUCK_MODE_5__POR },
-	{ TOMTOM_A_BUCK_CTRL_VCL_1, TOMTOM_A_BUCK_CTRL_VCL_1__POR },
-	{ TOMTOM_A_BUCK_CTRL_VCL_2, TOMTOM_A_BUCK_CTRL_VCL_2__POR },
-	{ TOMTOM_A_BUCK_CTRL_VCL_3, TOMTOM_A_BUCK_CTRL_VCL_3__POR },
-	{ TOMTOM_A_BUCK_CTRL_CCL_1, TOMTOM_A_BUCK_CTRL_CCL_1__POR },
-	{ TOMTOM_A_BUCK_CTRL_CCL_2, TOMTOM_A_BUCK_CTRL_CCL_2__POR },
-	{ TOMTOM_A_BUCK_CTRL_CCL_3, TOMTOM_A_BUCK_CTRL_CCL_3__POR },
-	{ TOMTOM_A_BUCK_CTRL_CCL_4, TOMTOM_A_BUCK_CTRL_CCL_4__POR },
-	{ TOMTOM_A_BUCK_CTRL_PWM_DRVR_1, TOMTOM_A_BUCK_CTRL_PWM_DRVR_1__POR },
-	{ TOMTOM_A_BUCK_CTRL_PWM_DRVR_2, TOMTOM_A_BUCK_CTRL_PWM_DRVR_2__POR },
-	{ TOMTOM_A_BUCK_CTRL_PWM_DRVR_3, TOMTOM_A_BUCK_CTRL_PWM_DRVR_3__POR },
-	{ TOMTOM_A_BUCK_TMUX_A_D, TOMTOM_A_BUCK_TMUX_A_D__POR },
-	{ TOMTOM_A_NCP_BUCKREF, TOMTOM_A_NCP_BUCKREF__POR },
-	{ TOMTOM_A_NCP_EN, TOMTOM_A_NCP_EN__POR },
-	{ TOMTOM_A_NCP_CLK, TOMTOM_A_NCP_CLK__POR },
-	{ TOMTOM_A_NCP_STATIC, TOMTOM_A_NCP_STATIC__POR },
-	{ TOMTOM_A_NCP_VTH_LOW, TOMTOM_A_NCP_VTH_LOW__POR },
-	{ TOMTOM_A_NCP_VTH_HIGH, TOMTOM_A_NCP_VTH_HIGH__POR },
-	{ TOMTOM_A_NCP_ATEST, TOMTOM_A_NCP_ATEST__POR },
-	{ TOMTOM_A_NCP_DTEST, TOMTOM_A_NCP_DTEST__POR },
-	{ TOMTOM_A_NCP_DLY1, TOMTOM_A_NCP_DLY1__POR },
-	{ TOMTOM_A_NCP_DLY2, TOMTOM_A_NCP_DLY2__POR },
-	{ TOMTOM_A_RX_AUX_SW_CTL, TOMTOM_A_RX_AUX_SW_CTL__POR },
-	{ TOMTOM_A_RX_PA_AUX_IN_CONN, TOMTOM_A_RX_PA_AUX_IN_CONN__POR },
-	{ TOMTOM_A_RX_COM_TIMER_DIV, TOMTOM_A_RX_COM_TIMER_DIV__POR },
-	{ TOMTOM_A_RX_COM_OCP_CTL, TOMTOM_A_RX_COM_OCP_CTL__POR },
-	{ TOMTOM_A_RX_COM_OCP_COUNT, TOMTOM_A_RX_COM_OCP_COUNT__POR },
-	{ TOMTOM_A_RX_COM_DAC_CTL, TOMTOM_A_RX_COM_DAC_CTL__POR },
-	{ TOMTOM_A_RX_COM_BIAS, TOMTOM_A_RX_COM_BIAS__POR },
-	{ TOMTOM_A_RX_HPH_AUTO_CHOP, TOMTOM_A_RX_HPH_AUTO_CHOP__POR },
-	{ TOMTOM_A_RX_HPH_CHOP_CTL, TOMTOM_A_RX_HPH_CHOP_CTL__POR },
-	{ TOMTOM_A_RX_HPH_BIAS_PA, TOMTOM_A_RX_HPH_BIAS_PA__POR },
-	{ TOMTOM_A_RX_HPH_BIAS_LDO, TOMTOM_A_RX_HPH_BIAS_LDO__POR },
-	{ TOMTOM_A_RX_HPH_BIAS_CNP, TOMTOM_A_RX_HPH_BIAS_CNP__POR },
-	{ TOMTOM_A_RX_HPH_BIAS_WG_OCP, TOMTOM_A_RX_HPH_BIAS_WG_OCP__POR },
-	{ TOMTOM_A_RX_HPH_OCP_CTL, TOMTOM_A_RX_HPH_OCP_CTL__POR },
-	{ TOMTOM_A_RX_HPH_CNP_EN, TOMTOM_A_RX_HPH_CNP_EN__POR },
-	{ TOMTOM_A_RX_HPH_CNP_WG_CTL, TOMTOM_A_RX_HPH_CNP_WG_CTL__POR },
-	{ TOMTOM_A_RX_HPH_CNP_WG_TIME, TOMTOM_A_RX_HPH_CNP_WG_TIME__POR },
-	{ TOMTOM_A_RX_HPH_L_GAIN, TOMTOM_A_RX_HPH_L_GAIN__POR },
-	{ TOMTOM_A_RX_HPH_L_TEST, TOMTOM_A_RX_HPH_L_TEST__POR },
-	{ TOMTOM_A_RX_HPH_L_PA_CTL, TOMTOM_A_RX_HPH_L_PA_CTL__POR },
-	{ TOMTOM_A_RX_HPH_L_DAC_CTL, TOMTOM_A_RX_HPH_L_DAC_CTL__POR },
-	{ TOMTOM_A_RX_HPH_L_ATEST, TOMTOM_A_RX_HPH_L_ATEST__POR },
-	{ TOMTOM_A_RX_HPH_L_STATUS, TOMTOM_A_RX_HPH_L_STATUS__POR },
-	{ TOMTOM_A_RX_HPH_R_GAIN, TOMTOM_A_RX_HPH_R_GAIN__POR },
-	{ TOMTOM_A_RX_HPH_R_TEST, TOMTOM_A_RX_HPH_R_TEST__POR },
-	{ TOMTOM_A_RX_HPH_R_PA_CTL, TOMTOM_A_RX_HPH_R_PA_CTL__POR },
-	{ TOMTOM_A_RX_HPH_R_DAC_CTL, TOMTOM_A_RX_HPH_R_DAC_CTL__POR },
-	{ TOMTOM_A_RX_HPH_R_ATEST, TOMTOM_A_RX_HPH_R_ATEST__POR },
-	{ TOMTOM_A_RX_HPH_R_STATUS, TOMTOM_A_RX_HPH_R_STATUS__POR },
-	{ TOMTOM_A_RX_EAR_BIAS_PA, TOMTOM_A_RX_EAR_BIAS_PA__POR },
-	{ TOMTOM_A_RX_EAR_BIAS_CMBUFF, TOMTOM_A_RX_EAR_BIAS_CMBUFF__POR },
-	{ TOMTOM_A_RX_EAR_EN, TOMTOM_A_RX_EAR_EN__POR },
-	{ TOMTOM_A_RX_EAR_GAIN, TOMTOM_A_RX_EAR_GAIN__POR },
-	{ TOMTOM_A_RX_EAR_CMBUFF, TOMTOM_A_RX_EAR_CMBUFF__POR },
-	{ TOMTOM_A_RX_EAR_ICTL, TOMTOM_A_RX_EAR_ICTL__POR },
-	{ TOMTOM_A_RX_EAR_CCOMP, TOMTOM_A_RX_EAR_CCOMP__POR },
-	{ TOMTOM_A_RX_EAR_VCM, TOMTOM_A_RX_EAR_VCM__POR },
-	{ TOMTOM_A_RX_EAR_CNP, TOMTOM_A_RX_EAR_CNP__POR },
-	{ TOMTOM_A_RX_EAR_DAC_CTL_ATEST, TOMTOM_A_RX_EAR_DAC_CTL_ATEST__POR },
-	{ TOMTOM_A_RX_EAR_STATUS, TOMTOM_A_RX_EAR_STATUS__POR },
-	{ TOMTOM_A_RX_LINE_BIAS_PA, TOMTOM_A_RX_LINE_BIAS_PA__POR },
-	{ TOMTOM_A_RX_BUCK_BIAS1, TOMTOM_A_RX_BUCK_BIAS1__POR },
-	{ TOMTOM_A_RX_BUCK_BIAS2, TOMTOM_A_RX_BUCK_BIAS2__POR },
-	{ TOMTOM_A_RX_LINE_COM, TOMTOM_A_RX_LINE_COM__POR },
-	{ TOMTOM_A_RX_LINE_CNP_EN, TOMTOM_A_RX_LINE_CNP_EN__POR },
-	{ TOMTOM_A_RX_LINE_CNP_WG_CTL, TOMTOM_A_RX_LINE_CNP_WG_CTL__POR },
-	{ TOMTOM_A_RX_LINE_CNP_WG_TIME, TOMTOM_A_RX_LINE_CNP_WG_TIME__POR },
-	{ TOMTOM_A_RX_LINE_1_GAIN, TOMTOM_A_RX_LINE_1_GAIN__POR },
-	{ TOMTOM_A_RX_LINE_1_TEST, TOMTOM_A_RX_LINE_1_TEST__POR },
-	{ TOMTOM_A_RX_LINE_1_DAC_CTL, TOMTOM_A_RX_LINE_1_DAC_CTL__POR },
-	{ TOMTOM_A_RX_LINE_1_STATUS, TOMTOM_A_RX_LINE_1_STATUS__POR },
-	{ TOMTOM_A_RX_LINE_2_GAIN, TOMTOM_A_RX_LINE_2_GAIN__POR },
-	{ TOMTOM_A_RX_LINE_2_TEST, TOMTOM_A_RX_LINE_2_TEST__POR },
-	{ TOMTOM_A_RX_LINE_2_DAC_CTL, TOMTOM_A_RX_LINE_2_DAC_CTL__POR },
-	{ TOMTOM_A_RX_LINE_2_STATUS, TOMTOM_A_RX_LINE_2_STATUS__POR },
-	{ TOMTOM_A_RX_LINE_3_GAIN, TOMTOM_A_RX_LINE_3_GAIN__POR },
-	{ TOMTOM_A_RX_LINE_3_TEST, TOMTOM_A_RX_LINE_3_TEST__POR },
-	{ TOMTOM_A_RX_LINE_3_DAC_CTL, TOMTOM_A_RX_LINE_3_DAC_CTL__POR },
-	{ TOMTOM_A_RX_LINE_3_STATUS, TOMTOM_A_RX_LINE_3_STATUS__POR },
-	{ TOMTOM_A_RX_LINE_4_GAIN, TOMTOM_A_RX_LINE_4_GAIN__POR },
-	{ TOMTOM_A_RX_LINE_4_TEST, TOMTOM_A_RX_LINE_4_TEST__POR },
-	{ TOMTOM_A_RX_LINE_4_DAC_CTL, TOMTOM_A_RX_LINE_4_DAC_CTL__POR },
-	{ TOMTOM_A_RX_LINE_4_STATUS, TOMTOM_A_RX_LINE_4_STATUS__POR },
-	{ TOMTOM_A_RX_LINE_CNP_DBG, TOMTOM_A_RX_LINE_CNP_DBG__POR },
-	{ TOMTOM_A_SPKR_DRV1_EN, TOMTOM_A_SPKR_DRV1_EN__POR },
-	{ TOMTOM_A_SPKR_DRV1_GAIN, TOMTOM_A_SPKR_DRV1_GAIN__POR },
-	{ TOMTOM_A_SPKR_DRV1_DAC_CTL, TOMTOM_A_SPKR_DRV1_DAC_CTL__POR },
-	{ TOMTOM_A_SPKR_DRV1_OCP_CTL, TOMTOM_A_SPKR_DRV1_OCP_CTL__POR },
-	{ TOMTOM_A_SPKR_DRV1_CLIP_DET, TOMTOM_A_SPKR_DRV1_CLIP_DET__POR },
-	{ TOMTOM_A_SPKR_DRV1_IEC, TOMTOM_A_SPKR_DRV1_IEC__POR },
-	{ TOMTOM_A_SPKR_DRV1_DBG_DAC, TOMTOM_A_SPKR_DRV1_DBG_DAC__POR },
-	{ TOMTOM_A_SPKR_DRV1_DBG_PA, TOMTOM_A_SPKR_DRV1_DBG_PA__POR },
-	{ TOMTOM_A_SPKR_DRV1_DBG_PWRSTG, TOMTOM_A_SPKR_DRV1_DBG_PWRSTG__POR },
-	{ TOMTOM_A_SPKR_DRV1_BIAS_LDO, TOMTOM_A_SPKR_DRV1_BIAS_LDO__POR },
-	{ TOMTOM_A_SPKR_DRV1_BIAS_INT, TOMTOM_A_SPKR_DRV1_BIAS_INT__POR },
-	{ TOMTOM_A_SPKR_DRV1_BIAS_PA, TOMTOM_A_SPKR_DRV1_BIAS_PA__POR },
-	{ TOMTOM_A_SPKR_DRV1_STATUS_OCP, TOMTOM_A_SPKR_DRV1_STATUS_OCP__POR },
-	{ TOMTOM_A_SPKR_DRV1_STATUS_PA, TOMTOM_A_SPKR_DRV1_STATUS_PA__POR },
-	{ TOMTOM_A_SPKR1_PROT_EN, TOMTOM_A_SPKR1_PROT_EN__POR },
-	{ TOMTOM_A_SPKR1_PROT_ADC_TEST_EN,
-				TOMTOM_A_SPKR1_PROT_ADC_TEST_EN__POR },
-	{ TOMTOM_A_SPKR1_PROT_ATEST, TOMTOM_A_SPKR1_PROT_ATEST__POR },
-	{ TOMTOM_A_SPKR1_PROT_LDO_CTRL, TOMTOM_A_SPKR1_PROT_LDO_CTRL__POR },
-	{ TOMTOM_A_SPKR1_PROT_ISENSE_CTRL,
-				TOMTOM_A_SPKR1_PROT_ISENSE_CTRL__POR },
-	{ TOMTOM_A_SPKR1_PROT_VSENSE_CTRL,
-				TOMTOM_A_SPKR1_PROT_VSENSE_CTRL__POR },
-	{ TOMTOM_A_SPKR2_PROT_EN, TOMTOM_A_SPKR2_PROT_EN__POR },
-	{ TOMTOM_A_SPKR2_PROT_ADC_TEST_EN,
-				TOMTOM_A_SPKR2_PROT_ADC_TEST_EN__POR },
-	{ TOMTOM_A_SPKR2_PROT_ATEST, TOMTOM_A_SPKR2_PROT_ATEST__POR },
-	{ TOMTOM_A_SPKR2_PROT_LDO_CTRL, TOMTOM_A_SPKR2_PROT_LDO_CTRL__POR },
-	{ TOMTOM_A_SPKR2_PROT_ISENSE_CTRL,
-				TOMTOM_A_SPKR2_PROT_ISENSE_CTRL__POR },
-	{ TOMTOM_A_SPKR2_PROT_VSENSE_CTRL,
-				TOMTOM_A_SPKR2_PROT_VSENSE_CTRL__POR },
-	{ TOMTOM_A_MBHC_HPH, TOMTOM_A_MBHC_HPH__POR },
-	{ TOMTOM_A_CDC_ANC1_B1_CTL, TOMTOM_A_CDC_ANC1_B1_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_B1_CTL, TOMTOM_A_CDC_ANC2_B1_CTL__POR },
-	{ TOMTOM_A_CDC_ANC1_SHIFT, TOMTOM_A_CDC_ANC1_SHIFT__POR },
-	{ TOMTOM_A_CDC_ANC2_SHIFT, TOMTOM_A_CDC_ANC2_SHIFT__POR },
-	{ TOMTOM_A_CDC_ANC1_IIR_B1_CTL, TOMTOM_A_CDC_ANC1_IIR_B1_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_IIR_B1_CTL, TOMTOM_A_CDC_ANC2_IIR_B1_CTL__POR },
-	{ TOMTOM_A_CDC_ANC1_IIR_B2_CTL, TOMTOM_A_CDC_ANC1_IIR_B2_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_IIR_B2_CTL, TOMTOM_A_CDC_ANC2_IIR_B2_CTL__POR },
-	{ TOMTOM_A_CDC_ANC1_IIR_B3_CTL, TOMTOM_A_CDC_ANC1_IIR_B3_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_IIR_B3_CTL, TOMTOM_A_CDC_ANC2_IIR_B3_CTL__POR },
-	{ TOMTOM_A_CDC_ANC1_LPF_B1_CTL, TOMTOM_A_CDC_ANC1_LPF_B1_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_LPF_B1_CTL, TOMTOM_A_CDC_ANC2_LPF_B1_CTL__POR },
-	{ TOMTOM_A_CDC_ANC1_LPF_B2_CTL, TOMTOM_A_CDC_ANC1_LPF_B2_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_LPF_B2_CTL, TOMTOM_A_CDC_ANC2_LPF_B2_CTL__POR },
-	{ TOMTOM_A_CDC_ANC1_SPARE, TOMTOM_A_CDC_ANC1_SPARE__POR },
-	{ TOMTOM_A_CDC_ANC2_SPARE, TOMTOM_A_CDC_ANC2_SPARE__POR },
-	{ TOMTOM_A_CDC_ANC1_SMLPF_CTL, TOMTOM_A_CDC_ANC1_SMLPF_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_SMLPF_CTL, TOMTOM_A_CDC_ANC2_SMLPF_CTL__POR },
-	{ TOMTOM_A_CDC_ANC1_DCFLT_CTL, TOMTOM_A_CDC_ANC1_DCFLT_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_DCFLT_CTL, TOMTOM_A_CDC_ANC2_DCFLT_CTL__POR },
-	{ TOMTOM_A_CDC_ANC1_GAIN_CTL, TOMTOM_A_CDC_ANC1_GAIN_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_GAIN_CTL, TOMTOM_A_CDC_ANC2_GAIN_CTL__POR },
-	{ TOMTOM_A_CDC_ANC1_B2_CTL, TOMTOM_A_CDC_ANC1_B2_CTL__POR },
-	{ TOMTOM_A_CDC_ANC2_B2_CTL, TOMTOM_A_CDC_ANC2_B2_CTL__POR },
-	{ TOMTOM_A_CDC_TX1_VOL_CTL_TIMER, TOMTOM_A_CDC_TX1_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX2_VOL_CTL_TIMER, TOMTOM_A_CDC_TX2_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX3_VOL_CTL_TIMER, TOMTOM_A_CDC_TX3_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX4_VOL_CTL_TIMER, TOMTOM_A_CDC_TX4_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX5_VOL_CTL_TIMER, TOMTOM_A_CDC_TX5_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX6_VOL_CTL_TIMER, TOMTOM_A_CDC_TX6_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX7_VOL_CTL_TIMER, TOMTOM_A_CDC_TX7_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX8_VOL_CTL_TIMER, TOMTOM_A_CDC_TX8_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX9_VOL_CTL_TIMER, TOMTOM_A_CDC_TX9_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX10_VOL_CTL_TIMER,
-				TOMTOM_A_CDC_TX10_VOL_CTL_TIMER__POR },
-	{ TOMTOM_A_CDC_TX1_VOL_CTL_GAIN, TOMTOM_A_CDC_TX1_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX2_VOL_CTL_GAIN, TOMTOM_A_CDC_TX2_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX3_VOL_CTL_GAIN, TOMTOM_A_CDC_TX3_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX4_VOL_CTL_GAIN, TOMTOM_A_CDC_TX4_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX5_VOL_CTL_GAIN, TOMTOM_A_CDC_TX5_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX6_VOL_CTL_GAIN, TOMTOM_A_CDC_TX6_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX7_VOL_CTL_GAIN, TOMTOM_A_CDC_TX7_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX8_VOL_CTL_GAIN, TOMTOM_A_CDC_TX8_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX9_VOL_CTL_GAIN, TOMTOM_A_CDC_TX9_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX10_VOL_CTL_GAIN, TOMTOM_A_CDC_TX10_VOL_CTL_GAIN__POR },
-	{ TOMTOM_A_CDC_TX1_VOL_CTL_CFG, TOMTOM_A_CDC_TX1_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX2_VOL_CTL_CFG, TOMTOM_A_CDC_TX2_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX3_VOL_CTL_CFG, TOMTOM_A_CDC_TX3_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX4_VOL_CTL_CFG, TOMTOM_A_CDC_TX4_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX5_VOL_CTL_CFG, TOMTOM_A_CDC_TX5_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX6_VOL_CTL_CFG, TOMTOM_A_CDC_TX6_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX7_VOL_CTL_CFG, TOMTOM_A_CDC_TX7_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX8_VOL_CTL_CFG, TOMTOM_A_CDC_TX8_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX9_VOL_CTL_CFG, TOMTOM_A_CDC_TX9_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX10_VOL_CTL_CFG, TOMTOM_A_CDC_TX10_VOL_CTL_CFG__POR },
-	{ TOMTOM_A_CDC_TX1_MUX_CTL, TOMTOM_A_CDC_TX1_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX2_MUX_CTL, TOMTOM_A_CDC_TX2_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX3_MUX_CTL, TOMTOM_A_CDC_TX3_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX4_MUX_CTL, TOMTOM_A_CDC_TX4_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX5_MUX_CTL, TOMTOM_A_CDC_TX5_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX6_MUX_CTL, TOMTOM_A_CDC_TX6_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX7_MUX_CTL, TOMTOM_A_CDC_TX7_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX8_MUX_CTL, TOMTOM_A_CDC_TX8_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX9_MUX_CTL, TOMTOM_A_CDC_TX9_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX10_MUX_CTL, TOMTOM_A_CDC_TX10_MUX_CTL__POR },
-	{ TOMTOM_A_CDC_TX1_CLK_FS_CTL, TOMTOM_A_CDC_TX1_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX2_CLK_FS_CTL, TOMTOM_A_CDC_TX2_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX3_CLK_FS_CTL, TOMTOM_A_CDC_TX3_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX4_CLK_FS_CTL, TOMTOM_A_CDC_TX4_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX5_CLK_FS_CTL, TOMTOM_A_CDC_TX5_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX6_CLK_FS_CTL, TOMTOM_A_CDC_TX6_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX7_CLK_FS_CTL, TOMTOM_A_CDC_TX7_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX8_CLK_FS_CTL, TOMTOM_A_CDC_TX8_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX9_CLK_FS_CTL, TOMTOM_A_CDC_TX9_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX10_CLK_FS_CTL, TOMTOM_A_CDC_TX10_CLK_FS_CTL__POR },
-	{ TOMTOM_A_CDC_TX1_DMIC_CTL, TOMTOM_A_CDC_TX1_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_TX2_DMIC_CTL, TOMTOM_A_CDC_TX2_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_TX3_DMIC_CTL, TOMTOM_A_CDC_TX3_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_TX4_DMIC_CTL, TOMTOM_A_CDC_TX4_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_TX5_DMIC_CTL, TOMTOM_A_CDC_TX5_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_TX6_DMIC_CTL, TOMTOM_A_CDC_TX6_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_TX7_DMIC_CTL, TOMTOM_A_CDC_TX7_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_TX8_DMIC_CTL, TOMTOM_A_CDC_TX8_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_TX9_DMIC_CTL, TOMTOM_A_CDC_TX9_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_TX10_DMIC_CTL, TOMTOM_A_CDC_TX10_DMIC_CTL__POR },
-	{ TOMTOM_A_CDC_SPKR_CLIPDET_VAL0, TOMTOM_A_CDC_SPKR_CLIPDET_VAL0__POR },
-	{ TOMTOM_A_CDC_SPKR_CLIPDET_VAL1, TOMTOM_A_CDC_SPKR_CLIPDET_VAL1__POR },
-	{ TOMTOM_A_CDC_SPKR_CLIPDET_VAL2, TOMTOM_A_CDC_SPKR_CLIPDET_VAL2__POR },
-	{ TOMTOM_A_CDC_SPKR_CLIPDET_VAL3, TOMTOM_A_CDC_SPKR_CLIPDET_VAL3__POR },
-	{ TOMTOM_A_CDC_SPKR_CLIPDET_VAL4, TOMTOM_A_CDC_SPKR_CLIPDET_VAL4__POR },
-	{ TOMTOM_A_CDC_SPKR_CLIPDET_VAL5, TOMTOM_A_CDC_SPKR_CLIPDET_VAL5__POR },
-	{ TOMTOM_A_CDC_SPKR_CLIPDET_VAL6, TOMTOM_A_CDC_SPKR_CLIPDET_VAL6__POR },
-	{ TOMTOM_A_CDC_SPKR_CLIPDET_VAL7, TOMTOM_A_CDC_SPKR_CLIPDET_VAL7__POR },
-	{ TOMTOM_A_CDC_DEBUG_B1_CTL, TOMTOM_A_CDC_DEBUG_B1_CTL__POR },
-	{ TOMTOM_A_CDC_DEBUG_B2_CTL, TOMTOM_A_CDC_DEBUG_B2_CTL__POR },
-	{ TOMTOM_A_CDC_DEBUG_B3_CTL, TOMTOM_A_CDC_DEBUG_B3_CTL__POR },
-	{ TOMTOM_A_CDC_DEBUG_B4_CTL, TOMTOM_A_CDC_DEBUG_B4_CTL__POR },
-	{ TOMTOM_A_CDC_DEBUG_B5_CTL, TOMTOM_A_CDC_DEBUG_B5_CTL__POR },
-	{ TOMTOM_A_CDC_DEBUG_B6_CTL, TOMTOM_A_CDC_DEBUG_B6_CTL__POR },
-	{ TOMTOM_A_CDC_DEBUG_B7_CTL, TOMTOM_A_CDC_DEBUG_B7_CTL__POR },
-	{ TOMTOM_A_CDC_SRC1_PDA_CFG, TOMTOM_A_CDC_SRC1_PDA_CFG__POR },
-	{ TOMTOM_A_CDC_SRC2_PDA_CFG, TOMTOM_A_CDC_SRC2_PDA_CFG__POR },
-	{ TOMTOM_A_CDC_SRC1_FS_CTL, TOMTOM_A_CDC_SRC1_FS_CTL__POR },
-	{ TOMTOM_A_CDC_SRC2_FS_CTL, TOMTOM_A_CDC_SRC2_FS_CTL__POR },
-	{ TOMTOM_A_CDC_RX1_B1_CTL, TOMTOM_A_CDC_RX1_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX2_B1_CTL, TOMTOM_A_CDC_RX2_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX3_B1_CTL, TOMTOM_A_CDC_RX3_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX4_B1_CTL, TOMTOM_A_CDC_RX4_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX5_B1_CTL, TOMTOM_A_CDC_RX5_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX6_B1_CTL, TOMTOM_A_CDC_RX6_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX7_B1_CTL, TOMTOM_A_CDC_RX7_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX1_B2_CTL, TOMTOM_A_CDC_RX1_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX2_B2_CTL, TOMTOM_A_CDC_RX2_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX3_B2_CTL, TOMTOM_A_CDC_RX3_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX4_B2_CTL, TOMTOM_A_CDC_RX4_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX5_B2_CTL, TOMTOM_A_CDC_RX5_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX6_B2_CTL, TOMTOM_A_CDC_RX6_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX7_B2_CTL, TOMTOM_A_CDC_RX7_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX1_B3_CTL, TOMTOM_A_CDC_RX1_B3_CTL__POR },
-	{ TOMTOM_A_CDC_RX2_B3_CTL, TOMTOM_A_CDC_RX2_B3_CTL__POR },
-	{ TOMTOM_A_CDC_RX3_B3_CTL, TOMTOM_A_CDC_RX3_B3_CTL__POR },
-	{ TOMTOM_A_CDC_RX4_B3_CTL, TOMTOM_A_CDC_RX4_B3_CTL__POR },
-	{ TOMTOM_A_CDC_RX5_B3_CTL, TOMTOM_A_CDC_RX5_B3_CTL__POR },
-	{ TOMTOM_A_CDC_RX6_B3_CTL, TOMTOM_A_CDC_RX6_B3_CTL__POR },
-	{ TOMTOM_A_CDC_RX7_B3_CTL, TOMTOM_A_CDC_RX7_B3_CTL__POR },
-	{ TOMTOM_A_CDC_RX1_B4_CTL, TOMTOM_A_CDC_RX1_B4_CTL__POR },
-	{ TOMTOM_A_CDC_RX2_B4_CTL, TOMTOM_A_CDC_RX2_B4_CTL__POR },
-	{ TOMTOM_A_CDC_RX3_B4_CTL, TOMTOM_A_CDC_RX3_B4_CTL__POR },
-	{ TOMTOM_A_CDC_RX4_B4_CTL, TOMTOM_A_CDC_RX4_B4_CTL__POR },
-	{ TOMTOM_A_CDC_RX5_B4_CTL, TOMTOM_A_CDC_RX5_B4_CTL__POR },
-	{ TOMTOM_A_CDC_RX6_B4_CTL, TOMTOM_A_CDC_RX6_B4_CTL__POR },
-	{ TOMTOM_A_CDC_RX7_B4_CTL, TOMTOM_A_CDC_RX7_B4_CTL__POR },
-	{ TOMTOM_A_CDC_RX1_B5_CTL, TOMTOM_A_CDC_RX1_B5_CTL__POR },
-	{ TOMTOM_A_CDC_RX2_B5_CTL, TOMTOM_A_CDC_RX2_B5_CTL__POR },
-	{ TOMTOM_A_CDC_RX3_B5_CTL, TOMTOM_A_CDC_RX3_B5_CTL__POR },
-	{ TOMTOM_A_CDC_RX4_B5_CTL, TOMTOM_A_CDC_RX4_B5_CTL__POR },
-	{ TOMTOM_A_CDC_RX5_B5_CTL, TOMTOM_A_CDC_RX5_B5_CTL__POR },
-	{ TOMTOM_A_CDC_RX6_B5_CTL, TOMTOM_A_CDC_RX6_B5_CTL__POR },
-	{ TOMTOM_A_CDC_RX7_B5_CTL, TOMTOM_A_CDC_RX7_B5_CTL__POR },
-	{ TOMTOM_A_CDC_RX1_B6_CTL, TOMTOM_A_CDC_RX1_B6_CTL__POR },
-	{ TOMTOM_A_CDC_RX2_B6_CTL, TOMTOM_A_CDC_RX2_B6_CTL__POR },
-	{ TOMTOM_A_CDC_RX3_B6_CTL, TOMTOM_A_CDC_RX3_B6_CTL__POR },
-	{ TOMTOM_A_CDC_RX4_B6_CTL, TOMTOM_A_CDC_RX4_B6_CTL__POR },
-	{ TOMTOM_A_CDC_RX5_B6_CTL, TOMTOM_A_CDC_RX5_B6_CTL__POR },
-	{ TOMTOM_A_CDC_RX6_B6_CTL, TOMTOM_A_CDC_RX6_B6_CTL__POR },
-	{ TOMTOM_A_CDC_RX7_B6_CTL, TOMTOM_A_CDC_RX7_B6_CTL__POR },
-	{ TOMTOM_A_CDC_RX1_VOL_CTL_B1_CTL,
-				TOMTOM_A_CDC_RX1_VOL_CTL_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX2_VOL_CTL_B1_CTL,
-				TOMTOM_A_CDC_RX2_VOL_CTL_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX3_VOL_CTL_B1_CTL,
-				TOMTOM_A_CDC_RX3_VOL_CTL_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX4_VOL_CTL_B1_CTL,
-				TOMTOM_A_CDC_RX4_VOL_CTL_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX5_VOL_CTL_B1_CTL,
-				TOMTOM_A_CDC_RX5_VOL_CTL_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX6_VOL_CTL_B1_CTL,
-				TOMTOM_A_CDC_RX6_VOL_CTL_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX7_VOL_CTL_B1_CTL,
-				TOMTOM_A_CDC_RX7_VOL_CTL_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL,
-				TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL,
-				TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL,
-				TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL,
-				TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL,
-				TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL,
-				TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL,
-				TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL__POR },
-	{ TOMTOM_A_CDC_VBAT_CFG, TOMTOM_A_CDC_VBAT_CFG__POR },
-	{ TOMTOM_A_CDC_VBAT_ADC_CAL1, TOMTOM_A_CDC_VBAT_ADC_CAL1__POR },
-	{ TOMTOM_A_CDC_VBAT_ADC_CAL2, TOMTOM_A_CDC_VBAT_ADC_CAL2__POR },
-	{ TOMTOM_A_CDC_VBAT_ADC_CAL3, TOMTOM_A_CDC_VBAT_ADC_CAL3__POR },
-	{ TOMTOM_A_CDC_VBAT_PK_EST1, TOMTOM_A_CDC_VBAT_PK_EST1__POR },
-	{ TOMTOM_A_CDC_VBAT_PK_EST2, TOMTOM_A_CDC_VBAT_PK_EST2__POR },
-	{ TOMTOM_A_CDC_VBAT_PK_EST3, TOMTOM_A_CDC_VBAT_PK_EST3__POR },
-	{ TOMTOM_A_CDC_VBAT_RF_PROC1, TOMTOM_A_CDC_VBAT_RF_PROC1__POR },
-	{ TOMTOM_A_CDC_VBAT_RF_PROC2, TOMTOM_A_CDC_VBAT_RF_PROC2__POR },
-	{ TOMTOM_A_CDC_VBAT_TAC1, TOMTOM_A_CDC_VBAT_TAC1__POR },
-	{ TOMTOM_A_CDC_VBAT_TAC2, TOMTOM_A_CDC_VBAT_TAC2__POR },
-	{ TOMTOM_A_CDC_VBAT_TAC3, TOMTOM_A_CDC_VBAT_TAC3__POR },
-	{ TOMTOM_A_CDC_VBAT_TAC4, TOMTOM_A_CDC_VBAT_TAC4__POR },
-	{ TOMTOM_A_CDC_VBAT_GAIN_UPD1, TOMTOM_A_CDC_VBAT_GAIN_UPD1__POR },
-	{ TOMTOM_A_CDC_VBAT_GAIN_UPD2, TOMTOM_A_CDC_VBAT_GAIN_UPD2__POR },
-	{ TOMTOM_A_CDC_VBAT_GAIN_UPD3, TOMTOM_A_CDC_VBAT_GAIN_UPD3__POR },
-	{ TOMTOM_A_CDC_VBAT_GAIN_UPD4, TOMTOM_A_CDC_VBAT_GAIN_UPD4__POR },
-	{ TOMTOM_A_CDC_VBAT_DEBUG1, TOMTOM_A_CDC_VBAT_DEBUG1__POR },
-	{ TOMTOM_A_CDC_VBAT_GAIN_UPD_MON, TOMTOM_A_CDC_VBAT_GAIN_UPD_MON__POR },
-	{ TOMTOM_A_CDC_VBAT_GAIN_MON_VAL, TOMTOM_A_CDC_VBAT_GAIN_MON_VAL__POR },
-	{ TOMTOM_A_CDC_CLK_ANC_RESET_CTL, TOMTOM_A_CDC_CLK_ANC_RESET_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_RX_RESET_CTL, TOMTOM_A_CDC_CLK_RX_RESET_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_TX_RESET_B1_CTL,
-				TOMTOM_A_CDC_CLK_TX_RESET_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_TX_RESET_B2_CTL,
-				TOMTOM_A_CDC_CLK_TX_RESET_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_RX_I2S_CTL, TOMTOM_A_CDC_CLK_RX_I2S_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_TX_I2S_CTL, TOMTOM_A_CDC_CLK_TX_I2S_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_OTHR_RESET_B1_CTL,
-				TOMTOM_A_CDC_CLK_OTHR_RESET_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL,
-				TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL,
-				TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL,
-				TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_OTHR_CTL, TOMTOM_A_CDC_CLK_OTHR_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_ANC_CLK_EN_CTL,
-				TOMTOM_A_CDC_CLK_ANC_CLK_EN_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_RX_B1_CTL, TOMTOM_A_CDC_CLK_RX_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_RX_B2_CTL, TOMTOM_A_CDC_CLK_RX_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_MCLK_CTL, TOMTOM_A_CDC_CLK_MCLK_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_PDM_CTL, TOMTOM_A_CDC_CLK_PDM_CTL__POR },
-	{ TOMTOM_A_CDC_CLK_SD_CTL, TOMTOM_A_CDC_CLK_SD_CTL__POR },
-	{ TOMTOM_A_CDC_CLSH_B1_CTL, TOMTOM_A_CDC_CLSH_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CLSH_B2_CTL, TOMTOM_A_CDC_CLSH_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CLSH_B3_CTL, TOMTOM_A_CDC_CLSH_B3_CTL__POR },
-	{ TOMTOM_A_CDC_CLSH_BUCK_NCP_VARS,
-				TOMTOM_A_CDC_CLSH_BUCK_NCP_VARS__POR },
-	{ TOMTOM_A_CDC_CLSH_IDLE_HPH_THSD,
-				TOMTOM_A_CDC_CLSH_IDLE_HPH_THSD__POR },
-	{ TOMTOM_A_CDC_CLSH_IDLE_EAR_THSD,
-				TOMTOM_A_CDC_CLSH_IDLE_EAR_THSD__POR },
-	{ TOMTOM_A_CDC_CLSH_FCLKONLY_HPH_THSD,
-				TOMTOM_A_CDC_CLSH_FCLKONLY_HPH_THSD__POR },
-	{ TOMTOM_A_CDC_CLSH_FCLKONLY_EAR_THSD,
-				TOMTOM_A_CDC_CLSH_FCLKONLY_EAR_THSD__POR },
-	{ TOMTOM_A_CDC_CLSH_K_ADDR, TOMTOM_A_CDC_CLSH_K_ADDR__POR },
-	{ TOMTOM_A_CDC_CLSH_K_DATA, TOMTOM_A_CDC_CLSH_K_DATA__POR },
-	{ TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_L,
-				TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_L__POR },
-	{ TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_U,
-				TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_U__POR },
-	{ TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_L,
-				TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_L__POR },
-	{ TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_U,
-				TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_U__POR },
-	{ TOMTOM_A_CDC_CLSH_V_PA_HD_EAR, TOMTOM_A_CDC_CLSH_V_PA_HD_EAR__POR },
-	{ TOMTOM_A_CDC_CLSH_V_PA_HD_HPH, TOMTOM_A_CDC_CLSH_V_PA_HD_HPH__POR },
-	{ TOMTOM_A_CDC_CLSH_V_PA_MIN_EAR, TOMTOM_A_CDC_CLSH_V_PA_MIN_EAR__POR },
-	{ TOMTOM_A_CDC_CLSH_V_PA_MIN_HPH, TOMTOM_A_CDC_CLSH_V_PA_MIN_HPH__POR },
-	{ TOMTOM_A_CDC_IIR1_GAIN_B1_CTL, TOMTOM_A_CDC_IIR1_GAIN_B1_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_GAIN_B1_CTL, TOMTOM_A_CDC_IIR2_GAIN_B1_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_GAIN_B2_CTL, TOMTOM_A_CDC_IIR1_GAIN_B2_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_GAIN_B2_CTL, TOMTOM_A_CDC_IIR2_GAIN_B2_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_GAIN_B3_CTL, TOMTOM_A_CDC_IIR1_GAIN_B3_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_GAIN_B3_CTL, TOMTOM_A_CDC_IIR2_GAIN_B3_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_GAIN_B4_CTL, TOMTOM_A_CDC_IIR1_GAIN_B4_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_GAIN_B4_CTL, TOMTOM_A_CDC_IIR2_GAIN_B4_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_GAIN_B5_CTL, TOMTOM_A_CDC_IIR1_GAIN_B5_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_GAIN_B5_CTL, TOMTOM_A_CDC_IIR2_GAIN_B5_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_GAIN_B6_CTL, TOMTOM_A_CDC_IIR1_GAIN_B6_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_GAIN_B6_CTL, TOMTOM_A_CDC_IIR2_GAIN_B6_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_GAIN_B7_CTL, TOMTOM_A_CDC_IIR1_GAIN_B7_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_GAIN_B7_CTL, TOMTOM_A_CDC_IIR2_GAIN_B7_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_GAIN_B8_CTL, TOMTOM_A_CDC_IIR1_GAIN_B8_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_GAIN_B8_CTL, TOMTOM_A_CDC_IIR2_GAIN_B8_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_CTL, TOMTOM_A_CDC_IIR1_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_CTL, TOMTOM_A_CDC_IIR2_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_GAIN_TIMER_CTL,
-				TOMTOM_A_CDC_IIR1_GAIN_TIMER_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_GAIN_TIMER_CTL,
-				TOMTOM_A_CDC_IIR2_GAIN_TIMER_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_COEF_B1_CTL, TOMTOM_A_CDC_IIR1_COEF_B1_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_COEF_B1_CTL, TOMTOM_A_CDC_IIR2_COEF_B1_CTL__POR },
-	{ TOMTOM_A_CDC_IIR1_COEF_B2_CTL, TOMTOM_A_CDC_IIR1_COEF_B2_CTL__POR },
-	{ TOMTOM_A_CDC_IIR2_COEF_B2_CTL, TOMTOM_A_CDC_IIR2_COEF_B2_CTL__POR },
-	{ TOMTOM_A_CDC_TOP_GAIN_UPDATE, TOMTOM_A_CDC_TOP_GAIN_UPDATE__POR },
-	{ TOMTOM_A_CDC_PA_RAMP_B1_CTL, TOMTOM_A_CDC_PA_RAMP_B1_CTL__POR },
-	{ TOMTOM_A_CDC_PA_RAMP_B2_CTL, TOMTOM_A_CDC_PA_RAMP_B2_CTL__POR },
-	{ TOMTOM_A_CDC_PA_RAMP_B3_CTL, TOMTOM_A_CDC_PA_RAMP_B3_CTL__POR },
-	{ TOMTOM_A_CDC_PA_RAMP_B4_CTL, TOMTOM_A_CDC_PA_RAMP_B4_CTL__POR },
-	{ TOMTOM_A_CDC_SPKR_CLIPDET_B1_CTL,
-				TOMTOM_A_CDC_SPKR_CLIPDET_B1_CTL__POR },
-	{ TOMTOM_A_CDC_SPKR2_CLIPDET_B1_CTL,
-				TOMTOM_A_CDC_SPKR2_CLIPDET_B1_CTL__POR },
-	{ TOMTOM_A_CDC_COMP0_B1_CTL, TOMTOM_A_CDC_COMP0_B1_CTL__POR },
-	{ TOMTOM_A_CDC_COMP1_B1_CTL, TOMTOM_A_CDC_COMP1_B1_CTL__POR },
-	{ TOMTOM_A_CDC_COMP2_B1_CTL, TOMTOM_A_CDC_COMP2_B1_CTL__POR },
-	{ TOMTOM_A_CDC_COMP0_B2_CTL, TOMTOM_A_CDC_COMP0_B2_CTL__POR },
-	{ TOMTOM_A_CDC_COMP1_B2_CTL, TOMTOM_A_CDC_COMP1_B2_CTL__POR },
-	{ TOMTOM_A_CDC_COMP2_B2_CTL, TOMTOM_A_CDC_COMP2_B2_CTL__POR },
-	{ TOMTOM_A_CDC_COMP0_B3_CTL, TOMTOM_A_CDC_COMP0_B3_CTL__POR },
-	{ TOMTOM_A_CDC_COMP1_B3_CTL, TOMTOM_A_CDC_COMP1_B3_CTL__POR },
-	{ TOMTOM_A_CDC_COMP2_B3_CTL, TOMTOM_A_CDC_COMP2_B3_CTL__POR },
-	{ TOMTOM_A_CDC_COMP0_B4_CTL, TOMTOM_A_CDC_COMP0_B4_CTL__POR },
-	{ TOMTOM_A_CDC_COMP1_B4_CTL, TOMTOM_A_CDC_COMP1_B4_CTL__POR },
-	{ TOMTOM_A_CDC_COMP2_B4_CTL, TOMTOM_A_CDC_COMP2_B4_CTL__POR },
-	{ TOMTOM_A_CDC_COMP0_B5_CTL, TOMTOM_A_CDC_COMP0_B5_CTL__POR },
-	{ TOMTOM_A_CDC_COMP1_B5_CTL, TOMTOM_A_CDC_COMP1_B5_CTL__POR },
-	{ TOMTOM_A_CDC_COMP2_B5_CTL, TOMTOM_A_CDC_COMP2_B5_CTL__POR },
-	{ TOMTOM_A_CDC_COMP0_B6_CTL, TOMTOM_A_CDC_COMP0_B6_CTL__POR },
-	{ TOMTOM_A_CDC_COMP1_B6_CTL, TOMTOM_A_CDC_COMP1_B6_CTL__POR },
-	{ TOMTOM_A_CDC_COMP2_B6_CTL, TOMTOM_A_CDC_COMP2_B6_CTL__POR },
-	{ TOMTOM_A_CDC_COMP0_SHUT_DOWN_STATUS,
-				TOMTOM_A_CDC_COMP0_SHUT_DOWN_STATUS__POR },
-	{ TOMTOM_A_CDC_COMP1_SHUT_DOWN_STATUS,
-				TOMTOM_A_CDC_COMP1_SHUT_DOWN_STATUS__POR },
-	{ TOMTOM_A_CDC_COMP2_SHUT_DOWN_STATUS,
-				TOMTOM_A_CDC_COMP2_SHUT_DOWN_STATUS__POR },
-	{ TOMTOM_A_CDC_COMP0_FS_CFG, TOMTOM_A_CDC_COMP0_FS_CFG__POR },
-	{ TOMTOM_A_CDC_COMP1_FS_CFG, TOMTOM_A_CDC_COMP1_FS_CFG__POR },
-	{ TOMTOM_A_CDC_COMP2_FS_CFG, TOMTOM_A_CDC_COMP2_FS_CFG__POR },
-	{ TOMTOM_A_CDC_CONN_RX1_B1_CTL, TOMTOM_A_CDC_CONN_RX1_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX1_B2_CTL, TOMTOM_A_CDC_CONN_RX1_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX1_B3_CTL, TOMTOM_A_CDC_CONN_RX1_B3_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX2_B1_CTL, TOMTOM_A_CDC_CONN_RX2_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX2_B2_CTL, TOMTOM_A_CDC_CONN_RX2_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX2_B3_CTL, TOMTOM_A_CDC_CONN_RX2_B3_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX3_B1_CTL, TOMTOM_A_CDC_CONN_RX3_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX3_B2_CTL, TOMTOM_A_CDC_CONN_RX3_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX4_B1_CTL, TOMTOM_A_CDC_CONN_RX4_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX4_B2_CTL, TOMTOM_A_CDC_CONN_RX4_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX5_B1_CTL, TOMTOM_A_CDC_CONN_RX5_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX5_B2_CTL, TOMTOM_A_CDC_CONN_RX5_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX6_B1_CTL, TOMTOM_A_CDC_CONN_RX6_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX6_B2_CTL, TOMTOM_A_CDC_CONN_RX6_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX7_B1_CTL, TOMTOM_A_CDC_CONN_RX7_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX7_B2_CTL, TOMTOM_A_CDC_CONN_RX7_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX7_B3_CTL, TOMTOM_A_CDC_CONN_RX7_B3_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_ANC_B1_CTL, TOMTOM_A_CDC_CONN_ANC_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_ANC_B2_CTL, TOMTOM_A_CDC_CONN_ANC_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_B1_CTL, TOMTOM_A_CDC_CONN_TX_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_B2_CTL, TOMTOM_A_CDC_CONN_TX_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_B3_CTL, TOMTOM_A_CDC_CONN_TX_B3_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_B4_CTL, TOMTOM_A_CDC_CONN_TX_B4_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_EQ1_B1_CTL, TOMTOM_A_CDC_CONN_EQ1_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_EQ1_B2_CTL, TOMTOM_A_CDC_CONN_EQ1_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_EQ1_B3_CTL, TOMTOM_A_CDC_CONN_EQ1_B3_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_EQ1_B4_CTL, TOMTOM_A_CDC_CONN_EQ1_B4_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_EQ2_B1_CTL, TOMTOM_A_CDC_CONN_EQ2_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_EQ2_B2_CTL, TOMTOM_A_CDC_CONN_EQ2_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_EQ2_B3_CTL, TOMTOM_A_CDC_CONN_EQ2_B3_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_EQ2_B4_CTL, TOMTOM_A_CDC_CONN_EQ2_B4_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_SRC1_B1_CTL, TOMTOM_A_CDC_CONN_SRC1_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_SRC1_B2_CTL, TOMTOM_A_CDC_CONN_SRC1_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_SRC2_B1_CTL, TOMTOM_A_CDC_CONN_SRC2_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_SRC2_B2_CTL, TOMTOM_A_CDC_CONN_SRC2_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B1_CTL, TOMTOM_A_CDC_CONN_TX_SB_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B2_CTL, TOMTOM_A_CDC_CONN_TX_SB_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B3_CTL, TOMTOM_A_CDC_CONN_TX_SB_B3_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B4_CTL, TOMTOM_A_CDC_CONN_TX_SB_B4_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B5_CTL, TOMTOM_A_CDC_CONN_TX_SB_B5_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B6_CTL, TOMTOM_A_CDC_CONN_TX_SB_B6_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B7_CTL, TOMTOM_A_CDC_CONN_TX_SB_B7_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B8_CTL, TOMTOM_A_CDC_CONN_TX_SB_B8_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B9_CTL, TOMTOM_A_CDC_CONN_TX_SB_B9_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B10_CTL,
-				TOMTOM_A_CDC_CONN_TX_SB_B10_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_TX_SB_B11_CTL,
-				TOMTOM_A_CDC_CONN_TX_SB_B11_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX_SB_B1_CTL, TOMTOM_A_CDC_CONN_RX_SB_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_RX_SB_B2_CTL, TOMTOM_A_CDC_CONN_RX_SB_B2_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_CLSH_CTL, TOMTOM_A_CDC_CONN_CLSH_CTL__POR },
-	{ TOMTOM_A_CDC_CONN_MISC, TOMTOM_A_CDC_CONN_MISC__POR },
-	{ TOMTOM_A_CDC_CONN_RX8_B1_CTL, TOMTOM_A_CDC_CONN_RX8_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR_B1_CTL,
-				TOMTOM_A_CDC_CLIP_ADJ_SPKR_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR_CLIP_LEVEL_ADJUST,
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_CLIP_LEVEL_ADJUST__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR_MIN_CLIP_THRESHOLD,
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_MIN_CLIP_THRESHOLD__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR_THRESHOLD_STATUS,
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_THRESHOLD_STATUS__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR_SAMPLE_MARK,
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_SAMPLE_MARK__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR_BOOST_GATING,
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_BOOST_GATING__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR2_B1_CTL,
-				TOMTOM_A_CDC_CLIP_ADJ_SPKR2_B1_CTL__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR2_CLIP_LEVEL_ADJUST,
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR2_CLIP_LEVEL_ADJUST__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR2_MIN_CLIP_THRESHOLD,
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR2_MIN_CLIP_THRESHOLD__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR2_THRESHOLD_STATUS,
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR2_THRESHOLD_STATUS__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR2_SAMPLE_MARK,
-				TOMTOM_A_CDC_CLIP_ADJ_SPKR2_SAMPLE_MARK__POR },
-	{ TOMTOM_A_CDC_CLIP_ADJ_SPKR2_BOOST_GATING,
-				TOMTOM_A_CDC_CLIP_ADJ_SPKR2_BOOST_GATING__POR },
-	{ TOMTOM_A_CDC_MBHC_EN_CTL, TOMTOM_A_CDC_MBHC_EN_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_FIR_B1_CFG, TOMTOM_A_CDC_MBHC_FIR_B1_CFG__POR },
-	{ TOMTOM_A_CDC_MBHC_FIR_B2_CFG, TOMTOM_A_CDC_MBHC_FIR_B2_CFG__POR },
-	{ TOMTOM_A_CDC_MBHC_TIMER_B1_CTL, TOMTOM_A_CDC_MBHC_TIMER_B1_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_TIMER_B2_CTL, TOMTOM_A_CDC_MBHC_TIMER_B2_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_TIMER_B3_CTL, TOMTOM_A_CDC_MBHC_TIMER_B3_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_TIMER_B4_CTL, TOMTOM_A_CDC_MBHC_TIMER_B4_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_TIMER_B5_CTL, TOMTOM_A_CDC_MBHC_TIMER_B5_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_TIMER_B6_CTL, TOMTOM_A_CDC_MBHC_TIMER_B6_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_B1_STATUS, TOMTOM_A_CDC_MBHC_B1_STATUS__POR },
-	{ TOMTOM_A_CDC_MBHC_B2_STATUS, TOMTOM_A_CDC_MBHC_B2_STATUS__POR },
-	{ TOMTOM_A_CDC_MBHC_B3_STATUS, TOMTOM_A_CDC_MBHC_B3_STATUS__POR },
-	{ TOMTOM_A_CDC_MBHC_B4_STATUS, TOMTOM_A_CDC_MBHC_B4_STATUS__POR },
-	{ TOMTOM_A_CDC_MBHC_B5_STATUS, TOMTOM_A_CDC_MBHC_B5_STATUS__POR },
-	{ TOMTOM_A_CDC_MBHC_B1_CTL, TOMTOM_A_CDC_MBHC_B1_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_B2_CTL, TOMTOM_A_CDC_MBHC_B2_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B1_CTL, TOMTOM_A_CDC_MBHC_VOLT_B1_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B2_CTL, TOMTOM_A_CDC_MBHC_VOLT_B2_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B3_CTL, TOMTOM_A_CDC_MBHC_VOLT_B3_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B4_CTL, TOMTOM_A_CDC_MBHC_VOLT_B4_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B5_CTL, TOMTOM_A_CDC_MBHC_VOLT_B5_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B6_CTL, TOMTOM_A_CDC_MBHC_VOLT_B6_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B7_CTL, TOMTOM_A_CDC_MBHC_VOLT_B7_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B8_CTL, TOMTOM_A_CDC_MBHC_VOLT_B8_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B9_CTL, TOMTOM_A_CDC_MBHC_VOLT_B9_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B10_CTL, TOMTOM_A_CDC_MBHC_VOLT_B10_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B11_CTL, TOMTOM_A_CDC_MBHC_VOLT_B11_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_VOLT_B12_CTL, TOMTOM_A_CDC_MBHC_VOLT_B12_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_CLK_CTL, TOMTOM_A_CDC_MBHC_CLK_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_INT_CTL, TOMTOM_A_CDC_MBHC_INT_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_DEBUG_CTL, TOMTOM_A_CDC_MBHC_DEBUG_CTL__POR },
-	{ TOMTOM_A_CDC_MBHC_SPARE, TOMTOM_A_CDC_MBHC_SPARE__POR },
-	{ TOMTOM_A_CDC_RX8_B1_CTL, TOMTOM_A_CDC_RX8_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX8_B2_CTL, TOMTOM_A_CDC_RX8_B2_CTL__POR },
-	{ TOMTOM_A_CDC_RX8_B3_CTL, TOMTOM_A_CDC_RX8_B3_CTL__POR },
-	{ TOMTOM_A_CDC_RX8_B4_CTL, TOMTOM_A_CDC_RX8_B4_CTL__POR },
-	{ TOMTOM_A_CDC_RX8_B5_CTL, TOMTOM_A_CDC_RX8_B5_CTL__POR },
-	{ TOMTOM_A_CDC_RX8_B6_CTL, TOMTOM_A_CDC_RX8_B6_CTL__POR },
-	{ TOMTOM_A_CDC_RX8_VOL_CTL_B1_CTL,
-				TOMTOM_A_CDC_RX8_VOL_CTL_B1_CTL__POR },
-	{ TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL,
-				TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL__POR },
-	{ TOMTOM_A_CDC_SPKR2_CLIPDET_VAL0,
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL0__POR },
-	{ TOMTOM_A_CDC_SPKR2_CLIPDET_VAL1,
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL1__POR },
-	{ TOMTOM_A_CDC_SPKR2_CLIPDET_VAL2,
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL2__POR },
-	{ TOMTOM_A_CDC_SPKR2_CLIPDET_VAL3,
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL3__POR },
-	{ TOMTOM_A_CDC_SPKR2_CLIPDET_VAL4,
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL4__POR },
-	{ TOMTOM_A_CDC_SPKR2_CLIPDET_VAL5,
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL5__POR },
-	{ TOMTOM_A_CDC_SPKR2_CLIPDET_VAL6,
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL6__POR },
-	{ TOMTOM_A_CDC_SPKR2_CLIPDET_VAL7,
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL7__POR },
-	{ TOMTOM_A_CDC_BOOST_MODE_CTL, TOMTOM_A_CDC_BOOST_MODE_CTL__POR },
-	{ TOMTOM_A_CDC_BOOST_THRESHOLD, TOMTOM_A_CDC_BOOST_THRESHOLD__POR },
-	{ TOMTOM_A_CDC_BOOST_TAP_SEL, TOMTOM_A_CDC_BOOST_TAP_SEL__POR },
-	{ TOMTOM_A_CDC_BOOST_HOLD_TIME, TOMTOM_A_CDC_BOOST_HOLD_TIME__POR },
-	{ TOMTOM_A_CDC_BOOST_TRGR_EN, TOMTOM_A_CDC_BOOST_TRGR_EN__POR },
-};
-
-static bool wcd9330_is_readable_register(struct device *dev, unsigned int reg)
-{
-	return tomtom_reg_readable[reg];
-}
-
-static bool tomtom_is_digital_gain_register(unsigned int reg)
-{
-	bool rtn = false;
-
-	switch (reg) {
-	case TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL:
-	case TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL:
-	case TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL:
-	case TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL:
-	case TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL:
-	case TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL:
-	case TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL:
-	case TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL:
-	case TOMTOM_A_CDC_TX1_VOL_CTL_GAIN:
-	case TOMTOM_A_CDC_TX2_VOL_CTL_GAIN:
-	case TOMTOM_A_CDC_TX3_VOL_CTL_GAIN:
-	case TOMTOM_A_CDC_TX4_VOL_CTL_GAIN:
-	case TOMTOM_A_CDC_TX5_VOL_CTL_GAIN:
-	case TOMTOM_A_CDC_TX6_VOL_CTL_GAIN:
-	case TOMTOM_A_CDC_TX7_VOL_CTL_GAIN:
-	case TOMTOM_A_CDC_TX8_VOL_CTL_GAIN:
-	case TOMTOM_A_CDC_TX9_VOL_CTL_GAIN:
-	case TOMTOM_A_CDC_TX10_VOL_CTL_GAIN:
-		rtn = true;
-		break;
-	default:
-		break;
-	}
-	return rtn;
-}
-
-static bool wcd9330_is_volatile_register(struct device *dev, unsigned int reg)
-{
-
-	if ((reg >= TOMTOM_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
-		return true;
-
-	/* IIR Coeff registers are not cacheable */
-	if ((reg >= TOMTOM_A_CDC_IIR1_COEF_B1_CTL) &&
-		(reg <= TOMTOM_A_CDC_IIR2_COEF_B2_CTL))
-		return true;
-
-	/* ANC filter registers are not cacheable */
-	if ((reg >= TOMTOM_A_CDC_ANC1_IIR_B1_CTL) &&
-		(reg <= TOMTOM_A_CDC_ANC1_LPF_B2_CTL))
-		return true;
-
-	if ((reg >= TOMTOM_A_CDC_ANC2_IIR_B1_CTL) &&
-		(reg <= TOMTOM_A_CDC_ANC2_LPF_B2_CTL))
-		return true;
-
-	if (((reg >= TOMTOM_A_CDC_SPKR_CLIPDET_VAL0 &&
-	    reg <= TOMTOM_A_CDC_SPKR_CLIPDET_VAL7)) ||
-	    ((reg >= TOMTOM_A_CDC_SPKR2_CLIPDET_VAL0) &&
-	     (reg <= TOMTOM_A_CDC_SPKR2_CLIPDET_VAL7)))
-		return true;
-
-	/* Digital gain register is not cacheable so we have to write
-	 * the setting even it is the same
-	 */
-	if (tomtom_is_digital_gain_register(reg))
-		return true;
-
-	switch (reg) {
-	case TOMTOM_A_RX_HPH_L_STATUS:
-	case TOMTOM_A_RX_HPH_R_STATUS:
-	case TOMTOM_A_MBHC_INSERT_DET_STATUS:
-	case TOMTOM_A_RX_HPH_CNP_EN:
-	case TOMTOM_A_CDC_VBAT_GAIN_MON_VAL:
-	case TOMTOM_A_CDC_MAD_MAIN_CTL_1:
-	case TOMTOM_A_CDC_MAD_AUDIO_CTL_3:
-	case TOMTOM_A_CDC_MAD_AUDIO_CTL_4:
-	case TOMTOM_A_INTR_MODE:
-	case TOMTOM_A_INTR2_MASK0:
-	case TOMTOM_A_INTR2_STATUS0:
-	case TOMTOM_A_INTR2_CLEAR0:
-	case TOMTOM_SB_PGD_PORT_TX_BASE:
-	case TOMTOM_SB_PGD_PORT_RX_BASE:
-	case TOMTOM_A_CDC_ANC1_IIR_B1_CTL:
-	case TOMTOM_A_CDC_ANC1_GAIN_CTL:
-	case TOMTOM_A_SVASS_SPE_INBOX_TRG:
-		return true;
-	default:
-		return false;
-	}
-}
-
-struct regmap_config wcd9330_regmap_config = {
-	.reg_bits = 16,
-	.val_bits = 8,
-	.cache_type = REGCACHE_RBTREE,
-	.reg_defaults = wcd9330_defaults,
-	.num_reg_defaults = ARRAY_SIZE(wcd9330_defaults),
-	.max_register = WCD9330_MAX_REGISTER,
-	.volatile_reg = wcd9330_is_volatile_register,
-	.readable_reg = wcd9330_is_readable_register,
-};
diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c
index e8ba149..27249ee 100644
--- a/drivers/mfd/wcd934x-regmap.c
+++ b/drivers/mfd/wcd934x-regmap.c
@@ -1937,7 +1937,6 @@
 	case WCD934X_BIAS_VBG_FINE_ADJ:
 	case WCD934X_CODEC_CPR_SVS_CX_VDD:
 	case WCD934X_CODEC_CPR_SVS2_CX_VDD:
-	case WCD934X_CDC_TOP_TOP_CFG1:
 	case WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
 		return true;
 	}
diff --git a/drivers/mfd/wcd9xxx-core-init.c b/drivers/mfd/wcd9xxx-core-init.c
new file mode 100644
index 0000000..7f93399
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-core-init.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
+#include <linux/mfd/wcd9xxx/core.h>
+
+#define NUM_DRIVERS_REG_RET 3
+
+static int __init wcd9xxx_core_init(void)
+{
+	int ret[NUM_DRIVERS_REG_RET] = {0};
+	int i = 0;
+
+	ret[0] = msm_cdc_pinctrl_drv_init();
+	if (ret[0])
+		pr_err("%s: Failed init pinctrl drv: %d\n", __func__, ret[0]);
+
+	ret[1] = wcd9xxx_irq_drv_init();
+	if (ret[1])
+		pr_err("%s: Failed init irq drv: %d\n", __func__, ret[1]);
+
+	ret[2] = wcd9xxx_init();
+	if (ret[2])
+		pr_err("%s: Failed wcd core drv: %d\n", __func__, ret[2]);
+
+	for (i = 0; i < NUM_DRIVERS_REG_RET; i++) {
+		if (ret[i])
+			return ret[i];
+	}
+
+	return 0;
+}
+module_init(wcd9xxx_core_init);
+
+static void __exit wcd9xxx_core_exit(void)
+{
+	wcd9xxx_exit();
+	wcd9xxx_irq_drv_exit();
+	msm_cdc_pinctrl_drv_exit();
+}
+module_exit(wcd9xxx_core_exit);
+
+MODULE_DESCRIPTION("WCD9XXX CODEC core init driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index d143536..b373acb 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -1665,7 +1665,7 @@
 	.remove                 =       wcd9xxx_i2c_remove,
 };
 
-static int __init wcd9xxx_init(void)
+int wcd9xxx_init(void)
 {
 	int ret[NUM_WCD9XXX_REG_RET] = {0};
 	int i = 0;
@@ -1699,9 +1699,8 @@
 
 	return 0;
 }
-module_init(wcd9xxx_init);
 
-static void __exit wcd9xxx_exit(void)
+void wcd9xxx_exit(void)
 {
 	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
 
@@ -1710,7 +1709,6 @@
 	i2c_del_driver(&wcd9335_i2c_driver);
 	slim_driver_unregister(&wcd_slim_driver);
 }
-module_exit(wcd9xxx_exit);
 
 MODULE_DESCRIPTION("Codec core driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 0502e39d..092f446 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -406,30 +406,63 @@
 		return IRQ_NONE;
 }
 
+/**
+ * wcd9xxx_free_irq
+ *
+ * @wcd9xxx_res: pointer to core resource
+ * irq: irq number
+ * @data: data pointer
+ *
+ */
 void wcd9xxx_free_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
 			int irq, void *data)
 {
 	free_irq(phyirq_to_virq(wcd9xxx_res, irq), data);
 }
+EXPORT_SYMBOL(wcd9xxx_free_irq);
 
+/**
+ * wcd9xxx_enable_irq
+ *
+ * @wcd9xxx_res: pointer to core resource
+ * irq: irq number
+ *
+ */
 void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
 	if (wcd9xxx_res->irq)
 		enable_irq(phyirq_to_virq(wcd9xxx_res, irq));
 }
+EXPORT_SYMBOL(wcd9xxx_enable_irq);
 
+/**
+ * wcd9xxx_disable_irq
+ *
+ * @wcd9xxx_res: pointer to core resource
+ * irq: irq number
+ *
+ */
 void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
 	if (wcd9xxx_res->irq)
 		disable_irq_nosync(phyirq_to_virq(wcd9xxx_res, irq));
 }
+EXPORT_SYMBOL(wcd9xxx_disable_irq);
 
+/**
+ * wcd9xxx_disable_irq_sync
+ *
+ * @wcd9xxx_res: pointer to core resource
+ * irq: irq number
+ *
+ */
 void wcd9xxx_disable_irq_sync(
 			struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
 	if (wcd9xxx_res->irq)
 		disable_irq(phyirq_to_virq(wcd9xxx_res, irq));
 }
+EXPORT_SYMBOL(wcd9xxx_disable_irq_sync);
 
 static int wcd9xxx_irq_setup_downstream_irq(
 			struct wcd9xxx_core_resource *wcd9xxx_res)
@@ -470,6 +503,13 @@
 	return 0;
 }
 
+/**
+ * wcd9xxx_irq_init
+ *
+ * @wcd9xxx_res: pointer to core resource
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
 int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	int i, ret;
@@ -568,6 +608,7 @@
 	mutex_destroy(&wcd9xxx_res->nested_irq_lock);
 	return ret;
 }
+EXPORT_SYMBOL(wcd9xxx_irq_init);
 
 int wcd9xxx_request_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
 			int irq, irq_handler_t handler,
@@ -580,6 +621,7 @@
 	return request_threaded_irq(virq, NULL, handler, IRQF_TRIGGER_RISING,
 				    name, data);
 }
+EXPORT_SYMBOL(wcd9xxx_request_irq);
 
 void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
@@ -799,15 +841,13 @@
 	},
 };
 
-static int wcd9xxx_irq_drv_init(void)
+int wcd9xxx_irq_drv_init(void)
 {
 	return platform_driver_register(&wcd9xxx_irq_driver);
 }
-subsys_initcall(wcd9xxx_irq_drv_init);
 
-static void wcd9xxx_irq_drv_exit(void)
+void wcd9xxx_irq_drv_exit(void)
 {
 	platform_driver_unregister(&wcd9xxx_irq_driver);
 }
-module_exit(wcd9xxx_irq_drv_exit);
 #endif /* CONFIG_OF */
diff --git a/drivers/mfd/wcd9xxx-regmap.h b/drivers/mfd/wcd9xxx-regmap.h
index 6db8fc5..f44e8b1 100644
--- a/drivers/mfd/wcd9xxx-regmap.h
+++ b/drivers/mfd/wcd9xxx-regmap.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, 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
@@ -19,42 +19,25 @@
 
 typedef int (*regmap_patch_fptr)(struct regmap *, int);
 
-#ifdef CONFIG_WCD934X_CODEC
 extern struct regmap_config wcd934x_regmap_config;
 extern int wcd934x_regmap_register_patch(struct regmap *regmap,
 					 int version);
-#endif
 
-#ifdef CONFIG_WCD9335_CODEC
 extern struct regmap_config wcd9335_regmap_config;
 extern int wcd9335_regmap_register_patch(struct regmap *regmap,
 					 int version);
-#endif
-
-#ifdef CONFIG_WCD9330_CODEC
-extern struct regmap_config wcd9330_regmap_config;
-#endif
 
 static inline struct regmap_config *wcd9xxx_get_regmap_config(int type)
 {
 	struct regmap_config *regmap_config;
 
 	switch (type) {
-#ifdef CONFIG_WCD934X_CODEC
 	case WCD934X:
 		regmap_config = &wcd934x_regmap_config;
 		break;
-#endif
-#ifdef CONFIG_WCD9335_CODEC
 	case WCD9335:
 		regmap_config = &wcd9335_regmap_config;
 		break;
-#endif
-#ifdef CONFIG_WCD9330_CODEC
-	case WCD9330:
-		regmap_config = &wcd9330_regmap_config;
-		break;
-#endif
 	default:
 		regmap_config = NULL;
 		break;
@@ -68,16 +51,12 @@
 	regmap_patch_fptr apply_patch;
 
 	switch (type) {
-#ifdef CONFIG_WCD9335_CODEC
 	case WCD9335:
 		apply_patch = wcd9335_regmap_register_patch;
 		break;
-#endif
-#ifdef CONFIG_WCD934X_CODEC
 	case WCD934X:
 		apply_patch = wcd934x_regmap_register_patch;
 		break;
-#endif
 	default:
 		apply_patch = NULL;
 		break;
diff --git a/drivers/mfd/wcd9xxx-rst.c b/drivers/mfd/wcd9xxx-rst.c
new file mode 100644
index 0000000..c8e0b34
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-rst.c
@@ -0,0 +1,443 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-utils.h>
+#include <linux/mfd/wcd9335/registers.h>
+#include <linux/mfd/wcd934x/registers.h>
+#include <linux/mfd/wcd9335/irq.h>
+#include <linux/mfd/wcd934x/irq.h>
+
+/* wcd9335 interrupt table  */
+static const struct intr_data wcd9335_intr_table[] = {
+	{WCD9XXX_IRQ_SLIMBUS, false},
+	{WCD9335_IRQ_MBHC_SW_DET, true},
+	{WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, true},
+	{WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, true},
+	{WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, true},
+	{WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
+	{WCD9335_IRQ_FLL_LOCK_LOSS, false},
+	{WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, false},
+	{WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, false},
+	{WCD9335_IRQ_EAR_PA_CNP_COMPLETE, false},
+	{WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, false},
+	{WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, false},
+	{WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, false},
+	{WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, false},
+	{WCD9335_IRQ_HPH_PA_OCPL_FAULT, false},
+	{WCD9335_IRQ_HPH_PA_OCPR_FAULT, false},
+	{WCD9335_IRQ_EAR_PA_OCP_FAULT, false},
+	{WCD9335_IRQ_SOUNDWIRE, false},
+	{WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, false},
+	{WCD9335_IRQ_RCO_ERROR, false},
+	{WCD9335_IRQ_SVA_ERROR, false},
+	{WCD9335_IRQ_MAD_AUDIO, false},
+	{WCD9335_IRQ_MAD_BEACON, false},
+	{WCD9335_IRQ_SVA_OUTBOX1, true},
+	{WCD9335_IRQ_SVA_OUTBOX2, true},
+	{WCD9335_IRQ_MAD_ULTRASOUND, false},
+	{WCD9335_IRQ_VBAT_ATTACK, false},
+	{WCD9335_IRQ_VBAT_RESTORE, false},
+};
+
+static const struct intr_data wcd934x_intr_table[] = {
+	{WCD9XXX_IRQ_SLIMBUS, false},
+	{WCD934X_IRQ_MBHC_SW_DET, true},
+	{WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, true},
+	{WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, true},
+	{WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, true},
+	{WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
+	{WCD934X_IRQ_MISC, false},
+	{WCD934X_IRQ_HPH_PA_CNPL_COMPLETE, false},
+	{WCD934X_IRQ_HPH_PA_CNPR_COMPLETE, false},
+	{WCD934X_IRQ_EAR_PA_CNP_COMPLETE, false},
+	{WCD934X_IRQ_LINE_PA1_CNP_COMPLETE, false},
+	{WCD934X_IRQ_LINE_PA2_CNP_COMPLETE, false},
+	{WCD934X_IRQ_SLNQ_ANALOG_ERROR, false},
+	{WCD934X_IRQ_RESERVED_3, false},
+	{WCD934X_IRQ_HPH_PA_OCPL_FAULT, false},
+	{WCD934X_IRQ_HPH_PA_OCPR_FAULT, false},
+	{WCD934X_IRQ_EAR_PA_OCP_FAULT, false},
+	{WCD934X_IRQ_SOUNDWIRE, false},
+	{WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE, false},
+	{WCD934X_IRQ_RCO_ERROR, false},
+	{WCD934X_IRQ_CPE_ERROR, false},
+	{WCD934X_IRQ_MAD_AUDIO, false},
+	{WCD934X_IRQ_MAD_BEACON, false},
+	{WCD934X_IRQ_CPE1_INTR, true},
+	{WCD934X_IRQ_RESERVED_4, false},
+	{WCD934X_IRQ_MAD_ULTRASOUND, false},
+	{WCD934X_IRQ_VBAT_ATTACK, false},
+	{WCD934X_IRQ_VBAT_RESTORE, false},
+};
+
+/*
+ * wcd9335_bring_down: Bringdown WCD Codec
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd9335_bring_down(struct wcd9xxx *wcd9xxx)
+{
+	if (!wcd9xxx || !wcd9xxx->regmap)
+		return -EINVAL;
+
+	regmap_write(wcd9xxx->regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+		     0x04);
+
+	return 0;
+}
+
+/*
+ * wcd9335_bring_up: Bringup WCD Codec
+ *
+ * @wcd9xxx: Pointer to the wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd9335_bring_up(struct wcd9xxx *wcd9xxx)
+{
+	int ret = 0;
+	int val, byte0;
+	struct regmap *wcd_regmap;
+
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	if (!wcd9xxx->regmap) {
+		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
+			__func__);
+		return -EINVAL;
+	}
+	wcd_regmap = wcd9xxx->regmap;
+
+	regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val);
+	regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0);
+
+	if ((val < 0) || (byte0 < 0)) {
+		dev_err(wcd9xxx->dev, "%s: tasha codec version detection fail!\n",
+			__func__);
+		return -EINVAL;
+	}
+	if ((val & 0x80) && (byte0 == 0x0)) {
+		dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.1\n",
+			 __func__);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x5);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x7);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x3);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+	} else if (byte0 == 0x1) {
+		dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v2.0\n",
+			 __func__);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_TEST_2, 0x00);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
+		regmap_write(wcd_regmap, WCD9335_BIAS_VBG_FINE_ADJ, 0x65);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x5);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x7);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x3);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+	} else if ((byte0 == 0) && (!(val & 0x80))) {
+		dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.0\n",
+			 __func__);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
+		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+			     0x3);
+		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+	} else {
+		dev_err(wcd9xxx->dev, "%s: tasha codec version unknown\n",
+			__func__);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * wcd9335_get_cdc_info: Get codec specific information
+ *
+ * @wcd9xxx: pointer to wcd9xxx structure
+ * @wcd_type: pointer to wcd9xxx_codec_type structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd9335_get_cdc_info(struct wcd9xxx *wcd9xxx,
+			   struct wcd9xxx_codec_type *wcd_type)
+{
+	u16 id_minor, id_major;
+	struct regmap *wcd_regmap;
+	int rc, val, version = 0;
+
+	if (!wcd9xxx || !wcd_type)
+		return -EINVAL;
+
+	if (!wcd9xxx->regmap) {
+		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
+			__func__);
+		return -EINVAL;
+	}
+	wcd_regmap = wcd9xxx->regmap;
+
+	rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
+			(u8 *)&id_minor, sizeof(u16));
+	if (rc)
+		return -EINVAL;
+
+	rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
+			      (u8 *)&id_major, sizeof(u16));
+	if (rc)
+		return -EINVAL;
+
+	dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
+		 __func__, id_major, id_minor);
+
+	/* Version detection */
+	if (id_major == TASHA_MAJOR) {
+		regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0,
+			    &val);
+		version = ((u8)val & 0x80) >> 7;
+	} else if (id_major == TASHA2P0_MAJOR)
+		version = 2;
+	else
+		dev_err(wcd9xxx->dev, "%s: wcd9335 version unknown (major 0x%x, minor 0x%x)\n",
+			__func__, id_major, id_minor);
+
+	/* Fill codec type info */
+	wcd_type->id_major = id_major;
+	wcd_type->id_minor = id_minor;
+	wcd_type->num_irqs = WCD9335_NUM_IRQS;
+	wcd_type->version = version;
+	wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
+	wcd_type->i2c_chip_status = 0x01;
+	wcd_type->intr_tbl = wcd9335_intr_table;
+	wcd_type->intr_tbl_size = ARRAY_SIZE(wcd9335_intr_table);
+
+	wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
+						WCD9335_INTR_PIN1_STATUS0;
+	wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
+						WCD9335_INTR_PIN1_CLEAR0;
+	wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
+						WCD9335_INTR_PIN1_MASK0;
+	wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
+						WCD9335_INTR_LEVEL0;
+	wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
+						WCD9335_INTR_CLR_COMMIT;
+
+	return rc;
+}
+
+/*
+ * wcd934x_bring_down: Bringdown WCD Codec
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd934x_bring_down(struct wcd9xxx *wcd9xxx)
+{
+	if (!wcd9xxx || !wcd9xxx->regmap)
+		return -EINVAL;
+
+	regmap_write(wcd9xxx->regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+		     0x04);
+
+	return 0;
+}
+
+/*
+ * wcd934x_bring_up: Bringup WCD Codec
+ *
+ * @wcd9xxx: Pointer to the wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd934x_bring_up(struct wcd9xxx *wcd9xxx)
+{
+	struct regmap *wcd_regmap;
+
+	if (!wcd9xxx)
+		return -EINVAL;
+
+	if (!wcd9xxx->regmap) {
+		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
+			__func__);
+		return -EINVAL;
+	}
+	wcd_regmap = wcd9xxx->regmap;
+
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
+	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
+	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
+	/* Add 1msec delay for VOUT to settle */
+	usleep_range(1000, 1100);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
+
+	return 0;
+}
+
+/*
+ * wcd934x_get_cdc_info: Get codec specific information
+ *
+ * @wcd9xxx: pointer to wcd9xxx structure
+ * @wcd_type: pointer to wcd9xxx_codec_type structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+static int wcd934x_get_cdc_info(struct wcd9xxx *wcd9xxx,
+			   struct wcd9xxx_codec_type *wcd_type)
+{
+	u16 id_minor, id_major;
+	struct regmap *wcd_regmap;
+	int rc, version = -1;
+
+	if (!wcd9xxx || !wcd_type)
+		return -EINVAL;
+
+	if (!wcd9xxx->regmap) {
+		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null\n", __func__);
+		return -EINVAL;
+	}
+	wcd_regmap = wcd9xxx->regmap;
+
+	rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
+			      (u8 *)&id_minor, sizeof(u16));
+	if (rc)
+		return -EINVAL;
+
+	rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
+			      (u8 *)&id_major, sizeof(u16));
+	if (rc)
+		return -EINVAL;
+
+	dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
+		 __func__, id_major, id_minor);
+
+	if (id_major != TAVIL_MAJOR)
+		goto version_unknown;
+
+	/*
+	 * As fine version info cannot be retrieved before tavil probe.
+	 * Assign coarse versions for possible future use before tavil probe.
+	 */
+	if (id_minor == cpu_to_le16(0))
+		version = TAVIL_VERSION_1_0;
+	else if (id_minor == cpu_to_le16(0x01))
+		version = TAVIL_VERSION_1_1;
+
+version_unknown:
+	if (version < 0)
+		dev_err(wcd9xxx->dev, "%s: wcd934x version unknown\n",
+			__func__);
+
+	/* Fill codec type info */
+	wcd_type->id_major = id_major;
+	wcd_type->id_minor = id_minor;
+	wcd_type->num_irqs = WCD934X_NUM_IRQS;
+	wcd_type->version = version;
+	wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
+	wcd_type->i2c_chip_status = 0x01;
+	wcd_type->intr_tbl = wcd934x_intr_table;
+	wcd_type->intr_tbl_size = ARRAY_SIZE(wcd934x_intr_table);
+
+	wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
+						WCD934X_INTR_PIN1_STATUS0;
+	wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
+						WCD934X_INTR_PIN1_CLEAR0;
+	wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
+						WCD934X_INTR_PIN1_MASK0;
+	wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
+						WCD934X_INTR_LEVEL0;
+	wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
+						WCD934X_INTR_CLR_COMMIT;
+
+	return rc;
+}
+
+codec_bringdown_fn wcd9xxx_bringdown_fn(int type)
+{
+	codec_bringdown_fn cdc_bdown_fn;
+
+	switch (type) {
+	case WCD934X:
+		cdc_bdown_fn = wcd934x_bring_down;
+		break;
+	case WCD9335:
+		cdc_bdown_fn = wcd9335_bring_down;
+		break;
+	default:
+		cdc_bdown_fn = NULL;
+		break;
+	}
+
+	return cdc_bdown_fn;
+}
+
+codec_bringup_fn wcd9xxx_bringup_fn(int type)
+{
+	codec_bringup_fn cdc_bup_fn;
+
+	switch (type) {
+	case WCD934X:
+		cdc_bup_fn = wcd934x_bring_up;
+		break;
+	case WCD9335:
+		cdc_bup_fn = wcd9335_bring_up;
+		break;
+	default:
+		cdc_bup_fn = NULL;
+		break;
+	}
+
+	return cdc_bup_fn;
+}
+
+codec_type_fn wcd9xxx_get_codec_info_fn(int type)
+{
+	codec_type_fn cdc_type_fn;
+
+	switch (type) {
+	case WCD934X:
+		cdc_type_fn = wcd934x_get_cdc_info;
+		break;
+	case WCD9335:
+		cdc_type_fn = wcd9335_get_cdc_info;
+		break;
+	default:
+		cdc_type_fn = NULL;
+		break;
+	}
+
+	return cdc_type_fn;
+}
+
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 8bf1404..a99ad5a 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -47,7 +47,18 @@
 	return 0;
 }
 
-
+/**
+ * wcd9xxx_init_slimslave
+ *
+ * @wcd9xxx: pointer to wcd9xxx struct
+ * @wcd9xxx_pgd_la: pgd_la value
+ * @tx_num: tx number
+ * @rx_num: rx number
+ * @tx_slot: pointer to tx slot
+ * @rx_slot: pointer to rx slot
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
 int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la,
 			   unsigned int tx_num, unsigned int *tx_slot,
 			   unsigned int rx_num, unsigned int *rx_slot)
@@ -117,6 +128,7 @@
 err:
 	return ret;
 }
+EXPORT_SYMBOL(wcd9xxx_init_slimslave);
 
 int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx)
 {
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
index 77080cc..afa2113 100644
--- a/drivers/misc/cxl/file.c
+++ b/drivers/misc/cxl/file.c
@@ -155,11 +155,8 @@
 
 	/* Do this outside the status_mutex to avoid a circular dependency with
 	 * the locking in cxl_mmap_fault() */
-	if (copy_from_user(&work, uwork,
-			   sizeof(struct cxl_ioctl_start_work))) {
-		rc = -EFAULT;
-		goto out;
-	}
+	if (copy_from_user(&work, uwork, sizeof(work)))
+		return -EFAULT;
 
 	mutex_lock(&ctx->status_mutex);
 	if (ctx->status != OPENED) {
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c
index a217a74..224c710 100644
--- a/drivers/misc/cxl/native.c
+++ b/drivers/misc/cxl/native.c
@@ -1066,13 +1066,16 @@
 
 void cxl_native_release_psl_err_irq(struct cxl *adapter)
 {
-	if (adapter->native->err_virq != irq_find_mapping(NULL, adapter->native->err_hwirq))
+	if (adapter->native->err_virq == 0 ||
+	    adapter->native->err_virq !=
+	    irq_find_mapping(NULL, adapter->native->err_hwirq))
 		return;
 
 	cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000);
 	cxl_unmap_irq(adapter->native->err_virq, adapter);
 	cxl_ops->release_one_irq(adapter, adapter->native->err_hwirq);
 	kfree(adapter->irq_name);
+	adapter->native->err_virq = 0;
 }
 
 int cxl_native_register_serr_irq(struct cxl_afu *afu)
@@ -1102,13 +1105,15 @@
 
 void cxl_native_release_serr_irq(struct cxl_afu *afu)
 {
-	if (afu->serr_virq != irq_find_mapping(NULL, afu->serr_hwirq))
+	if (afu->serr_virq == 0 ||
+	    afu->serr_virq != irq_find_mapping(NULL, afu->serr_hwirq))
 		return;
 
 	cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000);
 	cxl_unmap_irq(afu->serr_virq, afu);
 	cxl_ops->release_one_irq(afu->adapter, afu->serr_hwirq);
 	kfree(afu->err_irq_name);
+	afu->serr_virq = 0;
 }
 
 int cxl_native_register_psl_irq(struct cxl_afu *afu)
@@ -1131,12 +1136,15 @@
 
 void cxl_native_release_psl_irq(struct cxl_afu *afu)
 {
-	if (afu->native->psl_virq != irq_find_mapping(NULL, afu->native->psl_hwirq))
+	if (afu->native->psl_virq == 0 ||
+	    afu->native->psl_virq !=
+	    irq_find_mapping(NULL, afu->native->psl_hwirq))
 		return;
 
 	cxl_unmap_irq(afu->native->psl_virq, afu);
 	cxl_ops->release_one_irq(afu->adapter, afu->native->psl_hwirq);
 	kfree(afu->psl_irq_name);
+	afu->native->psl_virq = 0;
 }
 
 static void recover_psl_err(struct cxl_afu *afu, u64 errstat)
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index dbe676d..0c98ed4 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -678,8 +678,10 @@
 {
 	struct mei_cl_device *cldev = to_mei_cl_device(dev);
 	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
+	u8 version = mei_me_cl_ver(cldev->me_cl);
 
-	return scnprintf(buf, PAGE_SIZE, "mei:%s:%pUl:", cldev->name, uuid);
+	return scnprintf(buf, PAGE_SIZE, "mei:%s:%pUl:%02X:",
+			 cldev->name, uuid, version);
 }
 static DEVICE_ATTR_RO(modalias);
 
diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
index b97a584..d20b518 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
@@ -17,7 +17,6 @@
 #include "q6audio_common.h"
 #include "audio_utils_aio.h"
 #include <sound/msm-audio-effects-q6-v2.h>
-#include <sound/msm-dts-eagle.h>
 
 #define MAX_CHANNELS_SUPPORTED		8
 #define WAIT_TIMEDOUT_DURATION_SECS	1
@@ -53,31 +52,11 @@
 		pr_err("%s: audio client null to init pp\n", __func__);
 		return;
 	}
-	switch (ac->topology) {
-	case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
-
-		ret = q6asm_set_softvolume_v2(ac, &softvol,
-					      SOFT_VOLUME_INSTANCE_1);
-		if (ret < 0)
-			pr_err("%s: Send SoftVolume1 Param failed ret=%d\n",
-				__func__, ret);
-		ret = q6asm_set_softvolume_v2(ac, &softvol,
-					      SOFT_VOLUME_INSTANCE_2);
-		if (ret < 0)
-			pr_err("%s: Send SoftVolume2 Param failed ret=%d\n",
-				 __func__, ret);
-
-		msm_dts_eagle_init_master_module(ac);
-
-		break;
-	default:
-		ret = q6asm_set_softvolume_v2(ac, &softvol,
-					      SOFT_VOLUME_INSTANCE_1);
-		if (ret < 0)
-			pr_err("%s: Send SoftVolume Param failed ret=%d\n",
-				__func__, ret);
-		break;
-	}
+	ret = q6asm_set_softvolume_v2(ac, &softvol,
+				      SOFT_VOLUME_INSTANCE_1);
+	if (ret < 0)
+		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+			__func__, ret);
 }
 
 static void audio_effects_deinit_pp(struct audio_client *ac)
@@ -86,13 +65,6 @@
 		pr_err("%s: audio client null to deinit pp\n", __func__);
 		return;
 	}
-	switch (ac->topology) {
-	case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
-		msm_dts_eagle_deinit_master_module(ac);
-		break;
-	default:
-		break;
-	}
 }
 
 static void audio_effects_event_handler(uint32_t opcode, uint32_t token,
@@ -149,6 +121,8 @@
 	case AUDIO_START: {
 		pr_debug("%s: AUDIO_START\n", __func__);
 
+		mutex_lock(&effects->lock);
+
 		rc = q6asm_open_read_write_v2(effects->ac,
 					FORMAT_LINEAR_PCM,
 					FORMAT_MULTI_CHANNEL_LINEAR_PCM,
@@ -160,6 +134,7 @@
 			pr_err("%s: Open failed for hw accelerated effects:rc=%d\n",
 				__func__, rc);
 			rc = -EINVAL;
+			mutex_unlock(&effects->lock);
 			goto ioctl_fail;
 		}
 		effects->opened = 1;
@@ -176,6 +151,7 @@
 			pr_err("%s: Write buffer Allocation failed rc = %d\n",
 				__func__, rc);
 			rc = -ENOMEM;
+			mutex_unlock(&effects->lock);
 			goto ioctl_fail;
 		}
 		atomic_set(&effects->in_count, effects->config.input.num_buf);
@@ -186,6 +162,7 @@
 			pr_err("%s: Read buffer Allocation failed rc = %d\n",
 				__func__, rc);
 			rc = -ENOMEM;
+			mutex_unlock(&effects->lock);
 			goto readbuf_fail;
 		}
 		atomic_set(&effects->out_count, effects->config.output.num_buf);
@@ -200,6 +177,7 @@
 		if (rc < 0) {
 			pr_err("%s: pcm read block config failed\n", __func__);
 			rc = -EINVAL;
+			mutex_unlock(&effects->lock);
 			goto cfg_fail;
 		}
 		pr_debug("%s: dec: sample_rate: %d, num_channels: %d, bit_width: %d\n",
@@ -214,6 +192,7 @@
 			pr_err("%s: pcm write format block config failed\n",
 				__func__);
 			rc = -EINVAL;
+			mutex_unlock(&effects->lock);
 			goto cfg_fail;
 		}
 
@@ -226,6 +205,7 @@
 			effects->started = 0;
 			pr_err("%s: ASM run state failed\n", __func__);
 		}
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	case AUDIO_EFFECTS_WRITE: {
@@ -287,8 +267,11 @@
 		uint32_t idx = 0;
 		uint32_t size = 0;
 
+		mutex_lock(&effects->lock);
+
 		if (!effects->started) {
 			rc = -EFAULT;
+			mutex_unlock(&effects->lock);
 			goto ioctl_fail;
 		}
 
@@ -305,11 +288,13 @@
 		if (!rc) {
 			pr_err("%s: read wait_event_timeout\n", __func__);
 			rc = -EFAULT;
+			mutex_unlock(&effects->lock);
 			goto ioctl_fail;
 		}
 		if (!atomic_read(&effects->in_count)) {
 			pr_err("%s: pcm stopped in_count 0\n", __func__);
 			rc = -EFAULT;
+			mutex_unlock(&effects->lock);
 			goto ioctl_fail;
 		}
 
@@ -317,15 +302,18 @@
 		if (bufptr) {
 			if (!((void *)arg)) {
 				rc = -EFAULT;
+				mutex_unlock(&effects->lock);
 				goto ioctl_fail;
 			}
 			if ((effects->config.buf_cfg.input_len > size) ||
 				copy_to_user((void *)arg, bufptr,
 					  effects->config.buf_cfg.input_len)) {
 				rc = -EFAULT;
+				mutex_unlock(&effects->lock);
 				goto ioctl_fail;
 			}
 		}
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	default:
@@ -414,34 +402,6 @@
 			      &(effects->audio_effects.topo_switch_vol),
 			      (long *)&values[1], SOFT_VOLUME_INSTANCE_2);
 		break;
-	case DTS_EAGLE_MODULE_ENABLE:
-		pr_debug("%s: DTS_EAGLE_MODULE_ENABLE\n", __func__);
-		if (msm_audio_effects_is_effmodule_supp_in_top(
-			effects_module, effects->ac->topology)) {
-			/*
-			 * HPX->OFF: first disable HPX and then
-			 * enable SA+
-			 * HPX->ON: first disable SA+ and then
-			 * enable HPX
-			 */
-			bool hpx_state = (bool)values[1];
-
-			if (hpx_state)
-				msm_audio_effects_enable_extn(effects->ac,
-					&(effects->audio_effects),
-					false);
-			msm_dts_eagle_enable_asm(effects->ac,
-				hpx_state,
-				AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
-			msm_dts_eagle_enable_asm(effects->ac,
-				hpx_state,
-				AUDPROC_MODULE_ID_DTS_HPX_POSTMIX);
-			if (!hpx_state)
-				msm_audio_effects_enable_extn(effects->ac,
-					&(effects->audio_effects),
-					true);
-		}
-		break;
 	default:
 		pr_err("%s: Invalid effects config module\n", __func__);
 		rc = -EINVAL;
@@ -459,6 +419,7 @@
 	switch (cmd) {
 	case AUDIO_SET_EFFECTS_CONFIG: {
 		pr_debug("%s: AUDIO_SET_EFFECTS_CONFIG\n", __func__);
+		mutex_lock(&effects->lock);
 		memset(&effects->config, 0, sizeof(effects->config));
 		if (copy_from_user(&effects->config, (void *)arg,
 				   sizeof(effects->config))) {
@@ -476,6 +437,7 @@
 			 effects->config.input.num_buf,
 			 effects->config.input.sample_rate,
 			 effects->config.input.num_channels);
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	case AUDIO_EFFECTS_SET_BUF_LEN: {
@@ -497,6 +459,7 @@
 
 		buf_avail.input_num_avail = atomic_read(&effects->in_count);
 		buf_avail.output_num_avail = atomic_read(&effects->out_count);
+		mutex_lock(&effects->lock);
 		pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
 			 __func__, buf_avail.output_num_avail,
 			 buf_avail.input_num_avail);
@@ -506,16 +469,20 @@
 				__func__);
 			rc = -EFAULT;
 		}
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	case AUDIO_EFFECTS_SET_PP_PARAMS: {
+		mutex_lock(&effects->lock);
 		if (copy_from_user(argvalues, (void *)arg,
 				   MAX_PP_PARAMS_SZ*sizeof(long))) {
 			pr_err("%s: copy from user for pp params failed\n",
 				__func__);
+			mutex_unlock(&effects->lock);
 			return -EFAULT;
 		}
 		rc = audio_effects_set_pp_param(effects, argvalues);
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	default:
@@ -582,12 +549,14 @@
 		struct msm_hwacc_effects_config32 config32;
 		struct msm_hwacc_effects_config *config = &effects->config;
 
+		mutex_lock(&effects->lock);
 		memset(&effects->config, 0, sizeof(effects->config));
 		if (copy_from_user(&config32, (void *)arg,
 				   sizeof(config32))) {
 			pr_err("%s: copy to user for AUDIO_SET_EFFECTS_CONFIG failed\n",
 				__func__);
 			rc = -EFAULT;
+			mutex_unlock(&effects->lock);
 			break;
 		}
 		config->input.buf_size = config32.input.buf_size;
@@ -624,17 +593,20 @@
 			 effects->config.input.num_buf,
 			 effects->config.input.sample_rate,
 			 effects->config.input.num_channels);
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	case AUDIO_EFFECTS_SET_BUF_LEN32: {
 		struct msm_hwacc_buf_cfg32 buf_cfg32;
 		struct msm_hwacc_effects_config *config = &effects->config;
 
+		mutex_lock(&effects->lock);
 		if (copy_from_user(&buf_cfg32, (void *)arg,
 				   sizeof(buf_cfg32))) {
 			pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n",
 				__func__);
 			rc = -EFAULT;
+			mutex_unlock(&effects->lock);
 			break;
 		}
 		config->buf_cfg.input_len = buf_cfg32.input_len;
@@ -642,6 +614,7 @@
 		pr_debug("%s: write buf len: %d, read buf len: %d\n",
 			 __func__, effects->config.buf_cfg.output_len,
 			 effects->config.buf_cfg.input_len);
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	case AUDIO_EFFECTS_GET_BUF_AVAIL32: {
@@ -649,6 +622,7 @@
 
 		memset(&buf_avail, 0, sizeof(buf_avail));
 
+		mutex_lock(&effects->lock);
 		buf_avail.input_num_avail = atomic_read(&effects->in_count);
 		buf_avail.output_num_avail = atomic_read(&effects->out_count);
 		pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
@@ -660,22 +634,26 @@
 				__func__);
 			rc = -EFAULT;
 		}
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	case AUDIO_EFFECTS_SET_PP_PARAMS32: {
 		long argvalues[MAX_PP_PARAMS_SZ] = {0};
 		int argvalues32[MAX_PP_PARAMS_SZ] = {0};
 
+		mutex_lock(&effects->lock);
 		if (copy_from_user(argvalues32, (void *)arg,
 				   MAX_PP_PARAMS_SZ*sizeof(int))) {
 			pr_err("%s: copy from user failed for pp params\n",
 				__func__);
+			mutex_unlock(&effects->lock);
 			return -EFAULT;
 		}
 		for (i = 0; i < MAX_PP_PARAMS_SZ; i++)
 			argvalues[i] = argvalues32[i];
 
 		rc = audio_effects_set_pp_param(effects, argvalues);
+		mutex_unlock(&effects->lock);
 		break;
 	}
 	case AUDIO_START32: {
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index 4c9fa8f..80f6e57 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -858,6 +858,7 @@
 	long rc;
 	struct msm_audio_event32 usr_evt_32;
 	struct msm_audio_event usr_evt;
+	memset(&usr_evt, 0, sizeof(struct msm_audio_event));
 
 	if (copy_from_user(&usr_evt_32, arg,
 				sizeof(struct msm_audio_event32))) {
@@ -867,6 +868,11 @@
 	usr_evt.timeout_ms = usr_evt_32.timeout_ms;
 
 	rc = audio_aio_process_event_req_common(audio, &usr_evt);
+	if (rc < 0) {
+		pr_err("%s: audio process event failed, rc = %ld",
+			__func__, rc);
+		return rc;
+	}
 
 	usr_evt_32.event_type = usr_evt.event_type;
 	switch (usr_evt_32.event_type) {
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
index c964dcb..3da46b6 100644
--- a/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
@@ -179,7 +179,7 @@
 };
 
 /* The opened devices container */
-static int s_opened_devs[MAX_DEVS_NUMBER];
+static atomic_t s_opened_devs[MAX_DEVS_NUMBER];
 
 static struct wakeup_source usf_wakeup_source;
 
@@ -2348,14 +2348,11 @@
 	uint16_t ind = 0;
 
 	for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
-		if (minor == s_opened_devs[ind]) {
+		if (minor == atomic_cmpxchg(&s_opened_devs[ind], 0, minor)) {
 			pr_err("%s: device %d is already opened\n",
 			       __func__, minor);
 			return USF_UNDEF_DEV_ID;
-		}
-
-		if (s_opened_devs[ind] == 0) {
-			s_opened_devs[ind] = minor;
+		} else {
 			pr_debug("%s: device %d is added; ind=%d\n",
 				__func__, minor, ind);
 			return ind;
@@ -2410,7 +2407,7 @@
 	usf_disable(&usf->usf_tx);
 	usf_disable(&usf->usf_rx);
 
-	s_opened_devs[usf->dev_ind] = 0;
+	atomic_set(&s_opened_devs[usf->dev_ind], 0);
 
 	wakeup_source_trash(&usf_wakeup_source);
 	mutex_unlock(&usf->mutex);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c1857c7..e8b9b48 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -2912,7 +2912,11 @@
 		}
 		if (req.cmd_id == QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND) {
 			pr_warn("RPMB key status is 0x%x\n", resp.result);
-			*(uint32_t *)req.resp_buf = resp.result;
+			if (put_user(resp.result,
+				(uint32_t __user *)req.resp_buf)) {
+				ret = -EINVAL;
+				goto exit;
+			}
 			ret = 0;
 		}
 		break;
@@ -4382,9 +4386,9 @@
 		return -EINVAL;
 	}
 
-	if (strlen(app_name) >= MAX_APP_NAME_SIZE) {
+	if (strnlen(app_name, MAX_APP_NAME_SIZE) == MAX_APP_NAME_SIZE) {
 		pr_err("The app_name (%s) with length %zu is not valid\n",
-			app_name, strlen(app_name));
+			app_name, strnlen(app_name, MAX_APP_NAME_SIZE));
 		return -EINVAL;
 	}
 
@@ -6507,11 +6511,16 @@
 	void *cmd_buf = NULL;
 	size_t cmd_len;
 	struct sglist_info *table = data->sglistinfo_ptr;
+	void *req_ptr = NULL;
+	void *resp_ptr = NULL;
 
 	ret  = __qseecom_qteec_validate_msg(data, req);
 	if (ret)
 		return ret;
 
+	req_ptr = req->req_ptr;
+	resp_ptr = req->resp_ptr;
+
 	/* find app_id & img_name from list */
 	spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
 	list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
@@ -6529,6 +6538,11 @@
 		return -ENOENT;
 	}
 
+	req->req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
+						(uintptr_t)req->req_ptr);
+	req->resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
+						(uintptr_t)req->resp_ptr);
+
 	if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
 			(cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
 		ret = __qseecom_update_qteec_req_buf(
@@ -6540,10 +6554,10 @@
 	if (qseecom.qsee_version < QSEE_VERSION_40) {
 		ireq.app_id = data->client.app_id;
 		ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
-						(uintptr_t)req->req_ptr);
+						(uintptr_t)req_ptr);
 		ireq.req_len = req->req_len;
 		ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
-						(uintptr_t)req->resp_ptr);
+						(uintptr_t)resp_ptr);
 		ireq.resp_len = req->resp_len;
 		ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
 		ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
@@ -6554,10 +6568,10 @@
 	} else {
 		ireq_64bit.app_id = data->client.app_id;
 		ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
-						(uintptr_t)req->req_ptr);
+						(uintptr_t)req_ptr);
 		ireq_64bit.req_len = req->req_len;
 		ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
-						(uintptr_t)req->resp_ptr);
+						(uintptr_t)resp_ptr);
 		ireq_64bit.resp_len = req->resp_len;
 		if ((data->client.app_arch == ELFCLASS32) &&
 			((ireq_64bit.req_ptr >=
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9ac6568..f300435 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1718,8 +1718,6 @@
 
 	/* We couldn't get a response from the card.  Give up. */
 	if (err) {
-		if (card->err_in_sdr104)
-			return ERR_RETRY;
 		/* Check if the card is removed */
 		if (mmc_detect_card_removed(card->host))
 			return ERR_NOMEDIUM;
@@ -2210,8 +2208,7 @@
 	     brq->data.error == -ETIMEDOUT ||
 	     brq->cmd.error == -EILSEQ ||
 	     brq->cmd.error == -EIO ||
-	     brq->cmd.error == -ETIMEDOUT ||
-	     brq->sbc.error))
+	     brq->cmd.error == -ETIMEDOUT))
 		card->err_in_sdr104 = true;
 
 	/*
@@ -4664,10 +4661,6 @@
 static void mmc_blk_shutdown(struct mmc_card *card)
 {
 	_mmc_blk_suspend(card, 1);
-
-	/* send power off notification */
-	if (mmc_card_mmc(card))
-		mmc_send_pon(card);
 }
 
 #ifdef CONFIG_PM_SLEEP
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index ccfd225..3fd621c 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -133,14 +133,11 @@
 
 		ret = mq->cmdq_issue_fn(mq, mq->cmdq_req_peeked);
 		/*
-		 * Don't requeue if issue_fn fails, just bug on.
-		 * We don't expect failure here and there is no recovery other
-		 * than fixing the actual issue if there is any.
+		 * Don't requeue if issue_fn fails.
+		 * Recovery will be come by completion softirq
 		 * Also we end the request if there is a partition switch error,
 		 * so we should not requeue the request here.
 		 */
-		if (ret)
-			BUG_ON(1);
 	} /* loop */
 
 	return 0;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 1c28cf8..e3696c5 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -167,6 +167,19 @@
 	if (mmc_bus_needs_resume(host))
 		return 0;
 	ret = host->bus_ops->suspend(host);
+
+	/*
+	 * bus_ops->suspend may fail due to some reason
+	 * In such cases if we return error to PM framework
+	 * from here without calling pm_generic_resume then mmc
+	 * request may get stuck since PM framework will assume
+	 * that mmc bus is not suspended (because of error) and
+	 * it won't call resume again.
+	 *
+	 * So in case of error call pm_generic_resume().
+	 */
+	if (ret)
+		pm_generic_resume(dev);
 	return ret;
 }
 
diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h
index 00a1971..3f3f24b 100644
--- a/drivers/mmc/core/bus.h
+++ b/drivers/mmc/core/bus.h
@@ -15,7 +15,7 @@
 static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)	\
 {										\
 	struct mmc_card *card = mmc_dev_to_card(dev);				\
-	return sprintf(buf, fmt, args);						\
+	return snprintf(buf, PAGE_SIZE, fmt, args);			\
 }										\
 static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1848cdf..c19aa0c 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -456,22 +456,6 @@
 }
 EXPORT_SYMBOL(mmc_clk_update_freq);
 
-void mmc_recovery_fallback_lower_speed(struct mmc_host *host)
-{
-	if (!host->card)
-		return;
-
-	if (host->sdr104_wa && mmc_card_sd(host->card) &&
-	    (host->ios.timing == MMC_TIMING_UHS_SDR104) &&
-	    !host->card->sdr104_blocked) {
-		pr_err("%s: %s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n",
-			mmc_hostname(host), __func__);
-		mmc_host_clear_sdr104(host);
-		mmc_hw_reset(host);
-		host->card->sdr104_blocked = true;
-	}
-}
-
 static int mmc_devfreq_set_target(struct device *dev,
 				unsigned long *freq, u32 devfreq_flags)
 {
@@ -523,9 +507,6 @@
 	if (abort)
 		goto out;
 
-	if (mmc_card_sd(host->card) && host->card->sdr104_blocked)
-		goto rel_host;
-
 	/*
 	 * In case we were able to claim host there is no need to
 	 * defer the frequency change. It will be done now
@@ -534,18 +515,15 @@
 
 	mmc_host_clk_hold(host);
 	err = mmc_clk_update_freq(host, *freq, clk_scaling->state);
-	if (err && err != -EAGAIN) {
+	if (err && err != -EAGAIN)
 		pr_err("%s: clock scale to %lu failed with error %d\n",
 			mmc_hostname(host), *freq, err);
-		mmc_recovery_fallback_lower_speed(host);
-	} else {
+	else
 		pr_debug("%s: clock change to %lu finished successfully (%s)\n",
 			mmc_hostname(host), *freq, current->comm);
-	}
 
 
 	mmc_host_clk_release(host);
-rel_host:
 	mmc_release_host(host);
 out:
 	return err;
@@ -566,9 +544,6 @@
 	if (!host->clk_scaling.enable)
 		return;
 
-	if (mmc_card_sd(host->card) && host->card->sdr104_blocked)
-		return;
-
 	spin_lock_bh(&host->clk_scaling.lock);
 
 	if (host->clk_scaling.clk_scaling_in_progress ||
@@ -589,15 +564,13 @@
 
 	err = mmc_clk_update_freq(host, target_freq,
 		host->clk_scaling.state);
-	if (err && err != -EAGAIN) {
+	if (err && err != -EAGAIN)
 		pr_err("%s: failed on deferred scale clocks (%d)\n",
 			mmc_hostname(host), err);
-		mmc_recovery_fallback_lower_speed(host);
-	} else {
+	else
 		pr_debug("%s: clocks were successfully scaled to %lu (%s)\n",
 			mmc_hostname(host),
 			target_freq, current->comm);
-	}
 	host->clk_scaling.clk_scaling_in_progress = false;
 	atomic_dec(&host->clk_scaling.devfreq_abort);
 }
@@ -849,10 +822,15 @@
 	if (!mmc_can_scale_clk(host))
 		return 0;
 
+	/*
+	 * If clock scaling is already exited when resume is called, like
+	 * during mmc shutdown, it is not an error and should not fail the
+	 * API calling this.
+	 */
 	if (!host->clk_scaling.devfreq) {
-		pr_err("%s: %s: no devfreq is assosiated with this device\n",
+		pr_warn("%s: %s: no devfreq is assosiated with this device\n",
 			mmc_hostname(host), __func__);
-		return -EPERM;
+		return 0;
 	}
 
 	atomic_set(&host->clk_scaling.devfreq_abort, 0);
@@ -1593,13 +1571,8 @@
 			}
 		}
 		if (!cmd->error || !cmd->retries ||
-		    mmc_card_removed(host->card)) {
-			if (cmd->error && !cmd->retries &&
-			     cmd->opcode != MMC_SEND_STATUS &&
-			     cmd->opcode != MMC_SEND_TUNING_BLOCK)
-				mmc_recovery_fallback_lower_speed(host);
+		    mmc_card_removed(host->card))
 			break;
-		}
 
 		mmc_retune_recheck(host);
 
@@ -2267,6 +2240,45 @@
 EXPORT_SYMBOL(__mmc_claim_host);
 
 /**
+ *     mmc_try_claim_host - try exclusively to claim a host
+ *        and keep trying for given time, with a gap of 10ms
+ *     @host: mmc host to claim
+ *     @dealy_ms: delay in ms
+ *
+ *     Returns %1 if the host is claimed, %0 otherwise.
+ */
+int mmc_try_claim_host(struct mmc_host *host, unsigned int delay_ms)
+{
+	int claimed_host = 0;
+	unsigned long flags;
+	int retry_cnt = delay_ms/10;
+	bool pm = false;
+
+	do {
+		spin_lock_irqsave(&host->lock, flags);
+		if (!host->claimed || host->claimer == current) {
+			host->claimed = 1;
+			host->claimer = current;
+			host->claim_cnt += 1;
+			claimed_host = 1;
+			if (host->claim_cnt == 1)
+				pm = true;
+		}
+		spin_unlock_irqrestore(&host->lock, flags);
+		if (!claimed_host)
+			mmc_delay(10);
+	} while (!claimed_host && retry_cnt--);
+
+	if (pm)
+		pm_runtime_get_sync(mmc_dev(host));
+
+	if (host->ops->enable && claimed_host && host->claim_cnt == 1)
+		host->ops->enable(host);
+	return claimed_host;
+}
+EXPORT_SYMBOL(mmc_try_claim_host);
+
+/**
  *	mmc_release_host - release a host
  *	@host: mmc host to release
  *
@@ -4152,12 +4164,10 @@
  */
 int mmc_cmdq_hw_reset(struct mmc_host *host)
 {
-	if (!host->bus_ops->power_restore)
-	return -EOPNOTSUPP;
+	if (!host->bus_ops->reset)
+		return -EOPNOTSUPP;
 
-	mmc_power_cycle(host, host->ocr_avail);
-	mmc_select_voltage(host, host->card->ocr);
-	return host->bus_ops->power_restore(host);
+	return host->bus_ops->reset(host);
 }
 EXPORT_SYMBOL(mmc_cmdq_hw_reset);
 
@@ -4254,18 +4264,12 @@
 	}
 
 	if (ret) {
-		if (host->ops->get_cd && host->ops->get_cd(host)) {
-			mmc_recovery_fallback_lower_speed(host);
-			ret = 0;
-		} else {
-			mmc_card_set_removed(host->card);
-			if (host->card->sdr104_blocked) {
-				mmc_host_set_sdr104(host);
-				host->card->sdr104_blocked = false;
-			}
-			pr_debug("%s: card remove detected\n",
-					mmc_hostname(host));
+		mmc_card_set_removed(host->card);
+		if (host->card->sdr104_blocked) {
+			mmc_host_set_sdr104(host);
+			host->card->sdr104_blocked = false;
 		}
+		pr_debug("%s: card remove detected\n", mmc_hostname(host));
 	}
 
 	return ret;
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 0c8ff86..d1a0235 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -354,6 +354,33 @@
 
 DEFINE_SIMPLE_ATTRIBUTE(mmc_force_err_fops, NULL, mmc_force_err_set, "%llu\n");
 
+static int mmc_err_state_get(void *data, u64 *val)
+{
+	struct mmc_host *host = data;
+
+	if (!host)
+		return -EINVAL;
+
+	*val = host->err_occurred ? 1 : 0;
+
+	return 0;
+}
+
+static int mmc_err_state_clear(void *data, u64 val)
+{
+	struct mmc_host *host = data;
+
+	if (!host)
+		return -EINVAL;
+
+	host->err_occurred = false;
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mmc_err_state, mmc_err_state_get,
+		mmc_err_state_clear, "%llu\n");
+
 void mmc_add_host_debugfs(struct mmc_host *host)
 {
 	struct dentry *root;
@@ -399,6 +426,10 @@
 				root, host, &mmc_ring_buffer_fops))
 		goto err_node;
 #endif
+	if (!debugfs_create_file("err_state", S_IRUSR | S_IWUSR, root, host,
+		&mmc_err_state))
+		goto err_node;
+
 #ifdef CONFIG_MMC_CLKGATE
 	if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
 				root, &host->clk_delay))
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index eb730fd..c92ea77 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -325,6 +325,7 @@
 		mod_timer(&host->retune_timer,
 			  jiffies + host->retune_period * HZ);
 }
+EXPORT_SYMBOL(mmc_retune_enable);
 
 /*
  * Pause re-tuning for a small set of operations.  The pause begins after the
@@ -357,6 +358,7 @@
 	host->retune_now = 0;
 	host->need_retune = 0;
 }
+EXPORT_SYMBOL(mmc_retune_disable);
 
 void mmc_retune_timer_stop(struct mmc_host *host)
 {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a36bcbb..3184dcd 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -2610,7 +2610,7 @@
 
 static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 {
-	int err = 0;
+	int err = 0, ret;
 
 	BUG_ON(!host);
 	BUG_ON(!host->card);
@@ -2619,6 +2619,8 @@
 	if (err) {
 		pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
 			mmc_hostname(host), __func__, err);
+		if (host->card->cmdq_init)
+			wake_up(&host->cmdq_ctx.wait);
 		return err;
 	}
 
@@ -2643,12 +2645,12 @@
 	if (mmc_card_doing_bkops(host->card)) {
 		err = mmc_stop_bkops(host->card);
 		if (err)
-			goto out;
+			goto out_err;
 	}
 
 	err = mmc_flush_cache(host->card);
 	if (err)
-		goto out;
+		goto out_err;
 
 	if (mmc_can_sleepawake(host)) {
 		/*
@@ -2665,16 +2667,38 @@
 		err = mmc_deselect_cards(host);
 	}
 
-	if (!err) {
-		mmc_power_off(host);
-		mmc_card_set_suspended(host->card);
+	if (err)
+		goto out_err;
+	mmc_power_off(host);
+	mmc_card_set_suspended(host->card);
+
+	goto out;
+
+out_err:
+	/*
+	 * In case of err let's put controller back in cmdq mode and unhalt
+	 * the controller.
+	 * We expect cmdq_enable and unhalt won't return any error
+	 * since it is anyway enabling few registers.
+	 */
+	if (host->card->cmdq_init) {
+		mmc_host_clk_hold(host);
+		ret = host->cmdq_ops->enable(host);
+		if (ret)
+			pr_err("%s: %s: enabling CMDQ mode failed (%d)\n",
+				mmc_hostname(host), __func__, ret);
+		mmc_host_clk_release(host);
+		mmc_cmdq_halt(host, false);
 	}
+
 out:
 	/* Kick CMDQ thread to process any requests came in while suspending */
 	if (host->card->cmdq_init)
 		wake_up(&host->cmdq_ctx.wait);
 
 	mmc_release_host(host);
+	if (err)
+		mmc_resume_clk_scaling(host);
 	return err;
 }
 
@@ -2696,6 +2720,9 @@
 	if (mmc_card_hs400(card)) {
 		if (card->ext_csd.strobe_support && host->ops->enhanced_strobe)
 			err = host->ops->enhanced_strobe(host);
+		else if (host->ops->execute_tuning)
+			err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS200);
 	} else if (mmc_card_hs200(card) && host->ops->execute_tuning) {
 		err = host->ops->execute_tuning(host,
 			MMC_SEND_TUNING_BLOCK_HS200);
@@ -2960,6 +2987,7 @@
 static int mmc_reset(struct mmc_host *host)
 {
 	struct mmc_card *card = host->card;
+	int ret;
 
 	/*
 	 * In the case of recovery, we can't expect flushing the cache to work
@@ -2980,7 +3008,45 @@
 		/* Do a brute force power cycle */
 		mmc_power_cycle(host, card->ocr);
 	}
-	return mmc_init_card(host, card->ocr, card);
+
+	/* Suspend clk scaling to avoid switching frequencies intermittently */
+
+	ret = mmc_suspend_clk_scaling(host);
+	if (ret) {
+		pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
+			mmc_hostname(host), __func__, ret);
+		return ret;
+	}
+
+	ret = mmc_init_card(host, host->card->ocr, host->card);
+	if (ret) {
+		pr_err("%s: %s: mmc_init_card failed (%d)\n",
+			mmc_hostname(host), __func__, ret);
+		return ret;
+	}
+
+	ret = mmc_resume_clk_scaling(host);
+	if (ret)
+		pr_err("%s: %s: fail to resume clock scaling (%d)\n",
+			mmc_hostname(host), __func__, ret);
+
+	return ret;
+}
+
+static int mmc_shutdown(struct mmc_host *host)
+{
+	struct mmc_card *card = host->card;
+
+	/*
+	 * Exit clock scaling so that it doesn't kick in after
+	 * power off notification is sent
+	 */
+	if (host->caps2 & MMC_CAP2_CLK_SCALE)
+		mmc_exit_clk_scaling(card->host);
+	/* send power off notification */
+	if (mmc_card_mmc(card))
+		mmc_send_pon(card);
+	return 0;
 }
 
 static const struct mmc_bus_ops mmc_ops = {
@@ -2993,6 +3059,7 @@
 	.alive = mmc_alive,
 	.change_bus_speed = mmc_change_bus_speed,
 	.reset = mmc_reset,
+	.shutdown = mmc_shutdown,
 };
 
 /*
diff --git a/drivers/mmc/core/ring_buffer.c b/drivers/mmc/core/ring_buffer.c
new file mode 100644
index 0000000..83945e1
--- /dev/null
+++ b/drivers/mmc/core/ring_buffer.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mmc/ring_buffer.h>
+#include <linux/mmc/host.h>
+
+void mmc_stop_tracing(struct mmc_host *mmc)
+{
+	mmc->trace_buf.stop_tracing = true;
+}
+
+void mmc_trace_write(struct mmc_host *mmc,
+			const char *fmt, ...)
+{
+	unsigned int idx;
+	va_list args;
+	char *event;
+	unsigned long flags;
+	char str[MMC_TRACE_EVENT_SZ];
+
+	if (unlikely(!mmc->trace_buf.data) ||
+			unlikely(mmc->trace_buf.stop_tracing))
+		return;
+
+	/*
+	 * Here an increment and modulus is used to keep
+	 * index within array bounds. The cast to unsigned is
+	 * necessary so increment and rolover wraps to 0 correctly
+	 */
+	spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags);
+	mmc->trace_buf.wr_idx += 1;
+	idx = ((unsigned int)mmc->trace_buf.wr_idx) &
+			(MMC_TRACE_RBUF_NUM_EVENTS - 1);
+	spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags);
+
+	/* Catch some unlikely machine specific wrap-around bug */
+	if (unlikely(idx > (MMC_TRACE_RBUF_NUM_EVENTS - 1))) {
+		pr_err("%s: %s: Invalid idx:%d for mmc trace, tracing stopped !\n",
+			mmc_hostname(mmc), __func__, idx);
+		mmc_stop_tracing(mmc);
+		return;
+	}
+
+	event = &mmc->trace_buf.data[idx * MMC_TRACE_EVENT_SZ];
+	va_start(args, fmt);
+	snprintf(str, MMC_TRACE_EVENT_SZ, "<%d> %lld: %s: %s",
+		raw_smp_processor_id(),
+		ktime_to_ns(ktime_get()),
+		mmc_hostname(mmc), fmt);
+	memset(event, '\0', MMC_TRACE_EVENT_SZ);
+	vscnprintf(event, MMC_TRACE_EVENT_SZ, str, args);
+	va_end(args);
+}
+
+void mmc_trace_init(struct mmc_host *mmc)
+{
+	BUILD_BUG_ON_NOT_POWER_OF_2(MMC_TRACE_RBUF_NUM_EVENTS);
+
+	mmc->trace_buf.data = (char *)
+				__get_free_pages(GFP_KERNEL|__GFP_ZERO,
+				MMC_TRACE_RBUF_SZ_ORDER);
+
+	if (!mmc->trace_buf.data) {
+		pr_err("%s: %s: Unable to allocate trace for mmc\n",
+			__func__, mmc_hostname(mmc));
+		return;
+	}
+
+	spin_lock_init(&mmc->trace_buf.trace_lock);
+	mmc->trace_buf.wr_idx = -1;
+}
+
+void mmc_trace_free(struct mmc_host *mmc)
+{
+	if (mmc->trace_buf.data)
+		free_pages((unsigned long)mmc->trace_buf.data,
+			MMC_TRACE_RBUF_SZ_ORDER);
+}
+
+void mmc_dump_trace_buffer(struct mmc_host *mmc, struct seq_file *s)
+{
+	unsigned int idx, cur_idx;
+	unsigned int N = MMC_TRACE_RBUF_NUM_EVENTS - 1;
+	char *event;
+	unsigned long flags;
+
+	if (!mmc->trace_buf.data)
+		return;
+
+	spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags);
+	idx = ((unsigned int)mmc->trace_buf.wr_idx) & N;
+	cur_idx = (idx + 1) & N;
+
+	do {
+		event = &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ];
+		if (s)
+			seq_printf(s, "%s", (char *)event);
+		else
+			pr_err("%s", (char *)event);
+		cur_idx = (cur_idx + 1) & N;
+		if (cur_idx == idx) {
+			event =
+			  &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ];
+			if (s)
+				seq_printf(s, "latest_event: %s",
+					(char *)event);
+			else
+				pr_err("latest_event: %s", (char *)event);
+			break;
+		}
+	} while (1);
+	spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags);
+}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 7112f9f..650f658 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1185,7 +1185,17 @@
 	BUG_ON(!host);
 	BUG_ON(!host->card);
 
-	mmc_get_card(host->card);
+	/*
+	 * Try to acquire claim host. If failed to get the lock in 2 sec,
+	 * just return; This is to ensure that when this call is invoked
+	 * due to pm_suspend, not to block suspend for longer duration.
+	 */
+	pm_runtime_get_sync(&host->card->dev);
+	if (!mmc_try_claim_host(host, 2000)) {
+		pm_runtime_mark_last_busy(&host->card->dev);
+		pm_runtime_put_autosuspend(&host->card->dev);
+		return;
+	}
 
 	/*
 	 * Just check if our card has been removed.
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index 77c5ca3..bfe1242 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -943,12 +943,17 @@
 		 * before setting doorbell, hence one is not needed here.
 		 */
 		for_each_set_bit(tag, &comp_status, cq_host->num_slots) {
-			/* complete the corresponding mrq */
-			pr_debug("%s: completing tag -> %lu\n",
-				 mmc_hostname(mmc), tag);
-			MMC_TRACE(mmc, "%s: completing tag -> %lu\n",
-				__func__, tag);
+			mrq = get_req_by_tag(cq_host, tag);
+			if (!((mrq->cmd && mrq->cmd->error) ||
+					mrq->cmdq_req->resp_err ||
+					(mrq->data && mrq->data->error))) {
+				/* complete the corresponding mrq */
+				pr_debug("%s: completing tag -> %lu\n",
+					 mmc_hostname(mmc), tag);
+				MMC_TRACE(mmc, "%s: completing tag -> %lu\n",
+					__func__, tag);
 				cmdq_finish_data(mmc, tag);
+			}
 		}
 	}
 
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index a819b88..f3f181d 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1824,7 +1824,7 @@
 	}
 
 	pdata->status_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
-	if (gpio_is_valid(pdata->status_gpio) & !(flags & OF_GPIO_ACTIVE_LOW))
+	if (gpio_is_valid(pdata->status_gpio) && !(flags & OF_GPIO_ACTIVE_LOW))
 		pdata->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
 
 	of_property_read_u32(np, "qcom,bus-width", &bus_width);
@@ -1937,7 +1937,7 @@
 	sdhci_msm_pm_qos_parse(dev, pdata);
 
 	if (of_get_property(np, "qcom,core_3_0v_support", NULL))
-		pdata->core_3_0v_support = true;
+		msm_host->core_3_0v_support = true;
 
 	pdata->sdr104_wa = of_property_read_bool(np, "qcom,sdr104-wa");
 
@@ -2345,21 +2345,6 @@
 	return ret;
 }
 
-/*
- * Reset vreg by ensuring it is off during probe. A call
- * to enable vreg is needed to balance disable vreg
- */
-static int sdhci_msm_vreg_reset(struct sdhci_msm_pltfm_data *pdata)
-{
-	int ret;
-
-	ret = sdhci_msm_setup_vreg(pdata, 1, true);
-	if (ret)
-		return ret;
-	ret = sdhci_msm_setup_vreg(pdata, 0, true);
-	return ret;
-}
-
 /* This init function should be called only once for each SDHC slot */
 static int sdhci_msm_vreg_init(struct device *dev,
 				struct sdhci_msm_pltfm_data *pdata,
@@ -2394,7 +2379,7 @@
 		if (ret)
 			goto vdd_reg_deinit;
 	}
-	ret = sdhci_msm_vreg_reset(pdata);
+
 	if (ret)
 		dev_err(dev, "vreg reset failed (%d)\n", ret);
 	goto out;
@@ -2571,7 +2556,9 @@
 		io_level = REQ_IO_HIGH;
 	}
 	if (irq_status & CORE_PWRCTL_BUS_OFF) {
-		ret = sdhci_msm_setup_vreg(msm_host->pdata, false, false);
+		if (msm_host->pltfm_init_done)
+			ret = sdhci_msm_setup_vreg(msm_host->pdata,
+					false, false);
 		if (!ret) {
 			ret = sdhci_msm_setup_pins(msm_host->pdata, false);
 			ret |= sdhci_msm_set_vdd_io_vol(msm_host->pdata,
@@ -2617,8 +2604,9 @@
 	 * completed before its next update to registers within hc_mem.
 	 */
 	mb();
-
-	if ((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & CORE_3_0V_SUPPORT))
+	if ((io_level & REQ_IO_HIGH) &&
+			(msm_host->caps_0 & CORE_3_0V_SUPPORT) &&
+			!msm_host->core_3_0v_support)
 		writel_relaxed((readl_relaxed(host->ioaddr +
 				msm_host_offset->CORE_VENDOR_SPEC) &
 				~CORE_IO_PAD_PWR_SWITCH), host->ioaddr +
@@ -2717,14 +2705,15 @@
 					msm_host->offset;
 	unsigned long flags;
 	bool done = false;
-	u32 io_sig_sts;
+	u32 io_sig_sts = SWITCHABLE_SIGNALLING_VOL;
 
 	spin_lock_irqsave(&host->lock, flags);
 	pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
 			mmc_hostname(host->mmc), __func__, req_type,
 			msm_host->curr_pwr_state, msm_host->curr_io_level);
-	io_sig_sts = sdhci_msm_readl_relaxed(host,
-			msm_host_offset->CORE_GENERICS);
+	if (!msm_host->mci_removed)
+		io_sig_sts = sdhci_msm_readl_relaxed(host,
+				msm_host_offset->CORE_GENERICS);
 
 	/*
 	 * The IRQ for request type IO High/Low will be generated when -
@@ -3268,6 +3257,21 @@
 	pr_err("-------------------------\n");
 }
 
+static void sdhci_msm_cache_debug_data(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	struct sdhci_msm_debug_data *cached_data = &msm_host->cached_data;
+
+	memcpy(&cached_data->copy_mmc, msm_host->mmc,
+		sizeof(struct mmc_host));
+	if (msm_host->mmc->card)
+		memcpy(&cached_data->copy_card, msm_host->mmc->card,
+			sizeof(struct mmc_card));
+	memcpy(&cached_data->copy_host, host,
+		sizeof(struct sdhci_host));
+}
+
 void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -3279,6 +3283,7 @@
 	u32 test_bus_val = 0;
 	u32 debug_reg[MAX_TEST_BUS] = {0};
 
+	sdhci_msm_cache_debug_data(host);
 	pr_info("----------- VENDOR REGISTER DUMP -----------\n");
 	if (host->cq_host)
 		sdhci_msm_cmdq_dump_debug_ram(host);
@@ -3812,8 +3817,8 @@
 		group->req.type = PM_QOS_REQ_AFFINE_CORES;
 		cpumask_copy(&group->req.cpus_affine,
 			&msm_host->pdata->pm_qos_data.cpu_group_map.mask[i]);
-		/* For initialization phase, set the performance mode latency */
-		group->latency = latency[i].latency[SDHCI_PERFORMANCE_MODE];
+		/* We set default latency here for all pm_qos cpu groups. */
+		group->latency = PM_QOS_DEFAULT_VALUE;
 		pm_qos_add_request(&group->req, PM_QOS_CPU_DMA_LATENCY,
 			group->latency);
 		pr_info("%s (): voted for group #%d (mask=0x%lx) latency=%d (0x%p)\n",
@@ -4023,7 +4028,7 @@
 		msm_host->use_14lpp_dll = true;
 
 	/* Fake 3.0V support for SDIO devices which requires such voltage */
-	if (msm_host->pdata->core_3_0v_support) {
+	if (msm_host->core_3_0v_support) {
 		caps |= CORE_3_0V_SUPPORT;
 			writel_relaxed((readl_relaxed(host->ioaddr +
 			SDHCI_CAPABILITIES) | caps), host->ioaddr +
@@ -4494,6 +4499,8 @@
 		goto vreg_deinit;
 	}
 
+	msm_host->pltfm_init_done = true;
+
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_AUTOSUSPEND_DELAY_MS);
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index 53b1953..c536a7d 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -150,7 +150,6 @@
 	u32 *sup_ice_clk_table;
 	unsigned char sup_ice_clk_cnt;
 	struct sdhci_msm_pm_qos_data pm_qos_data;
-	bool core_3_0v_support;
 	bool sdr104_wa;
 };
 
@@ -171,6 +170,12 @@
 	int state;
 };
 
+struct sdhci_msm_debug_data {
+	struct mmc_host copy_mmc;
+	struct mmc_card copy_card;
+	struct sdhci_host copy_host;
+};
+
 struct sdhci_msm_host {
 	struct platform_device	*pdev;
 	void __iomem *core_mem;    /* MSM SDCC mapped address */
@@ -186,6 +191,7 @@
 	atomic_t clks_on; /* Set if clocks are enabled */
 	struct sdhci_msm_pltfm_data *pdata;
 	struct mmc_host  *mmc;
+	struct sdhci_msm_debug_data cached_data;
 	struct sdhci_pltfm_data sdhci_msm_pdata;
 	u32 curr_pwr_state;
 	u32 curr_io_level;
@@ -218,6 +224,8 @@
 	bool tuning_in_progress;
 	bool mci_removed;
 	const struct sdhci_msm_offset *offset;
+	bool core_3_0v_support;
+	bool pltfm_init_done;
 };
 
 extern char *saved_command_line;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 83be863..8fbcdae 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -148,6 +148,8 @@
 			       readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
 	}
 
+	host->mmc->err_occurred = true;
+
 	if (host->ops->dump_vendor_regs)
 		host->ops->dump_vendor_regs(host);
 	sdhci_dump_state(host);
@@ -2418,7 +2420,13 @@
 
 	if (host->ops->platform_execute_tuning) {
 		spin_unlock_irqrestore(&host->lock, flags);
+		/*
+		 * Make sure re-tuning won't get triggered for the CRC errors
+		 * occurred while executing tuning
+		 */
+		mmc_retune_disable(mmc);
 		err = host->ops->platform_execute_tuning(host, opcode);
+		mmc_retune_enable(mmc);
 		return err;
 	}
 
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 58329d2..e0f0c06 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -50,6 +50,19 @@
 	  say M here and read <file:Documentation/kbuild/modules.txt>.
 	  The module will be called ms02-nv.
 
+config MTD_MSM_QPIC_NAND
+	tristate "MSM QPIC NAND Device Support"
+	depends on MTD && (ARCH_QCOM || ARCH_MSM) && !MTD_MSM_NAND
+	select CRC16
+	select BITREVERSE
+	select MTD_NAND_IDS
+	default n
+	help
+	  Support for NAND controller in Qualcomm Technologies, Inc.
+	  Parallel Interface controller (QPIC). This new controller
+	  supports BAM mode and BCH error correction mechanism. Based on the
+	  device capabilities either 4 bit or 8 bit BCH ECC will be used.
+
 config MTD_DATAFLASH
 	tristate "Support for AT45xxx DataFlash"
 	depends on SPI_MASTER
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 7912d3a..1abde5d 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -10,6 +10,7 @@
 obj-$(CONFIG_MTD_MTDRAM)	+= mtdram.o
 obj-$(CONFIG_MTD_LART)		+= lart.o
 obj-$(CONFIG_MTD_BLOCK2MTD)	+= block2mtd.o
+obj-$(CONFIG_MTD_MSM_QPIC_NAND) += msm_qpic_nand.o
 obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o
 obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
 obj-$(CONFIG_MTD_SPEAR_SMI)	+= spear_smi.o
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
new file mode 100644
index 0000000..44b56b6
--- /dev/null
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -0,0 +1,3594 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_qpic_nand.h"
+
+#define QPIC_BAM_DEFAULT_IPC_LOGLVL 2
+
+/* The driver supports devices upto 4K page */
+#define MAX_CW_PER_PAGE 8
+/*
+ * Max descriptors needed for erase, read, write operations.
+ * Usually, this is (2 * MAX_CW_PER_PAGE).
+ */
+#define MAX_DESC 16
+
+static bool enable_euclean;
+
+/*
+ * Get the DMA memory for requested amount of size. It returns the pointer
+ * to free memory available from the allocated pool. Returns NULL if there
+ * is no free memory.
+ */
+static void *msm_nand_get_dma_buffer(struct msm_nand_chip *chip, size_t size)
+{
+	uint32_t bitmask, free_bitmask, old_bitmask;
+	uint32_t need_mask, current_need_mask;
+	int free_index;
+
+	need_mask = (1UL << DIV_ROUND_UP(size, MSM_NAND_DMA_BUFFER_SLOT_SZ))
+			- 1;
+	bitmask = atomic_read(&chip->dma_buffer_busy);
+	free_bitmask = ~bitmask;
+	if (free_bitmask == 0)
+		return NULL;
+
+	do {
+		free_index = __ffs(free_bitmask);
+		current_need_mask = need_mask << free_index;
+
+		if (size + free_index * MSM_NAND_DMA_BUFFER_SLOT_SZ >=
+						 MSM_NAND_DMA_BUFFER_SIZE)
+			return NULL;
+
+		if ((bitmask & current_need_mask) == 0) {
+			old_bitmask =
+				atomic_cmpxchg(&chip->dma_buffer_busy,
+					       bitmask,
+					       bitmask | current_need_mask);
+			if (old_bitmask == bitmask)
+				return chip->dma_virt_addr +
+				free_index * MSM_NAND_DMA_BUFFER_SLOT_SZ;
+			free_bitmask = 0;/* force return */
+		}
+		/* current free range was too small, clear all free bits */
+		/* below the top busy bit within current_need_mask */
+		free_bitmask &=
+			~(~0U >> (32 - fls(bitmask & current_need_mask)));
+	} while (free_bitmask);
+
+	return NULL;
+}
+
+/*
+ * Releases the DMA memory used to the free pool and also wakes up any user
+ * thread waiting on wait queue for free memory to be available.
+ */
+static void msm_nand_release_dma_buffer(struct msm_nand_chip *chip,
+					void *buffer, size_t size)
+{
+	int index;
+	uint32_t used_mask;
+
+	used_mask = (1UL << DIV_ROUND_UP(size, MSM_NAND_DMA_BUFFER_SLOT_SZ))
+			- 1;
+	index = ((uint8_t *)buffer - chip->dma_virt_addr) /
+		MSM_NAND_DMA_BUFFER_SLOT_SZ;
+	atomic_sub(used_mask << index, &chip->dma_buffer_busy);
+
+	wake_up(&chip->dma_wait_queue);
+}
+
+/*
+ * Calculates page address of the buffer passed, offset of buffer within
+ * that page and then maps it for DMA by calling dma_map_page().
+ */
+static dma_addr_t msm_nand_dma_map(struct device *dev, void *addr, size_t size,
+					 enum dma_data_direction dir)
+{
+	struct page *page;
+	unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+
+	if (virt_addr_valid(addr))
+		page = virt_to_page(addr);
+	else {
+		if (WARN_ON(size + offset > PAGE_SIZE))
+			return ~0;
+		page = vmalloc_to_page(addr);
+	}
+	return dma_map_page(dev, page, offset, size, dir);
+}
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static int msm_nand_bus_set_vote(struct msm_nand_info *info,
+			unsigned int vote)
+{
+	int ret = 0;
+
+	ret = msm_bus_scale_client_update_request(info->clk_data.client_handle,
+			vote);
+	if (ret)
+		pr_err("msm_bus_scale_client_update_request() failed, bus_client_handle=0x%x, vote=%d, err=%d\n",
+			info->clk_data.client_handle, vote, ret);
+	return ret;
+}
+
+static int msm_nand_setup_clocks_and_bus_bw(struct msm_nand_info *info,
+				bool vote)
+{
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(info->clk_data.qpic_clk)) {
+		ret = -EINVAL;
+		goto out;
+	}
+	if (atomic_read(&info->clk_data.clk_enabled) == vote)
+		goto out;
+	if (!atomic_read(&info->clk_data.clk_enabled) && vote) {
+		ret = msm_nand_bus_set_vote(info, 1);
+		if (ret) {
+			pr_err("Failed to vote for bus with %d\n", ret);
+			goto out;
+		}
+		ret = clk_prepare_enable(info->clk_data.qpic_clk);
+		if (ret) {
+			pr_err("Failed to enable the bus-clock with error %d\n",
+				ret);
+			msm_nand_bus_set_vote(info, 0);
+			goto out;
+		}
+	} else if (atomic_read(&info->clk_data.clk_enabled) && !vote) {
+		clk_disable_unprepare(info->clk_data.qpic_clk);
+		msm_nand_bus_set_vote(info, 0);
+	}
+	atomic_set(&info->clk_data.clk_enabled, vote);
+out:
+	return ret;
+}
+#else
+static int msm_nand_setup_clocks_and_bus_bw(struct msm_nand_info *info,
+				bool vote)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int msm_nand_runtime_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct msm_nand_info *info = dev_get_drvdata(dev);
+
+	ret = msm_nand_setup_clocks_and_bus_bw(info, false);
+
+	return ret;
+}
+
+static int msm_nand_runtime_resume(struct device *dev)
+{
+	int ret = 0;
+	struct msm_nand_info *info = dev_get_drvdata(dev);
+
+	ret = msm_nand_setup_clocks_and_bus_bw(info, true);
+
+	return ret;
+}
+
+static void msm_nand_print_rpm_info(struct device *dev)
+{
+	pr_err("RPM: runtime_status=%d, usage_count=%d, is_suspended=%d, disable_depth=%d, runtime_error=%d, request_pending=%d, request=%d\n",
+		dev->power.runtime_status, atomic_read(&dev->power.usage_count),
+		dev->power.is_suspended, dev->power.disable_depth,
+		dev->power.runtime_error, dev->power.request_pending,
+		dev->power.request);
+}
+#else
+static int msm_nand_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int msm_nand_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+
+static void msm_nand_print_rpm_info(struct device *dev)
+{
+}
+#endif
+
+#ifdef CONFIG_PM
+static int msm_nand_suspend(struct device *dev)
+{
+	int ret = 0;
+
+	if (!pm_runtime_suspended(dev))
+		ret = msm_nand_runtime_suspend(dev);
+
+	return ret;
+}
+
+static int msm_nand_resume(struct device *dev)
+{
+	int ret = 0;
+
+	if (!pm_runtime_suspended(dev))
+		ret = msm_nand_runtime_resume(dev);
+
+	return ret;
+}
+#else
+static int msm_nand_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int msm_nand_resume(struct device *dev)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int msm_nand_get_device(struct device *dev)
+{
+	int ret = 0;
+
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		pr_err("Failed to resume with %d\n", ret);
+		msm_nand_print_rpm_info(dev);
+	} else { /* Reset to success */
+		ret = 0;
+	}
+	return ret;
+}
+
+static int msm_nand_put_device(struct device *dev)
+{
+	int ret = 0;
+
+	pm_runtime_mark_last_busy(dev);
+	ret = pm_runtime_put_autosuspend(dev);
+	if (ret < 0) {
+		pr_err("Failed to suspend with %d\n", ret);
+		msm_nand_print_rpm_info(dev);
+	} else { /* Reset to success */
+		ret = 0;
+	}
+	return ret;
+}
+#else
+static int msm_nand_get_device(struct device *dev)
+{
+	return 0;
+}
+
+static int msm_nand_put_device(struct device *dev)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_MSM_BUS_SCALING
+static int msm_nand_bus_register(struct platform_device *pdev,
+		struct msm_nand_info *info)
+{
+	int ret = 0;
+
+	info->clk_data.use_cases = msm_bus_cl_get_pdata(pdev);
+	if (!info->clk_data.use_cases) {
+		ret = -EINVAL;
+		pr_err("msm_bus_cl_get_pdata failed\n");
+		goto out;
+	}
+	info->clk_data.client_handle =
+		msm_bus_scale_register_client(info->clk_data.use_cases);
+	if (!info->clk_data.client_handle) {
+		ret = -EINVAL;
+		pr_err("msm_bus_scale_register_client failed\n");
+	}
+out:
+	return ret;
+}
+
+static void msm_nand_bus_unregister(struct msm_nand_info *info)
+{
+	if (info->clk_data.client_handle)
+		msm_bus_scale_unregister_client(info->clk_data.client_handle);
+}
+#else
+static int msm_nand_bus_register(struct platform_device *pdev,
+		struct msm_nand_info *info)
+{
+	return 0;
+}
+
+static void msm_nand_bus_unregister(struct msm_nand_info *info)
+{
+}
+#endif
+
+/*
+ * Wrapper function to prepare a single SPS command element with the data
+ * that is passed to this function.
+ */
+static inline void msm_nand_prep_ce(struct sps_command_element *ce,
+				uint32_t addr, uint32_t command, uint32_t data)
+{
+	ce->addr = addr;
+	ce->command = (command & WRITE) ? (uint32_t) SPS_WRITE_COMMAND :
+			(uint32_t) SPS_READ_COMMAND;
+	ce->data = data;
+	ce->mask = 0xFFFFFFFF;
+}
+
+static int msm_nand_sps_get_iovec(struct sps_pipe *pipe, uint32_t indx,
+				unsigned int cnt, struct sps_iovec *iovec)
+{
+	int ret = 0;
+
+	do {
+		do {
+			ret = sps_get_iovec((pipe), (iovec));
+		} while (((iovec)->addr == 0x0) && ((iovec)->size == 0x0));
+		if (ret)
+			return ret;
+	} while (--(cnt));
+	return ret;
+}
+
+/*
+ * Wrapper function to prepare a single command descriptor with a single
+ * SPS command element with the data that is passed to this function.
+ *
+ * Since for any command element it is a must to have this flag
+ * SPS_IOVEC_FLAG_CMD, this function by default updates this flag for a
+ * command element that is passed and thus, the caller need not explicilty
+ * pass this flag. The other flags must be passed based on the need.  If a
+ * command element doesn't have any other flag, then 0 can be passed to flags.
+ */
+static inline void msm_nand_prep_single_desc(struct msm_nand_sps_cmd *sps_cmd,
+				uint32_t addr, uint32_t command,
+				uint32_t data, uint32_t flags)
+{
+	msm_nand_prep_ce(&sps_cmd->ce, addr, command, data);
+	sps_cmd->flags = SPS_IOVEC_FLAG_CMD | flags;
+}
+/*
+ * Read a single NANDc register as mentioned by its parameter addr. The return
+ * value indicates whether read is successful or not. The register value read
+ * is stored in val.
+ */
+static int msm_nand_flash_rd_reg(struct msm_nand_info *info, uint32_t addr,
+				uint32_t *val)
+{
+	int ret = 0, submitted_num_desc = 1;
+	struct msm_nand_sps_cmd *cmd;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	struct {
+		struct msm_nand_sps_cmd cmd;
+		uint32_t data;
+	} *dma_buffer;
+	struct sps_iovec iovec_temp;
+
+	wait_event(chip->dma_wait_queue, (dma_buffer = msm_nand_get_dma_buffer(
+		    chip, sizeof(*dma_buffer))));
+	cmd = &dma_buffer->cmd;
+	msm_nand_prep_single_desc(cmd, addr, READ, msm_virt_to_dma(chip,
+			&dma_buffer->data), SPS_IOVEC_FLAG_INT);
+
+	mutex_lock(&info->lock);
+	ret = msm_nand_get_device(chip->dev);
+	if (ret)
+		goto out;
+	ret = sps_transfer_one(info->sps.cmd_pipe.handle,
+			msm_virt_to_dma(chip, &cmd->ce),
+			sizeof(struct sps_command_element), NULL, cmd->flags);
+	if (ret) {
+		pr_err("failed to submit command %x ret %d\n", addr, ret);
+		msm_nand_put_device(chip->dev);
+		goto out;
+	}
+	ret = msm_nand_sps_get_iovec(info->sps.cmd_pipe.handle,
+			info->sps.cmd_pipe.index, submitted_num_desc,
+			&iovec_temp);
+	if (ret) {
+		pr_err("Failed to get iovec for pipe %d: (ret%d)\n",
+				(info->sps.cmd_pipe.index), ret);
+		goto out;
+	}
+	ret = msm_nand_put_device(chip->dev);
+	if (ret)
+		goto out;
+	*val = dma_buffer->data;
+out:
+	mutex_unlock(&info->lock);
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+	return ret;
+}
+
+/*
+ * Read the Flash ID from the Nand Flash Device. The return value < 0
+ * indicates failure. When successful, the Flash ID is stored in parameter
+ * read_id.
+ */
+#define READID_CMDS 5
+static int msm_nand_flash_read_id(struct msm_nand_info *info,
+		bool read_onfi_signature, uint32_t *read_id,
+		uint32_t *read_id2)
+{
+	int err = 0, i = 0;
+	struct msm_nand_sps_cmd *cmd;
+	struct sps_iovec *iovec;
+	struct sps_iovec iovec_temp;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	/*
+	 * The following 5 commands are required to read id -
+	 * write commands - addr0, flash, exec
+	 * read_commands - read_id, read_id2
+	 */
+	struct {
+		struct sps_transfer xfer;
+		struct sps_iovec cmd_iovec[READID_CMDS];
+		struct msm_nand_sps_cmd cmd[READID_CMDS];
+		uint32_t data[READID_CMDS];
+	} *dma_buffer;
+
+	wait_event(chip->dma_wait_queue, (dma_buffer = msm_nand_get_dma_buffer
+				(chip, sizeof(*dma_buffer))));
+	if (read_onfi_signature)
+		dma_buffer->data[0] = FLASH_READ_ONFI_SIGNATURE_ADDRESS;
+	else
+		dma_buffer->data[0] = FLASH_READ_DEVICE_ID_ADDRESS;
+
+	dma_buffer->data[1] = EXTENDED_FETCH_ID | MSM_NAND_CMD_FETCH_ID;
+	dma_buffer->data[2] = 1;
+	dma_buffer->data[3] = 0xeeeeeeee;
+	dma_buffer->data[4] = 0xeeeeeeee;
+
+	cmd = dma_buffer->cmd;
+	msm_nand_prep_single_desc(cmd, MSM_NAND_ADDR0(info), WRITE,
+			dma_buffer->data[0], SPS_IOVEC_FLAG_LOCK);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_FLASH_CMD(info), WRITE,
+			dma_buffer->data[1], 0);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_EXEC_CMD(info), WRITE,
+			dma_buffer->data[2], SPS_IOVEC_FLAG_NWD);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_READ_ID(info), READ,
+			msm_virt_to_dma(chip, &dma_buffer->data[3]), 0);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_READ_ID2(info), READ,
+			msm_virt_to_dma(chip, &dma_buffer->data[4]),
+			SPS_IOVEC_FLAG_UNLOCK | SPS_IOVEC_FLAG_INT);
+	cmd++;
+
+	WARN_ON(cmd - dma_buffer->cmd > READID_CMDS);
+	dma_buffer->xfer.iovec_count = (cmd - dma_buffer->cmd);
+	dma_buffer->xfer.iovec = dma_buffer->cmd_iovec;
+	dma_buffer->xfer.iovec_phys = msm_virt_to_dma(chip,
+					&dma_buffer->cmd_iovec);
+	iovec = dma_buffer->xfer.iovec;
+
+	for (i = 0; i < dma_buffer->xfer.iovec_count; i++) {
+		iovec->addr =  msm_virt_to_dma(chip, &dma_buffer->cmd[i].ce);
+		iovec->size = sizeof(struct sps_command_element);
+		iovec->flags = dma_buffer->cmd[i].flags;
+		iovec++;
+	}
+
+	mutex_lock(&info->lock);
+	err = msm_nand_get_device(chip->dev);
+	if (err)
+		goto out;
+	err =  sps_transfer(info->sps.cmd_pipe.handle, &dma_buffer->xfer);
+	if (err) {
+		pr_err("Failed to submit commands %d\n", err);
+		msm_nand_put_device(chip->dev);
+		goto out;
+	}
+	err = msm_nand_sps_get_iovec(info->sps.cmd_pipe.handle,
+			info->sps.cmd_pipe.index, dma_buffer->xfer.iovec_count,
+			&iovec_temp);
+
+	if (err) {
+		pr_err("Failed to get iovec for pipe %d: (err:%d)\n",
+				(info->sps.cmd_pipe.index), err);
+		goto out;
+	}
+	pr_debug("Read ID register value 0x%x\n", dma_buffer->data[3]);
+	if (!read_onfi_signature)
+		pr_debug("nandid: %x maker %02x device %02x\n",
+		       dma_buffer->data[3], dma_buffer->data[3] & 0xff,
+		       (dma_buffer->data[3] >> 8) & 0xff);
+	*read_id = dma_buffer->data[3];
+	if (read_id2) {
+		pr_debug("Extended Read ID register value 0x%x\n",
+				dma_buffer->data[4]);
+		*read_id2 = dma_buffer->data[4];
+	}
+	err = msm_nand_put_device(chip->dev);
+out:
+	mutex_unlock(&info->lock);
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+	return err;
+}
+
+/*
+ * Contains data for common configuration registers that must be programmed
+ * for every NANDc operation.
+ */
+struct msm_nand_common_cfgs {
+	uint32_t cmd;
+	uint32_t addr0;
+	uint32_t addr1;
+	uint32_t cfg0;
+	uint32_t cfg1;
+};
+
+/*
+ * Function to prepare SPS command elements to write into NANDc configuration
+ * registers as per the data defined in struct msm_nand_common_cfgs. This is
+ * required for the following NANDc operations - Erase, Bad Block checking
+ * and for reading ONFI parameter page.
+ */
+static void msm_nand_prep_cfg_cmd_desc(struct msm_nand_info *info,
+				struct msm_nand_common_cfgs data,
+				struct msm_nand_sps_cmd **curr_cmd)
+{
+	struct msm_nand_sps_cmd *cmd;
+
+	cmd = *curr_cmd;
+	msm_nand_prep_single_desc(cmd, MSM_NAND_FLASH_CMD(info), WRITE,
+			data.cmd, SPS_IOVEC_FLAG_LOCK);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_ADDR0(info), WRITE,
+			data.addr0, 0);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_ADDR1(info), WRITE,
+			data.addr1, 0);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_DEV0_CFG0(info), WRITE,
+			data.cfg0, 0);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_DEV0_CFG1(info), WRITE,
+			data.cfg1, 0);
+	cmd++;
+	*curr_cmd = cmd;
+}
+
+/*
+ * Function to check the CRC integrity check on ONFI parameter page read.
+ * For ONFI parameter page read, the controller ECC will be disabled. Hence,
+ * it is mandatory to manually compute CRC and check it against the value
+ * stored within ONFI page.
+ */
+static uint16_t msm_nand_flash_onfi_crc_check(uint8_t *buffer, uint16_t count)
+{
+	int i;
+	uint16_t result;
+
+	for (i = 0; i < count; i++)
+		buffer[i] = bitrev8(buffer[i]);
+
+	result = bitrev16(crc16(bitrev16(0x4f4e), buffer, count));
+
+	for (i = 0; i < count; i++)
+		buffer[i] = bitrev8(buffer[i]);
+
+	return result;
+}
+
+/*
+ * Structure that contains NANDc register data for commands required
+ * for reading ONFI parameter page.
+ */
+struct msm_nand_flash_onfi_data {
+	struct msm_nand_common_cfgs cfg;
+	uint32_t exec;
+	uint32_t ecc_bch_cfg;
+};
+
+struct version {
+	uint16_t nand_major;
+	uint16_t nand_minor;
+	uint16_t qpic_major;
+	uint16_t qpic_minor;
+};
+
+static int msm_nand_version_check(struct msm_nand_info *info,
+			struct version *nandc_version)
+{
+	uint32_t qpic_ver = 0, nand_ver = 0;
+	int err = 0;
+
+	/* Lookup the version to identify supported features */
+	err = msm_nand_flash_rd_reg(info, MSM_NAND_VERSION(info),
+		&nand_ver);
+	if (err) {
+		pr_err("Failed to read NAND_VERSION, err=%d\n", err);
+		goto out;
+	}
+	nandc_version->nand_major = (nand_ver & MSM_NAND_VERSION_MAJOR_MASK) >>
+		MSM_NAND_VERSION_MAJOR_SHIFT;
+	nandc_version->nand_minor = (nand_ver & MSM_NAND_VERSION_MINOR_MASK) >>
+		MSM_NAND_VERSION_MINOR_SHIFT;
+
+	err = msm_nand_flash_rd_reg(info, MSM_NAND_QPIC_VERSION(info),
+		&qpic_ver);
+	if (err) {
+		pr_err("Failed to read QPIC_VERSION, err=%d\n", err);
+		goto out;
+	}
+	nandc_version->qpic_major = (qpic_ver & MSM_NAND_VERSION_MAJOR_MASK) >>
+			MSM_NAND_VERSION_MAJOR_SHIFT;
+	nandc_version->qpic_minor = (qpic_ver & MSM_NAND_VERSION_MINOR_MASK) >>
+			MSM_NAND_VERSION_MINOR_SHIFT;
+	pr_info("nand_major:%d, nand_minor:%d, qpic_major:%d, qpic_minor:%d\n",
+		nandc_version->nand_major, nandc_version->nand_minor,
+		nandc_version->qpic_major, nandc_version->qpic_minor);
+out:
+	return err;
+}
+
+/*
+ * Function to identify whether the attached NAND flash device is
+ * complaint to ONFI spec or not. If yes, then it reads the ONFI parameter
+ * page to get the device parameters.
+ */
+#define ONFI_CMDS 9
+static int msm_nand_flash_onfi_probe(struct msm_nand_info *info)
+{
+	struct msm_nand_chip *chip = &info->nand_chip;
+	struct flash_identification *flash = &info->flash_dev;
+	uint32_t crc_chk_count = 0, page_address = 0;
+	int ret = 0, i = 0, submitted_num_desc = 1;
+
+	/* SPS parameters */
+	struct msm_nand_sps_cmd *cmd, *curr_cmd;
+	struct sps_iovec *iovec;
+	struct sps_iovec iovec_temp;
+	uint32_t rdata;
+
+	/* ONFI Identifier/Parameter Page parameters */
+	uint8_t *onfi_param_info_buf = NULL;
+	dma_addr_t dma_addr_param_info = 0;
+	struct onfi_param_page *onfi_param_page_ptr;
+	struct msm_nand_flash_onfi_data data;
+	uint32_t onfi_signature = 0;
+
+	/*
+	 * The following 9 commands are required to get onfi parameters -
+	 * flash, addr0, addr1, cfg0, cfg1, dev0_ecc_cfg,
+	 * read_loc_0, exec, flash_status (read cmd).
+	 */
+	struct {
+		struct sps_transfer xfer;
+		struct sps_iovec cmd_iovec[ONFI_CMDS];
+		struct msm_nand_sps_cmd cmd[ONFI_CMDS];
+		uint32_t flash_status;
+	} *dma_buffer;
+
+
+	/* Lookup the version to identify supported features */
+	struct version nandc_version = {0};
+
+	ret = msm_nand_version_check(info, &nandc_version);
+	if (!ret && !(nandc_version.nand_major == 1 &&
+			nandc_version.nand_minor >= 5 &&
+			nandc_version.qpic_major == 1 &&
+			nandc_version.qpic_minor >= 5)) {
+		ret = -EPERM;
+		goto out;
+	}
+	wait_event(chip->dma_wait_queue, (onfi_param_info_buf =
+		msm_nand_get_dma_buffer(chip, ONFI_PARAM_INFO_LENGTH)));
+	dma_addr_param_info = msm_virt_to_dma(chip, onfi_param_info_buf);
+
+	wait_event(chip->dma_wait_queue, (dma_buffer = msm_nand_get_dma_buffer
+				(chip, sizeof(*dma_buffer))));
+
+	ret = msm_nand_flash_read_id(info, 1, &onfi_signature, NULL);
+	if (ret < 0) {
+		pr_err("Failed to read ONFI signature\n");
+		goto free_dma;
+	}
+	if (onfi_signature != ONFI_PARAMETER_PAGE_SIGNATURE) {
+		pr_info("Found a non ONFI device\n");
+		ret = -EIO;
+		goto free_dma;
+	}
+
+	memset(&data, 0, sizeof(struct msm_nand_flash_onfi_data));
+
+	/* Lookup the partition to which apps has access to */
+	for (i = 0; i < FLASH_PTABLE_MAX_PARTS_V4; i++) {
+		if (mtd_part[i].name && !strcmp("boot", mtd_part[i].name)) {
+			page_address = mtd_part[i].offset << 6;
+			break;
+		}
+	}
+	if (!page_address) {
+		pr_info("%s: no apps partition found in smem\n", __func__);
+		ret = -EPERM;
+		goto free_dma;
+	}
+	data.cfg.cmd = MSM_NAND_CMD_PAGE_READ_ONFI;
+	data.exec = 1;
+	data.cfg.addr0 = (page_address << 16) |
+				FLASH_READ_ONFI_PARAMETERS_ADDRESS;
+	data.cfg.addr1 = (page_address >> 16) & 0xFF;
+	data.cfg.cfg0 =	MSM_NAND_CFG0_RAW_ONFI_PARAM_INFO;
+	data.cfg.cfg1 = MSM_NAND_CFG1_RAW_ONFI_PARAM_INFO;
+	data.ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
+	dma_buffer->flash_status = 0xeeeeeeee;
+
+	curr_cmd = cmd = dma_buffer->cmd;
+	msm_nand_prep_cfg_cmd_desc(info, data.cfg, &curr_cmd);
+
+	cmd = curr_cmd;
+	msm_nand_prep_single_desc(cmd, MSM_NAND_DEV0_ECC_CFG(info), WRITE,
+			data.ecc_bch_cfg, 0);
+	cmd++;
+
+	rdata = (0 << 0) | (ONFI_PARAM_INFO_LENGTH << 16) | (1 << 31);
+	msm_nand_prep_single_desc(cmd, MSM_NAND_READ_LOCATION_0(info), WRITE,
+			rdata, 0);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_EXEC_CMD(info), WRITE,
+		data.exec, SPS_IOVEC_FLAG_NWD);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_FLASH_STATUS(info), READ,
+		msm_virt_to_dma(chip, &dma_buffer->flash_status),
+		SPS_IOVEC_FLAG_UNLOCK | SPS_IOVEC_FLAG_INT);
+	cmd++;
+
+	WARN_ON(cmd - dma_buffer->cmd > ONFI_CMDS);
+	dma_buffer->xfer.iovec_count = (cmd - dma_buffer->cmd);
+	dma_buffer->xfer.iovec = dma_buffer->cmd_iovec;
+	dma_buffer->xfer.iovec_phys = msm_virt_to_dma(chip,
+					&dma_buffer->cmd_iovec);
+	iovec = dma_buffer->xfer.iovec;
+
+	for (i = 0; i < dma_buffer->xfer.iovec_count; i++) {
+		iovec->addr =  msm_virt_to_dma(chip,
+				&dma_buffer->cmd[i].ce);
+		iovec->size = sizeof(struct sps_command_element);
+		iovec->flags = dma_buffer->cmd[i].flags;
+		iovec++;
+	}
+	mutex_lock(&info->lock);
+	ret = msm_nand_get_device(chip->dev);
+	if (ret)
+		goto unlock_mutex;
+	/* Submit data descriptor */
+	ret = sps_transfer_one(info->sps.data_prod.handle, dma_addr_param_info,
+			ONFI_PARAM_INFO_LENGTH, NULL, SPS_IOVEC_FLAG_INT);
+	if (ret) {
+		pr_err("Failed to submit data descriptors %d\n", ret);
+		goto put_dev;
+	}
+	/* Submit command descriptors */
+	ret =  sps_transfer(info->sps.cmd_pipe.handle,
+			&dma_buffer->xfer);
+	if (ret) {
+		pr_err("Failed to submit commands %d\n", ret);
+		goto put_dev;
+	}
+
+	ret = msm_nand_sps_get_iovec(info->sps.cmd_pipe.handle,
+			info->sps.cmd_pipe.index, dma_buffer->xfer.iovec_count,
+			&iovec_temp);
+
+	if (ret) {
+		pr_err("Failed to get iovec for pipe %d: (ret:%d)\n",
+				(info->sps.cmd_pipe.index), ret);
+		goto put_dev;
+	}
+	ret = msm_nand_sps_get_iovec(info->sps.data_prod.handle,
+			info->sps.data_prod.index, submitted_num_desc,
+			&iovec_temp);
+	if (ret) {
+		pr_err("Failed to get iovec for pipe %d: (ret:%d)\n",
+				(info->sps.data_prod.index), ret);
+		goto put_dev;
+	}
+
+	ret = msm_nand_put_device(chip->dev);
+	mutex_unlock(&info->lock);
+	if (ret)
+		goto free_dma;
+
+	/* Check for flash status errors */
+	if (dma_buffer->flash_status & (FS_OP_ERR | FS_MPU_ERR)) {
+		pr_err("MPU/OP err (0x%x) is set\n", dma_buffer->flash_status);
+		ret = -EIO;
+		goto free_dma;
+	}
+
+	for (crc_chk_count = 0; crc_chk_count < ONFI_PARAM_INFO_LENGTH
+			/ ONFI_PARAM_PAGE_LENGTH; crc_chk_count++) {
+		onfi_param_page_ptr =
+			(struct onfi_param_page *)
+			(&(onfi_param_info_buf
+			[ONFI_PARAM_PAGE_LENGTH *
+			crc_chk_count]));
+		if (msm_nand_flash_onfi_crc_check(
+			(uint8_t *)onfi_param_page_ptr,
+			ONFI_PARAM_PAGE_LENGTH - 2) ==
+			onfi_param_page_ptr->integrity_crc) {
+			break;
+		}
+	}
+	if (crc_chk_count >= ONFI_PARAM_INFO_LENGTH
+			/ ONFI_PARAM_PAGE_LENGTH) {
+		pr_err("CRC Check failed on param page\n");
+		ret = -EIO;
+		goto free_dma;
+	}
+	ret = msm_nand_flash_read_id(info, 0, &flash->flash_id, NULL);
+	if (ret < 0) {
+		pr_err("Failed to read flash ID\n");
+		goto free_dma;
+	}
+	flash->widebus  = onfi_param_page_ptr->features_supported & 0x01;
+	flash->pagesize = onfi_param_page_ptr->number_of_data_bytes_per_page;
+	flash->blksize  = onfi_param_page_ptr->number_of_pages_per_block *
+					flash->pagesize;
+	flash->oobsize  = onfi_param_page_ptr->number_of_spare_bytes_per_page;
+	flash->density  = onfi_param_page_ptr->number_of_blocks_per_logical_unit
+					* flash->blksize;
+	flash->ecc_correctability = onfi_param_page_ptr->
+					number_of_bits_ecc_correctability;
+
+	pr_info("Found an ONFI compliant device %s\n",
+			onfi_param_page_ptr->device_model);
+	/*
+	 * Temporary hack for MT29F4G08ABC device.
+	 * Since the device is not properly adhering
+	 * to ONFi specification it is reporting
+	 * as 16 bit device though it is 8 bit device!!!
+	 */
+	if (!strcmp(onfi_param_page_ptr->device_model, "MT29F4G08ABC"))
+		flash->widebus  = 0;
+	goto free_dma;
+put_dev:
+	msm_nand_put_device(chip->dev);
+unlock_mutex:
+	mutex_unlock(&info->lock);
+free_dma:
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+	msm_nand_release_dma_buffer(chip, onfi_param_info_buf,
+			ONFI_PARAM_INFO_LENGTH);
+out:
+	return ret;
+}
+
+/*
+ * Structure that contains read/write parameters required for reading/writing
+ * from/to a page.
+ */
+struct msm_nand_rw_params {
+	uint32_t page;
+	uint32_t page_count;
+	uint32_t sectordatasize;
+	uint32_t sectoroobsize;
+	uint32_t cwperpage;
+	uint32_t oob_len_cmd;
+	uint32_t oob_len_data;
+	uint32_t start_sector;
+	uint32_t oob_col;
+	dma_addr_t data_dma_addr;
+	dma_addr_t oob_dma_addr;
+	dma_addr_t ecc_dma_addr;
+	dma_addr_t data_dma_addr_curr;
+	dma_addr_t oob_dma_addr_curr;
+	dma_addr_t ecc_dma_addr_curr;
+	bool read;
+};
+
+/*
+ * Structure that contains NANDc register data required for reading/writing
+ * from/to a page.
+ */
+struct msm_nand_rw_reg_data {
+	uint32_t cmd;
+	uint32_t addr0;
+	uint32_t addr1;
+	uint32_t cfg0;
+	uint32_t cfg1;
+	uint32_t ecc_bch_cfg;
+	uint32_t exec;
+	uint32_t ecc_cfg;
+	uint32_t clrfstatus;
+	uint32_t clrrstatus;
+};
+
+/*
+ * Function that validates page read/write MTD parameters received from upper
+ * layers such as MTD/YAFFS2 and returns error for any unsupported operations
+ * by the driver. In case of success, it also maps the data and oob buffer
+ * received for DMA.
+ */
+static int msm_nand_validate_mtd_params(struct mtd_info *mtd, bool read,
+					loff_t offset,
+					struct mtd_oob_ops *ops,
+					struct msm_nand_rw_params *args)
+{
+	struct msm_nand_info *info = mtd->priv;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	int err = 0;
+
+	pr_debug("========================================================\n");
+	pr_debug("offset 0x%llx mode %d\ndatbuf 0x%pK datlen 0x%x\n",
+			offset, ops->mode, ops->datbuf, ops->len);
+	pr_debug("oobbuf 0x%pK ooblen 0x%x\n", ops->oobbuf, ops->ooblen);
+
+	if (ops->mode == MTD_OPS_PLACE_OOB) {
+		pr_err("MTD_OPS_PLACE_OOB is not supported\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (mtd->writesize == PAGE_SIZE_2K)
+		args->page = offset >> 11;
+
+	if (mtd->writesize == PAGE_SIZE_4K)
+		args->page = offset >> 12;
+
+	args->oob_len_cmd = ops->ooblen;
+	args->oob_len_data = ops->ooblen;
+	args->cwperpage = (mtd->writesize >> 9);
+	args->read = (read ? true : false);
+
+	if (offset & (mtd->writesize - 1)) {
+		pr_err("unsupported offset 0x%llx\n", offset);
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (!read && !ops->datbuf) {
+		pr_err("No data buffer provided for write!!\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (ops->mode == MTD_OPS_RAW) {
+		if (!ops->datbuf) {
+			pr_err("No data buffer provided for RAW mode\n");
+			err =  -EINVAL;
+			goto out;
+		} else if ((ops->len % (mtd->writesize +
+				mtd->oobsize)) != 0) {
+			pr_err("unsupported data len %d for RAW mode\n",
+				ops->len);
+			err = -EINVAL;
+			goto out;
+		}
+		args->page_count = ops->len / (mtd->writesize + mtd->oobsize);
+
+	} else if (ops->mode == MTD_OPS_AUTO_OOB) {
+		if (ops->datbuf && (ops->len % mtd->writesize) != 0) {
+			/* when ops->datbuf is NULL, ops->len can be ooblen */
+			pr_err("unsupported data len %d for AUTO mode\n",
+					ops->len);
+			err = -EINVAL;
+			goto out;
+		}
+		if (read && ops->oobbuf && !ops->datbuf) {
+			args->start_sector = args->cwperpage - 1;
+			args->page_count = ops->ooblen / mtd->oobavail;
+			if ((args->page_count == 0) && (ops->ooblen))
+				args->page_count = 1;
+		} else if (ops->datbuf) {
+			args->page_count = ops->len / mtd->writesize;
+		}
+	}
+
+	if (ops->datbuf) {
+		if (read)
+			memset(ops->datbuf, 0xFF, ops->len);
+		args->data_dma_addr_curr = args->data_dma_addr =
+			msm_nand_dma_map(chip->dev, ops->datbuf, ops->len,
+				      (read ? DMA_FROM_DEVICE : DMA_TO_DEVICE));
+		if (dma_mapping_error(chip->dev, args->data_dma_addr)) {
+			pr_err("dma mapping failed for 0x%pK\n", ops->datbuf);
+			err = -EIO;
+			goto out;
+		}
+	}
+	if (ops->oobbuf) {
+		if (read)
+			memset(ops->oobbuf, 0xFF, ops->ooblen);
+		args->oob_dma_addr_curr = args->oob_dma_addr =
+			msm_nand_dma_map(chip->dev, ops->oobbuf, ops->ooblen,
+				(read ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE));
+		if (dma_mapping_error(chip->dev, args->oob_dma_addr)) {
+			pr_err("dma mapping failed for 0x%pK\n", ops->oobbuf);
+			err = -EIO;
+			goto dma_map_oobbuf_failed;
+		}
+	}
+	goto out;
+dma_map_oobbuf_failed:
+	if (ops->datbuf)
+		dma_unmap_page(chip->dev, args->data_dma_addr, ops->len,
+				(read ? DMA_FROM_DEVICE : DMA_TO_DEVICE));
+out:
+	return err;
+}
+
+/*
+ * Function that updates NANDc register data (struct msm_nand_rw_reg_data)
+ * required for page read/write.
+ */
+static void msm_nand_update_rw_reg_data(struct msm_nand_chip *chip,
+					struct mtd_oob_ops *ops,
+					struct msm_nand_rw_params *args,
+					struct msm_nand_rw_reg_data *data)
+{
+	if (args->read) {
+		if (ops->mode != MTD_OPS_RAW) {
+			data->cmd = MSM_NAND_CMD_PAGE_READ_ECC;
+			data->cfg0 =
+			(chip->cfg0 & ~(7U << CW_PER_PAGE)) |
+			(((args->cwperpage-1) - args->start_sector)
+			 << CW_PER_PAGE);
+			data->cfg1 = chip->cfg1;
+			data->ecc_bch_cfg = chip->ecc_bch_cfg;
+		} else {
+			data->cmd = MSM_NAND_CMD_PAGE_READ_ALL;
+			data->cfg0 =
+			(chip->cfg0_raw & ~(7U << CW_PER_PAGE)) |
+			(((args->cwperpage-1) - args->start_sector)
+			 << CW_PER_PAGE);
+			data->cfg1 = chip->cfg1_raw;
+			data->ecc_bch_cfg = chip->ecc_cfg_raw;
+		}
+
+	} else {
+		if (ops->mode != MTD_OPS_RAW) {
+			data->cmd = MSM_NAND_CMD_PRG_PAGE;
+			data->cfg0 = chip->cfg0;
+			data->cfg1 = chip->cfg1;
+			data->ecc_bch_cfg = chip->ecc_bch_cfg;
+		} else {
+			data->cmd = MSM_NAND_CMD_PRG_PAGE_ALL;
+			data->cfg0 = chip->cfg0_raw;
+			data->cfg1 = chip->cfg1_raw;
+			data->ecc_bch_cfg = chip->ecc_cfg_raw;
+		}
+		data->clrfstatus = MSM_NAND_RESET_FLASH_STS;
+		data->clrrstatus = MSM_NAND_RESET_READ_STS;
+	}
+	data->exec = 1;
+	data->ecc_cfg = chip->ecc_buf_cfg;
+}
+
+/*
+ * Function to prepare series of SPS command descriptors required for a page
+ * read/write operation.
+ */
+static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops,
+				struct msm_nand_rw_params *args,
+				struct msm_nand_rw_reg_data *data,
+				struct msm_nand_info *info,
+				uint32_t curr_cw,
+				struct msm_nand_rw_cmd_desc *cmd_list,
+				uint32_t *cw_desc_cnt,
+				uint32_t ecc_parity_bytes)
+{
+	struct msm_nand_chip *chip = &info->nand_chip;
+	uint32_t rdata;
+	/* read_location register parameters */
+	uint32_t offset, size, last_read;
+	struct sps_command_element *curr_ce, *start_ce;
+	uint32_t *flags_ptr, *num_ce_ptr;
+
+	if (curr_cw == args->start_sector) {
+		curr_ce = start_ce = &cmd_list->setup_desc.ce[0];
+		num_ce_ptr = &cmd_list->setup_desc.num_ce;
+		flags_ptr = &cmd_list->setup_desc.flags;
+		*flags_ptr = CMD_LCK;
+		cmd_list->count = 1;
+		msm_nand_prep_ce(curr_ce, MSM_NAND_FLASH_CMD(info), WRITE,
+				data->cmd);
+		curr_ce++;
+
+		msm_nand_prep_ce(curr_ce, MSM_NAND_ADDR0(info), WRITE,
+				data->addr0);
+		curr_ce++;
+
+		msm_nand_prep_ce(curr_ce, MSM_NAND_ADDR1(info), WRITE,
+				data->addr1);
+		curr_ce++;
+
+		msm_nand_prep_ce(curr_ce, MSM_NAND_DEV0_CFG0(info), WRITE,
+				data->cfg0);
+		curr_ce++;
+
+		msm_nand_prep_ce(curr_ce, MSM_NAND_DEV0_CFG1(info), WRITE,
+				data->cfg1);
+		curr_ce++;
+
+		msm_nand_prep_ce(curr_ce, MSM_NAND_DEV0_ECC_CFG(info), WRITE,
+				data->ecc_bch_cfg);
+		curr_ce++;
+
+		msm_nand_prep_ce(curr_ce, MSM_NAND_EBI2_ECC_BUF_CFG(info),
+				WRITE, data->ecc_cfg);
+		curr_ce++;
+
+		if (!args->read) {
+			msm_nand_prep_ce(curr_ce, MSM_NAND_FLASH_STATUS(info),
+					WRITE, data->clrfstatus);
+			curr_ce++;
+			goto sub_exec_cmd;
+		} else {
+			msm_nand_prep_ce(curr_ce,
+					MSM_NAND_ERASED_CW_DETECT_CFG(info),
+					WRITE, CLR_ERASED_PAGE_DET);
+			curr_ce++;
+			msm_nand_prep_ce(curr_ce,
+					MSM_NAND_ERASED_CW_DETECT_CFG(info),
+					WRITE, SET_ERASED_PAGE_DET);
+			curr_ce++;
+		}
+	} else {
+		curr_ce = start_ce = &cmd_list->cw_desc[*cw_desc_cnt].ce[0];
+		num_ce_ptr = &cmd_list->cw_desc[*cw_desc_cnt].num_ce;
+		flags_ptr = &cmd_list->cw_desc[*cw_desc_cnt].flags;
+		*cw_desc_cnt += 1;
+		*flags_ptr = CMD;
+		cmd_list->count++;
+	}
+	if (!args->read)
+		goto sub_exec_cmd;
+
+	if (ops->mode == MTD_OPS_RAW) {
+		if (ecc_parity_bytes) {
+			rdata = (BYTES_517 << 0) | (ecc_parity_bytes << 16)
+				| (1 << 31);
+			msm_nand_prep_ce(curr_ce,
+					MSM_NAND_READ_LOCATION_0(info),
+					WRITE, rdata);
+			curr_ce++;
+		} else {
+			rdata = (0 << 0) | (chip->cw_size << 16) | (1 << 31);
+			msm_nand_prep_ce(curr_ce,
+					MSM_NAND_READ_LOCATION_0(info),
+					WRITE, rdata);
+			curr_ce++;
+		}
+	}
+	if (ops->mode == MTD_OPS_AUTO_OOB) {
+		if (ops->datbuf) {
+			offset = 0;
+			size = (curr_cw < (args->cwperpage - 1)) ? 516 :
+				(512 - ((args->cwperpage - 1) << 2));
+			last_read = (curr_cw < (args->cwperpage - 1)) ? 1 :
+				(ops->oobbuf ? 0 : 1);
+			rdata = (offset << 0) | (size << 16) |
+				(last_read << 31);
+
+			msm_nand_prep_ce(curr_ce,
+					MSM_NAND_READ_LOCATION_0(info),
+					WRITE,
+					rdata);
+			curr_ce++;
+		}
+		if (curr_cw == (args->cwperpage - 1) && ops->oobbuf) {
+			offset = 512 - ((args->cwperpage - 1) << 2);
+			size = (args->cwperpage) << 2;
+			if (size > args->oob_len_cmd)
+				size = args->oob_len_cmd;
+			args->oob_len_cmd -= size;
+			last_read = 1;
+			rdata = (offset << 0) | (size << 16) |
+				(last_read << 31);
+
+			if (!ops->datbuf)
+				msm_nand_prep_ce(curr_ce,
+						MSM_NAND_READ_LOCATION_0(info),
+						WRITE, rdata);
+			else
+				msm_nand_prep_ce(curr_ce,
+						MSM_NAND_READ_LOCATION_1(info),
+						WRITE, rdata);
+			curr_ce++;
+		}
+	}
+sub_exec_cmd:
+	*flags_ptr |= NWD;
+	msm_nand_prep_ce(curr_ce, MSM_NAND_EXEC_CMD(info), WRITE, data->exec);
+	curr_ce++;
+
+	*num_ce_ptr = curr_ce - start_ce;
+}
+
+/*
+ * Function to prepare and submit SPS data descriptors required for a page
+ * read/write operation.
+ */
+static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops,
+				struct msm_nand_rw_params *args,
+				struct msm_nand_info *info,
+				uint32_t curr_cw,
+				uint32_t ecc_parity_bytes)
+{
+	struct msm_nand_chip *chip = &info->nand_chip;
+	struct sps_pipe *data_pipe_handle;
+	uint32_t sectordatasize, sectoroobsize;
+	uint32_t sps_flags = 0;
+	int err = 0;
+
+	if (args->read)
+		data_pipe_handle = info->sps.data_prod.handle;
+	else
+		data_pipe_handle = info->sps.data_cons.handle;
+
+	if (ops->mode == MTD_OPS_RAW) {
+		if (ecc_parity_bytes && args->read) {
+			if (curr_cw == (args->cwperpage - 1))
+				sps_flags |= SPS_IOVEC_FLAG_INT;
+
+			/* read only ecc bytes */
+			err = sps_transfer_one(data_pipe_handle,
+					args->ecc_dma_addr_curr,
+					ecc_parity_bytes, NULL,
+					sps_flags);
+			if (err)
+				goto out;
+			args->ecc_dma_addr_curr += ecc_parity_bytes;
+		} else {
+			sectordatasize = chip->cw_size;
+			if (!args->read)
+				sps_flags = SPS_IOVEC_FLAG_EOT;
+			if (curr_cw == (args->cwperpage - 1))
+				sps_flags |= SPS_IOVEC_FLAG_INT;
+
+			err = sps_transfer_one(data_pipe_handle,
+					args->data_dma_addr_curr,
+					sectordatasize, NULL,
+					sps_flags);
+			if (err)
+				goto out;
+			args->data_dma_addr_curr += sectordatasize;
+		}
+	} else if (ops->mode == MTD_OPS_AUTO_OOB) {
+		if (ops->datbuf) {
+			sectordatasize = (curr_cw < (args->cwperpage - 1))
+			? 516 : (512 - ((args->cwperpage - 1) << 2));
+
+			if (!args->read) {
+				sps_flags = SPS_IOVEC_FLAG_EOT;
+				if (curr_cw == (args->cwperpage - 1) &&
+						ops->oobbuf)
+					sps_flags = 0;
+			}
+			if ((curr_cw == (args->cwperpage - 1)) && !ops->oobbuf)
+				sps_flags |= SPS_IOVEC_FLAG_INT;
+
+			err = sps_transfer_one(data_pipe_handle,
+					args->data_dma_addr_curr,
+					sectordatasize, NULL,
+					sps_flags);
+			if (err)
+				goto out;
+			args->data_dma_addr_curr += sectordatasize;
+		}
+
+		if (ops->oobbuf && (curr_cw == (args->cwperpage - 1))) {
+			sectoroobsize = args->cwperpage << 2;
+			if (sectoroobsize > args->oob_len_data)
+				sectoroobsize = args->oob_len_data;
+
+			if (!args->read)
+				sps_flags |= SPS_IOVEC_FLAG_EOT;
+			sps_flags |= SPS_IOVEC_FLAG_INT;
+			err = sps_transfer_one(data_pipe_handle,
+					args->oob_dma_addr_curr,
+					sectoroobsize, NULL,
+					sps_flags);
+			if (err)
+				goto out;
+			args->oob_dma_addr_curr += sectoroobsize;
+			args->oob_len_data -= sectoroobsize;
+		}
+	}
+out:
+	return err;
+}
+
+/*
+ * Read ECC bytes and check whether page is erased or not.
+ *
+ * The NAND devices manufactured with newer process node technology are
+ * susceptible to bit-flips. These bit-flips are easily fixable with the
+ * ECC engine and ECC information stored on the NAND device. This device
+ * specific information is found in the data sheet for the NAND device
+ * and is usually specified as a "number of bit-flips expected per code-
+ * word". For example, "a single bit-flip per codeword". Also this means
+ * that the number of ECC errors don't increase over period of time as in
+ * the past and can't be used to predict a "bad-block about to happen"
+ * situation anymore.
+ *
+ * So what this means to erased pages:
+ * Since ECC data for an erased page is all 0xFF's, the ECC engine would
+ * not be able to correct any bit-flips that occur in these newer parts.
+ * If the NAND controller is unable to identify the erased page due to
+ * the bit-flips, then there would be "uncorrectable ECC errors" detected
+ * and would get reported to file system layer (YAFFS2/UBIFS etc) and would
+ * result in a good block being marked as a bad block and also lead to
+ * error scenarios.
+
+ * So to handle this, the following will be done by software until newer
+ * NAND controller hardware is avialable that can detected erased pages
+ * with bit-flips successfully.
+ *
+ * 1. msm_nand_read_oob() calls this function when "uncorrectable ECC
+ *	errors" occur.
+ * 2. This function then performs a raw read of the page.
+ * 3. This read is done to extract ECC bytes and not data from that page.
+ * 4. For each codeword’s ECC data, the following is done
+ *	a. Count number of zero bits
+ *	b. If that count is greater than <BIT-FLIPS-EXPECTED>, then it is
+ *		not an erased page.
+ *	c. Else repeat for next codeword’s ECC data
+ *	d. If all codewords have less than <BIT-FLIPS-EXPECTED> bits of
+ *		zeros, then it’s considered an erased page.
+ *
+ * Since "uncorrectable ECC errors" do not occur except for either an
+ * erased page or in the case of an actual errror, this solution would
+ * work.
+ *
+ */
+static int msm_nand_is_erased_page(struct mtd_info *mtd, loff_t from,
+			     struct mtd_oob_ops *ops,
+			     struct msm_nand_rw_params *rw_params,
+			     bool *erased_page)
+{
+	struct msm_nand_info *info = mtd->priv;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	uint32_t cwperpage = (mtd->writesize >> 9);
+	int err, submitted_num_desc = 0;
+	uint32_t n = 0, num_zero_bits = 0, total_ecc_byte_cnt;
+	struct msm_nand_rw_reg_data data;
+	struct sps_iovec *iovec;
+	struct sps_iovec iovec_temp;
+	struct mtd_oob_ops raw_ops;
+
+	/*
+	 * The following 6 commands will be sent only once for the first
+	 * codeword (CW) - addr0, addr1, dev0_cfg0, dev0_cfg1,
+	 * dev0_ecc_cfg, ebi2_ecc_buf_cfg. The following 6 commands will
+	 * be sent for every CW - flash, read_location_0, read_location_1,
+	 * exec, flash_status and buffer_status.
+	 */
+	struct msm_nand_rw_cmd_desc *cmd_list = NULL;
+	uint32_t cw_desc_cnt = 0;
+	struct {
+		struct sps_transfer xfer;
+		struct sps_iovec cmd_iovec[MAX_DESC];
+		struct {
+			uint32_t count;
+			struct msm_nand_cmd_setup_desc setup_desc;
+			struct msm_nand_cmd_cw_desc cw_desc[MAX_DESC - 1];
+		} cmd_list;
+		struct {
+			uint32_t flash_status;
+			uint32_t buffer_status;
+			uint32_t erased_cw_status;
+		} result[MAX_CW_PER_PAGE];
+	} *dma_buffer;
+	uint8_t *ecc;
+
+	pr_debug("========================================================\n");
+	total_ecc_byte_cnt = (chip->ecc_parity_bytes * cwperpage);
+	memcpy(&raw_ops, ops, sizeof(struct mtd_oob_ops));
+	raw_ops.mode = MTD_OPS_RAW;
+	ecc = kzalloc(total_ecc_byte_cnt, GFP_KERNEL);
+
+	wait_event(chip->dma_wait_queue, (dma_buffer = msm_nand_get_dma_buffer(
+					chip, sizeof(*dma_buffer))));
+
+	memset(&data, 0, sizeof(struct msm_nand_rw_reg_data));
+	msm_nand_update_rw_reg_data(chip, &raw_ops, rw_params, &data);
+	cmd_list = (struct msm_nand_rw_cmd_desc *)&dma_buffer->cmd_list;
+
+	/* map the ecc for dma operations */
+	rw_params->ecc_dma_addr_curr = rw_params->ecc_dma_addr =
+		dma_map_single(chip->dev, ecc, total_ecc_byte_cnt,
+				DMA_FROM_DEVICE);
+
+	data.addr0 = (rw_params->page << 16) | rw_params->oob_col;
+	data.addr1 = (rw_params->page >> 16) & 0xff;
+	for (n = rw_params->start_sector; n < cwperpage; n++) {
+		struct sps_command_element *curr_ce, *start_ce;
+
+		dma_buffer->result[n].flash_status = 0xeeeeeeee;
+		dma_buffer->result[n].buffer_status = 0xeeeeeeee;
+		dma_buffer->result[n].erased_cw_status = 0xeeeeee00;
+
+		msm_nand_prep_rw_cmd_desc(&raw_ops, rw_params, &data, info,
+				n, cmd_list, &cw_desc_cnt,
+				chip->ecc_parity_bytes);
+
+		start_ce = &cmd_list->cw_desc[cw_desc_cnt].ce[0];
+		curr_ce = start_ce;
+		cmd_list->cw_desc[cw_desc_cnt].flags = CMD;
+		if (n == (cwperpage - 1))
+			cmd_list->cw_desc[cw_desc_cnt].flags |=
+				INT_UNLCK;
+		cmd_list->count++;
+
+		msm_nand_prep_ce(curr_ce, MSM_NAND_FLASH_STATUS(info),
+				READ, msm_virt_to_dma(chip,
+				&dma_buffer->result[n].flash_status));
+		curr_ce++;
+
+		msm_nand_prep_ce(curr_ce, MSM_NAND_BUFFER_STATUS(info),
+				READ, msm_virt_to_dma(chip,
+				&dma_buffer->result[n].buffer_status));
+		curr_ce++;
+
+		msm_nand_prep_ce(curr_ce,
+				MSM_NAND_ERASED_CW_DETECT_STATUS(info),
+				READ, msm_virt_to_dma(chip,
+				&dma_buffer->result[n].erased_cw_status));
+		curr_ce++;
+		cmd_list->cw_desc[cw_desc_cnt++].num_ce = curr_ce -
+			start_ce;
+	}
+
+	dma_buffer->xfer.iovec_count = cmd_list->count;
+	dma_buffer->xfer.iovec = dma_buffer->cmd_iovec;
+	dma_buffer->xfer.iovec_phys = msm_virt_to_dma(chip,
+			&dma_buffer->cmd_iovec);
+	iovec = dma_buffer->xfer.iovec;
+
+	iovec->addr =  msm_virt_to_dma(chip,
+			&cmd_list->setup_desc.ce[0]);
+	iovec->size = sizeof(struct sps_command_element) *
+		cmd_list->setup_desc.num_ce;
+	iovec->flags = cmd_list->setup_desc.flags;
+	iovec++;
+	for (n = 0; n < (cmd_list->count - 1); n++) {
+		iovec->addr =  msm_virt_to_dma(chip,
+				&cmd_list->cw_desc[n].ce[0]);
+		iovec->size = sizeof(struct sps_command_element) *
+			cmd_list->cw_desc[n].num_ce;
+		iovec->flags = cmd_list->cw_desc[n].flags;
+		iovec++;
+	}
+	mutex_lock(&info->lock);
+	err = msm_nand_get_device(chip->dev);
+	if (err)
+		goto unlock_mutex;
+	/* Submit data descriptors */
+	for (n = rw_params->start_sector; n < cwperpage; n++) {
+		err = msm_nand_submit_rw_data_desc(&raw_ops,
+				rw_params, info, n,
+				chip->ecc_parity_bytes);
+		if (err) {
+			pr_err("Failed to submit data descs %d\n", err);
+			panic("error in nand driver\n");
+			goto put_dev;
+		}
+	}
+	submitted_num_desc = cwperpage - rw_params->start_sector;
+
+	/* Submit command descriptors */
+	err =  sps_transfer(info->sps.cmd_pipe.handle,
+			&dma_buffer->xfer);
+	if (err) {
+		pr_err("Failed to submit commands %d\n", err);
+		goto put_dev;
+	}
+
+	err = msm_nand_sps_get_iovec(info->sps.cmd_pipe.handle,
+			info->sps.cmd_pipe.index,
+			dma_buffer->xfer.iovec_count,
+			&iovec_temp);
+	if (err) {
+		pr_err("Failed to get iovec for pipe %d: (err:%d)\n",
+				(info->sps.cmd_pipe.index), err);
+		goto put_dev;
+	}
+	err = msm_nand_sps_get_iovec(info->sps.data_prod.handle,
+			info->sps.data_prod.index, submitted_num_desc,
+			&iovec_temp);
+	if (err) {
+		pr_err("Failed to get iovec for pipe %d: (err:%d)\n",
+				(info->sps.data_prod.index), err);
+		goto put_dev;
+	}
+
+	err = msm_nand_put_device(chip->dev);
+	mutex_unlock(&info->lock);
+	if (err)
+		goto free_dma;
+
+	pr_debug("addr0: 0x%08x, addr1: 0x%08x\n", data.addr0, data.addr1);
+	for (n = rw_params->start_sector; n < cwperpage; n++)
+		pr_debug("cw %d: flash_sts %x buffr_sts %x, erased_cw_status: %x\n",
+				n, dma_buffer->result[n].flash_status,
+				dma_buffer->result[n].buffer_status,
+				dma_buffer->result[n].erased_cw_status);
+
+	goto free_dma;
+put_dev:
+	msm_nand_put_device(chip->dev);
+unlock_mutex:
+	mutex_unlock(&info->lock);
+free_dma:
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+	/* umap ecc dma memory */
+	dma_unmap_single(chip->dev, rw_params->ecc_dma_addr,
+			total_ecc_byte_cnt, DMA_FROM_DEVICE);
+	/* check for bit flips in ecc data */
+	for (n = rw_params->start_sector; n < cwperpage; n++) {
+		uint8_t *ecc_temp = ecc;
+		int last_pos = 0, next_pos = 0;
+		int ecc_bytes_percw_in_bits = (chip->ecc_parity_bytes * 8);
+
+		do {
+			last_pos = find_next_zero_bit(ecc_temp,
+					ecc_bytes_percw_in_bits, next_pos);
+
+			if (last_pos < ecc_bytes_percw_in_bits)
+				num_zero_bits++;
+
+			if (num_zero_bits > 4) {
+				*erased_page = false;
+				goto free_mem;
+			}
+
+			next_pos = last_pos + 1;
+		} while (last_pos < ecc_bytes_percw_in_bits);
+
+		num_zero_bits = last_pos = next_pos = 0;
+		ecc_temp += chip->ecc_parity_bytes;
+	}
+
+	if ((n == cwperpage) && (num_zero_bits <= 4))
+		*erased_page = true;
+free_mem:
+	kfree(ecc);
+	pr_debug("========================================================\n");
+	return err;
+}
+
+/*
+ * Function that gets called from upper layers such as MTD/YAFFS2 to read a
+ * page with main or/and spare data.
+ */
+static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from,
+			     struct mtd_oob_ops *ops)
+{
+	struct msm_nand_info *info = mtd->priv;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	struct flash_identification *flash_dev = &info->flash_dev;
+	uint32_t cwperpage = (mtd->writesize >> 9);
+	int err, pageerr = 0, rawerr = 0, submitted_num_desc = 0;
+	uint32_t n = 0, pages_read = 0;
+	uint32_t ecc_errors = 0, total_ecc_errors = 0, ecc_capability;
+	struct msm_nand_rw_params rw_params;
+	struct msm_nand_rw_reg_data data;
+	struct sps_iovec *iovec;
+	struct sps_iovec iovec_temp;
+	bool erased_page;
+	uint64_t fix_data_in_pages = 0;
+
+	/*
+	 * The following 6 commands will be sent only once for the first
+	 * codeword (CW) - addr0, addr1, dev0_cfg0, dev0_cfg1,
+	 * dev0_ecc_cfg, ebi2_ecc_buf_cfg. The following 6 commands will
+	 * be sent for every CW - flash, read_location_0, read_location_1,
+	 * exec, flash_status and buffer_status.
+	 */
+	struct {
+		struct sps_transfer xfer;
+		struct sps_iovec cmd_iovec[MAX_DESC];
+		struct {
+			uint32_t count;
+			struct msm_nand_cmd_setup_desc setup_desc;
+			struct msm_nand_cmd_cw_desc cw_desc[MAX_DESC - 1];
+		} cmd_list;
+		struct {
+			uint32_t flash_status;
+			uint32_t buffer_status;
+			uint32_t erased_cw_status;
+		} result[MAX_CW_PER_PAGE];
+	} *dma_buffer;
+	struct msm_nand_rw_cmd_desc *cmd_list = NULL;
+
+	memset(&rw_params, 0, sizeof(struct msm_nand_rw_params));
+	err = msm_nand_validate_mtd_params(mtd, true, from, ops, &rw_params);
+	if (err)
+		goto validate_mtd_params_failed;
+
+	wait_event(chip->dma_wait_queue, (dma_buffer = msm_nand_get_dma_buffer(
+			    chip, sizeof(*dma_buffer))));
+
+	rw_params.oob_col = rw_params.start_sector * chip->cw_size;
+	if (chip->cfg1 & (1 << WIDE_FLASH))
+		rw_params.oob_col >>= 1;
+
+	memset(&data, 0, sizeof(struct msm_nand_rw_reg_data));
+	msm_nand_update_rw_reg_data(chip, ops, &rw_params, &data);
+	cmd_list = (struct msm_nand_rw_cmd_desc *)&dma_buffer->cmd_list;
+
+	ecc_capability = flash_dev->ecc_capability;
+
+	while (rw_params.page_count-- > 0) {
+		uint32_t cw_desc_cnt = 0;
+
+		erased_page = false;
+		data.addr0 = (rw_params.page << 16) | rw_params.oob_col;
+		data.addr1 = (rw_params.page >> 16) & 0xff;
+
+		for (n = rw_params.start_sector; n < cwperpage; n++) {
+			struct sps_command_element *curr_ce, *start_ce;
+
+			dma_buffer->result[n].flash_status = 0xeeeeeeee;
+			dma_buffer->result[n].buffer_status = 0xeeeeeeee;
+			dma_buffer->result[n].erased_cw_status = 0xeeeeee00;
+
+			msm_nand_prep_rw_cmd_desc(ops, &rw_params, &data, info,
+					n, cmd_list, &cw_desc_cnt, 0);
+
+			start_ce = &cmd_list->cw_desc[cw_desc_cnt].ce[0];
+			curr_ce = start_ce;
+			cmd_list->cw_desc[cw_desc_cnt].flags = CMD;
+			if (n == (cwperpage - 1))
+				cmd_list->cw_desc[cw_desc_cnt].flags |=
+								INT_UNLCK;
+			cmd_list->count++;
+
+			msm_nand_prep_ce(curr_ce, MSM_NAND_FLASH_STATUS(info),
+				READ, msm_virt_to_dma(chip,
+					&dma_buffer->result[n].flash_status));
+			curr_ce++;
+
+			msm_nand_prep_ce(curr_ce, MSM_NAND_BUFFER_STATUS(info),
+				READ, msm_virt_to_dma(chip,
+					&dma_buffer->result[n].buffer_status));
+			curr_ce++;
+
+			msm_nand_prep_ce(curr_ce,
+				MSM_NAND_ERASED_CW_DETECT_STATUS(info),
+				READ, msm_virt_to_dma(chip,
+				&dma_buffer->result[n].erased_cw_status));
+			curr_ce++;
+			cmd_list->cw_desc[cw_desc_cnt++].num_ce = curr_ce -
+				start_ce;
+		}
+
+		dma_buffer->xfer.iovec_count = cmd_list->count;
+		dma_buffer->xfer.iovec = dma_buffer->cmd_iovec;
+		dma_buffer->xfer.iovec_phys = msm_virt_to_dma(chip,
+						&dma_buffer->cmd_iovec);
+		iovec = dma_buffer->xfer.iovec;
+
+		iovec->addr =  msm_virt_to_dma(chip,
+				&cmd_list->setup_desc.ce[0]);
+		iovec->size = sizeof(struct sps_command_element) *
+			cmd_list->setup_desc.num_ce;
+		iovec->flags = cmd_list->setup_desc.flags;
+		iovec++;
+		for (n = 0; n < (cmd_list->count - 1); n++) {
+			iovec->addr =  msm_virt_to_dma(chip,
+						&cmd_list->cw_desc[n].ce[0]);
+			iovec->size = sizeof(struct sps_command_element) *
+						cmd_list->cw_desc[n].num_ce;
+			iovec->flags = cmd_list->cw_desc[n].flags;
+			iovec++;
+		}
+		mutex_lock(&info->lock);
+		err = msm_nand_get_device(chip->dev);
+		if (err)
+			goto unlock_mutex;
+		/* Submit data descriptors */
+		for (n = rw_params.start_sector; n < cwperpage; n++) {
+			err = msm_nand_submit_rw_data_desc(ops,
+						&rw_params, info, n, 0);
+			if (err) {
+				pr_err("Failed to submit data descs %d\n", err);
+				panic("error in nand driver\n");
+				goto put_dev;
+			}
+		}
+
+		if (ops->mode == MTD_OPS_RAW) {
+			submitted_num_desc = cwperpage - rw_params.start_sector;
+		} else if (ops->mode == MTD_OPS_AUTO_OOB) {
+			if (ops->datbuf)
+				submitted_num_desc = cwperpage -
+							rw_params.start_sector;
+			if (ops->oobbuf)
+				submitted_num_desc++;
+		}
+
+		/* Submit command descriptors */
+		err =  sps_transfer(info->sps.cmd_pipe.handle,
+				&dma_buffer->xfer);
+		if (err) {
+			pr_err("Failed to submit commands %d\n", err);
+			goto put_dev;
+		}
+
+		err = msm_nand_sps_get_iovec(info->sps.cmd_pipe.handle,
+				info->sps.cmd_pipe.index,
+				dma_buffer->xfer.iovec_count,
+				&iovec_temp);
+		if (err) {
+			pr_err("Failed to get iovec for pipe %d: (err: %d)\n",
+					(info->sps.cmd_pipe.index), err);
+			goto put_dev;
+		}
+		err = msm_nand_sps_get_iovec(info->sps.data_prod.handle,
+				info->sps.data_prod.index, submitted_num_desc,
+				&iovec_temp);
+		if (err) {
+			pr_err("Failed to get iovec for pipe %d: (err: %d)\n",
+					(info->sps.data_prod.index), err);
+			goto put_dev;
+		}
+
+		err = msm_nand_put_device(chip->dev);
+		mutex_unlock(&info->lock);
+		if (err)
+			goto free_dma;
+		/* Check for flash status errors */
+		pageerr = rawerr = 0;
+		for (n = rw_params.start_sector; n < cwperpage; n++) {
+			if (dma_buffer->result[n].flash_status & (FS_OP_ERR |
+					FS_MPU_ERR)) {
+				rawerr = -EIO;
+				/*
+				 * Check if ECC error was due to an erased
+				 * codeword. If so, ignore the error.
+				 *
+				 * NOTE: There is a bug in erased page
+				 * detection hardware block when reading
+				 * only spare data. In order to work around
+				 * this issue, instead of using PAGE_ALL_ERASED
+				 * bit to check for whether a whole page is
+				 * erased or not, we use CODEWORD_ALL_ERASED
+				 * and  CODEWORD_ERASED bits together and check
+				 * each codeword that has FP_OP_ERR bit set is
+				 * an erased codeword or not.
+				 */
+				if ((dma_buffer->result[n].erased_cw_status &
+					ERASED_CW) == ERASED_CW) {
+					/*
+					 * At least one code word is detected
+					 * as an erased code word.
+					 */
+					pr_debug("erased codeword detected - ignore ecc error\n");
+					continue;
+				}
+				pageerr = rawerr;
+				break;
+			}
+		}
+		/* check for uncorrectable errors */
+		if (pageerr) {
+			for (n = rw_params.start_sector; n < cwperpage; n++) {
+				if (dma_buffer->result[n].buffer_status &
+					BS_UNCORRECTABLE_BIT) {
+					/*
+					 * Check if page is actually
+					 * erased or not.
+					 */
+					err = msm_nand_is_erased_page(mtd,
+							from, ops,
+							&rw_params,
+							&erased_page);
+					if (err)
+						goto free_dma;
+					if (!erased_page) {
+						mtd->ecc_stats.failed++;
+						pageerr = -EBADMSG;
+						break;
+					}
+					pageerr = 0;
+					pr_debug("Uncorrectable ECC errors dectected on an erased page and has been fixed.\n");
+					break;
+				}
+			}
+		}
+
+		if (rawerr && !pageerr && erased_page) {
+			/*
+			 * This means an erased page had bit flips and now
+			 * those bit-flips need to be cleared in the data
+			 * being sent to upper layers. This will keep track
+			 * of those pages and at the end, the data will be
+			 * fixed before this function returns.
+			 * Note that a whole page worth of data will be fixed
+			 * and this will only handle about 64 pages being read
+			 * at a time i.e. one erase block worth of pages.
+			 */
+			fix_data_in_pages |= BIT(rw_params.page_count);
+		}
+		/* check for correctable errors */
+		if (!rawerr) {
+			for (n = rw_params.start_sector; n < cwperpage; n++) {
+				ecc_errors =
+				    dma_buffer->result[n].buffer_status
+				    & BS_CORRECTABLE_ERR_MSK;
+				if (ecc_errors) {
+					total_ecc_errors += ecc_errors;
+					mtd->ecc_stats.corrected += ecc_errors;
+					/*
+					 * Since the nand device can have the
+					 * ecc errors even on the first ever
+					 * write. Any reporting of EUCLEAN
+					 * when there are less then the ecc
+					 * capability of the device is not
+					 * useful.
+					 *
+					 * Also don't report EUCLEAN unless
+					 * the enable_euclean is set.
+					 */
+					if (enable_euclean &&
+					    ecc_errors >= ecc_capability)
+						pageerr = -EUCLEAN;
+				}
+			}
+		}
+		if (pageerr && (pageerr != -EUCLEAN || err == 0))
+			err = pageerr;
+
+		if (rawerr && !pageerr) {
+			pr_debug("%llx %x %x empty page\n",
+			       (loff_t)rw_params.page * mtd->writesize,
+			       ops->len, ops->ooblen);
+		} else {
+			for (n = rw_params.start_sector; n < cwperpage; n++)
+				pr_debug("cw %d: flash_sts %x buffr_sts %x, erased_cw_status: %x, pageerr: %d, rawerr: %d\n",
+				n, dma_buffer->result[n].flash_status,
+				dma_buffer->result[n].buffer_status,
+				dma_buffer->result[n].erased_cw_status,
+				pageerr, rawerr);
+		}
+		if (err && err != -EUCLEAN && err != -EBADMSG)
+			goto free_dma;
+		pages_read++;
+		rw_params.page++;
+	}
+	goto free_dma;
+put_dev:
+	msm_nand_put_device(chip->dev);
+unlock_mutex:
+	mutex_unlock(&info->lock);
+free_dma:
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+	if (ops->oobbuf)
+		dma_unmap_page(chip->dev, rw_params.oob_dma_addr,
+				 ops->ooblen, DMA_FROM_DEVICE);
+	if (ops->datbuf)
+		dma_unmap_page(chip->dev, rw_params.data_dma_addr,
+				 ops->len, DMA_BIDIRECTIONAL);
+	/*
+	 * If there were any erased pages detected with ECC errors, then
+	 * it is most likely that the data is not all 0xff. So memset that
+	 * page to all 0xff.
+	 */
+	while (fix_data_in_pages) {
+		int temp_page = 0, oobsize = rw_params.cwperpage << 2;
+		int count = 0, offset = 0;
+
+		temp_page = fix_data_in_pages & BIT_MASK(0);
+		fix_data_in_pages = fix_data_in_pages >> 1;
+		count++;
+
+		if (!temp_page)
+			continue;
+
+		offset = (count - 1) * mtd->writesize;
+		if (ops->datbuf)
+			memset((ops->datbuf + offset), 0xff, mtd->writesize);
+
+		offset = (count - 1) * oobsize;
+		if (ops->oobbuf)
+			memset(ops->oobbuf + offset, 0xff, oobsize);
+	}
+validate_mtd_params_failed:
+	if (ops->mode != MTD_OPS_RAW)
+		ops->retlen = mtd->writesize * pages_read;
+	else
+		ops->retlen = (mtd->writesize +  mtd->oobsize) * pages_read;
+	ops->oobretlen = ops->ooblen - rw_params.oob_len_data;
+	if (err)
+		pr_err("0x%llx datalen 0x%x ooblen %x err %d corrected %d\n",
+		       from, ops->datbuf ? ops->len : 0, ops->ooblen, err,
+		       total_ecc_errors);
+	pr_debug("ret %d, retlen %d oobretlen %d\n",
+			err, ops->retlen, ops->oobretlen);
+
+	pr_debug("========================================================\n");
+	return err;
+}
+
+/**
+ * msm_nand_read_partial_page() - read partial page
+ * @mtd: pointer to mtd info
+ * @from: start address of the page
+ * @ops: pointer to mtd_oob_ops
+ *
+ * Reads a page into a bounce buffer and copies the required
+ * number of bytes to actual buffer. The pages that are aligned
+ * do not use bounce buffer.
+ */
+static int msm_nand_read_partial_page(struct mtd_info *mtd,
+		loff_t from, struct mtd_oob_ops *ops)
+{
+	int err = 0;
+	unsigned char *actual_buf;
+	unsigned char *bounce_buf;
+	loff_t aligned_from;
+	loff_t offset;
+	size_t len;
+	size_t actual_len, ret_len;
+	int is_euclean = 0;
+	int is_ebadmsg = 0;
+
+	actual_len = ops->len;
+	ret_len = 0;
+	actual_buf = ops->datbuf;
+
+	bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);
+	if (!bounce_buf) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* Get start address of page to read from */
+	ops->len = mtd->writesize;
+	offset = from & (mtd->writesize - 1);
+	aligned_from = from - offset;
+
+	for (;;) {
+		bool no_copy = false;
+
+		len = mtd->writesize - offset;
+		if (len > actual_len)
+			len = actual_len;
+
+		if (offset == 0 && len == mtd->writesize)
+			no_copy = true;
+
+		if (!virt_addr_valid(actual_buf) &&
+				!is_buffer_in_page(actual_buf, ops->len))
+			no_copy = false;
+
+		ops->datbuf = no_copy ? actual_buf : bounce_buf;
+		err = msm_nand_read_oob(mtd, aligned_from, ops);
+		if (err == -EUCLEAN) {
+			is_euclean = 1;
+			err = 0;
+		}
+
+		if (err == -EBADMSG) {
+			is_ebadmsg = 1;
+			err = 0;
+		}
+
+		if (err < 0) {
+			/* Clear previously set EUCLEAN / EBADMSG */
+			is_euclean = 0;
+			is_ebadmsg = 0;
+			ret_len = ops->retlen;
+			break;
+		}
+
+		if (!no_copy)
+			memcpy(actual_buf, bounce_buf + offset, len);
+
+		actual_len -= len;
+		ret_len += len;
+
+		if (actual_len == 0)
+			break;
+
+		actual_buf += len;
+		offset = 0;
+		aligned_from += mtd->writesize;
+	}
+
+	ops->retlen = ret_len;
+	kfree(bounce_buf);
+out:
+	if (is_euclean == 1)
+		err = -EUCLEAN;
+
+	/* Snub EUCLEAN if we also have EBADMSG */
+	if (is_ebadmsg == 1)
+		err = -EBADMSG;
+	return err;
+}
+
+/*
+ * Function that gets called from upper layers such as MTD/YAFFS2 to read a
+ * page with only main data.
+ */
+static int msm_nand_read(struct mtd_info *mtd, loff_t from, size_t len,
+	      size_t *retlen, u_char *buf)
+{
+	int ret;
+	int is_euclean = 0;
+	int is_ebadmsg = 0;
+	struct mtd_oob_ops ops;
+	unsigned char *bounce_buf = NULL;
+
+	ops.mode = MTD_OPS_AUTO_OOB;
+	ops.retlen = 0;
+	ops.ooblen = 0;
+	ops.oobbuf = NULL;
+	*retlen = 0;
+
+	if (!(from & (mtd->writesize - 1)) && !(len % mtd->writesize)) {
+		/*
+		 * Handle reading of large size read buffer in vmalloc
+		 * address space that does not fit in an MMU page.
+		 */
+		if (!virt_addr_valid(buf) && !is_buffer_in_page(buf, len)) {
+			ops.len = mtd->writesize;
+
+			bounce_buf = kmalloc(ops.len, GFP_KERNEL);
+			if (!bounce_buf) {
+				ret = -ENOMEM;
+				goto out;
+			}
+
+			for (;;) {
+				bool no_copy = false;
+
+				if (!is_buffer_in_page(buf, ops.len)) {
+					memcpy(bounce_buf, buf, ops.len);
+					ops.datbuf = (uint8_t *) bounce_buf;
+				} else {
+					ops.datbuf = (uint8_t *) buf;
+					no_copy = true;
+				}
+				ret = msm_nand_read_oob(mtd, from, &ops);
+				if (ret == -EUCLEAN) {
+					is_euclean = 1;
+					ret = 0;
+				}
+				if (ret == -EBADMSG) {
+					is_ebadmsg = 1;
+					ret = 0;
+				}
+				if (ret < 0) {
+					/* Clear previously set errors */
+					is_euclean = 0;
+					is_ebadmsg = 0;
+					break;
+				}
+
+
+				if (!no_copy)
+					memcpy(buf, bounce_buf, ops.retlen);
+
+				len -= ops.retlen;
+				*retlen += ops.retlen;
+				if (len == 0)
+					break;
+				buf += ops.retlen;
+				from += ops.retlen;
+
+				if (len < mtd->writesize) {
+					ops.len = len;
+					ops.datbuf = buf;
+					ret = msm_nand_read_partial_page(
+						mtd, from, &ops);
+					*retlen += ops.retlen;
+					break;
+				}
+			}
+			kfree(bounce_buf);
+		} else {
+			ops.len = len;
+			ops.datbuf = (uint8_t *)buf;
+			ret =  msm_nand_read_oob(mtd, from, &ops);
+			*retlen = ops.retlen;
+		}
+	} else {
+		ops.len = len;
+		ops.datbuf = (uint8_t *)buf;
+		ret = msm_nand_read_partial_page(mtd, from, &ops);
+		*retlen = ops.retlen;
+	}
+out:
+	if (is_euclean == 1)
+		ret = -EUCLEAN;
+
+	/* Snub EUCLEAN if we also have EBADMSG */
+	if (is_ebadmsg == 1)
+		ret = -EBADMSG;
+
+	return ret;
+}
+
+/*
+ * Function that gets called from upper layers such as MTD/YAFFS2 to write a
+ * page with both main and spare data.
+ */
+static int msm_nand_write_oob(struct mtd_info *mtd, loff_t to,
+				struct mtd_oob_ops *ops)
+{
+	struct msm_nand_info *info = mtd->priv;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	uint32_t cwperpage = (mtd->writesize >> 9);
+	uint32_t n, flash_sts, pages_written = 0;
+	int err = 0, submitted_num_desc = 0;
+	struct msm_nand_rw_params rw_params;
+	struct msm_nand_rw_reg_data data;
+	struct sps_iovec *iovec;
+	struct sps_iovec iovec_temp;
+	/*
+	 * The following 7 commands will be sent only once :
+	 * For first codeword (CW) - addr0, addr1, dev0_cfg0, dev0_cfg1,
+	 * dev0_ecc_cfg, ebi2_ecc_buf_cfg.
+	 * For last codeword (CW) - read_status(write)
+	 *
+	 * The following 4 commands will be sent for every CW :
+	 * flash, exec, flash_status (read), flash_status (write).
+	 */
+	struct {
+		struct sps_transfer xfer;
+		struct sps_iovec cmd_iovec[MAX_DESC + 1];
+		struct {
+			uint32_t count;
+			struct msm_nand_cmd_setup_desc setup_desc;
+			struct msm_nand_cmd_cw_desc cw_desc[MAX_DESC];
+		} cmd_list;
+		struct {
+			uint32_t flash_status;
+		} data[MAX_CW_PER_PAGE];
+	} *dma_buffer;
+	struct msm_nand_rw_cmd_desc *cmd_list = NULL;
+
+	memset(&rw_params, 0, sizeof(struct msm_nand_rw_params));
+	err = msm_nand_validate_mtd_params(mtd, false, to, ops, &rw_params);
+	if (err)
+		goto validate_mtd_params_failed;
+
+	wait_event(chip->dma_wait_queue, (dma_buffer =
+			msm_nand_get_dma_buffer(chip, sizeof(*dma_buffer))));
+
+	memset(&data, 0, sizeof(struct msm_nand_rw_reg_data));
+	msm_nand_update_rw_reg_data(chip, ops, &rw_params, &data);
+	cmd_list = (struct msm_nand_rw_cmd_desc *)&dma_buffer->cmd_list;
+
+	while (rw_params.page_count-- > 0) {
+		uint32_t cw_desc_cnt = 0;
+		struct sps_command_element *curr_ce, *start_ce;
+
+		data.addr0 = (rw_params.page << 16);
+		data.addr1 = (rw_params.page >> 16) & 0xff;
+
+		for (n = 0; n < cwperpage ; n++) {
+			dma_buffer->data[n].flash_status = 0xeeeeeeee;
+
+			msm_nand_prep_rw_cmd_desc(ops, &rw_params, &data, info,
+					n, cmd_list, &cw_desc_cnt, 0);
+
+			curr_ce = &cmd_list->cw_desc[cw_desc_cnt].ce[0];
+			cmd_list->cw_desc[cw_desc_cnt].flags = CMD;
+			cmd_list->count++;
+
+			msm_nand_prep_ce(curr_ce, MSM_NAND_FLASH_STATUS(info),
+				READ, msm_virt_to_dma(chip,
+					&dma_buffer->data[n].flash_status));
+			cmd_list->cw_desc[cw_desc_cnt++].num_ce = 1;
+		}
+
+		start_ce = &cmd_list->cw_desc[cw_desc_cnt].ce[0];
+		curr_ce = start_ce;
+		cmd_list->cw_desc[cw_desc_cnt].flags = CMD_INT_UNLCK;
+		cmd_list->count++;
+		msm_nand_prep_ce(curr_ce, MSM_NAND_FLASH_STATUS(info),
+				WRITE, data.clrfstatus);
+		curr_ce++;
+
+		msm_nand_prep_ce(curr_ce, MSM_NAND_READ_STATUS(info),
+				WRITE, data.clrrstatus);
+		curr_ce++;
+		cmd_list->cw_desc[cw_desc_cnt++].num_ce = curr_ce - start_ce;
+
+		dma_buffer->xfer.iovec_count = cmd_list->count;
+		dma_buffer->xfer.iovec = dma_buffer->cmd_iovec;
+		dma_buffer->xfer.iovec_phys = msm_virt_to_dma(chip,
+						&dma_buffer->cmd_iovec);
+		iovec = dma_buffer->xfer.iovec;
+
+		iovec->addr =  msm_virt_to_dma(chip,
+				&cmd_list->setup_desc.ce[0]);
+		iovec->size = sizeof(struct sps_command_element) *
+					cmd_list->setup_desc.num_ce;
+		iovec->flags = cmd_list->setup_desc.flags;
+		iovec++;
+		for (n = 0; n < (cmd_list->count - 1); n++) {
+			iovec->addr =  msm_virt_to_dma(chip,
+					&cmd_list->cw_desc[n].ce[0]);
+			iovec->size = sizeof(struct sps_command_element) *
+					cmd_list->cw_desc[n].num_ce;
+			iovec->flags = cmd_list->cw_desc[n].flags;
+			iovec++;
+		}
+		mutex_lock(&info->lock);
+		err = msm_nand_get_device(chip->dev);
+		if (err)
+			goto unlock_mutex;
+		/* Submit data descriptors */
+		for (n = 0; n < cwperpage; n++) {
+			err = msm_nand_submit_rw_data_desc(ops,
+						&rw_params, info, n, 0);
+			if (err) {
+				pr_err("Failed to submit data descs %d\n", err);
+				panic("Error in nand driver\n");
+				goto put_dev;
+			}
+		}
+
+		if (ops->mode == MTD_OPS_RAW) {
+			submitted_num_desc = n;
+		} else if (ops->mode == MTD_OPS_AUTO_OOB) {
+			if (ops->datbuf)
+				submitted_num_desc = n;
+			if (ops->oobbuf)
+				submitted_num_desc++;
+		}
+
+		/* Submit command descriptors */
+		err =  sps_transfer(info->sps.cmd_pipe.handle,
+				&dma_buffer->xfer);
+		if (err) {
+			pr_err("Failed to submit commands %d\n", err);
+			goto put_dev;
+		}
+
+		err = msm_nand_sps_get_iovec(info->sps.cmd_pipe.handle,
+				info->sps.cmd_pipe.index,
+				dma_buffer->xfer.iovec_count,
+				&iovec_temp);
+		if (err) {
+			pr_err("Failed to get iovec for pipe %d (err:%d)\n",
+					(info->sps.cmd_pipe.index), err);
+			goto put_dev;
+		}
+		err = msm_nand_sps_get_iovec(info->sps.data_cons.handle,
+				info->sps.data_cons.index, submitted_num_desc,
+				&iovec_temp);
+		if (err) {
+			pr_err("Failed to get iovec for pipe %d (err:%d)\n",
+					(info->sps.data_cons.index), err);
+			goto put_dev;
+		}
+
+		err = msm_nand_put_device(chip->dev);
+		mutex_unlock(&info->lock);
+		if (err)
+			goto free_dma;
+
+		for (n = 0; n < cwperpage; n++)
+			pr_debug("write pg %d: flash_status[%d] = %x\n",
+				rw_params.page, n,
+				dma_buffer->data[n].flash_status);
+
+		/*  Check for flash status errors */
+		for (n = 0; n < cwperpage; n++) {
+			flash_sts = dma_buffer->data[n].flash_status;
+			if (flash_sts & (FS_OP_ERR | FS_MPU_ERR)) {
+				pr_err("MPU/OP err (0x%x) set\n", flash_sts);
+				err = -EIO;
+				goto free_dma;
+			}
+			if (n == (cwperpage - 1)) {
+				if (!(flash_sts & FS_DEVICE_WP) ||
+					(flash_sts & FS_DEVICE_STS_ERR)) {
+					pr_err("Dev sts err 0x%x\n", flash_sts);
+					err = -EIO;
+					goto free_dma;
+				}
+			}
+		}
+		pages_written++;
+		rw_params.page++;
+	}
+	goto free_dma;
+put_dev:
+	msm_nand_put_device(chip->dev);
+unlock_mutex:
+	mutex_unlock(&info->lock);
+free_dma:
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+	if (ops->oobbuf)
+		dma_unmap_page(chip->dev, rw_params.oob_dma_addr,
+				 ops->ooblen, DMA_TO_DEVICE);
+	if (ops->datbuf)
+		dma_unmap_page(chip->dev, rw_params.data_dma_addr,
+				ops->len, DMA_TO_DEVICE);
+validate_mtd_params_failed:
+	if (ops->mode != MTD_OPS_RAW)
+		ops->retlen = mtd->writesize * pages_written;
+	else
+		ops->retlen = (mtd->writesize + mtd->oobsize) * pages_written;
+
+	ops->oobretlen = ops->ooblen - rw_params.oob_len_data;
+	if (err)
+		pr_err("to %llx datalen %x ooblen %x failed with err %d\n",
+		       to, ops->len, ops->ooblen, err);
+	pr_debug("ret %d, retlen %d oobretlen %d\n",
+			err, ops->retlen, ops->oobretlen);
+
+	pr_debug("================================================\n");
+	return err;
+}
+
+/*
+ * Function that gets called from upper layers such as MTD/YAFFS2 to write a
+ * page with only main data.
+ */
+static int msm_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+			  size_t *retlen, const u_char *buf)
+{
+	int ret;
+	struct mtd_oob_ops ops;
+	unsigned char *bounce_buf = NULL;
+
+	ops.mode = MTD_OPS_AUTO_OOB;
+	ops.retlen = 0;
+	ops.ooblen = 0;
+	ops.oobbuf = NULL;
+
+	/* partial page writes are not supported */
+	if ((to & (mtd->writesize - 1)) || (len % mtd->writesize)) {
+		ret = -EINVAL;
+		*retlen = ops.retlen;
+		pr_err("%s: partial page writes are not supported\n", __func__);
+		goto out;
+	}
+
+	/*
+	 * Handle writing of large size write buffer in vmalloc
+	 * address space that does not fit in an MMU page.
+	 */
+	if (!virt_addr_valid(buf) && !is_buffer_in_page(buf, len)) {
+		ops.len = mtd->writesize;
+
+		bounce_buf = kmalloc(ops.len, GFP_KERNEL);
+		if (!bounce_buf) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		for (;;) {
+			if (!is_buffer_in_page(buf, ops.len)) {
+				memcpy(bounce_buf, buf, ops.len);
+				ops.datbuf = (uint8_t *) bounce_buf;
+			} else {
+				ops.datbuf = (uint8_t *) buf;
+			}
+			ret = msm_nand_write_oob(mtd, to, &ops);
+			if (ret < 0)
+				break;
+
+			len -= mtd->writesize;
+			*retlen += mtd->writesize;
+			if (len == 0)
+				break;
+
+			buf += mtd->writesize;
+			to += mtd->writesize;
+		}
+		kfree(bounce_buf);
+	} else {
+		ops.len = len;
+		ops.datbuf = (uint8_t *)buf;
+		ret =  msm_nand_write_oob(mtd, to, &ops);
+		*retlen = ops.retlen;
+	}
+out:
+	return ret;
+}
+
+/*
+ * Structure that contains NANDc register data for commands required
+ * for Erase operation.
+ */
+struct msm_nand_erase_reg_data {
+	struct msm_nand_common_cfgs cfg;
+	uint32_t exec;
+	uint32_t flash_status;
+	uint32_t clrfstatus;
+	uint32_t clrrstatus;
+};
+
+/*
+ * Function that gets called from upper layers such as MTD/YAFFS2 to erase a
+ * block within NAND device.
+ */
+#define ERASE_CMDS 9
+static int msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	int i = 0, err = 0;
+	struct msm_nand_info *info = mtd->priv;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	uint32_t page = 0;
+	struct msm_nand_sps_cmd *cmd, *curr_cmd;
+	struct msm_nand_erase_reg_data data;
+	struct sps_iovec *iovec;
+	struct sps_iovec iovec_temp;
+	/*
+	 * The following 9 commands are required to erase a page -
+	 * flash, addr0, addr1, cfg0, cfg1, exec, flash_status(read),
+	 * flash_status(write), read_status.
+	 */
+	struct {
+		struct sps_transfer xfer;
+		struct sps_iovec cmd_iovec[ERASE_CMDS];
+		struct msm_nand_sps_cmd cmd[ERASE_CMDS];
+		uint32_t flash_status;
+	} *dma_buffer;
+
+	if (mtd->writesize == PAGE_SIZE_2K)
+		page = instr->addr >> 11;
+
+	if (mtd->writesize == PAGE_SIZE_4K)
+		page = instr->addr >> 12;
+
+	if (instr->addr & (mtd->erasesize - 1)) {
+		pr_err("unsupported erase address, 0x%llx\n", instr->addr);
+		err = -EINVAL;
+		goto out;
+	}
+	if (instr->len != mtd->erasesize) {
+		pr_err("unsupported erase len, %lld\n", instr->len);
+		err = -EINVAL;
+		goto out;
+	}
+
+	wait_event(chip->dma_wait_queue, (dma_buffer = msm_nand_get_dma_buffer(
+			    chip, sizeof(*dma_buffer))));
+	cmd = dma_buffer->cmd;
+
+	memset(&data, 0, sizeof(struct msm_nand_erase_reg_data));
+	data.cfg.cmd = MSM_NAND_CMD_BLOCK_ERASE;
+	data.cfg.addr0 = page;
+	data.cfg.addr1 = 0;
+	data.cfg.cfg0 = chip->cfg0 & (~(7 << CW_PER_PAGE));
+	data.cfg.cfg1 = chip->cfg1;
+	data.exec = 1;
+	dma_buffer->flash_status = 0xeeeeeeee;
+	data.clrfstatus = MSM_NAND_RESET_FLASH_STS;
+	data.clrrstatus = MSM_NAND_RESET_READ_STS;
+
+	curr_cmd = cmd;
+	msm_nand_prep_cfg_cmd_desc(info, data.cfg, &curr_cmd);
+
+	cmd = curr_cmd;
+	msm_nand_prep_single_desc(cmd, MSM_NAND_EXEC_CMD(info), WRITE,
+			data.exec, SPS_IOVEC_FLAG_NWD);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_FLASH_STATUS(info), READ,
+		msm_virt_to_dma(chip, &dma_buffer->flash_status), 0);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_FLASH_STATUS(info), WRITE,
+			data.clrfstatus, 0);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_READ_STATUS(info), WRITE,
+			data.clrrstatus,
+			SPS_IOVEC_FLAG_UNLOCK | SPS_IOVEC_FLAG_INT);
+	cmd++;
+
+	WARN_ON((cmd - dma_buffer->cmd) > ERASE_CMDS);
+	dma_buffer->xfer.iovec_count = (cmd - dma_buffer->cmd);
+	dma_buffer->xfer.iovec = dma_buffer->cmd_iovec;
+	dma_buffer->xfer.iovec_phys = msm_virt_to_dma(chip,
+					&dma_buffer->cmd_iovec);
+	iovec = dma_buffer->xfer.iovec;
+
+	for (i = 0; i < dma_buffer->xfer.iovec_count; i++) {
+		iovec->addr =  msm_virt_to_dma(chip, &dma_buffer->cmd[i].ce);
+		iovec->size = sizeof(struct sps_command_element);
+		iovec->flags = dma_buffer->cmd[i].flags;
+		iovec++;
+	}
+	mutex_lock(&info->lock);
+	err = msm_nand_get_device(chip->dev);
+	if (err)
+		goto unlock_mutex;
+
+	err =  sps_transfer(info->sps.cmd_pipe.handle, &dma_buffer->xfer);
+	if (err) {
+		pr_err("Failed to submit commands %d\n", err);
+		goto put_dev;
+	}
+	err = msm_nand_sps_get_iovec(info->sps.cmd_pipe.handle,
+			info->sps.cmd_pipe.index, dma_buffer->xfer.iovec_count,
+			&iovec_temp);
+	if (err) {
+		pr_err("Failed to get iovec for pipe %d (err: %d)\n",
+				(info->sps.cmd_pipe.index), err);
+		goto put_dev;
+	}
+	err = msm_nand_put_device(chip->dev);
+	if (err)
+		goto unlock_mutex;
+
+	/*  Check for flash status errors */
+	if (dma_buffer->flash_status & (FS_OP_ERR |
+			FS_MPU_ERR | FS_DEVICE_STS_ERR)) {
+		pr_err("MPU/OP/DEV err (0x%x) set\n", dma_buffer->flash_status);
+		err = -EIO;
+	}
+	if (!(dma_buffer->flash_status & FS_DEVICE_WP)) {
+		pr_err("Device is write protected\n");
+		err = -EIO;
+	}
+	if (err) {
+		pr_err("Erase failed, 0x%llx\n", instr->addr);
+		instr->fail_addr = instr->addr;
+		instr->state = MTD_ERASE_FAILED;
+	} else {
+		instr->state = MTD_ERASE_DONE;
+		instr->fail_addr = 0xffffffff;
+		mtd_erase_callback(instr);
+	}
+	goto unlock_mutex;
+put_dev:
+	msm_nand_put_device(chip->dev);
+unlock_mutex:
+	mutex_unlock(&info->lock);
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
+out:
+	return err;
+}
+
+/*
+ * Structure that contains NANDc register data for commands required
+ * for checking if a block is bad.
+ */
+struct msm_nand_blk_isbad_data {
+	struct msm_nand_common_cfgs cfg;
+	uint32_t ecc_bch_cfg;
+	uint32_t exec;
+	uint32_t read_offset;
+};
+
+/*
+ * Function that gets called from upper layers such as MTD/YAFFS2 to check if
+ * a block is bad. This is done by reading the first page within a block and
+ * checking whether the bad block byte location contains 0xFF or not. If it
+ * doesn't contain 0xFF, then it is considered as bad block.
+ */
+#define ISBAD_CMDS 9
+static int msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct msm_nand_info *info = mtd->priv;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	int i = 0, ret = 0, bad_block = 0, submitted_num_desc = 1;
+	uint8_t *buf;
+	uint32_t page = 0, rdata, cwperpage;
+	struct msm_nand_sps_cmd *cmd, *curr_cmd;
+	struct msm_nand_blk_isbad_data data;
+	struct sps_iovec *iovec;
+	struct sps_iovec iovec_temp;
+	/*
+	 * The following 9 commands are required to check bad block -
+	 * flash, addr0, addr1, cfg0, cfg1, ecc_cfg, read_loc_0,
+	 * exec, flash_status(read).
+	 */
+	struct {
+		struct sps_transfer xfer;
+		struct sps_iovec cmd_iovec[ISBAD_CMDS];
+		struct msm_nand_sps_cmd cmd[ISBAD_CMDS];
+		uint32_t flash_status;
+	} *dma_buffer;
+
+	if (mtd->writesize == PAGE_SIZE_2K)
+		page = ofs >> 11;
+
+	if (mtd->writesize == PAGE_SIZE_4K)
+		page = ofs >> 12;
+
+	cwperpage = (mtd->writesize >> 9);
+
+	if (ofs > mtd->size) {
+		pr_err("Invalid offset 0x%llx\n", ofs);
+		bad_block = -EINVAL;
+		goto out;
+	}
+	if (ofs & (mtd->erasesize - 1)) {
+		pr_err("unsupported block address, 0x%x\n", (uint32_t)ofs);
+		bad_block = -EINVAL;
+		goto out;
+	}
+
+	wait_event(chip->dma_wait_queue, (dma_buffer = msm_nand_get_dma_buffer(
+				chip, sizeof(*dma_buffer) + 4)));
+	buf = (uint8_t *)dma_buffer + sizeof(*dma_buffer);
+
+	cmd = dma_buffer->cmd;
+	memset(&data, 0, sizeof(struct msm_nand_blk_isbad_data));
+	data.cfg.cmd = MSM_NAND_CMD_PAGE_READ_ALL;
+	data.cfg.cfg0 = chip->cfg0_raw & ~(7U << CW_PER_PAGE);
+	data.cfg.cfg1 = chip->cfg1_raw;
+
+	if (chip->cfg1 & (1 << WIDE_FLASH))
+		data.cfg.addr0 = (page << 16) |
+			((chip->cw_size * (cwperpage-1)) >> 1);
+	else
+		data.cfg.addr0 = (page << 16) |
+			(chip->cw_size * (cwperpage-1));
+
+	data.cfg.addr1 = (page >> 16) & 0xff;
+	data.ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
+	data.exec = 1;
+	data.read_offset = (mtd->writesize - (chip->cw_size * (cwperpage-1)));
+	dma_buffer->flash_status = 0xeeeeeeee;
+
+	curr_cmd = cmd;
+	msm_nand_prep_cfg_cmd_desc(info, data.cfg, &curr_cmd);
+
+	cmd = curr_cmd;
+	msm_nand_prep_single_desc(cmd, MSM_NAND_DEV0_ECC_CFG(info), WRITE,
+			data.ecc_bch_cfg, 0);
+	cmd++;
+
+	rdata = (data.read_offset << 0) | (4 << 16) | (1 << 31);
+	msm_nand_prep_single_desc(cmd, MSM_NAND_READ_LOCATION_0(info), WRITE,
+			rdata, 0);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_EXEC_CMD(info), WRITE,
+			data.exec, SPS_IOVEC_FLAG_NWD);
+	cmd++;
+
+	msm_nand_prep_single_desc(cmd, MSM_NAND_FLASH_STATUS(info), READ,
+		msm_virt_to_dma(chip, &dma_buffer->flash_status),
+		SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_UNLOCK);
+	cmd++;
+
+	WARN_ON(cmd - dma_buffer->cmd > ISBAD_CMDS);
+	dma_buffer->xfer.iovec_count = (cmd - dma_buffer->cmd);
+	dma_buffer->xfer.iovec = dma_buffer->cmd_iovec;
+	dma_buffer->xfer.iovec_phys = msm_virt_to_dma(chip,
+					&dma_buffer->cmd_iovec);
+	iovec = dma_buffer->xfer.iovec;
+
+	for (i = 0; i < dma_buffer->xfer.iovec_count; i++) {
+		iovec->addr =  msm_virt_to_dma(chip, &dma_buffer->cmd[i].ce);
+		iovec->size = sizeof(struct sps_command_element);
+		iovec->flags = dma_buffer->cmd[i].flags;
+		iovec++;
+	}
+	mutex_lock(&info->lock);
+	ret = msm_nand_get_device(chip->dev);
+	if (ret) {
+		mutex_unlock(&info->lock);
+		goto free_dma;
+	}
+	/* Submit data descriptor */
+	ret = sps_transfer_one(info->sps.data_prod.handle,
+			msm_virt_to_dma(chip, buf),
+			4, NULL, SPS_IOVEC_FLAG_INT);
+
+	if (ret) {
+		pr_err("Failed to submit data desc %d\n", ret);
+		goto put_dev;
+	}
+	/* Submit command descriptor */
+	ret =  sps_transfer(info->sps.cmd_pipe.handle, &dma_buffer->xfer);
+	if (ret) {
+		pr_err("Failed to submit commands %d\n", ret);
+		goto put_dev;
+	}
+
+	ret = msm_nand_sps_get_iovec(info->sps.cmd_pipe.handle,
+			info->sps.cmd_pipe.index, dma_buffer->xfer.iovec_count,
+			&iovec_temp);
+	if (ret) {
+		pr_err("Failed to get iovec for pipe %d (ret: %d)\n",
+				(info->sps.cmd_pipe.index), ret);
+		goto put_dev;
+	}
+	ret = msm_nand_sps_get_iovec(info->sps.data_prod.handle,
+			info->sps.data_prod.index, submitted_num_desc,
+			&iovec_temp);
+	if (ret) {
+		pr_err("Failed to get iovec for pipe %d (ret: %d)\n",
+				(info->sps.data_prod.index), ret);
+		goto put_dev;
+	}
+
+	ret = msm_nand_put_device(chip->dev);
+	mutex_unlock(&info->lock);
+	if (ret)
+		goto free_dma;
+
+	/* Check for flash status errors */
+	if (dma_buffer->flash_status & (FS_OP_ERR | FS_MPU_ERR)) {
+		pr_err("MPU/OP err set: %x\n", dma_buffer->flash_status);
+		bad_block = -EIO;
+		goto free_dma;
+	}
+
+	/* Check for bad block marker byte */
+	if (chip->cfg1 & (1 << WIDE_FLASH)) {
+		if (buf[0] != 0xFF || buf[1] != 0xFF)
+			bad_block = 1;
+	} else {
+		if (buf[0] != 0xFF)
+			bad_block = 1;
+	}
+	goto free_dma;
+put_dev:
+	msm_nand_put_device(chip->dev);
+	mutex_unlock(&info->lock);
+free_dma:
+	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer) + 4);
+out:
+	return ret ? ret : bad_block;
+}
+
+/*
+ * Function that gets called from upper layers such as MTD/YAFFS2 to mark a
+ * block as bad. This is done by writing the first page within a block with 0,
+ * thus setting the bad block byte location as well to 0.
+ */
+static int msm_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct mtd_oob_ops ops;
+	int ret;
+	uint8_t *buf;
+	size_t len;
+
+	if (ofs > mtd->size) {
+		pr_err("Invalid offset 0x%llx\n", ofs);
+		ret = -EINVAL;
+		goto out;
+	}
+	if (ofs & (mtd->erasesize - 1)) {
+		pr_err("unsupported block address, 0x%x\n", (uint32_t)ofs);
+		ret = -EINVAL;
+		goto out;
+	}
+	len = mtd->writesize + mtd->oobsize;
+	buf = kzalloc(len, GFP_KERNEL);
+	if (!buf) {
+		pr_err("unable to allocate memory for 0x%x size\n", len);
+		ret = -ENOMEM;
+		goto out;
+	}
+	ops.mode = MTD_OPS_RAW;
+	ops.len = len;
+	ops.retlen = 0;
+	ops.ooblen = 0;
+	ops.datbuf = buf;
+	ops.oobbuf = NULL;
+	ret =  msm_nand_write_oob(mtd, ofs, &ops);
+	kfree(buf);
+out:
+	return ret;
+}
+
+/*
+ * Function that scans for the attached NAND device. This fills out all
+ * the uninitialized function pointers with the defaults. The flash ID is
+ * read and the mtd/chip structures are filled with the appropriate values.
+ */
+static int msm_nand_scan(struct mtd_info *mtd)
+{
+	struct msm_nand_info *info = mtd->priv;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	struct flash_identification *supported_flash = &info->flash_dev;
+	int err = 0;
+	uint32_t i, j, mtd_writesize;
+	uint8_t dev_found = 0, wide_bus;
+	uint32_t manid, devid, devcfg;
+	uint32_t flash_id = 0, flash_id2 = 0;
+	uint8_t id_byte[NAND_MAX_ID_LEN];
+	uint32_t bad_block_byte, spare_bytes;
+	struct nand_flash_dev *flashdev = NULL;
+	struct nand_manufacturers  *flashman = NULL;
+
+	/* Probe the Flash device for ONFI compliance */
+	if (!msm_nand_flash_onfi_probe(info)) {
+		dev_found = 1;
+	} else {
+		err = msm_nand_flash_read_id(info, 0, &flash_id, &flash_id2);
+		if (err < 0) {
+			pr_err("Failed to read Flash ID\n");
+			err = -EINVAL;
+			goto out;
+		}
+		manid  = id_byte[0] = flash_id & 0xFF;
+		devid  = id_byte[1] = (flash_id >> 8) & 0xFF;
+		devcfg = id_byte[3] = (flash_id >> 24) & 0xFF;
+		id_byte[2] = (flash_id >> 16) & 0xFF;
+		id_byte[4] = flash_id2 & 0xFF;
+		id_byte[5] = (flash_id2 >> 8) & 0xFF;
+		id_byte[6] = (flash_id2 >> 16) & 0xFF;
+		id_byte[7] = (flash_id2 >> 24) & 0xFF;
+
+		for (i = 0; !flashman && nand_manuf_ids[i].id; ++i)
+			if (nand_manuf_ids[i].id == manid)
+				flashman = &nand_manuf_ids[i];
+		for (i = 0; !flashdev && nand_flash_ids[i].id; ++i) {
+			/*
+			 * If id_len is specified for an entry in the nand ids
+			 * array, then at least 4 bytes of the nand id is
+			 * present in the nand ids array - use that to identify
+			 * the nand device first. If that is not present, only
+			 * then fall back to searching the legacy or extended
+			 * ids in the nand ids array.
+			 * The id_len number of bytes in the nand id read from
+			 * the device are checked against those in the nand id
+			 * table for exact match.
+			 */
+			if (nand_flash_ids[i].id_len) {
+				for (j = 0; j < nand_flash_ids[i].id_len; j++) {
+					if (nand_flash_ids[i].id[j] ==
+							id_byte[j])
+						continue;
+					else
+						break;
+				}
+				if (j == nand_flash_ids[i].id_len)
+					flashdev = &nand_flash_ids[i];
+			} else if (!nand_flash_ids[i].id_len &&
+					nand_flash_ids[i].dev_id == devid)
+				flashdev = &nand_flash_ids[i];
+		}
+		if (!flashdev || !flashman) {
+			pr_err("unknown nand flashid=%x manuf=%x devid=%x\n",
+				flash_id, manid, devid);
+			err = -ENOENT;
+			goto out;
+		}
+		dev_found = 1;
+		if (!flashdev->pagesize) {
+			pr_err("missing page size info - extract from NAND ID\n");
+			supported_flash->widebus = devcfg & (1 << 6) ? 1 : 0;
+			supported_flash->pagesize = 1024 << (devcfg & 0x3);
+			supported_flash->blksize = (64 * 1024) <<
+							((devcfg >> 4) & 0x3);
+			supported_flash->oobsize = (8 << ((devcfg >> 2) & 1)) *
+				(supported_flash->pagesize >> 9);
+		} else {
+			supported_flash->widebus = flashdev->options &
+				       NAND_BUSWIDTH_16 ? 1 : 0;
+			supported_flash->pagesize = flashdev->pagesize;
+			supported_flash->blksize = flashdev->erasesize;
+			supported_flash->oobsize = flashdev->oobsize;
+			supported_flash->ecc_correctability =
+					flashdev->ecc.strength_ds;
+			if (!flashdev->ecc.strength_ds)
+				pr_err("num ecc correctable bit not specified and defaults to 4 bit BCH\n");
+		}
+		supported_flash->flash_id = flash_id;
+		supported_flash->density = ((uint64_t)flashdev->chipsize) << 20;
+	}
+
+	if (dev_found) {
+		wide_bus       = supported_flash->widebus;
+		mtd->size      = supported_flash->density;
+		mtd->writesize = supported_flash->pagesize;
+		mtd->oobsize   = supported_flash->oobsize;
+		mtd->erasesize = supported_flash->blksize;
+		mtd->writebufsize = mtd->writesize;
+		mtd_writesize = mtd->writesize;
+
+		/* Check whether NAND device support 8bit ECC*/
+		if (supported_flash->ecc_correctability >= 8) {
+			chip->bch_caps = MSM_NAND_CAP_8_BIT_BCH;
+			supported_flash->ecc_capability = 8;
+		} else {
+			chip->bch_caps = MSM_NAND_CAP_4_BIT_BCH;
+			supported_flash->ecc_capability = 4;
+		}
+
+		pr_info("NAND Id: 0x%x Buswidth: %dBits Density: %lld MByte\n",
+			supported_flash->flash_id, (wide_bus) ? 16 : 8,
+			(mtd->size >> 20));
+		pr_info("pagesize: %d Erasesize: %d oobsize: %d (in Bytes)\n",
+			mtd->writesize, mtd->erasesize, mtd->oobsize);
+		pr_info("BCH ECC: %d Bit\n", supported_flash->ecc_capability);
+	}
+
+	chip->cw_size = (chip->bch_caps & MSM_NAND_CAP_8_BIT_BCH) ? 532 : 528;
+	chip->cfg0 = (((mtd_writesize >> 9) - 1) << CW_PER_PAGE)
+		|  (516 <<  UD_SIZE_BYTES)
+		|  (0 << DISABLE_STATUS_AFTER_WRITE)
+		|  (5 << NUM_ADDR_CYCLES);
+
+	bad_block_byte = (mtd_writesize - (chip->cw_size * (
+					(mtd_writesize >> 9) - 1)) + 1);
+	chip->cfg1 = (7 <<  NAND_RECOVERY_CYCLES)
+		|    (0 <<  CS_ACTIVE_BSY)
+		|    (bad_block_byte <<  BAD_BLOCK_BYTE_NUM)
+		|    (0 << BAD_BLOCK_IN_SPARE_AREA)
+		|    (2 << WR_RD_BSY_GAP)
+		| ((wide_bus ? 1 : 0) << WIDE_FLASH)
+		| (1 << ENABLE_BCH_ECC);
+
+	/*
+	 * For 4bit BCH ECC (default ECC), parity bytes = 7(x8) or 8(x16 I/O)
+	 * For 8bit BCH ECC, parity bytes = 13 (x8) or 14 (x16 I/O).
+	 */
+	chip->ecc_parity_bytes = (chip->bch_caps & MSM_NAND_CAP_8_BIT_BCH) ?
+				(wide_bus ? 14 : 13) : (wide_bus ? 8 : 7);
+
+	spare_bytes = chip->cw_size - (BYTES_512 + chip->ecc_parity_bytes);
+	chip->cfg0_raw = (((mtd_writesize >> 9) - 1) << CW_PER_PAGE)
+		|	(5 << NUM_ADDR_CYCLES)
+		|	(spare_bytes << SPARE_SIZE_BYTES)
+		|	(BYTES_512 << UD_SIZE_BYTES);
+
+	chip->cfg1_raw = (2 << WR_RD_BSY_GAP)
+		|    (1 << BAD_BLOCK_IN_SPARE_AREA)
+		|    (21 <<  BAD_BLOCK_BYTE_NUM)
+		|    (0 <<  CS_ACTIVE_BSY)
+		| (7 <<  NAND_RECOVERY_CYCLES)
+		| ((wide_bus ? 1 : 0) << WIDE_FLASH)
+		| (1 << DEV0_CFG1_ECC_DISABLE);
+
+	chip->ecc_bch_cfg = (0 << ECC_CFG_ECC_DISABLE)
+			|   (0 << ECC_SW_RESET)
+			|   (516 << ECC_NUM_DATA_BYTES)
+			|   (chip->ecc_parity_bytes << ECC_PARITY_SIZE_BYTES)
+			|   (1 << ECC_FORCE_CLK_OPEN);
+
+	chip->ecc_cfg_raw = (1 << ECC_FORCE_CLK_OPEN)
+			|   (BYTES_512 << ECC_NUM_DATA_BYTES)
+			|   (chip->ecc_parity_bytes << ECC_PARITY_SIZE_BYTES)
+			|   (0 << ECC_SW_RESET)
+			|   (1 << ECC_CFG_ECC_DISABLE);
+
+	if (chip->bch_caps & MSM_NAND_CAP_8_BIT_BCH) {
+		chip->cfg0 |= (wide_bus ? 0 << SPARE_SIZE_BYTES :
+				2 << SPARE_SIZE_BYTES);
+		chip->ecc_bch_cfg |= (1 << ECC_MODE);
+		chip->ecc_cfg_raw |= (1 << ECC_MODE);
+	} else {
+		chip->cfg0 |= (wide_bus ? 2 << SPARE_SIZE_BYTES :
+				4 << SPARE_SIZE_BYTES);
+		chip->ecc_bch_cfg |= (0 << ECC_MODE);
+		chip->ecc_cfg_raw |= (0 << ECC_MODE);
+	}
+
+	chip->ecc_buf_cfg = 0x203; /* No of bytes covered by ECC - 516 bytes */
+
+	pr_info("CFG0: 0x%08x,           CFG1: 0x%08x\n"
+		"            RAWCFG0: 0x%08x,        RAWCFG1: 0x%08x\n"
+		"          ECCBUFCFG: 0x%08x,      ECCBCHCFG: 0x%08x\n"
+		"          RAWECCCFG: 0x%08x, BAD BLOCK BYTE: 0x%08x\n",
+		chip->cfg0, chip->cfg1,	chip->cfg0_raw, chip->cfg1_raw,
+		chip->ecc_buf_cfg, chip->ecc_bch_cfg,
+		chip->ecc_cfg_raw, bad_block_byte);
+
+	if (mtd->writesize == 2048)
+		mtd->oobavail = 16;
+	else if (mtd->writesize == 4096)
+		mtd->oobavail = 32;
+	else {
+		pr_err("Unsupported NAND pagesize: 0x%x\n", mtd->writesize);
+		err = -ENODEV;
+		goto out;
+	}
+
+	/* Fill in remaining MTD driver data */
+	mtd->type = MTD_NANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH;
+	mtd->_erase = msm_nand_erase;
+	mtd->_block_isbad = msm_nand_block_isbad;
+	mtd->_block_markbad = msm_nand_block_markbad;
+	mtd->_read = msm_nand_read;
+	mtd->_write = msm_nand_write;
+	mtd->_read_oob  = msm_nand_read_oob;
+	mtd->_write_oob = msm_nand_write_oob;
+	mtd->owner = THIS_MODULE;
+out:
+	return err;
+}
+
+#define BAM_APPS_PIPE_LOCK_GRP0 0
+#define BAM_APPS_PIPE_LOCK_GRP1 1
+/*
+ * This function allocates, configures, connects an end point and
+ * also registers event notification for an end point. It also allocates
+ * DMA memory for descriptor FIFO of a pipe.
+ */
+static int msm_nand_init_endpoint(struct msm_nand_info *info,
+				struct msm_nand_sps_endpt *end_point,
+				uint32_t pipe_index)
+{
+	int rc = 0;
+	struct sps_pipe *pipe_handle;
+	struct sps_connect *sps_config = &end_point->config;
+	struct sps_register_event *sps_event = &end_point->event;
+
+	pipe_handle = sps_alloc_endpoint();
+	if (!pipe_handle) {
+		pr_err("sps_alloc_endpoint() failed\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	rc = sps_get_config(pipe_handle, sps_config);
+	if (rc) {
+		pr_err("sps_get_config() failed %d\n", rc);
+		goto free_endpoint;
+	}
+
+	if (pipe_index == SPS_DATA_PROD_PIPE_INDEX) {
+		/* READ CASE: source - BAM; destination - system memory */
+		sps_config->source = info->sps.bam_handle;
+		sps_config->destination = SPS_DEV_HANDLE_MEM;
+		sps_config->mode = SPS_MODE_SRC;
+		sps_config->src_pipe_index = pipe_index;
+	} else if (pipe_index == SPS_DATA_CONS_PIPE_INDEX ||
+			pipe_index == SPS_CMD_CONS_PIPE_INDEX) {
+		/* WRITE CASE: source - system memory; destination - BAM */
+		sps_config->source = SPS_DEV_HANDLE_MEM;
+		sps_config->destination = info->sps.bam_handle;
+		sps_config->mode = SPS_MODE_DEST;
+		sps_config->dest_pipe_index = pipe_index;
+	}
+
+	sps_config->options = SPS_O_AUTO_ENABLE | SPS_O_POLL |
+				SPS_O_ACK_TRANSFERS;
+
+	if (pipe_index == SPS_DATA_PROD_PIPE_INDEX ||
+			pipe_index == SPS_DATA_CONS_PIPE_INDEX)
+		sps_config->lock_group = BAM_APPS_PIPE_LOCK_GRP0;
+	else if (pipe_index == SPS_CMD_CONS_PIPE_INDEX)
+		sps_config->lock_group = BAM_APPS_PIPE_LOCK_GRP1;
+
+	/*
+	 * Descriptor FIFO is a cyclic FIFO. If SPS_MAX_DESC_NUM descriptors
+	 * are allowed to be submitted before we get any ack for any of them,
+	 * the descriptor FIFO size should be: (SPS_MAX_DESC_NUM + 1) *
+	 * sizeof(struct sps_iovec).
+	 */
+	sps_config->desc.size = (SPS_MAX_DESC_NUM + 1) *
+					sizeof(struct sps_iovec);
+	sps_config->desc.base = dmam_alloc_coherent(info->nand_chip.dev,
+					sps_config->desc.size,
+					&sps_config->desc.phys_base,
+					GFP_KERNEL);
+	if (!sps_config->desc.base) {
+		pr_err("dmam_alloc_coherent() failed for size %x\n",
+				sps_config->desc.size);
+		rc = -ENOMEM;
+		goto free_endpoint;
+	}
+	memset(sps_config->desc.base, 0x00, sps_config->desc.size);
+
+	rc = sps_connect(pipe_handle, sps_config);
+	if (rc) {
+		pr_err("sps_connect() failed %d\n", rc);
+		goto free_endpoint;
+	}
+
+	sps_event->options = SPS_O_EOT;
+	sps_event->mode = SPS_TRIGGER_WAIT;
+	sps_event->user = (void *)info;
+
+	rc = sps_register_event(pipe_handle, sps_event);
+	if (rc) {
+		pr_err("sps_register_event() failed %d\n", rc);
+		goto sps_disconnect;
+	}
+	end_point->index = pipe_index;
+	end_point->handle = pipe_handle;
+	pr_debug("pipe handle 0x%x for pipe %d\n", (uint32_t)pipe_handle,
+			pipe_index);
+	goto out;
+sps_disconnect:
+	sps_disconnect(pipe_handle);
+free_endpoint:
+	sps_free_endpoint(pipe_handle);
+out:
+	return rc;
+}
+
+/* This function disconnects and frees an end point */
+static void msm_nand_deinit_endpoint(struct msm_nand_info *info,
+				struct msm_nand_sps_endpt *end_point)
+{
+	sps_disconnect(end_point->handle);
+	sps_free_endpoint(end_point->handle);
+}
+
+/*
+ * This function registers BAM device and initializes its end points for
+ * the following pipes -
+ * system consumer pipe for data (pipe#0),
+ * system producer pipe for data (pipe#1),
+ * system consumer pipe for commands (pipe#2).
+ */
+static int msm_nand_bam_init(struct msm_nand_info *nand_info)
+{
+	struct sps_bam_props bam = {0};
+	int rc = 0;
+
+	bam.phys_addr = nand_info->bam_phys;
+	bam.virt_addr = nand_info->bam_base;
+	bam.irq = nand_info->bam_irq;
+	/*
+	 * NAND device is accessible from both Apps and Modem processor and
+	 * thus, NANDc and BAM are shared between both the processors. But BAM
+	 * must be enabled and instantiated only once during boot up by
+	 * Trustzone before Modem/Apps is brought out from reset.
+	 *
+	 * This is indicated to SPS driver on Apps by marking flag
+	 * SPS_BAM_MGR_DEVICE_REMOTE. The following are the global
+	 * initializations that will be done by Trustzone - Execution
+	 * Environment, Pipes assignment to Apps/Modem, Pipe Super groups and
+	 * Descriptor summing threshold.
+	 *
+	 * NANDc BAM device supports 2 execution environments - Modem and Apps
+	 * and thus the flag SPS_BAM_MGR_MULTI_EE is set.
+	 */
+	bam.manage = SPS_BAM_MGR_DEVICE_REMOTE | SPS_BAM_MGR_MULTI_EE;
+	bam.ipc_loglevel = QPIC_BAM_DEFAULT_IPC_LOGLVL;
+
+	rc = sps_phy2h(bam.phys_addr, &nand_info->sps.bam_handle);
+	if (!rc)
+		goto init_sps_ep;
+	rc = sps_register_bam_device(&bam, &nand_info->sps.bam_handle);
+	if (rc) {
+		pr_err("%s: sps_register_bam_device() failed with %d\n",
+			__func__, rc);
+		goto out;
+	}
+	pr_info("%s: BAM device registered: bam_handle 0x%lx\n",
+			__func__, nand_info->sps.bam_handle);
+init_sps_ep:
+	rc = msm_nand_init_endpoint(nand_info, &nand_info->sps.data_prod,
+					SPS_DATA_PROD_PIPE_INDEX);
+	if (rc)
+		goto out;
+	rc = msm_nand_init_endpoint(nand_info, &nand_info->sps.data_cons,
+					SPS_DATA_CONS_PIPE_INDEX);
+	if (rc)
+		goto deinit_data_prod;
+
+	rc = msm_nand_init_endpoint(nand_info, &nand_info->sps.cmd_pipe,
+					SPS_CMD_CONS_PIPE_INDEX);
+	if (rc)
+		goto deinit_data_cons;
+	goto out;
+deinit_data_cons:
+	msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_cons);
+deinit_data_prod:
+	msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_prod);
+out:
+	return rc;
+}
+
+/*
+ * This function disconnects and frees its end points for all the pipes.
+ * Since the BAM is shared resource, it is not deregistered as its handle
+ * might be in use with LCDC.
+ */
+static void msm_nand_bam_free(struct msm_nand_info *nand_info)
+{
+	msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_prod);
+	msm_nand_deinit_endpoint(nand_info, &nand_info->sps.data_cons);
+	msm_nand_deinit_endpoint(nand_info, &nand_info->sps.cmd_pipe);
+}
+
+/* This function enables DMA support for the NANDc in BAM mode. */
+static int msm_nand_enable_dma(struct msm_nand_info *info)
+{
+	struct msm_nand_sps_cmd *sps_cmd;
+	struct msm_nand_chip *chip = &info->nand_chip;
+	int ret, submitted_num_desc = 1;
+	struct sps_iovec iovec_temp;
+
+	wait_event(chip->dma_wait_queue,
+		   (sps_cmd = msm_nand_get_dma_buffer(chip, sizeof(*sps_cmd))));
+
+	msm_nand_prep_single_desc(sps_cmd, MSM_NAND_CTRL(info), WRITE,
+			(1 << BAM_MODE_EN), SPS_IOVEC_FLAG_INT);
+
+	mutex_lock(&info->lock);
+	ret = msm_nand_get_device(chip->dev);
+	if (ret) {
+		mutex_unlock(&info->lock);
+		goto out;
+	}
+	ret = sps_transfer_one(info->sps.cmd_pipe.handle,
+			msm_virt_to_dma(chip, &sps_cmd->ce),
+			sizeof(struct sps_command_element), NULL,
+			sps_cmd->flags);
+	if (ret) {
+		pr_err("Failed to submit command: %d\n", ret);
+		goto put_dev;
+	}
+	ret = msm_nand_sps_get_iovec(info->sps.cmd_pipe.handle,
+			info->sps.cmd_pipe.index, submitted_num_desc,
+			&iovec_temp);
+	if (ret) {
+		pr_err("Failed to get iovec for pipe %d (ret: %d)\n",
+				(info->sps.cmd_pipe.index), ret);
+		goto put_dev;
+	}
+put_dev:
+	ret = msm_nand_put_device(chip->dev);
+out:
+	mutex_unlock(&info->lock);
+	msm_nand_release_dma_buffer(chip, sps_cmd, sizeof(*sps_cmd));
+	return ret;
+
+}
+
+static int msm_nand_parse_smem_ptable(int *nr_parts)
+{
+
+	uint32_t  i, j;
+	uint32_t len = FLASH_PTABLE_HDR_LEN;
+	struct flash_partition_entry *pentry;
+	char *delimiter = ":";
+	void *temp_ptable = NULL;
+
+	pr_info("Parsing partition table info from SMEM\n");
+	temp_ptable = smem_get_entry(SMEM_AARM_PARTITION_TABLE, &len, 0,
+					SMEM_ANY_HOST_FLAG);
+
+	if (!temp_ptable) {
+		pr_err("Error reading partition table header\n");
+		goto out;
+	}
+
+	/* Read only the header portion of ptable */
+	ptable = *(struct flash_partition_table *)temp_ptable;
+
+	/* Verify ptable magic */
+	if (ptable.magic1 != FLASH_PART_MAGIC1 ||
+			ptable.magic2 != FLASH_PART_MAGIC2) {
+		pr_err("Partition table magic verification failed\n");
+		goto out;
+	}
+	/* Ensure that # of partitions is less than the max we have allocated */
+	if (ptable.numparts > FLASH_PTABLE_MAX_PARTS_V4) {
+		pr_err("Partition numbers exceed the max limit\n");
+		goto out;
+	}
+	/* Find out length of partition data based on table version. */
+	if (ptable.version <= FLASH_PTABLE_V3) {
+		len = FLASH_PTABLE_HDR_LEN + FLASH_PTABLE_MAX_PARTS_V3 *
+			sizeof(struct flash_partition_entry);
+	} else if (ptable.version == FLASH_PTABLE_V4) {
+		len = FLASH_PTABLE_HDR_LEN + FLASH_PTABLE_MAX_PARTS_V4 *
+			sizeof(struct flash_partition_entry);
+	} else {
+		pr_err("Unknown ptable version (%d)", ptable.version);
+		goto out;
+	}
+
+	*nr_parts = ptable.numparts;
+
+	/*
+	 * Now that the partition table header has been parsed, verified
+	 * and the length of the partition table calculated, read the
+	 * complete partition table.
+	 */
+	temp_ptable = smem_get_entry(SMEM_AARM_PARTITION_TABLE, &len, 0,
+					SMEM_ANY_HOST_FLAG);
+	if (!temp_ptable) {
+		pr_err("Error reading partition table\n");
+		goto out;
+	}
+
+	/* Read only the header portion of ptable */
+	ptable = *(struct flash_partition_table *)temp_ptable;
+
+	for (i = 0; i < ptable.numparts; i++) {
+		pentry = &ptable.part_entry[i];
+		if (pentry->name[0] == '\0')
+			continue;
+		/* Convert name to lower case and discard the initial chars */
+		mtd_part[i].name        = pentry->name;
+		for (j = 0; j < strlen(mtd_part[i].name); j++)
+			*(mtd_part[i].name + j) =
+				tolower(*(mtd_part[i].name + j));
+		strsep(&(mtd_part[i].name), delimiter);
+		mtd_part[i].offset      = pentry->offset;
+		mtd_part[i].mask_flags  = pentry->attr;
+		mtd_part[i].size        = pentry->length;
+		pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n",
+			i, pentry->name, pentry->offset, pentry->length,
+			pentry->attr);
+	}
+	pr_info("SMEM partition table found: ver: %d len: %d\n",
+		ptable.version, ptable.numparts);
+	return 0;
+out:
+	return -EINVAL;
+}
+
+#define BOOT_DEV_MASK 0x1E
+#define BOOT_DEV_NAND 0x4
+
+/*
+ * This function gets called when its device named msm-nand is added to
+ * device tree .dts file with all its resources such as physical addresses
+ * for NANDc and BAM, BAM IRQ.
+ *
+ * It also expects the NAND flash partition information to be passed in .dts
+ * file so that it can parse the partitions by calling MTD function
+ * mtd_device_parse_register().
+ *
+ */
+static int msm_nand_probe(struct platform_device *pdev)
+{
+	struct msm_nand_info *info;
+	struct resource *res;
+	int i, err, nr_parts;
+	struct device *dev;
+	u32 adjustment_offset;
+	void __iomem *boot_cfg_base;
+	u32 boot_dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"boot_cfg");
+	if (res && res->start) {
+		boot_cfg_base = devm_ioremap(&pdev->dev, res->start,
+						resource_size(res));
+		if (!boot_cfg_base) {
+			pr_err("ioremap() failed for addr 0x%x size 0x%x\n",
+				res->start, resource_size(res));
+			return -ENOMEM;
+		}
+		boot_dev = (readl_relaxed(boot_cfg_base) & BOOT_DEV_MASK) >> 1;
+		if (boot_dev != BOOT_DEV_NAND) {
+			pr_err("disabling nand as boot device (%x) is not NAND\n",
+					boot_dev);
+			return -ENODEV;
+		}
+	}
+	/*
+	 * The partition information can also be passed from kernel command
+	 * line. Also, the MTD core layer supports adding the whole device as
+	 * one MTD device when no partition information is available at all.
+	 */
+	info = devm_kzalloc(&pdev->dev, sizeof(struct msm_nand_info),
+				GFP_KERNEL);
+	if (!info) {
+		err = -ENOMEM;
+		goto out;
+	}
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"nand_phys");
+	if (!res || !res->start) {
+		pr_err("NAND phys address range is not provided\n");
+		err = -ENODEV;
+		goto out;
+	}
+	info->nand_phys = res->start;
+
+	err = of_property_read_u32(pdev->dev.of_node,
+				   "qcom,reg-adjustment-offset",
+				   &adjustment_offset);
+	if (err) {
+		pr_err("adjustment_offset not found, err = %d\n", err);
+		WARN_ON(1);
+		return err;
+	}
+
+	info->nand_phys_adjusted = info->nand_phys + adjustment_offset;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"bam_phys");
+	if (!res || !res->start) {
+		pr_err("BAM phys address range is not provided\n");
+		err = -ENODEV;
+		goto out;
+	}
+	info->bam_phys = res->start;
+	info->bam_base = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!info->bam_base) {
+		pr_err("BAM ioremap() failed for addr 0x%x size 0x%x\n",
+			res->start, resource_size(res));
+		err = -ENOMEM;
+		goto out;
+	}
+
+	info->bam_irq = platform_get_irq_byname(pdev, "bam_irq");
+	if (info->bam_irq < 0) {
+		pr_err("BAM IRQ is not provided\n");
+		err = -ENODEV;
+		goto out;
+	}
+
+	info->mtd.name = dev_name(&pdev->dev);
+	info->mtd.priv = info;
+	info->mtd.owner = THIS_MODULE;
+	info->nand_chip.dev = &pdev->dev;
+	init_waitqueue_head(&info->nand_chip.dma_wait_queue);
+	mutex_init(&info->lock);
+
+	dev = &pdev->dev;
+	if (dma_supported(dev, DMA_BIT_MASK(32))) {
+		info->dma_mask = DMA_BIT_MASK(32);
+		dev->coherent_dma_mask = info->dma_mask;
+	}
+
+	info->nand_chip.dma_virt_addr =
+		dmam_alloc_coherent(&pdev->dev, MSM_NAND_DMA_BUFFER_SIZE,
+			&info->nand_chip.dma_phys_addr, GFP_KERNEL);
+	if (!info->nand_chip.dma_virt_addr) {
+		pr_err("No memory for DMA buffer size %x\n",
+				MSM_NAND_DMA_BUFFER_SIZE);
+		err = -ENOMEM;
+		goto out;
+	}
+	err = msm_nand_bus_register(pdev, info);
+	if (err)
+		goto out;
+	info->clk_data.qpic_clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (!IS_ERR_OR_NULL(info->clk_data.qpic_clk)) {
+		err = clk_set_rate(info->clk_data.qpic_clk,
+			MSM_NAND_BUS_VOTE_MAX_RATE);
+	} else {
+		err = PTR_ERR(info->clk_data.qpic_clk);
+		pr_err("Failed to get clock handle, err=%d\n", err);
+	}
+	if (err)
+		goto bus_unregister;
+
+	err = msm_nand_setup_clocks_and_bus_bw(info, true);
+	if (err)
+		goto bus_unregister;
+	dev_set_drvdata(&pdev->dev, info);
+	err = pm_runtime_set_active(&pdev->dev);
+	if (err)
+		pr_err("pm_runtime_set_active() failed with error %d", err);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_NAND_IDLE_TIMEOUT);
+
+	err = msm_nand_bam_init(info);
+	if (err) {
+		pr_err("msm_nand_bam_init() failed %d\n", err);
+		goto clk_rpm_disable;
+	}
+	err = msm_nand_enable_dma(info);
+	if (err) {
+		pr_err("Failed to enable DMA in NANDc\n");
+		goto free_bam;
+	}
+	err = msm_nand_parse_smem_ptable(&nr_parts);
+	if (err < 0) {
+		pr_err("Failed to parse partition table in SMEM\n");
+		goto free_bam;
+	}
+	if (msm_nand_scan(&info->mtd)) {
+		pr_err("No nand device found\n");
+		err = -ENXIO;
+		goto free_bam;
+	}
+	for (i = 0; i < nr_parts; i++) {
+		mtd_part[i].offset *= info->mtd.erasesize;
+		mtd_part[i].size *= info->mtd.erasesize;
+	}
+	err = mtd_device_parse_register(&info->mtd, NULL, NULL,
+		&mtd_part[0], nr_parts);
+	if (err < 0) {
+		pr_err("Unable to register MTD partitions %d\n", err);
+		goto free_bam;
+	}
+
+	pr_info("NANDc phys addr 0x%lx, BAM phys addr 0x%lx, BAM IRQ %d\n",
+			info->nand_phys, info->bam_phys, info->bam_irq);
+	pr_info("Allocated DMA buffer at virt_addr 0x%pK, phys_addr 0x%x\n",
+		info->nand_chip.dma_virt_addr, info->nand_chip.dma_phys_addr);
+	goto out;
+free_bam:
+	msm_nand_bam_free(info);
+clk_rpm_disable:
+	msm_nand_setup_clocks_and_bus_bw(info, false);
+	pm_runtime_disable(&(pdev)->dev);
+	pm_runtime_set_suspended(&(pdev)->dev);
+bus_unregister:
+	msm_nand_bus_unregister(info);
+out:
+	return err;
+}
+
+/*
+ * Remove functionality that gets called when driver/device msm-nand
+ * is removed.
+ */
+static int msm_nand_remove(struct platform_device *pdev)
+{
+	struct msm_nand_info *info = dev_get_drvdata(&pdev->dev);
+
+	if (pm_runtime_suspended(&(pdev)->dev))
+		pm_runtime_resume(&(pdev)->dev);
+
+	pm_runtime_disable(&(pdev)->dev);
+	pm_runtime_set_suspended(&(pdev)->dev);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	if (info) {
+		msm_nand_setup_clocks_and_bus_bw(info, false);
+		if (info->clk_data.client_handle)
+			msm_nand_bus_unregister(info);
+		mtd_device_unregister(&info->mtd);
+		msm_nand_bam_free(info);
+	}
+	return 0;
+}
+
+#define DRIVER_NAME "msm_qpic_nand"
+static const struct of_device_id msm_nand_match_table[] = {
+	{ .compatible = "qcom,msm-nand", },
+	{},
+};
+
+static const struct dev_pm_ops msm_nand_pm_ops = {
+	.suspend		= msm_nand_suspend,
+	.resume			= msm_nand_resume,
+	.runtime_suspend	= msm_nand_runtime_suspend,
+	.runtime_resume		= msm_nand_runtime_resume,
+};
+
+static struct platform_driver msm_nand_driver = {
+	.probe		= msm_nand_probe,
+	.remove		= msm_nand_remove,
+	.driver = {
+		.name		= DRIVER_NAME,
+		.of_match_table = msm_nand_match_table,
+		.pm		= &msm_nand_pm_ops,
+	},
+};
+
+module_param(enable_euclean, bool, 0644);
+MODULE_PARM_DESC(enable_euclean, "Set this parameter to enable reporting EUCLEAN to upper layer when the correctable bitflips are equal to the max correctable limit.");
+
+module_platform_driver(msm_nand_driver);
+
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM QPIC NAND flash driver");
diff --git a/drivers/mtd/devices/msm_qpic_nand.h b/drivers/mtd/devices/msm_qpic_nand.h
new file mode 100644
index 0000000..9b6701c
--- /dev/null
+++ b/drivers/mtd/devices/msm_qpic_nand.h
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __QPIC_NAND_H
+#define __QPIC_NAND_H
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/crc16.h>
+#include <linux/bitrev.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/ctype.h>
+#include <linux/msm-sps.h>
+#include <linux/msm-bus.h>
+#include <soc/qcom/smem.h>
+
+#define PAGE_SIZE_2K 2048
+#define PAGE_SIZE_4K 4096
+
+#undef WRITE /* To avoid redefinition in above header files */
+#undef READ /* To avoid redefinition in above header files */
+#define WRITE 1
+#define READ 0
+
+#define MSM_NAND_IDLE_TIMEOUT   200 /* msecs */
+#define MSM_NAND_BUS_VOTE_MAX_RATE  100000000 /* Hz */
+
+/*
+ * The maximum no of descriptors per transfer (page read/write) won't be more
+ * than 64. For more details on what those commands are, please refer to the
+ * page read and page write functions in the driver.
+ */
+#define SPS_MAX_DESC_NUM 64
+#define SPS_DATA_CONS_PIPE_INDEX 0
+#define SPS_DATA_PROD_PIPE_INDEX 1
+#define SPS_CMD_CONS_PIPE_INDEX 2
+
+#define msm_virt_to_dma(chip, vaddr) \
+	((chip)->dma_phys_addr + \
+	((uint8_t *)(vaddr) - (chip)->dma_virt_addr))
+
+/*
+ * A single page read/write request would typically need DMA memory of about
+ * 1K memory approximately. So for a single request this memory is more than
+ * enough.
+ *
+ * But to accommodate multiple clients we allocate 8K of memory. Though only
+ * one client request can be submitted to NANDc at any time, other clients can
+ * still prepare the descriptors while waiting for current client request to
+ * be done. Thus for a total memory of 8K, the driver can currently support
+ * maximum clients up to 7 or 8 at a time. The client for which there is no
+ * free DMA memory shall wait on the wait queue until other clients free up
+ * the required memory.
+ */
+#define MSM_NAND_DMA_BUFFER_SIZE SZ_8K
+/*
+ * This defines the granularity at which the buffer management is done. The
+ * total number of slots is based on the size of the atomic_t variable
+ * dma_buffer_busy(number of bits) within the structure msm_nand_chip.
+ */
+#define MSM_NAND_DMA_BUFFER_SLOT_SZ \
+	(MSM_NAND_DMA_BUFFER_SIZE / (sizeof(((atomic_t *)0)->counter) * 8))
+
+/* ONFI(Open NAND Flash Interface) parameters */
+#define MSM_NAND_CFG0_RAW_ONFI_IDENTIFIER 0x88000800
+#define MSM_NAND_CFG0_RAW_ONFI_PARAM_INFO 0x88040000
+#define MSM_NAND_CFG1_RAW_ONFI_IDENTIFIER 0x0005045d
+#define MSM_NAND_CFG1_RAW_ONFI_PARAM_INFO 0x0005045d
+#define ONFI_PARAM_INFO_LENGTH 0x0200
+#define ONFI_PARAM_PAGE_LENGTH 0x0100
+#define ONFI_PARAMETER_PAGE_SIGNATURE 0x49464E4F
+#define FLASH_READ_ONFI_SIGNATURE_ADDRESS 0x20
+#define FLASH_READ_ONFI_PARAMETERS_ADDRESS 0x00
+#define FLASH_READ_DEVICE_ID_ADDRESS 0x00
+
+#define MSM_NAND_RESET_FLASH_STS 0x00000020
+#define MSM_NAND_RESET_READ_STS 0x000000C0
+
+/* QPIC NANDc (NAND Controller) Register Set */
+#define MSM_NAND_REG(info, off)		    (info->nand_phys + off)
+#define MSM_NAND_REG_ADJUSTED(info, off)    (info->nand_phys_adjusted + off)
+#define MSM_NAND_QPIC_VERSION(info)	    MSM_NAND_REG_ADJUSTED(info, 0x20100)
+#define MSM_NAND_FLASH_CMD(info)	    MSM_NAND_REG(info, 0x30000)
+#define MSM_NAND_ADDR0(info)                MSM_NAND_REG(info, 0x30004)
+#define MSM_NAND_ADDR1(info)                MSM_NAND_REG(info, 0x30008)
+#define MSM_NAND_EXEC_CMD(info)             MSM_NAND_REG(info, 0x30010)
+#define MSM_NAND_FLASH_STATUS(info)         MSM_NAND_REG(info, 0x30014)
+#define FS_OP_ERR (1 << 4)
+#define FS_MPU_ERR (1 << 8)
+#define FS_DEVICE_STS_ERR (1 << 16)
+#define FS_DEVICE_WP (1 << 23)
+
+#define MSM_NAND_BUFFER_STATUS(info)        MSM_NAND_REG(info, 0x30018)
+#define BS_UNCORRECTABLE_BIT (1 << 8)
+#define BS_CORRECTABLE_ERR_MSK 0x1F
+
+#define MSM_NAND_DEV0_CFG0(info)            MSM_NAND_REG(info, 0x30020)
+#define DISABLE_STATUS_AFTER_WRITE 4
+#define CW_PER_PAGE	6
+#define UD_SIZE_BYTES	9
+#define SPARE_SIZE_BYTES 23
+#define NUM_ADDR_CYCLES	27
+
+#define MSM_NAND_DEV0_CFG1(info)            MSM_NAND_REG(info, 0x30024)
+#define DEV0_CFG1_ECC_DISABLE	0
+#define WIDE_FLASH		1
+#define NAND_RECOVERY_CYCLES	2
+#define CS_ACTIVE_BSY		5
+#define BAD_BLOCK_BYTE_NUM	6
+#define BAD_BLOCK_IN_SPARE_AREA 16
+#define WR_RD_BSY_GAP		17
+#define ENABLE_BCH_ECC		27
+
+#define BYTES_512		512
+#define BYTES_516		516
+#define BYTES_517		517
+
+#define MSM_NAND_DEV0_ECC_CFG(info)	    MSM_NAND_REG(info, 0x30028)
+#define ECC_CFG_ECC_DISABLE	0
+#define ECC_SW_RESET	1
+#define ECC_MODE	4
+#define ECC_PARITY_SIZE_BYTES 8
+#define ECC_NUM_DATA_BYTES 16
+#define ECC_FORCE_CLK_OPEN 30
+
+#define MSM_NAND_READ_ID(info)              MSM_NAND_REG(info, 0x30040)
+#define MSM_NAND_READ_STATUS(info)          MSM_NAND_REG(info, 0x30044)
+#define MSM_NAND_READ_ID2(info)              MSM_NAND_REG(info, 0x30048)
+#define EXTENDED_FETCH_ID           BIT(19)
+#define MSM_NAND_DEV_CMD1(info)             MSM_NAND_REG(info, 0x300A4)
+#define MSM_NAND_DEV_CMD_VLD(info)          MSM_NAND_REG(info, 0x300AC)
+#define MSM_NAND_EBI2_ECC_BUF_CFG(info)     MSM_NAND_REG(info, 0x300F0)
+
+#define MSM_NAND_ERASED_CW_DETECT_CFG(info)	MSM_NAND_REG(info, 0x300E8)
+#define ERASED_CW_ECC_MASK	1
+#define AUTO_DETECT_RES		0
+#define MASK_ECC		(1 << ERASED_CW_ECC_MASK)
+#define RESET_ERASED_DET	(1 << AUTO_DETECT_RES)
+#define ACTIVE_ERASED_DET	(0 << AUTO_DETECT_RES)
+#define CLR_ERASED_PAGE_DET	(RESET_ERASED_DET | MASK_ECC)
+#define SET_ERASED_PAGE_DET	(ACTIVE_ERASED_DET | MASK_ECC)
+
+#define MSM_NAND_ERASED_CW_DETECT_STATUS(info)  MSM_NAND_REG(info, 0x300EC)
+#define PAGE_ALL_ERASED		7
+#define CODEWORD_ALL_ERASED	6
+#define PAGE_ERASED		5
+#define CODEWORD_ERASED		4
+#define ERASED_PAGE	((1 << PAGE_ALL_ERASED) | (1 << PAGE_ERASED))
+#define ERASED_CW	((1 << CODEWORD_ALL_ERASED) | (1 << CODEWORD_ERASED))
+
+#define MSM_NAND_CTRL(info)		    MSM_NAND_REG(info, 0x30F00)
+#define BAM_MODE_EN	0
+#define MSM_NAND_VERSION(info)         MSM_NAND_REG_ADJUSTED(info, 0x30F08)
+#define MSM_NAND_READ_LOCATION_0(info)      MSM_NAND_REG(info, 0x30F20)
+#define MSM_NAND_READ_LOCATION_1(info)      MSM_NAND_REG(info, 0x30F24)
+
+/* device commands */
+#define MSM_NAND_CMD_PAGE_READ          0x32
+#define MSM_NAND_CMD_PAGE_READ_ECC      0x33
+#define MSM_NAND_CMD_PAGE_READ_ALL      0x34
+#define MSM_NAND_CMD_PAGE_READ_ONFI     0x35
+#define MSM_NAND_CMD_PRG_PAGE           0x36
+#define MSM_NAND_CMD_PRG_PAGE_ECC       0x37
+#define MSM_NAND_CMD_PRG_PAGE_ALL       0x39
+#define MSM_NAND_CMD_BLOCK_ERASE        0x3A
+#define MSM_NAND_CMD_FETCH_ID           0x0B
+
+/* Version Mask */
+#define MSM_NAND_VERSION_MAJOR_MASK	0xF0000000
+#define MSM_NAND_VERSION_MAJOR_SHIFT	28
+#define MSM_NAND_VERSION_MINOR_MASK	0x0FFF0000
+#define MSM_NAND_VERSION_MINOR_SHIFT	16
+
+#define CMD		SPS_IOVEC_FLAG_CMD
+#define CMD_LCK		(CMD | SPS_IOVEC_FLAG_LOCK)
+#define INT		SPS_IOVEC_FLAG_INT
+#define INT_UNLCK	(INT | SPS_IOVEC_FLAG_UNLOCK)
+#define CMD_INT_UNLCK	(CMD | INT_UNLCK)
+#define NWD		SPS_IOVEC_FLAG_NWD
+
+/* Structure that defines a NAND SPS command element */
+struct msm_nand_sps_cmd {
+	struct sps_command_element ce;
+	uint32_t flags;
+};
+
+struct msm_nand_cmd_setup_desc {
+	struct sps_command_element ce[11];
+	uint32_t flags;
+	uint32_t num_ce;
+};
+
+struct msm_nand_cmd_cw_desc {
+	struct sps_command_element ce[3];
+	uint32_t flags;
+	uint32_t num_ce;
+};
+
+struct msm_nand_rw_cmd_desc {
+	uint32_t count;
+	struct msm_nand_cmd_setup_desc setup_desc;
+	struct msm_nand_cmd_cw_desc cw_desc[];
+};
+
+/*
+ * Structure that defines the NAND controller properties as per the
+ * NAND flash device/chip that is attached.
+ */
+struct msm_nand_chip {
+	struct device *dev;
+	/*
+	 * DMA memory will be allocated only once during probe and this memory
+	 * will be used by all NAND clients. This wait queue is needed to
+	 * make the applications wait for DMA memory to be free'd when the
+	 * complete memory is exhausted.
+	 */
+	wait_queue_head_t dma_wait_queue;
+	atomic_t dma_buffer_busy;
+	uint8_t *dma_virt_addr;
+	dma_addr_t dma_phys_addr;
+	uint32_t ecc_parity_bytes;
+	uint32_t bch_caps; /* Controller BCH ECC capabilities */
+#define MSM_NAND_CAP_4_BIT_BCH      (1 << 0)
+#define MSM_NAND_CAP_8_BIT_BCH      (1 << 1)
+	uint32_t cw_size;
+	/* NANDc register configurations */
+	uint32_t cfg0, cfg1, cfg0_raw, cfg1_raw;
+	uint32_t ecc_buf_cfg;
+	uint32_t ecc_bch_cfg;
+	uint32_t ecc_cfg_raw;
+};
+
+/* Structure that defines an SPS end point for a NANDc BAM pipe. */
+struct msm_nand_sps_endpt {
+	struct sps_pipe *handle;
+	struct sps_connect config;
+	struct sps_register_event event;
+	struct completion completion;
+	uint32_t index;
+};
+
+/*
+ * Structure that defines NANDc SPS data - BAM handle and an end point
+ * for each BAM pipe.
+ */
+struct msm_nand_sps_info {
+	unsigned long bam_handle;
+	struct msm_nand_sps_endpt data_prod;
+	struct msm_nand_sps_endpt data_cons;
+	struct msm_nand_sps_endpt cmd_pipe;
+};
+
+/*
+ * Structure that contains flash device information. This gets updated after
+ * the NAND flash device detection.
+ */
+struct flash_identification {
+	uint32_t flash_id;
+	uint64_t density;
+	uint32_t widebus;
+	uint32_t pagesize;
+	uint32_t blksize;
+	uint32_t oobsize;
+	uint32_t ecc_correctability;
+	uint32_t ecc_capability; /* Set based on the ECC capability selected. */
+};
+
+struct msm_nand_clk_data {
+	struct clk *qpic_clk;
+	struct msm_bus_scale_pdata *use_cases;
+	uint32_t client_handle;
+	atomic_t clk_enabled;
+	atomic_t curr_vote;
+};
+
+/* Structure that defines NANDc private data. */
+struct msm_nand_info {
+	struct mtd_info		mtd;
+	struct msm_nand_chip	nand_chip;
+	struct msm_nand_sps_info sps;
+	unsigned long bam_phys;
+	unsigned long nand_phys;
+	unsigned long nand_phys_adjusted;
+	void __iomem *bam_base;
+	int bam_irq;
+	/*
+	 * This lock must be acquired before submitting any command or data
+	 * descriptors to BAM pipes and must be held until all the submitted
+	 * descriptors are processed.
+	 *
+	 * This is required to ensure that both command and descriptors are
+	 * submitted atomically without interruption from other clients,
+	 * when there are requests from more than client at any time.
+	 * Othewise, data and command descriptors can be submitted out of
+	 * order for a request which can cause data corruption.
+	 */
+	struct mutex lock;
+	struct flash_identification flash_dev;
+	struct msm_nand_clk_data clk_data;
+	u64 dma_mask;
+};
+
+/* Structure that defines an ONFI parameter page (512B) */
+struct onfi_param_page {
+	uint32_t parameter_page_signature;
+	uint16_t revision_number;
+	uint16_t features_supported;
+	uint16_t optional_commands_supported;
+	uint8_t  reserved0[22];
+	uint8_t  device_manufacturer[12];
+	uint8_t  device_model[20];
+	uint8_t  jedec_manufacturer_id;
+	uint16_t date_code;
+	uint8_t  reserved1[13];
+	uint32_t number_of_data_bytes_per_page;
+	uint16_t number_of_spare_bytes_per_page;
+	uint32_t number_of_data_bytes_per_partial_page;
+	uint16_t number_of_spare_bytes_per_partial_page;
+	uint32_t number_of_pages_per_block;
+	uint32_t number_of_blocks_per_logical_unit;
+	uint8_t  number_of_logical_units;
+	uint8_t  number_of_address_cycles;
+	uint8_t  number_of_bits_per_cell;
+	uint16_t maximum_bad_blocks_per_logical_unit;
+	uint16_t block_endurance;
+	uint8_t  guaranteed_valid_begin_blocks;
+	uint16_t guaranteed_valid_begin_blocks_endurance;
+	uint8_t  number_of_programs_per_page;
+	uint8_t  partial_program_attributes;
+	uint8_t  number_of_bits_ecc_correctability;
+	uint8_t  number_of_interleaved_address_bits;
+	uint8_t  interleaved_operation_attributes;
+	uint8_t  reserved2[13];
+	uint8_t  io_pin_capacitance;
+	uint16_t timing_mode_support;
+	uint16_t program_cache_timing_mode_support;
+	uint16_t maximum_page_programming_time;
+	uint16_t maximum_block_erase_time;
+	uint16_t maximum_page_read_time;
+	uint16_t maximum_change_column_setup_time;
+	uint8_t  reserved3[23];
+	uint16_t vendor_specific_revision_number;
+	uint8_t  vendor_specific[88];
+	uint16_t integrity_crc;
+} __attribute__((__packed__));
+
+#define FLASH_PART_MAGIC1	0x55EE73AA
+#define FLASH_PART_MAGIC2	0xE35EBDDB
+#define FLASH_PTABLE_V3		3
+#define FLASH_PTABLE_V4		4
+#define FLASH_PTABLE_MAX_PARTS_V3 16
+#define FLASH_PTABLE_MAX_PARTS_V4 32
+#define FLASH_PTABLE_HDR_LEN (4*sizeof(uint32_t))
+#define FLASH_PTABLE_ENTRY_NAME_SIZE 16
+
+struct flash_partition_entry {
+	char name[FLASH_PTABLE_ENTRY_NAME_SIZE];
+	u32 offset;     /* Offset in blocks from beginning of device */
+	u32 length;     /* Length of the partition in blocks */
+	u8 attr;	/* Flags for this partition */
+};
+
+struct flash_partition_table {
+	u32 magic1;
+	u32 magic2;
+	u32 version;
+	u32 numparts;
+	struct flash_partition_entry part_entry[FLASH_PTABLE_MAX_PARTS_V4];
+};
+
+static struct flash_partition_table ptable;
+
+static struct mtd_partition mtd_part[FLASH_PTABLE_MAX_PARTS_V4];
+
+static inline bool is_buffer_in_page(const void *buf, size_t len)
+{
+	return !(((unsigned long) buf & ~PAGE_MASK) + len > PAGE_SIZE);
+}
+#endif /* __QPIC_NAND_H */
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index fccdd49..c62923b 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -617,7 +617,7 @@
 	return ret;
 }
 
-int mtd_add_partition(struct mtd_info *master, const char *name,
+int mtd_add_partition(struct mtd_info *master, char *name,
 		      long long offset, long long length)
 {
 	struct mtd_partition part;
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index ede407d..2312412 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -112,7 +112,7 @@
 		partname = of_get_property(pp, "label", &len);
 		if (!partname)
 			partname = of_get_property(pp, "name", &len);
-		parts[i].name = partname;
+		parts[i].name = (char *)partname;
 
 		if (of_get_property(pp, "read-only", &len))
 			parts[i].mask_flags |= MTD_WRITEABLE;
@@ -186,7 +186,7 @@
 		if (names && (plen > 0)) {
 			int len = strlen(names) + 1;
 
-			parts[i].name = names;
+			parts[i].name = (char *)names;
 			plen -= len;
 			names += len;
 		} else {
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 9d91f96..8cc7467 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -112,7 +112,6 @@
 source "drivers/net/ethernet/micrel/Kconfig"
 source "drivers/net/ethernet/microchip/Kconfig"
 source "drivers/net/ethernet/moxa/Kconfig"
-source "drivers/net/ethernet/msm/Kconfig"
 source "drivers/net/ethernet/myricom/Kconfig"
 
 config FEALNX
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index b31cbc2..a09423d 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -52,7 +52,6 @@
 obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/
 obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/
 obj-$(CONFIG_NET_VENDOR_MOXART) += moxa/
-obj-$(CONFIG_ARCH_QCOM) += msm/
 obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/
 obj-$(CONFIG_FEALNX) += fealnx.o
 obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 0a9108c..0a5ee1d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1931,7 +1931,7 @@
 	}
 
 	/* select a non-FCoE queue */
-	return fallback(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
+	return fallback(dev, skb) % (BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos);
 }
 
 void bnx2x_set_num_queues(struct bnx2x *bp)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 19dc9e2..f9c2feb 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -2226,10 +2226,14 @@
 		if (err)
 			goto irq_err;
 	}
+
+	mutex_lock(&uld_mutex);
 	enable_rx(adap);
 	t4_sge_start(adap);
 	t4_intr_enable(adap);
 	adap->flags |= FULL_INIT_DONE;
+	mutex_unlock(&uld_mutex);
+
 	notify_ulds(adap, CXGB4_STATE_UP);
 #if IS_ENABLED(CONFIG_IPV6)
 	update_clip(adap);
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index c044667..e31199f 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -710,6 +710,8 @@
 	if (ret)
 		return ret;
 
+	napi_enable(&priv->napi);
+
 	ethoc_init_ring(priv, dev->mem_start);
 	ethoc_reset(priv);
 
@@ -722,7 +724,6 @@
 	}
 
 	phy_start(dev->phydev);
-	napi_enable(&priv->napi);
 
 	if (netif_msg_ifup(priv)) {
 		dev_info(&dev->dev, "I/O: %08lx Memory: %08lx-%08lx\n",
diff --git a/drivers/net/ethernet/msm/Kconfig b/drivers/net/ethernet/msm/Kconfig
deleted file mode 100644
index 586e03e..0000000
--- a/drivers/net/ethernet/msm/Kconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# msm network device configuration
-#
-
-config ECM_IPA
-	tristate "STD ECM LAN Driver support"
-	depends on IPA || IPA3
-	help
-	  Enables LAN between applications processor and a tethered
-	  host using the STD ECM protocol.
-	  This Network interface is aimed to allow data path go through
-	  IPA core while using STD ECM protocol.
-
-config RNDIS_IPA
-	tristate "RNDIS_IPA Network Interface Driver support"
-	depends on IPA || IPA3
-	help
-	  Enables LAN between applications processor and a tethered
-	  host using the RNDIS protocol.
-	  This Network interface is aimed to allow data path go through
-	  IPA core while using RNDIS protocol.
-
diff --git a/drivers/net/ethernet/msm/Makefile b/drivers/net/ethernet/msm/Makefile
deleted file mode 100644
index ec2699a..0000000
--- a/drivers/net/ethernet/msm/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for the msm networking support.
-#
-
-obj-$(CONFIG_ECM_IPA) += ecm_ipa.o
-obj-$(CONFIG_RNDIS_IPA) += rndis_ipa.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index b2893fb..ef6bff8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1953,7 +1953,7 @@
 
 		priv->hw->desc->prepare_tso_tx_desc(desc, 0, buff_size,
 			0, 1,
-			(last_segment) && (buff_size < TSO_MAX_BUFF_SIZE),
+			(last_segment) && (tmp_len <= TSO_MAX_BUFF_SIZE),
 			0, 0);
 
 		tmp_len -= TSO_MAX_BUFF_SIZE;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 4b7a363..35aa28b 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1276,6 +1276,10 @@
 		return -EINVAL;
 	}
 
+	if (!(tun->flags & IFF_NO_PI))
+		if (pi.flags & htons(CHECKSUM_UNNECESSARY))
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+
 	switch (tun->flags & TUN_TYPE_MASK) {
 	case IFF_TUN:
 		if (tun->flags & IFF_NO_PI) {
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 3c4c2cf..55c4408 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -59,6 +59,8 @@
 
 static int vxlan_sock_add(struct vxlan_dev *vxlan);
 
+static void vxlan_vs_del_dev(struct vxlan_dev *vxlan);
+
 /* per-network namespace private data for this module */
 struct vxlan_net {
 	struct list_head  vxlan_list;
@@ -717,6 +719,22 @@
 	call_rcu(&f->rcu, vxlan_fdb_free);
 }
 
+static void vxlan_dst_free(struct rcu_head *head)
+{
+	struct vxlan_rdst *rd = container_of(head, struct vxlan_rdst, rcu);
+
+	dst_cache_destroy(&rd->dst_cache);
+	kfree(rd);
+}
+
+static void vxlan_fdb_dst_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
+				  struct vxlan_rdst *rd)
+{
+	list_del_rcu(&rd->list);
+	vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH);
+	call_rcu(&rd->rcu, vxlan_dst_free);
+}
+
 static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
 			   union vxlan_addr *ip, __be16 *port, __be32 *vni,
 			   u32 *ifindex)
@@ -847,9 +865,7 @@
 	 * otherwise destroy the fdb entry
 	 */
 	if (rd && !list_is_singular(&f->remotes)) {
-		list_del_rcu(&rd->list);
-		vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH);
-		kfree_rcu(rd, rcu);
+		vxlan_fdb_dst_destroy(vxlan, f, rd);
 		goto out;
 	}
 
@@ -1026,6 +1042,8 @@
 	rcu_assign_pointer(vxlan->vn4_sock, NULL);
 	synchronize_net();
 
+	vxlan_vs_del_dev(vxlan);
+
 	if (__vxlan_sock_release_prep(sock4)) {
 		udp_tunnel_sock_release(sock4->sock);
 		kfree(sock4);
@@ -2286,6 +2304,15 @@
 	mod_timer(&vxlan->age_timer, next_timer);
 }
 
+static void vxlan_vs_del_dev(struct vxlan_dev *vxlan)
+{
+	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
+
+	spin_lock(&vn->sock_lock);
+	hlist_del_init_rcu(&vxlan->hlist);
+	spin_unlock(&vn->sock_lock);
+}
+
 static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
 {
 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
@@ -3056,12 +3083,6 @@
 static void vxlan_dellink(struct net_device *dev, struct list_head *head)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
-	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
-
-	spin_lock(&vn->sock_lock);
-	if (!hlist_unhashed(&vxlan->hlist))
-		hlist_del_rcu(&vxlan->hlist);
-	spin_unlock(&vn->sock_lock);
 
 	gro_cells_destroy(&vxlan->gro_cells);
 	list_del(&vxlan->next);
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index a0fa943..361d7dd0 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -564,7 +564,7 @@
 	msm_pcie_dev_tbl[MAX_RC_NUM * MAX_DEVICE_NUM];
 
 /* PCIe driver state */
-struct pcie_drv_sta {
+static struct pcie_drv_sta {
 	u32 rc_num;
 	struct mutex drv_lock;
 } pcie_drv;
@@ -690,14 +690,14 @@
 
 /* resources */
 static const struct msm_pcie_res_info_t msm_pcie_res_info[MSM_PCIE_MAX_RES] = {
-	{"parf",	0, 0},
-	{"phy",     0, 0},
-	{"dm_core",	0, 0},
-	{"elbi",	0, 0},
-	{"conf",	0, 0},
-	{"io",		0, 0},
-	{"bars",	0, 0},
-	{"tcsr",	0, 0}
+	{"parf",	NULL, NULL},
+	{"phy",     NULL, NULL},
+	{"dm_core",	NULL, NULL},
+	{"elbi",	NULL, NULL},
+	{"conf",	NULL, NULL},
+	{"io",		NULL, NULL},
+	{"bars",	NULL, NULL},
+	{"tcsr",	NULL, NULL}
 };
 
 /* irqs */
@@ -763,14 +763,14 @@
 }
 #endif
 
-static inline void msm_pcie_write_reg(void *base, u32 offset, u32 value)
+static inline void msm_pcie_write_reg(void __iomem *base, u32 offset, u32 value)
 {
 	writel_relaxed(value, base + offset);
 	/* ensure that changes propagated to the hardware */
 	wmb();
 }
 
-static inline void msm_pcie_write_reg_field(void *base, u32 offset,
+static inline void msm_pcie_write_reg_field(void __iomem *base, u32 offset,
 	const u32 mask, u32 val)
 {
 	u32 shift = find_first_bit((void *)&mask, 32);
@@ -976,7 +976,7 @@
 	int i, j;
 	u32 val = 0;
 	u32 *shadow;
-	void *cfg = dev->conf;
+	void __iomem *cfg = dev->conf;
 
 	for (i = 0; i < MAX_DEVICE_NUM; i++) {
 		if (!rc && !dev->pcidev_table[i].bdf)
@@ -1764,7 +1764,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_cmd_debug_ops = {
+static const struct file_operations msm_pcie_cmd_debug_ops = {
 	.write = msm_pcie_cmd_debug,
 };
 
@@ -1807,7 +1807,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_rc_sel_ops = {
+static const struct file_operations msm_pcie_rc_sel_ops = {
 	.write = msm_pcie_set_rc_sel,
 };
 
@@ -1865,7 +1865,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_base_sel_ops = {
+static const struct file_operations msm_pcie_base_sel_ops = {
 	.write = msm_pcie_set_base_sel,
 };
 
@@ -1911,7 +1911,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_linkdown_panic_ops = {
+static const struct file_operations msm_pcie_linkdown_panic_ops = {
 	.write = msm_pcie_set_linkdown_panic,
 };
 
@@ -1938,7 +1938,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_wr_offset_ops = {
+static const struct file_operations msm_pcie_wr_offset_ops = {
 	.write = msm_pcie_set_wr_offset,
 };
 
@@ -1965,7 +1965,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_wr_mask_ops = {
+static const struct file_operations msm_pcie_wr_mask_ops = {
 	.write = msm_pcie_set_wr_mask,
 };
 static ssize_t msm_pcie_set_wr_value(struct file *file,
@@ -1991,7 +1991,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_wr_value_ops = {
+static const struct file_operations msm_pcie_wr_value_ops = {
 	.write = msm_pcie_set_wr_value,
 };
 
@@ -2035,7 +2035,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_boot_option_ops = {
+static const struct file_operations msm_pcie_boot_option_ops = {
 	.write = msm_pcie_set_boot_option,
 };
 
@@ -2091,7 +2091,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_aer_enable_ops = {
+static const struct file_operations msm_pcie_aer_enable_ops = {
 	.write = msm_pcie_set_aer_enable,
 };
 
@@ -2118,7 +2118,7 @@
 	return count;
 }
 
-const struct file_operations msm_pcie_corr_counter_limit_ops = {
+static const struct file_operations msm_pcie_corr_counter_limit_ops = {
 	.write = msm_pcie_set_corr_counter_limit,
 };
 
@@ -2127,14 +2127,14 @@
 	rc_sel_max = (0x1 << MAX_RC_NUM) - 1;
 	wr_mask = 0xffffffff;
 
-	dent_msm_pcie = debugfs_create_dir("pci-msm", 0);
+	dent_msm_pcie = debugfs_create_dir("pci-msm", NULL);
 	if (IS_ERR(dent_msm_pcie)) {
 		pr_err("PCIe: fail to create the folder for debug_fs.\n");
 		return;
 	}
 
 	dfile_rc_sel = debugfs_create_file("rc_sel", 0664,
-					dent_msm_pcie, 0,
+					dent_msm_pcie, NULL,
 					&msm_pcie_rc_sel_ops);
 	if (!dfile_rc_sel || IS_ERR(dfile_rc_sel)) {
 		pr_err("PCIe: fail to create the file for debug_fs rc_sel.\n");
@@ -2142,7 +2142,7 @@
 	}
 
 	dfile_case = debugfs_create_file("case", 0664,
-					dent_msm_pcie, 0,
+					dent_msm_pcie, NULL,
 					&msm_pcie_cmd_debug_ops);
 	if (!dfile_case || IS_ERR(dfile_case)) {
 		pr_err("PCIe: fail to create the file for debug_fs case.\n");
@@ -2150,7 +2150,7 @@
 	}
 
 	dfile_base_sel = debugfs_create_file("base_sel", 0664,
-					dent_msm_pcie, 0,
+					dent_msm_pcie, NULL,
 					&msm_pcie_base_sel_ops);
 	if (!dfile_base_sel || IS_ERR(dfile_base_sel)) {
 		pr_err("PCIe: fail to create the file for debug_fs base_sel.\n");
@@ -2158,7 +2158,7 @@
 	}
 
 	dfile_linkdown_panic = debugfs_create_file("linkdown_panic", 0644,
-					dent_msm_pcie, 0,
+					dent_msm_pcie, NULL,
 					&msm_pcie_linkdown_panic_ops);
 	if (!dfile_linkdown_panic || IS_ERR(dfile_linkdown_panic)) {
 		pr_err("PCIe: fail to create the file for debug_fs linkdown_panic.\n");
@@ -2166,7 +2166,7 @@
 	}
 
 	dfile_wr_offset = debugfs_create_file("wr_offset", 0664,
-					dent_msm_pcie, 0,
+					dent_msm_pcie, NULL,
 					&msm_pcie_wr_offset_ops);
 	if (!dfile_wr_offset || IS_ERR(dfile_wr_offset)) {
 		pr_err("PCIe: fail to create the file for debug_fs wr_offset.\n");
@@ -2174,7 +2174,7 @@
 	}
 
 	dfile_wr_mask = debugfs_create_file("wr_mask", 0664,
-					dent_msm_pcie, 0,
+					dent_msm_pcie, NULL,
 					&msm_pcie_wr_mask_ops);
 	if (!dfile_wr_mask || IS_ERR(dfile_wr_mask)) {
 		pr_err("PCIe: fail to create the file for debug_fs wr_mask.\n");
@@ -2182,7 +2182,7 @@
 	}
 
 	dfile_wr_value = debugfs_create_file("wr_value", 0664,
-					dent_msm_pcie, 0,
+					dent_msm_pcie, NULL,
 					&msm_pcie_wr_value_ops);
 	if (!dfile_wr_value || IS_ERR(dfile_wr_value)) {
 		pr_err("PCIe: fail to create the file for debug_fs wr_value.\n");
@@ -2190,7 +2190,7 @@
 	}
 
 	dfile_boot_option = debugfs_create_file("boot_option", 0664,
-					dent_msm_pcie, 0,
+					dent_msm_pcie, NULL,
 					&msm_pcie_boot_option_ops);
 	if (!dfile_boot_option || IS_ERR(dfile_boot_option)) {
 		pr_err("PCIe: fail to create the file for debug_fs boot_option.\n");
@@ -2198,7 +2198,7 @@
 	}
 
 	dfile_aer_enable = debugfs_create_file("aer_enable", 0664,
-					dent_msm_pcie, 0,
+					dent_msm_pcie, NULL,
 					&msm_pcie_aer_enable_ops);
 	if (!dfile_aer_enable || IS_ERR(dfile_aer_enable)) {
 		pr_err("PCIe: fail to create the file for debug_fs aer_enable.\n");
@@ -2206,7 +2206,7 @@
 	}
 
 	dfile_corr_counter_limit = debugfs_create_file("corr_counter_limit",
-					0664, dent_msm_pcie, 0,
+					0664, dent_msm_pcie, NULL,
 					&msm_pcie_corr_counter_limit_ops);
 	if (!dfile_corr_counter_limit || IS_ERR(dfile_corr_counter_limit)) {
 		pr_err("PCIe: fail to create the file for debug_fs corr_counter_limit.\n");
@@ -2609,7 +2609,7 @@
 		gpio_free(dev->gpio[i].num);
 }
 
-int msm_pcie_vreg_init(struct msm_pcie_dev_t *dev)
+static int msm_pcie_vreg_init(struct msm_pcie_dev_t *dev)
 {
 	int i, rc = 0;
 	struct regulator *vreg;
@@ -3229,7 +3229,7 @@
 	}
 }
 
-void msm_pcie_config_msi_controller(struct msm_pcie_dev_t *dev)
+static void msm_pcie_config_msi_controller(struct msm_pcie_dev_t *dev)
 {
 	int i;
 
@@ -3638,7 +3638,7 @@
 	dev->dev_io_res = NULL;
 }
 
-int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options)
+static int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options)
 {
 	int ret = 0;
 	uint32_t val;
@@ -3895,7 +3895,7 @@
 	return ret;
 }
 
-void msm_pcie_disable(struct msm_pcie_dev_t *dev, u32 options)
+static void msm_pcie_disable(struct msm_pcie_dev_t *dev, u32 options)
 {
 	PCIE_DBG(dev, "RC%d: entry\n", dev->rc_idx);
 
@@ -4721,16 +4721,18 @@
 	}
 }
 
-void msm_pcie_destroy_irq(unsigned int irq)
+static void msm_pcie_destroy_irq(unsigned int irq, struct pci_dev *pdev)
 {
 	int pos;
-	struct pci_dev *pdev = irq_get_chip_data(irq);
 	struct msi_desc *entry = irq_get_msi_desc(irq);
 	struct msi_desc *firstentry;
 	struct msm_pcie_dev_t *dev;
 	u32 nvec;
 	int firstirq;
 
+	if (!pdev)
+		pdev = irq_get_chip_data(irq);
+
 	if (!pdev) {
 		pr_err("PCIe: pci device is null. IRQ:%d\n", irq);
 		return;
@@ -4789,7 +4791,7 @@
 void arch_teardown_msi_irq(unsigned int irq)
 {
 	PCIE_GEN_DBG("irq %d deallocated\n", irq);
-	msm_pcie_destroy_irq(irq);
+	msm_pcie_destroy_irq(irq, NULL);
 }
 
 void arch_teardown_msi_irqs(struct pci_dev *dev)
@@ -4809,7 +4811,7 @@
 			continue;
 		nvec = 1 << entry->msi_attrib.multiple;
 		for (i = 0; i < nvec; i++)
-			arch_teardown_msi_irq(entry->irq + i);
+			msm_pcie_destroy_irq(entry->irq + i, dev);
 	}
 }
 
@@ -5004,7 +5006,6 @@
 			firstirq = irq;
 
 		irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
-		irq_set_chip_data(irq, pdev);
 	}
 
 	/* write msi vector and data */
@@ -5092,7 +5093,7 @@
 	.map = msm_pcie_msi_map,
 };
 
-int32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
+static int32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
 {
 	int rc;
 	int msi_start =  0;
@@ -5232,7 +5233,7 @@
 	return 0;
 }
 
-void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
+static void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
 {
 	PCIE_DBG(dev, "RC%d\n", dev->rc_idx);
 
@@ -5574,7 +5575,7 @@
 		msm_pcie_dev[rc_idx].pcidev_table[i].short_bdf = 0;
 		msm_pcie_dev[rc_idx].pcidev_table[i].sid = 0;
 		msm_pcie_dev[rc_idx].pcidev_table[i].domain = rc_idx;
-		msm_pcie_dev[rc_idx].pcidev_table[i].conf_base = 0;
+		msm_pcie_dev[rc_idx].pcidev_table[i].conf_base = NULL;
 		msm_pcie_dev[rc_idx].pcidev_table[i].phy_address = 0;
 		msm_pcie_dev[rc_idx].pcidev_table[i].dev_ctrlstts_offset = 0;
 		msm_pcie_dev[rc_idx].pcidev_table[i].event_reg = NULL;
@@ -5724,7 +5725,7 @@
 	},
 };
 
-int __init pcie_init(void)
+static int __init pcie_init(void)
 {
 	int ret = 0, i;
 	char rc_name[MAX_RC_NAME_LEN];
@@ -5783,7 +5784,7 @@
 		msm_pcie_dev_tbl[i].short_bdf = 0;
 		msm_pcie_dev_tbl[i].sid = 0;
 		msm_pcie_dev_tbl[i].domain = -1;
-		msm_pcie_dev_tbl[i].conf_base = 0;
+		msm_pcie_dev_tbl[i].conf_base = NULL;
 		msm_pcie_dev_tbl[i].phy_address = 0;
 		msm_pcie_dev_tbl[i].dev_ctrlstts_offset = 0;
 		msm_pcie_dev_tbl[i].event_reg = NULL;
@@ -5998,7 +5999,7 @@
 	return ret;
 }
 
-void msm_pcie_fixup_resume(struct pci_dev *dev)
+static void msm_pcie_fixup_resume(struct pci_dev *dev)
 {
 	int ret;
 	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus);
@@ -6021,7 +6022,7 @@
 DECLARE_PCI_FIXUP_RESUME(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
 				 msm_pcie_fixup_resume);
 
-void msm_pcie_fixup_resume_early(struct pci_dev *dev)
+static void msm_pcie_fixup_resume_early(struct pci_dev *dev)
 {
 	int ret;
 	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus);
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.h b/drivers/phy/phy-qcom-ufs-qmp-v3.h
index 4851aac..f731aac 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-v3.h
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3.h
@@ -260,9 +260,9 @@
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SVS_SO_GAIN, 0x04),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE, 0x4B),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_PI_CONTROLS, 0xF1),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_PI_CONTROLS, 0x81),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FASTLOCK_COUNT_LOW, 0x80),
-	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6C),
+	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6E),
 	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A),
 	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02),
 	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03),
@@ -286,7 +286,7 @@
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN, 0x04),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE, 0x4B),
-	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_PI_CONTROLS, 0xF1),
+	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_PI_CONTROLS, 0x81),
 	UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW, 0x80),
 	UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_MULTI_LANE_CTRL1, 0x02),
 };
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 40ee647..02b28bd 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -150,7 +150,7 @@
 
 config PINCTRL_WCD
 	tristate "Qualcomm Technologies, Inc WCD pin controller driver"
-	depends on WCD934X_CODEC
+	depends on WCD9XXX_CODEC_CORE
 	help
 	  This is the pinctrl, pinmux, pinconf and gpiolib driver for the
 	  WCD gpio controller block.
diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c
index 009e27bf..fedd5f0 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-lpi.c
@@ -118,12 +118,12 @@
 	0x00005010,
 	0x00005020,
 	0x00005030,
-	0x00005040,
-	0x00005050,
 	0x00006000,
 	0x00006010,
 	0x00007000,
 	0x00007010,
+	0x00005040,
+	0x00005050,
 	0x00008000,
 	0x00008010,
 	0x00008020,
@@ -406,13 +406,21 @@
 static int lpi_notifier_service_cb(struct notifier_block *this,
 				   unsigned long opcode, void *ptr)
 {
+	static bool initial_boot = true;
+
 	pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
 
 	switch (opcode) {
 	case AUDIO_NOTIFIER_SERVICE_DOWN:
+		if (initial_boot) {
+			initial_boot = false;
+			break;
+		}
 		lpi_dev_up = false;
 		break;
 	case AUDIO_NOTIFIER_SERVICE_UP:
+		if (initial_boot)
+			initial_boot = false;
 		lpi_dev_up = true;
 		break;
 	default:
@@ -455,6 +463,7 @@
 		"pull up"
 	};
 
+	pctldev = pctldev ? : to_gpio_state(chip)->ctrl;
 	pindesc = pctldev->desc->pins[offset];
 	pad = pctldev->desc->pins[offset].drv_data;
 	ctl_reg = lpi_gpio_read(pad, LPI_GPIO_REG_DIR_CTL);
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 1946204..e5fe6ba 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -56,6 +56,24 @@
 	  for RmNet Data Driver and also exchange of QMI messages between
 	  A7 and Q6 IPA-driver.
 
+config ECM_IPA
+	tristate "STD ECM LAN Driver support"
+	depends on IPA || IPA3
+	help
+	  Enables LAN between applications processor and a tethered
+	  host using the STD ECM protocol.
+	  This Network interface is aimed to allow data path go through
+	  IPA core while using STD ECM protocol.
+
+config RNDIS_IPA
+	tristate "RNDIS_IPA Network Interface Driver support"
+	depends on IPA || IPA3
+	help
+	  Enables LAN between applications processor and a tethered
+	  host using the RNDIS protocol.
+	  This Network interface is aimed to allow data path go through
+	  IPA core while using RNDIS protocol.
+
 config IPA_UT
 	tristate "IPA Unit-Test Framework and Test Suites"
 	depends on IPA3 && DEBUG_FS
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 7fca7aa..9c133a8 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -1353,6 +1353,35 @@
 }
 EXPORT_SYMBOL(gsi_query_evt_ring_db_addr);
 
+int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl, uint64_t value)
+{
+	struct gsi_evt_ctx *ctx;
+
+	if (!gsi_ctx) {
+		pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
+		return -GSI_STATUS_NODEV;
+	}
+
+	if (evt_ring_hdl >= gsi_ctx->max_ev) {
+		GSIERR("bad params evt_ring_hdl=%lu\n", evt_ring_hdl);
+		return -GSI_STATUS_INVALID_PARAMS;
+	}
+
+	ctx = &gsi_ctx->evtr[evt_ring_hdl];
+
+	if (ctx->state != GSI_EVT_RING_STATE_ALLOCATED) {
+		GSIERR("bad state %d\n",
+				gsi_ctx->evtr[evt_ring_hdl].state);
+		return -GSI_STATUS_UNSUPPORTED_OP;
+	}
+
+	ctx->ring.wp_local = value;
+	gsi_ring_evt_doorbell(ctx);
+
+	return GSI_STATUS_SUCCESS;
+}
+EXPORT_SYMBOL(gsi_ring_evt_ring_db);
+
 int gsi_reset_evt_ring(unsigned long evt_ring_hdl)
 {
 	uint32_t val;
diff --git a/drivers/platform/msm/ipa/ipa_clients/Makefile b/drivers/platform/msm/ipa/ipa_clients/Makefile
index 61cef2d..61625f5 100644
--- a/drivers/platform/msm/ipa/ipa_clients/Makefile
+++ b/drivers/platform/msm/ipa/ipa_clients/Makefile
@@ -1,2 +1,4 @@
 obj-$(CONFIG_IPA3) += ipa_usb.o odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o
 obj-$(CONFIG_IPA) += odu_bridge.o ipa_mhi_client.o ipa_uc_offload.o
+obj-$(CONFIG_ECM_IPA) += ecm_ipa.o
+obj-$(CONFIG_RNDIS_IPA) += rndis_ipa.o
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
similarity index 100%
rename from drivers/net/ethernet/msm/ecm_ipa.c
rename to drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
index a02247d..9b3b53d 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017 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
@@ -1059,6 +1059,7 @@
 		IPA_MHI_ERR("Unexpected err evt: %d\n", notify->evt_id);
 	}
 	IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc);
+	ipa_assert();
 }
 
 static void ipa_mhi_gsi_ch_err_cb(struct gsi_chan_err_notify *notify)
@@ -1090,6 +1091,7 @@
 		IPA_MHI_ERR("Unexpected err evt: %d\n", notify->evt_id);
 	}
 	IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc);
+	ipa_assert();
 }
 
 
@@ -2044,6 +2046,8 @@
 	if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI)
 		ipa_mhi_update_host_ch_state(true);
 
+	return 0;
+
 fail_stop_event_update_dl_channel:
 		ipa_mhi_resume_channels(true,
 				ipa_mhi_client_ctx->dl_channels);
diff --git a/drivers/net/ethernet/msm/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
similarity index 100%
rename from drivers/net/ethernet/msm/rndis_ipa.c
rename to drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
diff --git a/drivers/net/ethernet/msm/rndis_ipa_trace.h b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa_trace.h
similarity index 100%
rename from drivers/net/ethernet/msm/rndis_ipa_trace.h
rename to drivers/platform/msm/ipa/ipa_clients/rndis_ipa_trace.h
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index f935bab..e8710a6 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -80,6 +80,9 @@
 	__stringify(ECM_DISCONNECT),
 	__stringify(IPA_TETHERING_STATS_UPDATE_STATS),
 	__stringify(IPA_TETHERING_STATS_UPDATE_NETWORK_STATS),
+	__stringify(IPA_QUOTA_REACH),
+	__stringify(IPA_SSR_BEFORE_SHUTDOWN),
+	__stringify(IPA_SSR_AFTER_POWERUP),
 };
 
 const char *ipa_hdr_l2_type_name[] = {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
index d657a06..bb6f8ec 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
@@ -600,12 +600,12 @@
 	mem_size = (ipa_ctx->hdr_proc_ctx_tbl_lcl) ?
 		IPA_MEM_PART(apps_hdr_proc_ctx_size) :
 		IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr);
-	if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) {
-		IPAERR("hdr proc ctx table overflow\n");
-		goto bad_len;
-	}
-
 	if (list_empty(&htbl->head_free_offset_list[bin])) {
+		if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) {
+			IPAERR("hdr proc ctx table overflow\n");
+			goto bad_len;
+		}
+
 		offset = kmem_cache_zalloc(ipa_ctx->hdr_proc_ctx_offset_cache,
 					   GFP_KERNEL);
 		if (!offset) {
@@ -711,30 +711,30 @@
 	mem_size = (ipa_ctx->hdr_tbl_lcl) ? IPA_MEM_PART(apps_hdr_size) :
 		IPA_MEM_PART(apps_hdr_size_ddr);
 
-	/*
-	 * if header does not fit to table, place it in DDR
-	 * This is valid for IPA 2.5 and on,
-	 * with the exception of IPA2.6L.
-	 */
-	if (htbl->end + ipa_hdr_bin_sz[bin] > mem_size) {
-		if (ipa_ctx->ipa_hw_type != IPA_HW_v2_5) {
-			IPAERR("not enough room for header\n");
-			goto bad_hdr_len;
-		} else {
-			entry->is_hdr_proc_ctx = true;
-			entry->phys_base = dma_map_single(ipa_ctx->pdev,
-				entry->hdr,
-				entry->hdr_len,
-				DMA_TO_DEVICE);
-			if (dma_mapping_error(ipa_ctx->pdev,
-				entry->phys_base)) {
-				IPAERR("dma_map_single failure for entry\n");
-				goto fail_dma_mapping;
+	if (list_empty(&htbl->head_free_offset_list[bin])) {
+		/*
+		 * if header does not fit to table, place it in DDR
+		 * This is valid for IPA 2.5 and on,
+		 * with the exception of IPA2.6L.
+		 */
+		if (htbl->end + ipa_hdr_bin_sz[bin] > mem_size) {
+			if (ipa_ctx->ipa_hw_type != IPA_HW_v2_5) {
+				IPAERR("not enough room for header\n");
+				goto bad_hdr_len;
+			} else {
+				entry->is_hdr_proc_ctx = true;
+				entry->phys_base = dma_map_single(ipa_ctx->pdev,
+					entry->hdr,
+					entry->hdr_len,
+					DMA_TO_DEVICE);
+				if (dma_mapping_error(ipa_ctx->pdev,
+					entry->phys_base)) {
+					IPAERR("dma_map_single failureed\n");
+					goto fail_dma_mapping;
+				}
 			}
-		}
-	} else {
-		entry->is_hdr_proc_ctx = false;
-		if (list_empty(&htbl->head_free_offset_list[bin])) {
+		} else {
+			entry->is_hdr_proc_ctx = false;
 			offset = kmem_cache_zalloc(ipa_ctx->hdr_offset_cache,
 						   GFP_KERNEL);
 			if (!offset) {
@@ -751,14 +751,15 @@
 			htbl->end += ipa_hdr_bin_sz[bin];
 			list_add(&offset->link,
 					&htbl->head_offset_list[bin]);
-		} else {
-			/* get the first free slot */
-			offset =
-			list_first_entry(&htbl->head_free_offset_list[bin],
-					struct ipa_hdr_offset_entry, link);
-			list_move(&offset->link, &htbl->head_offset_list[bin]);
+			entry->offset_entry = offset;
 		}
-
+	} else {
+		entry->is_hdr_proc_ctx = false;
+		/* get the first free slot */
+		offset =
+		list_first_entry(&htbl->head_free_offset_list[bin],
+				struct ipa_hdr_offset_entry, link);
+		list_move(&offset->link, &htbl->head_offset_list[bin]);
 		entry->offset_entry = offset;
 	}
 
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h
index 67dd031..4c504f1 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h
@@ -147,6 +147,9 @@
 int rmnet_ipa_query_tethering_stats(struct wan_ioctl_query_tether_stats *data,
 	bool reset);
 
+int rmnet_ipa_query_tethering_stats_all(
+	struct wan_ioctl_query_tether_stats_all *data);
+
 int rmnet_ipa_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data);
 
 int ipa_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req,
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c
index 9a3c146..a7ecf1c 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc.c
@@ -666,6 +666,12 @@
 			retries++;
 			if (retries == IPA_BAM_STOP_MAX_RETRY) {
 				IPAERR("Failed after %d tries\n", retries);
+				mutex_unlock(&ipa_ctx->uc_ctx.uc_lock);
+				/*
+				 * Max retry reached,
+				 * assert to check why cmd send failed.
+				 */
+				ipa_assert();
 			} else {
 				/* sleep for short period to flush IPA */
 				usleep_range(IPA_UC_WAIT_MIN_SLEEP,
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index bec4264..4652fc8 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -878,7 +878,7 @@
 
 void ipa2_set_client(int index, enum ipacm_client_enum client, bool uplink)
 {
-	if (client >= IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) {
+	if (client > IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) {
 		IPAERR("Bad client number! client =%d\n", client);
 	} else if (index >= IPA_MAX_NUM_PIPES || index < 0) {
 		IPAERR("Bad pipe index! index =%d\n", index);
@@ -940,6 +940,11 @@
  */
 bool ipa2_get_client_uplink(int pipe_idx)
 {
+	if (pipe_idx < 0 || pipe_idx >= IPA_MAX_NUM_PIPES) {
+		IPAERR("invalid pipe idx %d\n", pipe_idx);
+		return false;
+	}
+
 	return ipa_ctx->ipacm_client[pipe_idx].uplink;
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index bcd602c..11eeb2f 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -2338,6 +2338,29 @@
 	.remove = ipa_wwan_remove,
 };
 
+/**
+ * rmnet_ipa_send_ssr_notification(bool ssr_done) - send SSR notification
+ *
+ * This function sends the SSR notification before modem shutdown and
+ * after_powerup from SSR framework, to user-space module
+ */
+static void rmnet_ipa_send_ssr_notification(bool ssr_done)
+{
+	struct ipa_msg_meta msg_meta;
+	int rc;
+
+	memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
+	if (ssr_done)
+		msg_meta.msg_type = IPA_SSR_AFTER_POWERUP;
+	else
+		msg_meta.msg_type = IPA_SSR_BEFORE_SHUTDOWN;
+	rc = ipa_send_msg(&msg_meta, NULL, NULL);
+	if (rc) {
+		IPAWANERR("ipa_send_msg failed: %d\n", rc);
+		return;
+	}
+}
+
 static int ssr_notifier_cb(struct notifier_block *this,
 			   unsigned long code,
 			   void *data)
@@ -2345,6 +2368,8 @@
 	if (ipa_rmnet_ctx.ipa_rmnet_ssr) {
 		if (code == SUBSYS_BEFORE_SHUTDOWN) {
 			pr_info("IPA received MPSS BEFORE_SHUTDOWN\n");
+			/* send SSR before-shutdown notification to IPACM */
+			rmnet_ipa_send_ssr_notification(false);
 			atomic_set(&is_ssr, 1);
 			ipa_q6_pre_shutdown_cleanup();
 			if (ipa_netdevs[0])
@@ -2520,6 +2545,26 @@
 }
 
 /**
+ * rmnet_ipa_send_quota_reach_ind() - send quota_reach notification from
+ * IPA Modem
+ * This function sends the quota_reach indication from the IPA Modem driver
+ * via QMI, to user-space module
+ */
+static void rmnet_ipa_send_quota_reach_ind(void)
+{
+	struct ipa_msg_meta msg_meta;
+	int rc;
+
+	memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
+	msg_meta.msg_type = IPA_QUOTA_REACH;
+	rc = ipa_send_msg(&msg_meta, NULL, NULL);
+	if (rc) {
+		IPAWANERR("ipa_send_msg failed: %d\n", rc);
+		return;
+	}
+}
+
+/**
  * rmnet_ipa_poll_tethering_stats() - Tethering stats polling IOCTL handler
  * @data - IOCTL data
  *
@@ -2571,6 +2616,9 @@
 	if (!data->set_quota)
 		ipa_qmi_stop_data_qouta();
 
+	/* prevent string buffer overflows */
+	data->interface_name[IFNAMSIZ-1] = '\0';
+
 	index = find_vchannel_name_index(data->interface_name);
 	IPAWANERR("iface name %s, quota %lu\n",
 			  data->interface_name,
@@ -2808,10 +2856,6 @@
 		kfree(req);
 		kfree(resp);
 		return rc;
-	} else if (reset) {
-		kfree(req);
-		kfree(resp);
-		return 0;
 	}
 
 	if (resp->dl_dst_pipe_stats_list_valid) {
@@ -2947,6 +2991,49 @@
 	return rc;
 }
 
+int rmnet_ipa_query_tethering_stats_all(
+	struct wan_ioctl_query_tether_stats_all *data)
+{
+	struct wan_ioctl_query_tether_stats tether_stats;
+	enum ipa_upstream_type upstream_type;
+	int rc = 0;
+
+	memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats));
+	/* get IPA backhaul type */
+	upstream_type = find_upstream_type(data->upstreamIface);
+
+	if (upstream_type == IPA_UPSTEAM_MAX) {
+		IPAWANERR(" Wrong upstreamIface name %s\n",
+			data->upstreamIface);
+	} else if (upstream_type == IPA_UPSTEAM_WLAN) {
+		IPAWANDBG_LOW(" query wifi-backhaul stats\n");
+		rc = rmnet_ipa_query_tethering_stats_wifi(
+			&tether_stats, data->reset_stats);
+		if (rc) {
+			IPAWANERR("wlan WAN_IOC_QUERY_TETHER_STATS failed\n");
+			return rc;
+		}
+		data->tx_bytes = tether_stats.ipv4_tx_bytes
+			+ tether_stats.ipv6_tx_bytes;
+		data->rx_bytes = tether_stats.ipv4_rx_bytes
+			+ tether_stats.ipv6_rx_bytes;
+	} else {
+		IPAWANDBG_LOW(" query modem-backhaul stats\n");
+		tether_stats.ipa_client = data->ipa_client;
+		rc = rmnet_ipa_query_tethering_stats_modem(
+			&tether_stats, data->reset_stats);
+		if (rc) {
+			IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n");
+			return rc;
+		}
+		data->tx_bytes = tether_stats.ipv4_tx_bytes
+			+ tether_stats.ipv6_tx_bytes;
+		data->rx_bytes = tether_stats.ipv4_rx_bytes
+			+ tether_stats.ipv6_rx_bytes;
+	}
+	return rc;
+}
+
 int rmnet_ipa_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data)
 {
 	enum ipa_upstream_type upstream_type;
@@ -3048,6 +3135,8 @@
 	IPAWANERR("putting nlmsg: <%s> <%s> <%s>\n",
 		alert_msg, iface_name_l, iface_name_m);
 	kobject_uevent_env(&(ipa_netdevs[0]->dev.kobj), KOBJ_CHANGE, envp);
+
+	rmnet_ipa_send_quota_reach_ind();
 }
 
 /**
@@ -3072,6 +3161,9 @@
 		 */
 		ipa2_proxy_clk_unvote();
 
+		/* send SSR power-up notification to IPACM */
+		rmnet_ipa_send_ssr_notification(true);
+
 		/*
 		 * It is required to recover the network stats after
 		 * SSR recovery
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c
index 436cf21..793529d 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa_fd_ioctl.c
@@ -47,6 +47,10 @@
 #define WAN_IOC_QUERY_DL_FILTER_STATS32 _IOWR(WAN_IOC_MAGIC, \
 		WAN_IOCTL_QUERY_DL_FILTER_STATS, \
 		compat_uptr_t)
+#define WAN_IOC_QUERY_TETHER_STATS_ALL32 _IOWR(WAN_IOC_MAGIC, \
+		WAN_IOCTL_QUERY_TETHER_STATS_ALL, \
+		compat_uptr_t)
+
 #endif
 
 static unsigned int dev_num = 1;
@@ -242,6 +246,32 @@
 		}
 		break;
 
+	case WAN_IOC_QUERY_TETHER_STATS_ALL:
+		IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS_ALL :>>>\n");
+		pyld_sz = sizeof(struct wan_ioctl_query_tether_stats_all);
+		param = kzalloc(pyld_sz, GFP_KERNEL);
+		if (!param) {
+			retval = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+
+		if (rmnet_ipa_query_tethering_stats_all(
+			(struct wan_ioctl_query_tether_stats_all *)param)) {
+			IPAWANERR("WAN_IOC_QUERY_TETHER_STATS failed\n");
+			retval = -EFAULT;
+			break;
+		}
+
+		if (copy_to_user((u8 *)arg, param, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
+
 	case WAN_IOC_RESET_TETHER_STATS:
 		IPAWANDBG("device %s got WAN_IOC_RESET_TETHER_STATS :>>>\n",
 				DRIVER_NAME);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 837bf38..1c3995d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -556,6 +556,7 @@
 	struct ipa_ioc_nat_alloc_mem nat_mem;
 	struct ipa_ioc_v4_nat_init nat_init;
 	struct ipa_ioc_v4_nat_del nat_del;
+	struct ipa_ioc_nat_pdn_entry mdfy_pdn;
 	struct ipa_ioc_rm_dependency rm_depend;
 	size_t sz;
 	int pre_entry;
@@ -654,6 +655,18 @@
 		}
 		break;
 
+	case IPA_IOC_NAT_MODIFY_PDN:
+		if (copy_from_user((u8 *)&mdfy_pdn, (const void __user *)arg,
+			sizeof(struct ipa_ioc_nat_pdn_entry))) {
+			retval = -EFAULT;
+			break;
+		}
+		if (ipa4_nat_mdfy_pdn(&mdfy_pdn)) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
+
 	case IPA_IOC_ADD_HDR:
 		if (copy_from_user(header, (u8 *)arg,
 					sizeof(struct ipa_ioc_add_hdr))) {
@@ -3985,7 +3998,8 @@
 	 * IPAv3.5 and above requires to disable prefetch for USB in order
 	 * to allow MBIM to work, currently MBIM is not needed in MHI mode.
 	 */
-	if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5) &&
+	if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5
+		&& ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) &&
 		(!ipa3_ctx->ipa_config_is_mhi))
 		ipa3_disable_prefetch(IPA_CLIENT_USB_CONS);
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 564397a..2d08767 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -1058,8 +1058,21 @@
 	if (should_force_clear) {
 		result = ipa3_enable_force_clear(qmi_req_id, false,
 			source_pipe_bitmask);
-		if (result)
-			goto exit;
+		if (result) {
+			struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 };
+
+			/*
+			 * assuming here modem SSR\shutdown, AP can remove
+			 * the delay in this case
+			 */
+			IPAERR(
+				"failed to force clear %d, remove delay from SCND reg\n"
+				, result);
+			ep_ctrl_scnd.endp_delay = false;
+			ipahal_write_reg_n_fields(
+				IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl,
+				&ep_ctrl_scnd);
+		}
 	}
 	/* with force clear, wait for emptiness */
 	for (i = 0; i < IPA_POLL_FOR_EMPTINESS_NUM; i++) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index 1ee8ec8..2a7b977 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -61,6 +61,9 @@
 	__stringify(ECM_DISCONNECT),
 	__stringify(IPA_TETHERING_STATS_UPDATE_STATS),
 	__stringify(IPA_TETHERING_STATS_UPDATE_NETWORK_STATS),
+	__stringify(IPA_QUOTA_REACH),
+	__stringify(IPA_SSR_BEFORE_SHUTDOWN),
+	__stringify(IPA_SSR_AFTER_POWERUP),
 };
 
 const char *ipa3_hdr_l2_type_name[] = {
@@ -906,6 +909,10 @@
 			pr_err("hashable:%u rule_id:%u max_prio:%u prio:%u ",
 				entry->rule.hashable, entry->rule_id,
 				entry->rule.max_prio, entry->prio);
+			if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+				pr_err("pdn index %d, set metadata %d ",
+					entry->rule.pdn_idx,
+					entry->rule.set_metadata);
 			if (eq)
 				ipa3_attrib_dump_eq(
 					&entry->rule.eq_attrib);
@@ -968,6 +975,10 @@
 				bitmap, rules[rl].rule.retain_hdr);
 			pr_err("rule_id:%u prio:%u ",
 				rules[rl].id, rules[rl].priority);
+			if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+				pr_err("pdn: %u, set_metadata: %u ",
+					rules[rl].rule.pdn_idx,
+					rules[rl].rule.set_metadata);
 			ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
 		}
 
@@ -992,6 +1003,10 @@
 				bitmap, rules[rl].rule.retain_hdr);
 			pr_err("rule_id:%u  prio:%u ",
 				rules[rl].id, rules[rl].priority);
+			if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+				pr_err("pdn: %u, set_metadata: %u ",
+					rules[rl].rule.pdn_idx,
+					rules[rl].rule.set_metadata);
 			ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
 		}
 		pr_err("\n");
@@ -1502,6 +1517,7 @@
 	u32 value, i, j, rule_id;
 	u16 enable, tbl_entry, flag;
 	u32 no_entrys = 0;
+	struct ipa_pdn_entry *pdn_table = ipa3_ctx->nat_mem.pdn_mem.base;
 
 	mutex_lock(&ipa3_ctx->nat_mem.lock);
 	value = ipa3_ctx->nat_mem.public_ip_addr;
@@ -1512,6 +1528,15 @@
 				((value & 0x0000FF00) >> 8),
 				((value & 0x000000FF)));
 
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+		for (i = 0; i < IPA_MAX_PDN_NUM; i++) {
+			pr_err(
+				"PDN %d: ip 0x%X, src_metadata 0x%X, dst_metadata 0x%X\n",
+				i, pdn_table[i].public_ip,
+				pdn_table[i].src_metadata,
+				pdn_table[i].dst_metadata);
+		}
+
 	pr_err("Table Size:%d\n",
 				ipa3_ctx->nat_mem.size_base_tables);
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 915f2b8..4fb4da8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -1836,6 +1836,8 @@
 	struct gsi_xfer_elem gsi_xfer_elem_one;
 	u32 curr;
 
+	spin_lock_bh(&sys->spinlock);
+
 	rx_len_cached = sys->len;
 	curr = atomic_read(&sys->repl.head_idx);
 
@@ -1878,6 +1880,7 @@
 		mb();
 		atomic_set(&sys->repl.head_idx, curr);
 	}
+	spin_unlock_bh(&sys->spinlock);
 
 	queue_work(sys->repl_wq, &sys->repl_work);
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index d0ed782..bfcaa2b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -755,6 +755,23 @@
 		}
 	}
 
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		if (rule->pdn_idx) {
+			if (rule->action == IPA_PASS_TO_EXCEPTION ||
+				rule->action == IPA_PASS_TO_ROUTING) {
+				IPAERR(
+					"PDN index should be 0 when action is not pass to NAT\n");
+				goto error;
+			} else {
+				if (rule->pdn_idx >= IPA_MAX_PDN_NUM) {
+					IPAERR("PDN index %d is too large\n",
+						rule->pdn_idx);
+					goto error;
+				}
+			}
+		}
+	}
+
 	if (rule->rule_id) {
 		if (!(rule->rule_id & ipahal_get_rule_id_hi_bit())) {
 			IPAERR("invalid rule_id provided 0x%x\n"
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index 593d4fc..6e51472 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -373,12 +373,12 @@
 	mem_size = (ipa3_ctx->hdr_proc_ctx_tbl_lcl) ?
 		IPA_MEM_PART(apps_hdr_proc_ctx_size) :
 		IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr);
-	if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) {
-		IPAERR("hdr proc ctx table overflow\n");
-		goto bad_len;
-	}
-
 	if (list_empty(&htbl->head_free_offset_list[bin])) {
+		if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) {
+			IPAERR("hdr proc ctx table overflow\n");
+			goto bad_len;
+		}
+
 		offset = kmem_cache_zalloc(ipa3_ctx->hdr_proc_ctx_offset_cache,
 					   GFP_KERNEL);
 		if (!offset) {
@@ -483,20 +483,21 @@
 	mem_size = (ipa3_ctx->hdr_tbl_lcl) ? IPA_MEM_PART(apps_hdr_size) :
 		IPA_MEM_PART(apps_hdr_size_ddr);
 
-	/* if header does not fit to table, place it in DDR */
-	if (htbl->end + ipa_hdr_bin_sz[bin] > mem_size) {
-		entry->is_hdr_proc_ctx = true;
-		entry->phys_base = dma_map_single(ipa3_ctx->pdev,
-			entry->hdr,
-			entry->hdr_len,
-			DMA_TO_DEVICE);
-		if (dma_mapping_error(ipa3_ctx->pdev, entry->phys_base)) {
-			IPAERR("dma_map_single failure for entry\n");
-			goto fail_dma_mapping;
-		}
-	} else {
-		entry->is_hdr_proc_ctx = false;
-		if (list_empty(&htbl->head_free_offset_list[bin])) {
+	if (list_empty(&htbl->head_free_offset_list[bin])) {
+		/* if header does not fit to table, place it in DDR */
+		if (htbl->end + ipa_hdr_bin_sz[bin] > mem_size) {
+			entry->is_hdr_proc_ctx = true;
+			entry->phys_base = dma_map_single(ipa3_ctx->pdev,
+				entry->hdr,
+				entry->hdr_len,
+				DMA_TO_DEVICE);
+			if (dma_mapping_error(ipa3_ctx->pdev,
+				entry->phys_base)) {
+				IPAERR("dma_map_single failure for entry\n");
+				goto fail_dma_mapping;
+			}
+		} else {
+			entry->is_hdr_proc_ctx = false;
 			offset = kmem_cache_zalloc(ipa3_ctx->hdr_offset_cache,
 						   GFP_KERNEL);
 			if (!offset) {
@@ -513,14 +514,14 @@
 			htbl->end += ipa_hdr_bin_sz[bin];
 			list_add(&offset->link,
 					&htbl->head_offset_list[bin]);
-		} else {
-			/* get the first free slot */
-			offset =
-			list_first_entry(&htbl->head_free_offset_list[bin],
-					struct ipa_hdr_offset_entry, link);
-			list_move(&offset->link, &htbl->head_offset_list[bin]);
+			entry->offset_entry = offset;
 		}
-
+	} else {
+		entry->is_hdr_proc_ctx = false;
+		/* get the first free slot */
+		offset = list_first_entry(&htbl->head_free_offset_list[bin],
+			struct ipa_hdr_offset_entry, link);
+		list_move(&offset->link, &htbl->head_offset_list[bin]);
 		entry->offset_entry = offset;
 	}
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 9a406d6..c6d5c6e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -739,6 +739,19 @@
 };
 
 /**
+* struct ipa_pdn_entry - IPA PDN config table entry
+* @public_ip: the PDN's public ip
+* @src_metadata: the PDN's metadata to be replaced for source NAT
+* @dst_metadata: the PDN's metadata to be replaced for destination NAT
+* @resrvd: reserved field
+*/
+struct ipa_pdn_entry {
+	u32 public_ip;
+	u32 src_metadata;
+	u32 dst_metadata;
+	u32 resrvd;
+};
+/**
  * struct ipa3_nat_mem - IPA NAT memory description
  * @class: pointer to the struct class
  * @dev: the dev_t of the device
@@ -759,6 +772,7 @@
  * @size_base_tables: base table size
  * @size_expansion_tables: expansion table size
  * @public_ip_addr: ip address of nat table
+ * @pdn_mem: pdn config table SW cache memory structure
  */
 struct ipa3_nat_mem {
 	struct class *class;
@@ -784,6 +798,7 @@
 	void *tmp_vaddr;
 	dma_addr_t tmp_dma_handle;
 	bool is_tmp_mem;
+	struct ipa_mem_buffer pdn_mem;
 };
 
 /**
@@ -1580,6 +1595,8 @@
 
 int ipa3_nat_del_cmd(struct ipa_ioc_v4_nat_del *del);
 
+int ipa4_nat_mdfy_pdn(struct ipa_ioc_nat_pdn_entry *mdfy_pdn);
+
 /*
  * Messaging
  */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
index f66e3a3..0dd86fa 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
@@ -255,6 +255,24 @@
 		ep->gsi_evt_ring_hdl = *params->cached_gsi_evt_ring_hdl;
 	}
 
+	if (params->ev_ctx_host->wp == params->ev_ctx_host->rbase) {
+		IPA_MHI_ERR("event ring wp is not updated. base=wp=0x%llx\n",
+			params->ev_ctx_host->wp);
+		goto fail_alloc_ch;
+		return res;
+	}
+
+	IPA_MHI_DBG("Ring event db: evt_ring_hdl=%lu host_wp=0x%llx\n",
+		ep->gsi_evt_ring_hdl, params->ev_ctx_host->wp);
+	res = gsi_ring_evt_ring_db(ep->gsi_evt_ring_hdl,
+		params->ev_ctx_host->wp);
+	if (res) {
+		IPA_MHI_ERR("fail to ring evt ring db %d. hdl=%lu wp=0x%llx\n",
+			res, ep->gsi_evt_ring_hdl, params->ev_ctx_host->wp);
+		goto fail_alloc_ch;
+		return res;
+	}
+
 	memset(&ch_props, 0, sizeof(ch_props));
 	ch_props.prot = GSI_CHAN_PROT_MHI;
 	ch_props.dir = IPA_CLIENT_IS_PROD(client) ?
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
index e1177ca..6acc4d8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
@@ -34,7 +34,6 @@
 #define NAT_TABLE_ENTRY_SIZE_BYTE 32
 #define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4
 
-
 static int ipa3_nat_vma_fault_remap(
 	 struct vm_area_struct *vma, struct vm_fault *vmf)
 {
@@ -247,7 +246,7 @@
 int ipa3_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem)
 {
 	struct ipa3_nat_mem *nat_ctx = &(ipa3_ctx->nat_mem);
-	int gfp_flags = GFP_KERNEL | __GFP_ZERO;
+	gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
 	int result;
 
 	IPADBG("passed memory size %zu\n", mem->size);
@@ -295,11 +294,44 @@
 		IPADBG("using shared(local) memory\n");
 		nat_ctx->is_sys_mem = false;
 	}
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		struct ipa_pdn_entry *pdn_entries;
+		struct ipa_mem_buffer *pdn_mem = &ipa3_ctx->nat_mem.pdn_mem;
+
+		pdn_mem->size = sizeof(struct ipa_pdn_entry) * IPA_MAX_PDN_NUM;
+		if (IPA_MEM_PART(pdn_config_size) < pdn_mem->size) {
+			IPAERR(
+				"number of PDN entries exceeds SRAM available space\n");
+			result = -ENOMEM;
+			goto fail_alloc_pdn;
+		}
+
+		pdn_mem->base = dma_alloc_coherent(ipa3_ctx->pdev,
+			pdn_mem->size,
+			&pdn_mem->phys_base,
+			gfp_flags);
+		if (!pdn_mem->base) {
+			IPAERR("fail to allocate PDN memory\n");
+			result = -ENOMEM;
+			goto fail_alloc_pdn;
+		}
+		pdn_entries = pdn_mem->base;
+		memset(pdn_entries, 0, pdn_mem->size);
+		IPADBG("IPA NAT dev allocated PDN memory successfully\n");
+	}
 
 	nat_ctx->is_dev_init = true;
 	IPADBG("IPA NAT dev init successfully\n");
-	result = 0;
+	mutex_unlock(&nat_ctx->lock);
 
+	return 0;
+
+fail_alloc_pdn:
+	if (nat_ctx->vaddr) {
+		dma_free_coherent(ipa3_ctx->pdev, mem->size, nat_ctx->vaddr,
+			nat_ctx->dma_handle);
+		nat_ctx->vaddr = NULL;
+	}
 bail:
 	mutex_unlock(&nat_ctx->lock);
 
@@ -320,11 +352,13 @@
 #define TBL_ENTRY_SIZE 32
 #define INDX_TBL_ENTRY_SIZE 4
 
-	struct ipahal_imm_cmd_pyld *nop_cmd_pyld = NULL;
-	struct ipa3_desc desc[2];
+	struct ipa3_desc desc[3];
 	struct ipahal_imm_cmd_ip_v4_nat_init cmd;
-	struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
-	int result;
+	int num_cmd = 0;
+	int i = 0;
+	struct ipahal_imm_cmd_pyld *cmd_pyld[3];
+	struct ipahal_imm_cmd_dma_shared_mem mem_cmd = { 0 };
+	int result = 0;
 	u32 offset = 0;
 	size_t tmp;
 
@@ -412,21 +446,22 @@
 
 	memset(&desc, 0, sizeof(desc));
 	/* NO-OP IC for ensuring that IPA pipeline is empty */
-	nop_cmd_pyld =
+	cmd_pyld[num_cmd] =
 		ipahal_construct_nop_imm_cmd(false, IPAHAL_HPS_CLEAR, false);
-	if (!nop_cmd_pyld) {
+	if (!cmd_pyld[num_cmd]) {
 		IPAERR("failed to construct NOP imm cmd\n");
 		result = -ENOMEM;
 		goto bail;
 	}
 
-	desc[0].opcode = nop_cmd_pyld->opcode;
-	desc[0].type = IPA_IMM_CMD_DESC;
-	desc[0].callback = NULL;
-	desc[0].user1 = NULL;
-	desc[0].user2 = 0;
-	desc[0].pyld = nop_cmd_pyld->data;
-	desc[0].len = nop_cmd_pyld->len;
+	desc[num_cmd].opcode = cmd_pyld[num_cmd]->opcode;
+	desc[num_cmd].type = IPA_IMM_CMD_DESC;
+	desc[num_cmd].callback = NULL;
+	desc[num_cmd].user1 = NULL;
+	desc[num_cmd].user2 = 0;
+	desc[num_cmd].pyld = cmd_pyld[num_cmd]->data;
+	desc[num_cmd].len = cmd_pyld[num_cmd]->len;
+	num_cmd++;
 
 	if (ipa3_ctx->nat_mem.vaddr) {
 		IPADBG("using system memory for nat table\n");
@@ -453,7 +488,7 @@
 			IPAERR("index_expn_offset: 0x%x\n",
 				init->index_expn_offset);
 			result = -EPERM;
-			goto free_nop;
+			goto destroy_imm_cmd;
 		}
 		cmd.ipv4_rules_addr =
 			ipa3_ctx->nat_mem.dma_handle + init->ipv4_rules_offset;
@@ -495,25 +530,75 @@
 	IPADBG("Base Table size:0x%x\n", cmd.size_base_tables);
 	cmd.size_expansion_tables = init->expn_table_entries;
 	IPADBG("Expansion Table size:0x%x\n", cmd.size_expansion_tables);
-	cmd.public_ip_addr = init->ip_addr;
-	IPADBG("Public ip address:0x%x\n", cmd.public_ip_addr);
-	cmd_pyld = ipahal_construct_imm_cmd(
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		/*
+		 * public ip field changed to store the PDN config base
+		 * address in IPAv4
+		 */
+		cmd.public_ip_addr = IPA_MEM_PART(pdn_config_ofst);
+		IPADBG("pdn config base:0x%x\n", cmd.public_ip_addr);
+	} else {
+		cmd.public_ip_addr = init->ip_addr;
+		IPADBG("Public ip address:0x%x\n", cmd.public_ip_addr);
+	}
+	cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
 		IPA_IMM_CMD_IP_V4_NAT_INIT, &cmd, false);
-	if (!cmd_pyld) {
+	if (!cmd_pyld[num_cmd]) {
 		IPAERR("Fail to construct ip_v4_nat_init imm cmd\n");
 		result = -EPERM;
-		goto free_nop;
+		goto destroy_imm_cmd;
 	}
 
-	desc[1].opcode = cmd_pyld->opcode;
-	desc[1].type = IPA_IMM_CMD_DESC;
-	desc[1].callback = NULL;
-	desc[1].user1 = NULL;
-	desc[1].user2 = 0;
-	desc[1].pyld = cmd_pyld->data;
-	desc[1].len = cmd_pyld->len;
+	desc[num_cmd].opcode = cmd_pyld[num_cmd]->opcode;
+	desc[num_cmd].type = IPA_IMM_CMD_DESC;
+	desc[num_cmd].callback = NULL;
+	desc[num_cmd].user1 = NULL;
+	desc[num_cmd].user2 = 0;
+	desc[num_cmd].pyld = cmd_pyld[num_cmd]->data;
+	desc[num_cmd].len = cmd_pyld[num_cmd]->len;
+	num_cmd++;
+
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		struct ipa_pdn_entry *pdn_entries;
+
+		/* store ip in pdn entries cache array */
+		pdn_entries = ipa3_ctx->nat_mem.pdn_mem.base;
+		pdn_entries[0].public_ip = init->ip_addr;
+		pdn_entries[0].dst_metadata = 0;
+		pdn_entries[0].src_metadata = 0;
+		pdn_entries[0].resrvd = 0;
+
+		IPADBG("Public ip address:0x%x\n", init->ip_addr);
+
+		/* Copy the PDN config table to SRAM */
+		mem_cmd.is_read = false;
+		mem_cmd.skip_pipeline_clear = false;
+		mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+		mem_cmd.size = sizeof(struct ipa_pdn_entry) * IPA_MAX_PDN_NUM;
+		mem_cmd.system_addr = ipa3_ctx->nat_mem.pdn_mem.phys_base;
+		mem_cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+			IPA_MEM_PART(pdn_config_ofst);
+		cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
+			IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
+		if (!cmd_pyld[num_cmd]) {
+			IPAERR(
+			"fail construct dma_shared_mem cmd: for pdn table");
+			result = -ENOMEM;
+			goto destroy_imm_cmd;
+		}
+		desc[num_cmd].opcode = cmd_pyld[num_cmd]->opcode;
+		desc[num_cmd].type = IPA_IMM_CMD_DESC;
+		desc[num_cmd].callback = NULL;
+		desc[num_cmd].user1 = NULL;
+		desc[num_cmd].user2 = 0;
+		desc[num_cmd].pyld = cmd_pyld[num_cmd]->data;
+		desc[num_cmd].len = cmd_pyld[num_cmd]->len;
+		num_cmd++;
+		IPADBG("added PDN table copy cmd\n");
+	}
+
 	IPADBG("posting v4 init command\n");
-	if (ipa3_send_cmd(2, desc)) {
+	if (ipa3_send_cmd(num_cmd, desc)) {
 		IPAERR("Fail to send immediate command\n");
 		result = -EPERM;
 		goto destroy_imm_cmd;
@@ -550,16 +635,97 @@
 	ipa3_ctx->nat_mem.size_expansion_tables = init->expn_table_entries;
 
 	IPADBG("return\n");
-	result = 0;
 destroy_imm_cmd:
-	ipahal_destroy_imm_cmd(cmd_pyld);
-free_nop:
-	ipahal_destroy_imm_cmd(nop_cmd_pyld);
+	for (i = 0; i < num_cmd; i++)
+		ipahal_destroy_imm_cmd(cmd_pyld[i]);
 bail:
 	return result;
 }
 
 /**
+* ipa4_nat_mdfy_pdn() - Modify a PDN entry in PDN config table in IPA SRAM
+* @mdfy_pdn:	[in] PDN info to be written to SRAM
+*
+* Called by NAT client driver to modify an entry in the PDN config table
+*
+* Returns:	0 on success, negative on failure
+*/
+int ipa4_nat_mdfy_pdn(struct ipa_ioc_nat_pdn_entry *mdfy_pdn)
+{
+	struct ipahal_imm_cmd_dma_shared_mem mem_cmd = { 0 };
+	struct ipa3_desc desc;
+	struct ipahal_imm_cmd_pyld *cmd_pyld;
+	int result = 0;
+	struct ipa3_nat_mem *nat_ctx = &(ipa3_ctx->nat_mem);
+	struct ipa_pdn_entry *pdn_entries = nat_ctx->pdn_mem.base;
+
+	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+		IPAERR("IPA HW does not support multi PDN\n");
+		return -EPERM;
+	}
+	if (!nat_ctx->is_dev_init) {
+		IPAERR("attempt to modify a PDN entry before dev init\n");
+		return -EPERM;
+	}
+
+	if (mdfy_pdn->pdn_index > (IPA_MAX_PDN_NUM - 1)) {
+		IPAERR("pdn index out of range %d\n", mdfy_pdn->pdn_index);
+		return -EPERM;
+	}
+
+	mutex_lock(&nat_ctx->lock);
+
+	/* store ip in pdn entries cache array */
+	pdn_entries[mdfy_pdn->pdn_index].public_ip =
+		mdfy_pdn->public_ip;
+	pdn_entries[mdfy_pdn->pdn_index].dst_metadata =
+		mdfy_pdn->dst_metadata;
+	pdn_entries[mdfy_pdn->pdn_index].src_metadata =
+		mdfy_pdn->src_metadata;
+
+	IPADBG("Modify PDN in index %d: ", mdfy_pdn->pdn_index);
+	IPADBG("Public ip address:0x%x, ", mdfy_pdn->public_ip);
+	IPADBG("dst metadata:0x%x, ", mdfy_pdn->dst_metadata);
+	IPADBG("src metadata:0x%x\n", mdfy_pdn->src_metadata);
+
+	memset(&desc, 0, sizeof(desc));
+
+	/* Copy the PDN config table to SRAM */
+	mem_cmd.is_read = false;
+	mem_cmd.skip_pipeline_clear = false;
+	mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+	mem_cmd.size = sizeof(struct ipa_pdn_entry) * IPA_MAX_PDN_NUM;
+	mem_cmd.system_addr = nat_ctx->pdn_mem.phys_base;
+	mem_cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+		IPA_MEM_PART(pdn_config_ofst);
+	cmd_pyld = ipahal_construct_imm_cmd(
+		IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
+	if (!cmd_pyld) {
+		IPAERR(
+			"fail construct dma_shared_mem cmd: for pdn table");
+		result = -ENOMEM;
+		goto bail;
+	}
+	desc.opcode = cmd_pyld->opcode;
+	desc.type = IPA_IMM_CMD_DESC;
+	desc.callback = NULL;
+	desc.user1 = NULL;
+	desc.user2 = 0;
+	desc.pyld = cmd_pyld->data;
+	desc.len = cmd_pyld->len;
+
+	IPADBG("sending PDN table copy cmd");
+	if (ipa3_send_cmd(1, &desc)) {
+		IPAERR("Fail to send immediate command\n");
+		result = -EPERM;
+	}
+
+	ipahal_destroy_imm_cmd(cmd_pyld);
+bail:
+	mutex_unlock(&nat_ctx->lock);
+	return result;
+}
+/**
  * ipa3_nat_dma_cmd() - Post NAT_DMA command to IPA HW
  * @dma:	[in] initialization command attributes
  *
@@ -573,6 +739,7 @@
 
 	struct ipahal_imm_cmd_pyld *nop_cmd_pyld = NULL;
 	struct ipahal_imm_cmd_nat_dma cmd;
+	enum ipahal_imm_cmd_name cmd_name = IPA_IMM_CMD_NAT_DMA;
 	struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
 	struct ipa3_desc *desc = NULL;
 	u16 size = 0, cnt = 0;
@@ -675,13 +842,16 @@
 	desc[0].pyld = nop_cmd_pyld->data;
 	desc[0].len = nop_cmd_pyld->len;
 
+	/* NAT_DMA was renamed to TABLE_DMA starting from IPAv4 */
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+		cmd_name = IPA_IMM_CMD_TABLE_DMA;
+
 	for (cnt = 0; cnt < dma->entries; cnt++) {
 		cmd.table_index = dma->dma[cnt].table_index;
 		cmd.base_addr = dma->dma[cnt].base_addr;
 		cmd.offset = dma->dma[cnt].offset;
 		cmd.data = dma->dma[cnt].data;
-		cmd_pyld = ipahal_construct_imm_cmd(
-			IPA_IMM_CMD_NAT_DMA, &cmd, false);
+		cmd_pyld = ipahal_construct_imm_cmd(cmd_name, &cmd, false);
 		if (!cmd_pyld) {
 			IPAERR("Fail to construct nat_dma imm cmd\n");
 			continue;
@@ -718,6 +888,10 @@
  */
 void ipa3_nat_free_mem_and_device(struct ipa3_nat_mem *nat_ctx)
 {
+	struct ipahal_imm_cmd_dma_shared_mem mem_cmd = { 0 };
+	struct ipa3_desc desc;
+	struct ipahal_imm_cmd_pyld *cmd_pyld;
+
 	IPADBG("\n");
 	mutex_lock(&nat_ctx->lock);
 
@@ -729,6 +903,47 @@
 		nat_ctx->size = 0;
 		nat_ctx->vaddr = NULL;
 	}
+
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		struct ipa_pdn_entry *pdn_entries =
+			nat_ctx->pdn_mem.base;
+
+		/* zero the PDN table and copy the PDN config table to SRAM */
+		IPADBG("zeroing the PDN config table\n");
+		memset(pdn_entries, 0, sizeof(struct ipa_pdn_entry) *
+			IPA_MAX_PDN_NUM);
+		mem_cmd.is_read = false;
+		mem_cmd.skip_pipeline_clear = false;
+		mem_cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
+		mem_cmd.size = sizeof(struct ipa_pdn_entry) * IPA_MAX_PDN_NUM;
+		mem_cmd.system_addr = nat_ctx->pdn_mem.phys_base;
+		mem_cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
+			IPA_MEM_PART(pdn_config_ofst);
+		cmd_pyld = ipahal_construct_imm_cmd(
+			IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
+		if (!cmd_pyld) {
+			IPAERR(
+				"fail construct dma_shared_mem cmd: for pdn table");
+			goto lbl_free_pdn;
+		}
+		memset(&desc, 0, sizeof(desc));
+		desc.opcode = cmd_pyld->opcode;
+		desc.pyld = cmd_pyld->data;
+		desc.len = cmd_pyld->len;
+		desc.type = IPA_IMM_CMD_DESC;
+
+		IPADBG("sending PDN table copy cmd\n");
+		if (ipa3_send_cmd(1, &desc))
+			IPAERR("Fail to send immediate command\n");
+
+		ipahal_destroy_imm_cmd(cmd_pyld);
+lbl_free_pdn:
+		IPADBG("freeing the PDN memory\n");
+		dma_free_coherent(ipa3_ctx->pdev,
+			nat_ctx->pdn_mem.size,
+			nat_ctx->pdn_mem.base,
+			nat_ctx->pdn_mem.phys_base);
+	}
 	nat_ctx->is_mapped = false;
 	nat_ctx->is_sys_mem = false;
 	nat_ctx->is_dev_init = false;
@@ -762,7 +977,8 @@
 		base_addr = ipa3_ctx->nat_mem.tmp_dma_handle;
 	}
 
-	if (del->public_ip_addr == 0) {
+	if ((ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) &&
+		(del->public_ip_addr == 0)) {
 		IPADBG("Bad Parameter\n");
 		result = -EPERM;
 		goto bail;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
index 6cd82f8..d5d8503 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
@@ -190,6 +190,9 @@
 int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data,
 	bool reset);
 
+int rmnet_ipa3_query_tethering_stats_all(
+	struct wan_ioctl_query_tether_stats_all *data);
+
 int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data);
 
 int ipa3_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 079481d..3d1af57 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -43,6 +43,7 @@
 #define IPA_BCR_REG_VAL_v3_0 (0x00000001)
 #define IPA_BCR_REG_VAL_v3_5 (0x0000003B)
 #define IPA_BCR_REG_VAL_v4_0 (0x00000039)
+#define IPA_CLKON_CFG_v4_0 (0x30000000)
 #define IPA_AGGR_GRAN_MIN (1)
 #define IPA_AGGR_GRAN_MAX (32)
 #define IPA_EOT_COAL_GRAN_MIN (1)
@@ -2055,6 +2056,9 @@
 
 	ipahal_write_reg(IPA_BCR, val);
 
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+		ipahal_write_reg(IPA_CLKON_CFG, IPA_CLKON_CFG_v4_0);
+
 	ipa3_cfg_qsb();
 
 	return 0;
@@ -2200,7 +2204,7 @@
 
 void ipa3_set_client(int index, enum ipacm_client_enum client, bool uplink)
 {
-	if (client >= IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) {
+	if (client > IPACM_CLIENT_MAX || client < IPACM_CLIENT_USB) {
 		IPAERR("Bad client number! client =%d\n", client);
 	} else if (index >= IPA3_MAX_NUM_PIPES || index < 0) {
 		IPAERR("Bad pipe index! index =%d\n", index);
@@ -2262,6 +2266,11 @@
  */
 bool ipa3_get_client_uplink(int pipe_idx)
 {
+	if (pipe_idx < 0 || pipe_idx >= IPA3_MAX_NUM_PIPES) {
+		IPAERR("invalid pipe idx %d\n", pipe_idx);
+		return false;
+	}
+
 	return ipa3_ctx->ipacm_client[pipe_idx].uplink;
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
index d35b8a7..6f46ebf 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
@@ -32,6 +32,7 @@
 	__stringify(IPA_IMM_CMD_DMA_SHARED_MEM),
 	__stringify(IPA_IMM_CMD_IP_PACKET_TAG_STATUS),
 	__stringify(IPA_IMM_CMD_DMA_TASK_32B_ADDR),
+	__stringify(IPA_IMM_CMD_TABLE_DMA),
 };
 
 static const char *ipahal_pkt_status_exception_to_str
@@ -371,6 +372,31 @@
 	return pyld;
 }
 
+static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_table_dma_ipav4(
+	enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
+{
+	struct ipahal_imm_cmd_pyld *pyld;
+	struct ipa_imm_cmd_hw_table_dma_ipav4 *data;
+	struct ipahal_imm_cmd_table_dma *nat_params =
+		(struct ipahal_imm_cmd_table_dma *)params;
+
+	pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
+	if (unlikely(!pyld)) {
+		IPAHAL_ERR("kzalloc err\n");
+		return pyld;
+	}
+	pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
+	pyld->len = sizeof(*data);
+	data = (struct ipa_imm_cmd_hw_table_dma_ipav4 *)pyld->data;
+
+	data->table_index = nat_params->table_index;
+	data->base_addr = nat_params->base_addr;
+	data->offset = nat_params->offset;
+	data->data = nat_params->data;
+
+	return pyld;
+}
+
 static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_hdr_init_system(
 	enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
 {
@@ -640,6 +666,13 @@
 	[IPA_HW_v4_0][IPA_IMM_CMD_REGISTER_WRITE] = {
 		ipa_imm_cmd_construct_register_write_v_4_0,
 		12},
+	/* NAT_DMA was renamed to TABLE_DMA for IPAv4 */
+	[IPA_HW_v4_0][IPA_IMM_CMD_NAT_DMA] = {
+		NULL,
+		-1 },
+	[IPA_HW_v4_0][IPA_IMM_CMD_TABLE_DMA] = {
+		ipa_imm_cmd_construct_table_dma_ipav4,
+		14},
 	[IPA_HW_v4_0][IPA_IMM_CMD_DMA_SHARED_MEM] = {
 		ipa_imm_cmd_construct_dma_shared_mem_v_4_0,
 		19},
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
index e71a48b..f8bdc2c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
@@ -36,6 +36,7 @@
 	IPA_IMM_CMD_DMA_SHARED_MEM,
 	IPA_IMM_CMD_IP_PACKET_TAG_STATUS,
 	IPA_IMM_CMD_DMA_TASK_32B_ADDR,
+	IPA_IMM_CMD_TABLE_DMA,
 	IPA_IMM_CMD_MAX,
 };
 
@@ -204,6 +205,23 @@
 };
 
 /*
+ * struct ipahal_imm_cmd_table_dma - TABLE_DMA cmd payload
+ * Perform DMA operation on NAT and IPV6 connection tracking related mem
+ * addresses. Copy data into different locations within IPV6CT and NAT
+ * associated tbls. (For add/remove NAT rules)
+ * @table_index: NAT tbl index. Defines the tbl on which to perform DMA op.
+ * @base_addr: Base addr to which the DMA operation should be performed.
+ * @offset: offset in bytes from base addr to write 'data' to
+ * @data: data to be written
+ */
+struct ipahal_imm_cmd_table_dma {
+	u8 table_index;
+	u8 base_addr;
+	u32 offset;
+	u16 data;
+};
+
+/*
  * struct ipahal_imm_cmd_ip_packet_init - IP_PACKET_INIT cmd payload
  * Configuration for specific IP pkt. Shall be called prior to an IP pkt
  *  data. Pkt will not go through IP pkt processing.
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
index 053a581..4f20e0f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
@@ -162,6 +162,8 @@
 		struct ipahal_rt_rule_entry *rule);
 static int ipa_flt_parse_hw_rule(u8 *addr,
 		struct ipahal_flt_rule_entry *rule);
+static int ipa_flt_parse_hw_rule_ipav4(u8 *addr,
+		struct ipahal_flt_rule_entry *rule);
 
 #define IPA_IS_RAN_OUT_OF_EQ(__eq_array, __eq_index) \
 	(ARRAY_SIZE(__eq_array) <= (__eq_index))
@@ -349,6 +351,93 @@
 	return 0;
 }
 
+static int ipa_flt_gen_hw_rule_ipav4(struct ipahal_flt_rule_gen_params *params,
+	u32 *hw_len, u8 *buf)
+{
+	struct ipa4_0_flt_rule_hw_hdr *rule_hdr;
+	u8 *start;
+	u16 en_rule = 0;
+
+	start = buf;
+	rule_hdr = (struct ipa4_0_flt_rule_hw_hdr *)buf;
+
+	switch (params->rule->action) {
+	case IPA_PASS_TO_ROUTING:
+		rule_hdr->u.hdr.action = 0x0;
+		break;
+	case IPA_PASS_TO_SRC_NAT:
+		rule_hdr->u.hdr.action = 0x1;
+		break;
+	case IPA_PASS_TO_DST_NAT:
+		rule_hdr->u.hdr.action = 0x2;
+		break;
+	case IPA_PASS_TO_EXCEPTION:
+		rule_hdr->u.hdr.action = 0x3;
+		break;
+	default:
+		IPAHAL_ERR("Invalid Rule Action %d\n", params->rule->action);
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	ipa_assert_on(params->rt_tbl_idx & ~0x1F);
+	rule_hdr->u.hdr.rt_tbl_idx = params->rt_tbl_idx;
+	rule_hdr->u.hdr.retain_hdr = params->rule->retain_hdr ? 0x1 : 0x0;
+
+	ipa_assert_on(params->rule->pdn_idx & ~0xF);
+	rule_hdr->u.hdr.pdn_idx = params->rule->pdn_idx;
+	rule_hdr->u.hdr.set_metadata = params->rule->set_metadata;
+	rule_hdr->u.hdr.rsvd2 = 0;
+	rule_hdr->u.hdr.rsvd3 = 0;
+
+	ipa_assert_on(params->priority & ~0x3FF);
+	rule_hdr->u.hdr.priority = params->priority;
+	ipa_assert_on(params->id & ~((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
+	ipa_assert_on(params->id == ((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
+	rule_hdr->u.hdr.rule_id = params->id;
+
+	buf += sizeof(struct ipa4_0_flt_rule_hw_hdr);
+
+	if (params->rule->eq_attrib_type) {
+		if (ipa_fltrt_generate_hw_rule_bdy_from_eq(
+			&params->rule->eq_attrib, &buf)) {
+			IPAHAL_ERR("fail to generate hw rule from eq\n");
+			return -EPERM;
+		}
+		en_rule = params->rule->eq_attrib.rule_eq_bitmap;
+	} else {
+		if (ipa_fltrt_generate_hw_rule_bdy(params->ipt,
+			&params->rule->attrib, &buf, &en_rule)) {
+			IPAHAL_ERR("fail to generate hw rule\n");
+			return -EPERM;
+		}
+	}
+	rule_hdr->u.hdr.en_rule = en_rule;
+
+	IPAHAL_DBG_LOW("en_rule=0x%x, action=%d, rt_idx=%d, retain_hdr=%d\n",
+		en_rule,
+		rule_hdr->u.hdr.action,
+		rule_hdr->u.hdr.rt_tbl_idx,
+		rule_hdr->u.hdr.retain_hdr);
+	IPAHAL_DBG_LOW("priority=%d, rule_id=%d, pdn=%d, set_metadata=%d\n",
+		rule_hdr->u.hdr.priority,
+		rule_hdr->u.hdr.rule_id,
+		rule_hdr->u.hdr.pdn_idx,
+		rule_hdr->u.hdr.set_metadata);
+
+	ipa_write_64(rule_hdr->u.word, (u8 *)rule_hdr);
+
+	if (*hw_len == 0) {
+		*hw_len = buf - start;
+	} else if (*hw_len != (buf - start)) {
+		IPAHAL_ERR("hw_len differs b/w passed=0x%x calc=%td\n",
+			*hw_len, (buf - start));
+		return -EPERM;
+	}
+
+	return 0;
+}
+
 /*
  * This array contains the FLT/RT info for IPAv3 and later.
  * All the information on IPAv3 are statically defined below.
@@ -401,6 +490,50 @@
 			[IPA_IS_FRAG]			= 15,
 		},
 	},
+
+	/* IPAv4 */
+	[IPA_HW_v4_0] = {
+		true,
+		IPA3_0_HW_TBL_WIDTH,
+		IPA3_0_HW_TBL_SYSADDR_ALIGNMENT,
+		IPA3_0_HW_TBL_LCLADDR_ALIGNMENT,
+		IPA3_0_HW_TBL_BLK_SIZE_ALIGNMENT,
+		IPA3_0_HW_RULE_START_ALIGNMENT,
+		IPA3_0_HW_TBL_HDR_WIDTH,
+		IPA3_0_HW_TBL_ADDR_MASK,
+		IPA3_0_RULE_MAX_PRIORITY,
+		IPA3_0_RULE_MIN_PRIORITY,
+		IPA3_0_LOW_RULE_ID,
+		IPA3_0_RULE_ID_BIT_LEN,
+		IPA3_0_HW_RULE_BUF_SIZE,
+		ipa_write_64,
+		ipa_fltrt_create_flt_bitmap,
+		ipa_fltrt_create_tbl_addr,
+		ipa_fltrt_parse_tbl_addr,
+		ipa_rt_gen_hw_rule,
+		ipa_flt_gen_hw_rule_ipav4,
+		ipa_flt_generate_eq,
+		ipa_rt_parse_hw_rule,
+		ipa_flt_parse_hw_rule_ipav4,
+		{
+			[IPA_TOS_EQ] = 0,
+			[IPA_PROTOCOL_EQ] = 1,
+			[IPA_TC_EQ] = 2,
+			[IPA_OFFSET_MEQ128_0] = 3,
+			[IPA_OFFSET_MEQ128_1] = 4,
+			[IPA_OFFSET_MEQ32_0] = 5,
+			[IPA_OFFSET_MEQ32_1] = 6,
+			[IPA_IHL_OFFSET_MEQ32_0] = 7,
+			[IPA_IHL_OFFSET_MEQ32_1] = 8,
+			[IPA_METADATA_COMPARE] = 9,
+			[IPA_IHL_OFFSET_RANGE16_0] = 10,
+			[IPA_IHL_OFFSET_RANGE16_1] = 11,
+			[IPA_IHL_OFFSET_EQ_32] = 12,
+			[IPA_IHL_OFFSET_EQ_16] = 13,
+			[IPA_FL_EQ] = 14,
+			[IPA_IS_FRAG] = 15,
+		},
+	},
 };
 
 static int ipa_flt_generate_eq(enum ipa_ip_type ipt,
@@ -2276,6 +2409,55 @@
 		atrb, &rule->rule_size);
 }
 
+static int ipa_flt_parse_hw_rule_ipav4(u8 *addr,
+	struct ipahal_flt_rule_entry *rule)
+{
+	struct ipa4_0_flt_rule_hw_hdr *rule_hdr;
+	struct ipa_ipfltri_rule_eq *atrb;
+
+	IPAHAL_DBG_LOW("Entry\n");
+
+	rule_hdr = (struct ipa4_0_flt_rule_hw_hdr *)addr;
+	atrb = &rule->rule.eq_attrib;
+
+	if (rule_hdr->u.word == 0) {
+		/* table termintator - empty table */
+		rule->rule_size = 0;
+		return 0;
+	}
+
+	switch (rule_hdr->u.hdr.action) {
+	case 0x0:
+		rule->rule.action = IPA_PASS_TO_ROUTING;
+		break;
+	case 0x1:
+		rule->rule.action = IPA_PASS_TO_SRC_NAT;
+		break;
+	case 0x2:
+		rule->rule.action = IPA_PASS_TO_DST_NAT;
+		break;
+	case 0x3:
+		rule->rule.action = IPA_PASS_TO_EXCEPTION;
+		break;
+	default:
+		IPAHAL_ERR("Invalid Rule Action %d\n", rule_hdr->u.hdr.action);
+		WARN_ON(1);
+		rule->rule.action = rule_hdr->u.hdr.action;
+	}
+
+	rule->rule.rt_tbl_idx = rule_hdr->u.hdr.rt_tbl_idx;
+	rule->rule.retain_hdr = rule_hdr->u.hdr.retain_hdr;
+	rule->priority = rule_hdr->u.hdr.priority;
+	rule->id = rule_hdr->u.hdr.rule_id;
+	rule->rule.pdn_idx = rule_hdr->u.hdr.pdn_idx;
+	rule->rule.set_metadata = rule_hdr->u.hdr.set_metadata;
+
+	atrb->rule_eq_bitmap = rule_hdr->u.hdr.en_rule;
+	rule->rule.eq_attrib_type = 1;
+	return ipa_fltrt_parse_hw_rule_eq(addr, sizeof(*rule_hdr),
+		atrb, &rule->rule_size);
+}
+
 /*
  * ipahal_fltrt_init() - Build the FLT/RT information table
  *  See ipahal_fltrt_objs[] comments
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt_i.h
index 0c0637d..645383a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -137,6 +137,43 @@
 	} u;
 };
 
+/**
+ * struct ipa4_0_flt_rule_hw_hdr - HW header of IPA filter rule
+ * @word: filtering rule properties
+ * @en_rule: enable rule
+ * @action: post filtering action
+ * @rt_tbl_idx: index in routing table
+ * @retain_hdr: added to add back to the packet the header removed
+ *  as part of header removal. This will be done as part of
+ *  header insertion block.
+ * @pdn_idx: in case of go to src nat action possible to input the pdn index to
+ *  the NAT block
+ * @set_metadata: enable metadata replacement in the NAT block
+ * @priority: Rule priority. Added to distinguish rules order
+ *  at the integrated table consisting from hashable and
+ *  non-hashable parts
+ * @rsvd2: reserved bits
+ * @rule_id: rule ID that will be returned in the packet status
+ * @rsvd3: reserved bits
+ */
+struct ipa4_0_flt_rule_hw_hdr {
+	union {
+		u64 word;
+		struct {
+			u64 en_rule : 16;
+			u64 action : 5;
+			u64 rt_tbl_idx : 5;
+			u64 retain_hdr : 1;
+			u64 pdn_idx : 4;
+			u64 set_metadata : 1;
+			u64 priority : 10;
+			u64 rsvd2 : 6;
+			u64 rule_id : 10;
+			u64 rsvd3 : 6;
+		} hdr;
+	} u;
+};
+
 int ipahal_fltrt_init(enum ipa_hw_type ipa_hw_type);
 void ipahal_fltrt_destroy(void);
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
index 804c554..c023082 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
@@ -143,7 +143,8 @@
  * @size_expansion_tables: Num of entries in NAT expantion tbl and expantion
  *  idx tbl (each)
  * @rsvd2: reserved
- * @public_ip_addr: public IP address
+ * @public_ip_addr: public IP address. for IPAv4 this is the PDN config table
+ *  offset in SMEM
  */
 struct ipa_imm_cmd_hw_ip_v4_nat_init {
 	u64 ipv4_rules_addr:64;
@@ -250,6 +251,30 @@
 };
 
 /*
+ * struct ipa_imm_cmd_hw_table_dma_ipav4 - TABLE_DMA command payload
+ *  in H/W format
+ * Perform DMA operation on NAT and ipv6 connection tracking related mem
+ * addresses. Copy data into different locations within NAT associated tbls
+ * (For add/remove NAT rules)
+ * @table_index: NAT tbl index. Defines the NAT tbl on which to perform DMA op.
+ * @rsvd1: reserved
+ * @base_addr: Base addr to which the DMA operation should be performed.
+ * @rsvd2: reserved
+ * @offset: offset in bytes from base addr to write 'data' to
+ * @data: data to be written
+ * @rsvd3: reserved
+ */
+struct ipa_imm_cmd_hw_table_dma_ipav4 {
+	u64 table_index : 3;
+	u64 rsvd1 : 1;
+	u64 base_addr : 3;
+	u64 rsvd2 : 1;
+	u64 offset : 32;
+	u64 data : 16;
+	u64 rsvd3 : 8;
+};
+
+/*
  * struct ipa_imm_cmd_hw_hdr_init_system - HDR_INIT_SYSTEM command payload
  *  in H/W format.
  * Inits hdr table within sys mem with the hdrs and their length.
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index 3019e4d..af717cd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -85,6 +85,7 @@
 	__stringify(IPA_IDLE_INDICATION_CFG),
 	__stringify(IPA_DPS_SEQUENCER_FIRST),
 	__stringify(IPA_HPS_SEQUENCER_FIRST),
+	__stringify(IPA_CLKON_CFG),
 };
 
 static void ipareg_construct_dummy(enum ipahal_reg_name reg,
@@ -1490,6 +1491,9 @@
 	[IPA_HW_v4_0][IPA_ENDP_STATUS_n] = {
 		ipareg_construct_endp_status_n_v4_0, ipareg_parse_dummy,
 		0x00000840, 0x70},
+	[IPA_HW_v4_0][IPA_CLKON_CFG] = {
+		ipareg_construct_dummy, ipareg_parse_dummy,
+		0x00000044, 0},
 };
 
 /*
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
index c9293b8..79e2b9c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
@@ -88,6 +88,7 @@
 	IPA_IDLE_INDICATION_CFG,
 	IPA_DPS_SEQUENCER_FIRST,
 	IPA_HPS_SEQUENCER_FIRST,
+	IPA_CLKON_CFG,
 	IPA_REG_MAX,
 };
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index f408f23..16585a2 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1141,7 +1141,8 @@
 		memset(&meta, 0, sizeof(meta));
 		meta.pkt_init_dst_ep_valid = true;
 		meta.pkt_init_dst_ep_remote = true;
-		meta.pkt_init_dst_ep = IPA_CLIENT_Q6_LAN_CONS;
+		meta.pkt_init_dst_ep =
+			ipa3_get_ep_mapping(IPA_CLIENT_Q6_WAN_CONS);
 		ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, &meta);
 	} else {
 		ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL);
@@ -2442,6 +2443,29 @@
 	.remove = ipa3_wwan_remove,
 };
 
+/**
+ * rmnet_ipa_send_ssr_notification(bool ssr_done) - send SSR notification
+ *
+ * This function sends the SSR notification before modem shutdown and
+ * after_powerup from SSR framework, to user-space module
+ */
+static void rmnet_ipa_send_ssr_notification(bool ssr_done)
+{
+	struct ipa_msg_meta msg_meta;
+	int rc;
+
+	memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
+	if (ssr_done)
+		msg_meta.msg_type = IPA_SSR_AFTER_POWERUP;
+	else
+		msg_meta.msg_type = IPA_SSR_BEFORE_SHUTDOWN;
+	rc = ipa_send_msg(&msg_meta, NULL, NULL);
+	if (rc) {
+		IPAWANERR("ipa_send_msg failed: %d\n", rc);
+		return;
+	}
+}
+
 static int ipa3_ssr_notifier_cb(struct notifier_block *this,
 			   unsigned long code,
 			   void *data)
@@ -2452,6 +2476,8 @@
 	switch (code) {
 	case SUBSYS_BEFORE_SHUTDOWN:
 		IPAWANINFO("IPA received MPSS BEFORE_SHUTDOWN\n");
+		/* send SSR before-shutdown notification to IPACM */
+		rmnet_ipa_send_ssr_notification(false);
 		atomic_set(&rmnet_ipa3_ctx->is_ssr, 1);
 		ipa3_q6_pre_shutdown_cleanup();
 		if (IPA_NETDEV())
@@ -2628,6 +2654,26 @@
 }
 
 /**
+ * rmnet_ipa_send_quota_reach_ind() - send quota_reach notification from
+ * IPA Modem
+ * This function sends the quota_reach indication from the IPA Modem driver
+ * via QMI, to user-space module
+ */
+static void rmnet_ipa_send_quota_reach_ind(void)
+{
+	struct ipa_msg_meta msg_meta;
+	int rc;
+
+	memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
+	msg_meta.msg_type = IPA_QUOTA_REACH;
+	rc = ipa_send_msg(&msg_meta, NULL, NULL);
+	if (rc) {
+		IPAWANERR("ipa_send_msg failed: %d\n", rc);
+		return;
+	}
+}
+
+/**
  * rmnet_ipa3_poll_tethering_stats() - Tethering stats polling IOCTL handler
  * @data - IOCTL data
  *
@@ -2680,6 +2726,9 @@
 	if (!data->set_quota)
 		ipa3_qmi_stop_data_qouta();
 
+	/* prevent string buffer overflows */
+	data->interface_name[IFNAMSIZ-1] = '\0';
+
 	index = find_vchannel_name_index(data->interface_name);
 	IPAWANERR("iface name %s, quota %lu\n",
 		  data->interface_name,
@@ -2908,7 +2957,7 @@
 		IPAWANERR("reset the pipe stats\n");
 	} else {
 		/* print tethered-client enum */
-		IPAWANDBG_LOW("Tethered-client enum(%d)\n", data->ipa_client);
+		IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client);
 	}
 
 	rc = ipa3_qmi_get_data_stats(req, resp);
@@ -2917,10 +2966,6 @@
 		kfree(req);
 		kfree(resp);
 		return rc;
-	} else if (reset) {
-		kfree(req);
-		kfree(resp);
-		return 0;
 	}
 
 	if (resp->dl_dst_pipe_stats_list_valid) {
@@ -3058,6 +3103,49 @@
 	return rc;
 }
 
+int rmnet_ipa3_query_tethering_stats_all(
+	struct wan_ioctl_query_tether_stats_all *data)
+{
+	struct wan_ioctl_query_tether_stats tether_stats;
+	enum ipa_upstream_type upstream_type;
+	int rc = 0;
+
+	memset(&tether_stats, 0, sizeof(struct wan_ioctl_query_tether_stats));
+	/* get IPA backhaul type */
+	upstream_type = find_upstream_type(data->upstreamIface);
+
+	if (upstream_type == IPA_UPSTEAM_MAX) {
+		IPAWANERR(" Wrong upstreamIface name %s\n",
+			data->upstreamIface);
+	} else if (upstream_type == IPA_UPSTEAM_WLAN) {
+		IPAWANDBG_LOW(" query wifi-backhaul stats\n");
+		rc = rmnet_ipa3_query_tethering_stats_wifi(
+			&tether_stats, data->reset_stats);
+		if (rc) {
+			IPAWANERR("wlan WAN_IOC_QUERY_TETHER_STATS failed\n");
+			return rc;
+		}
+		data->tx_bytes = tether_stats.ipv4_tx_bytes
+			+ tether_stats.ipv6_tx_bytes;
+		data->rx_bytes = tether_stats.ipv4_rx_bytes
+			+ tether_stats.ipv6_rx_bytes;
+	} else {
+		IPAWANDBG_LOW(" query modem-backhaul stats\n");
+		tether_stats.ipa_client = data->ipa_client;
+		rc = rmnet_ipa3_query_tethering_stats_modem(
+			&tether_stats, data->reset_stats);
+		if (rc) {
+			IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n");
+			return rc;
+		}
+		data->tx_bytes = tether_stats.ipv4_tx_bytes
+			+ tether_stats.ipv6_tx_bytes;
+		data->rx_bytes = tether_stats.ipv4_rx_bytes
+			+ tether_stats.ipv6_rx_bytes;
+	}
+	return rc;
+}
+
 int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data)
 {
 	enum ipa_upstream_type upstream_type;
@@ -3155,6 +3243,8 @@
 		alert_msg, iface_name_l, iface_name_m);
 	kobject_uevent_env(&(IPA_NETDEV()->dev.kobj),
 		KOBJ_CHANGE, envp);
+
+	rmnet_ipa_send_quota_reach_ind();
 }
 
 /**
@@ -3179,6 +3269,9 @@
 		 */
 		ipa3_proxy_clk_unvote();
 
+		/* send SSR power-up notification to IPACM */
+		rmnet_ipa_send_ssr_notification(true);
+
 		/*
 		 * It is required to recover the network stats after
 		 * SSR recovery
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
index 3ef17f6..c7a6186 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
@@ -47,6 +47,9 @@
 #define WAN_IOC_QUERY_DL_FILTER_STATS32 _IOWR(WAN_IOC_MAGIC, \
 		WAN_IOCTL_QUERY_DL_FILTER_STATS, \
 		compat_uptr_t)
+#define WAN_IOC_QUERY_TETHER_STATS_ALL32 _IOWR(WAN_IOC_MAGIC, \
+		WAN_IOCTL_QUERY_TETHER_STATS_ALL, \
+		compat_uptr_t)
 #endif
 
 static unsigned int dev_num = 1;
@@ -265,6 +268,32 @@
 		}
 		break;
 
+	case WAN_IOC_QUERY_TETHER_STATS_ALL:
+		IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS_ALL :>>>\n");
+		pyld_sz = sizeof(struct wan_ioctl_query_tether_stats_all);
+		param = kzalloc(pyld_sz, GFP_KERNEL);
+		if (!param) {
+			retval = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(param, (u8 __user *)arg, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+
+		if (rmnet_ipa3_query_tethering_stats_all(
+			(struct wan_ioctl_query_tether_stats_all *)param)) {
+			IPAWANERR("WAN_IOC_QUERY_TETHER_STATS failed\n");
+			retval = -EFAULT;
+			break;
+		}
+
+		if (copy_to_user((void __user *)arg, param, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
+
 	case WAN_IOC_RESET_TETHER_STATS:
 		IPAWANDBG_LOW("device %s got WAN_IOC_RESET_TETHER_STATS :>>>\n",
 				DRIVER_NAME);
diff --git a/drivers/platform/msm/ipa/test/ipa_test_mhi.c b/drivers/platform/msm/ipa/test/ipa_test_mhi.c
index 5a41d64..3a89c7d 100644
--- a/drivers/platform/msm/ipa/test/ipa_test_mhi.c
+++ b/drivers/platform/msm/ipa/test/ipa_test_mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -326,6 +326,7 @@
 	struct ipa_mem_buffer out_buffer;
 	u32 prod_hdl;
 	u32 cons_hdl;
+	u32 test_prod_hdl;
 };
 
 static struct ipa_test_mhi_context *test_mhi_ctx;
@@ -774,6 +775,7 @@
 static int ipa_test_mhi_suite_setup(void **ppriv)
 {
 	int rc = 0;
+	struct ipa_sys_connect_params sys_in;
 
 	IPA_UT_DBG("Start Setup\n");
 
@@ -815,9 +817,22 @@
 		goto fail_free_mmio_spc;
 	}
 
+	/* connect PROD pipe for remote wakeup */
+	memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
+	sys_in.client = IPA_CLIENT_TEST_PROD;
+	sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
+	sys_in.ipa_ep_cfg.mode.mode = IPA_DMA;
+	sys_in.ipa_ep_cfg.mode.dst = IPA_CLIENT_MHI_CONS;
+	if (ipa_setup_sys_pipe(&sys_in, &test_mhi_ctx->test_prod_hdl)) {
+		IPA_UT_ERR("setup sys pipe failed.\n");
+		goto fail_destroy_data_structures;
+	}
+
 	*ppriv = test_mhi_ctx;
 	return 0;
 
+fail_destroy_data_structures:
+	ipa_mhi_test_destroy_data_structures();
 fail_free_mmio_spc:
 	ipa_test_mhi_free_mmio_space();
 fail_iounmap:
@@ -838,6 +853,7 @@
 	if (!test_mhi_ctx)
 		return  0;
 
+	ipa_teardown_sys_pipe(test_mhi_ctx->test_prod_hdl);
 	ipa_mhi_test_destroy_data_structures();
 	ipa_test_mhi_free_mmio_space();
 	iounmap(test_mhi_ctx->gsi_mmio);
@@ -1811,7 +1827,7 @@
 		memset(test_mhi_ctx->out_buffer.base + i, i & 0xFF, 1);
 	}
 
-	rc = ipa_tx_dp(IPA_CLIENT_MHI_CONS, skb, NULL);
+	rc = ipa_tx_dp(IPA_CLIENT_TEST_PROD, skb, NULL);
 	if (rc) {
 		IPA_UT_LOG("ipa_tx_dp failed %d\n", rc);
 		IPA_UT_TEST_FAIL_REPORT("ipa tx dp fail");
@@ -1982,7 +1998,7 @@
 		memset(test_mhi_ctx->out_buffer.base + i, i & 0xFF, 1);
 	}
 
-	rc = ipa_tx_dp(IPA_CLIENT_MHI_CONS, skb, NULL);
+	rc = ipa_tx_dp(IPA_CLIENT_TEST_PROD, skb, NULL);
 	if (rc) {
 		IPA_UT_LOG("ipa_tx_dp failed %d\n", rc);
 		IPA_UT_TEST_FAIL_REPORT("ipa tx dp fail");
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index 1fffa7c..7c77280 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -31,7 +31,7 @@
 #define GENI_SE_IOMMU_VA_SIZE	(0xC0000000)
 
 #define NUM_LOG_PAGES 2
-
+#define MAX_CLK_PERF_LEVEL 32
 static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000, 100000000};
 
 /**
@@ -52,6 +52,8 @@
  * @cur_ib:		Current Bus Instantaneous BW request value.
  * @bus_bw_set:		Clock plan for the bus driver.
  * @cur_bus_bw_idx:	Current index within the bus clock plan.
+ * @num_clk_levels:	Number of valid clock levels in clk_perf_tbl.
+ * @clk_perf_tbl:	Table of clock frequency input to Serial Engine clock.
  * @log_ctx:		Logging context to hold the debug information
  */
 struct geni_se_device {
@@ -72,6 +74,8 @@
 	int bus_bw_set_size;
 	unsigned long *bus_bw_set;
 	int cur_bus_bw_idx;
+	unsigned int num_clk_levels;
+	unsigned long *clk_perf_tbl;
 	void *log_ctx;
 };
 
@@ -809,6 +813,111 @@
 EXPORT_SYMBOL(geni_se_resources_init);
 
 /**
+ * geni_se_clk_tbl_get() - Get the clock table to program DFS
+ * @rsc:	Resource for which the clock table is requested.
+ * @tbl:	Table in which the output is returned.
+ *
+ * This function is called by the protocol drivers to determine the different
+ * clock frequencies supported by Serail Engine Core Clock. The protocol
+ * drivers use the output to determine the clock frequency index to be
+ * programmed into DFS.
+ *
+ * Return:	number of valid performance levels in the table on success,
+ *		standard Linux error codes on failure.
+ */
+int geni_se_clk_tbl_get(struct se_geni_rsc *rsc, unsigned long **tbl)
+{
+	struct geni_se_device *geni_se_dev;
+	int i;
+	unsigned long prev_freq = 0;
+
+	if (unlikely(!rsc || !rsc->wrapper_dev || !rsc->se_clk || !tbl))
+		return -EINVAL;
+
+	*tbl = NULL;
+	geni_se_dev = dev_get_drvdata(rsc->wrapper_dev);
+	if (unlikely(!geni_se_dev))
+		return -EPROBE_DEFER;
+
+	if (geni_se_dev->clk_perf_tbl) {
+		*tbl = geni_se_dev->clk_perf_tbl;
+		return geni_se_dev->num_clk_levels;
+	}
+
+	geni_se_dev->clk_perf_tbl = kzalloc(sizeof(*geni_se_dev->clk_perf_tbl) *
+						MAX_CLK_PERF_LEVEL, GFP_KERNEL);
+	if (!geni_se_dev->clk_perf_tbl)
+		return -ENOMEM;
+
+	for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) {
+		geni_se_dev->clk_perf_tbl[i] = clk_round_rate(rsc->se_clk,
+								prev_freq + 1);
+		if (geni_se_dev->clk_perf_tbl[i] == prev_freq) {
+			geni_se_dev->clk_perf_tbl[i] = 0;
+			break;
+		}
+		prev_freq = geni_se_dev->clk_perf_tbl[i];
+	}
+	geni_se_dev->num_clk_levels = i;
+	*tbl = geni_se_dev->clk_perf_tbl;
+	return geni_se_dev->num_clk_levels;
+}
+EXPORT_SYMBOL(geni_se_clk_tbl_get);
+
+/**
+ * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency
+ * @rsc:	Resource for which the clock frequency is requested.
+ * @req_freq:	Requested clock frequency.
+ * @index:	Index of the resultant frequency in the table.
+ * @res_freq:	Resultant frequency which matches or is closer to the
+ *		requested frequency.
+ * @exact:	Flag to indicate exact multiple requirement of the requested
+ *		frequency .
+ *
+ * This function is called by the protocol drivers to determine the matching
+ * or closest frequency of the Serial Engine clock to be selected in order
+ * to meet the performance requirements.
+ *
+ * Return:	0 on success, standard Linux error codes on failure.
+ */
+int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq,
+			   unsigned int *index, unsigned long *res_freq,
+			   bool exact)
+{
+	unsigned long *tbl;
+	int num_clk_levels;
+	int i;
+
+	num_clk_levels = geni_se_clk_tbl_get(rsc, &tbl);
+	if (num_clk_levels < 0)
+		return num_clk_levels;
+
+	if (num_clk_levels == 0)
+		return -EFAULT;
+
+	*res_freq = 0;
+	for (i = 0; i < num_clk_levels; i++) {
+		if (!(tbl[i] % req_freq)) {
+			*index = i;
+			*res_freq = tbl[i];
+			return 0;
+		}
+
+		if (!(*res_freq) || ((tbl[i] > *res_freq) &&
+				     (tbl[i] < req_freq))) {
+			*index = i;
+			*res_freq = tbl[i];
+		}
+	}
+
+	if (exact || !(*res_freq))
+		return -ENOKEY;
+
+	return 0;
+}
+EXPORT_SYMBOL(geni_se_clk_freq_match);
+
+/**
  * geni_se_tx_dma_prep() - Prepare the Serial Engine for TX DMA transfer
  * @wrapper_dev:	QUPv3 Wrapper Device to which the TX buffer is mapped.
  * @base:		Base address of the SE register block.
diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c
index ce073ed..a528e16 100644
--- a/drivers/platform/msm/seemp_core/seemp_logk.c
+++ b/drivers/platform/msm/seemp_core/seemp_logk.c
@@ -289,7 +289,7 @@
 	unsigned int bit_num = index%8;
 	unsigned char byte;
 
-	if (DIV_ROUND_UP(index, 8) > MASK_BUFFER_SIZE)
+	if (byte_num >= MASK_BUFFER_SIZE)
 		return false;
 
 	byte = pVec[byte_num];
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 907c94e8..f9ba30e 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -67,6 +67,7 @@
 static u32 debugfs_buf_size;
 static u32 debugfs_buf_used;
 static int wraparound;
+static struct mutex sps_debugfs_lock;
 
 struct dentry *dent;
 struct dentry *dfile_info;
@@ -85,6 +86,7 @@
 /* record debug info for debugfs */
 void sps_debugfs_record(const char *msg)
 {
+	mutex_lock(&sps_debugfs_lock);
 	if (debugfs_record_enabled) {
 		if (debugfs_buf_used + MAX_MSG_LEN >= debugfs_buf_size) {
 			debugfs_buf_used = 0;
@@ -98,6 +100,7 @@
 					debugfs_buf_size - debugfs_buf_used,
 					"\n**** end line of sps log ****\n\n");
 	}
+	mutex_unlock(&sps_debugfs_lock);
 }
 
 /* read the recorded debug info to userspace */
@@ -107,6 +110,7 @@
 	int ret = 0;
 	int size;
 
+	mutex_lock(&sps_debugfs_lock);
 	if (debugfs_record_enabled) {
 		if (wraparound)
 			size = debugfs_buf_size - MAX_MSG_LEN;
@@ -116,6 +120,7 @@
 		ret = simple_read_from_buffer(ubuf, count, ppos,
 				debugfs_buf, size);
 	}
+	mutex_unlock(&sps_debugfs_lock);
 
 	return ret;
 }
@@ -160,12 +165,14 @@
 
 	new_buf_size = buf_size_kb * SZ_1K;
 
+	mutex_lock(&sps_debugfs_lock);
 	if (debugfs_record_enabled) {
 		if (debugfs_buf_size == new_buf_size) {
 			/* need do nothing */
 			pr_info(
 				"sps:debugfs: input buffer size is the same as before.\n"
 				);
+			mutex_unlock(&sps_debugfs_lock);
 			return count;
 		}
 		/* release the current buffer */
@@ -183,12 +190,14 @@
 	if (!debugfs_buf) {
 		debugfs_buf_size = 0;
 		pr_err("sps:fail to allocate memory for debug_fs.\n");
+		mutex_unlock(&sps_debugfs_lock);
 		return -ENOMEM;
 	}
 
 	debugfs_buf_used = 0;
 	wraparound = false;
 	debugfs_record_enabled = true;
+	mutex_unlock(&sps_debugfs_lock);
 
 	return count;
 }
@@ -237,6 +246,7 @@
 		return count;
 	}
 
+	mutex_lock(&sps_debugfs_lock);
 	if (((option == 0) || (option == 2)) &&
 		((logging_option == 1) || (logging_option == 3))) {
 		debugfs_record_enabled = false;
@@ -248,6 +258,7 @@
 	}
 
 	logging_option = option;
+	mutex_unlock(&sps_debugfs_lock);
 
 	return count;
 }
@@ -595,6 +606,8 @@
 		goto bam_log_level_err;
 	}
 
+	mutex_init(&sps_debugfs_lock);
+
 	return;
 
 bam_log_level_err:
@@ -2088,7 +2101,7 @@
 				unsigned long *dev_handle)
 {
 	struct sps_bam *bam = NULL;
-	void *virt_addr = NULL;
+	void __iomem *virt_addr = NULL;
 	char bam_name[MAX_MSG_LEN];
 	u32 manage;
 	int ok;
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index 468c492..7cb0670 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2017, 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
@@ -202,7 +202,7 @@
 	/* BAM device state */
 	u32 state;
 	struct mutex lock;
-	void *base; /* BAM virtual base address */
+	void __iomem *base; /* BAM virtual base address */
 	u32 version;
 	spinlock_t isr_lock;
 	spinlock_t connection_lock;
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 2e57f7d..0c1b8ea 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -145,11 +145,6 @@
 				pr_info(msg, ##args);	\
 		} \
 	} while (0)
-#define SPS_DEBUGFS(msg, args...) do {					\
-		char buf[MAX_MSG_LEN];		\
-		snprintf(buf, MAX_MSG_LEN, msg"\n", ##args);	\
-		sps_debugfs_record(buf);	\
-	} while (0)
 #define SPS_ERR(dev, msg, args...) do {					\
 		if (logging_option != 1) {	\
 			if (unlikely(print_limit_option > 2))	\
@@ -157,8 +152,6 @@
 			else	\
 				pr_err(msg, ##args);	\
 		}	\
-		if (unlikely(debugfs_record_enabled))	\
-			SPS_DEBUGFS(msg, ##args);	\
 		SPS_IPC(3, dev, msg, args); \
 	} while (0)
 #define SPS_INFO(dev, msg, args...) do {				\
@@ -168,8 +161,6 @@
 			else	\
 				pr_info(msg, ##args);	\
 		}	\
-		if (unlikely(debugfs_record_enabled))	\
-			SPS_DEBUGFS(msg, ##args);	\
 		SPS_IPC(3, dev, msg, args); \
 	} while (0)
 #define SPS_DBG(dev, msg, args...) do {					\
@@ -181,8 +172,6 @@
 				pr_info(msg, ##args);	\
 		} else	\
 			pr_debug(msg, ##args);	\
-		if (unlikely(debugfs_record_enabled))	\
-			SPS_DEBUGFS(msg, ##args);	\
 		if (dev) { \
 			if ((dev)->ipc_loglevel <= 0)	\
 				SPS_IPC(0, dev, msg, args); \
@@ -197,8 +186,6 @@
 				pr_info(msg, ##args);	\
 		} else	\
 			pr_debug(msg, ##args);	\
-		if (unlikely(debugfs_record_enabled))	\
-			SPS_DEBUGFS(msg, ##args);	\
 		if (dev) { \
 			if ((dev)->ipc_loglevel <= 1)	\
 				SPS_IPC(1, dev, msg, args);	\
@@ -213,8 +200,6 @@
 				pr_info(msg, ##args);	\
 		} else	\
 			pr_debug(msg, ##args);	\
-		if (unlikely(debugfs_record_enabled))	\
-			SPS_DEBUGFS(msg, ##args);	\
 		if (dev) { \
 			if ((dev)->ipc_loglevel <= 2)	\
 				SPS_IPC(2, dev, msg, args); \
@@ -229,8 +214,6 @@
 				pr_info(msg, ##args);	\
 		} else	\
 			pr_debug(msg, ##args);	\
-		if (unlikely(debugfs_record_enabled))	\
-			SPS_DEBUGFS(msg, ##args);	\
 		if (dev) { \
 			if ((dev)->ipc_loglevel <= 3)	\
 				SPS_IPC(3, dev, msg, args); \
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index cd76ca2..8c43c4e 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -310,6 +310,7 @@
 	POWER_SUPPLY_ATTR(ctm_current_max),
 	POWER_SUPPLY_ATTR(hw_current_max),
 	POWER_SUPPLY_ATTR(real_type),
+	POWER_SUPPLY_ATTR(pr_swap),
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_ATTR(charge_counter_ext),
 	/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index bf5f952..8641a45 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -551,8 +551,6 @@
 		power_supply_set_property(chip->main_psy,
 				POWER_SUPPLY_PROP_CURRENT_MAX,
 				&pval);
-		/* wait for ICL change */
-		msleep(100);
 	}
 
 	/* set the effective ICL */
@@ -560,9 +558,6 @@
 	power_supply_set_property(chip->main_psy,
 			POWER_SUPPLY_PROP_CURRENT_MAX,
 			&pval);
-	if (rerun_aicl)
-		/* wait for ICL change */
-		msleep(100);
 
 	vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0);
 
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index e3ecf49..75e79bb 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -491,7 +491,7 @@
 	int i, mask = 0xff;
 	int64_t temp;
 
-	temp = DIV_ROUND_CLOSEST(val * sp[id].numrtr, sp[id].denmtr);
+	temp = (int64_t)div_s64((s64)val * sp[id].numrtr, sp[id].denmtr);
 	pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val);
 	for (i = 0; i < sp[id].len; i++) {
 		buf[i] = temp & mask;
@@ -1320,9 +1320,16 @@
 		return rc;
 	}
 
-	cc_soc_delta_pct = DIV_ROUND_CLOSEST(
-				abs(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
-				CC_SOC_30BIT);
+	cc_soc_delta_pct =
+		div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
+			CC_SOC_30BIT);
+
+	/* If the delta is < 50%, then skip processing full data */
+	if (cc_soc_delta_pct < 50) {
+		pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
+		return -ERANGE;
+	}
+
 	delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
 				100);
 	chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
@@ -1392,7 +1399,6 @@
 	return rc;
 }
 
-#define FULL_SOC_RAW	255
 static void fg_cap_learning_update(struct fg_chip *chip)
 {
 	int rc, batt_soc, batt_soc_msb;
@@ -3077,6 +3083,7 @@
 				pval->intval);
 			return -EINVAL;
 		}
+		break;
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 		rc = fg_set_constant_chg_voltage(chip, pval->intval);
 		break;
@@ -3937,7 +3944,7 @@
 }
 
 #define DEFAULT_CUTOFF_VOLT_MV		3200
-#define DEFAULT_EMPTY_VOLT_MV		2800
+#define DEFAULT_EMPTY_VOLT_MV		2850
 #define DEFAULT_RECHARGE_VOLT_MV	4250
 #define DEFAULT_CHG_TERM_CURR_MA	100
 #define DEFAULT_CHG_TERM_BASE_CURR_MA	75
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 7a6f2ea..becce31 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -432,6 +432,7 @@
 	POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
 	POWER_SUPPLY_PROP_HW_CURRENT_MAX,
 	POWER_SUPPLY_PROP_REAL_TYPE,
+	POWER_SUPPLY_PROP_PR_SWAP,
 };
 
 static int smb2_usb_get_prop(struct power_supply *psy,
@@ -454,8 +455,7 @@
 		if (!val->intval)
 			break;
 
-		rc = smblib_get_prop_typec_mode(chg, val);
-		if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+		if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
 			chg->micro_usb_mode) &&
 			chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
 			val->intval = 0;
@@ -492,7 +492,7 @@
 		else if (chip->bad_part)
 			val->intval = POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
 		else
-			rc = smblib_get_prop_typec_mode(chg, val);
+			val->intval = chg->typec_mode;
 		break;
 	case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
 		if (chg->micro_usb_mode)
@@ -536,6 +536,9 @@
 	case POWER_SUPPLY_PROP_HW_CURRENT_MAX:
 		rc = smblib_get_charge_current(chg, &val->intval);
 		break;
+	case POWER_SUPPLY_PROP_PR_SWAP:
+		rc = smblib_get_prop_pr_swap_in_progress(chg, val);
+		break;
 	default:
 		pr_err("get prop %d is not supported in usb\n", psp);
 		rc = -EINVAL;
@@ -594,6 +597,9 @@
 		rc = vote(chg->usb_icl_votable, CTM_VOTER,
 						val->intval >= 0, val->intval);
 		break;
+	case POWER_SUPPLY_PROP_PR_SWAP:
+		rc = smblib_set_prop_pr_swap_in_progress(chg, val);
+		break;
 	default:
 		pr_err("set prop %d is not supported\n", psp);
 		rc = -EINVAL;
@@ -671,8 +677,7 @@
 		if (!val->intval)
 			break;
 
-		rc = smblib_get_prop_typec_mode(chg, val);
-		if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+		if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
 			chg->micro_usb_mode) &&
 			chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
 			val->intval = 1;
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 20ff26a..6ead522 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -637,6 +637,7 @@
 	/* reset both usbin current and voltage votes */
 	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
 	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
 
 	cancel_delayed_work_sync(&chg->hvdcp_detect_work);
 
@@ -839,7 +840,6 @@
 {
 	int rc = 0;
 	bool override;
-	union power_supply_propval pval;
 
 	/* suspend and return if 25mA or less is requested */
 	if (icl_ua < USBIN_25MA)
@@ -849,14 +849,8 @@
 	if (icl_ua == INT_MAX)
 		goto override_suspend_config;
 
-	rc = smblib_get_prop_typec_mode(chg, &pval);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
-		goto enable_icl_changed_interrupt;
-	}
-
 	/* configure current */
-	if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+	if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
 		&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
 		rc = set_sdp_current(chg, icl_ua);
 		if (rc < 0) {
@@ -864,6 +858,7 @@
 			goto enable_icl_changed_interrupt;
 		}
 	} else {
+		set_sdp_current(chg, 100000);
 		rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
 		if (rc < 0) {
 			smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
@@ -877,7 +872,7 @@
 	if (icl_ua == INT_MAX) {
 		/* remove override if no voters - hw defaults is desired */
 		override = false;
-	} else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
+	} else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
 		if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
 			/* For std cable with type = SDP never override */
 			override = false;
@@ -917,15 +912,8 @@
 	int rc = 0;
 	u8 load_cfg;
 	bool override;
-	union power_supply_propval pval;
 
-	rc = smblib_get_prop_typec_mode(chg, &pval);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
-		return rc;
-	}
-
-	if ((pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+	if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
 		|| chg->micro_usb_mode)
 		&& (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
 		rc = get_sdp_current(chg, icl_ua);
@@ -1895,38 +1883,18 @@
 		return rc;
 
 	smblib_dbg(chg, PR_MISC, "re-running AICL\n");
-	switch (chg->smb_version) {
-	case PMI8998_SUBTYPE:
-		rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
-							&settled_icl_ua);
-		if (rc < 0) {
-			smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
-			return rc;
-		}
-
-		vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
-				max(settled_icl_ua - chg->param.usb_icl.step_u,
-				chg->param.usb_icl.step_u));
-		vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
-		break;
-	case PM660_SUBTYPE:
-		/*
-		 * Use restart_AICL instead of trigger_AICL as it runs the
-		 * complete AICL instead of starting from the last settled
-		 * value.
-		 */
-		rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
-					RESTART_AICL_BIT, RESTART_AICL_BIT);
-		if (rc < 0)
-			smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
-									rc);
-		break;
-	default:
-		smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
-				chg->smb_version);
-		return -EINVAL;
+	rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
+			&settled_icl_ua);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
+		return rc;
 	}
 
+	vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
+			max(settled_icl_ua - chg->param.usb_icl.step_u,
+				chg->param.usb_icl.step_u));
+	vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
+
 	return 0;
 }
 
@@ -1961,6 +1929,7 @@
 int smblib_dp_dm(struct smb_charger *chg, int val)
 {
 	int target_icl_ua, rc = 0;
+	union power_supply_propval pval;
 
 	switch (val) {
 	case POWER_SUPPLY_DP_DM_DP_PULSE:
@@ -1978,10 +1947,35 @@
 				rc, chg->pulse_cnt);
 		break;
 	case POWER_SUPPLY_DP_DM_ICL_DOWN:
-		chg->usb_icl_delta_ua -= 100000;
 		target_icl_ua = get_effective_result(chg->usb_icl_votable);
+		if (target_icl_ua < 0) {
+			/* no client vote, get the ICL from charger */
+			rc = power_supply_get_property(chg->usb_psy,
+					POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+					&pval);
+			if (rc < 0) {
+				smblib_err(chg,
+					"Couldn't get max current rc=%d\n",
+					rc);
+				return rc;
+			}
+			target_icl_ua = pval.intval;
+		}
+
+		/*
+		 * Check if any other voter voted on USB_ICL in case of
+		 * voter other than SW_QC3_VOTER reset and restart reduction
+		 * again.
+		 */
+		if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
+							SW_QC3_VOTER))
+			chg->usb_icl_delta_ua = 0;
+
+		chg->usb_icl_delta_ua += 100000;
 		vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
-				target_icl_ua + chg->usb_icl_delta_ua);
+						target_icl_ua - 100000);
+		smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
+				target_icl_ua, chg->usb_icl_delta_ua);
 		break;
 	case POWER_SUPPLY_DP_DM_ICL_UP:
 	default:
@@ -2217,8 +2211,6 @@
 static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
 {
 	switch (chg->typec_status[0]) {
-	case 0:
-		return POWER_SUPPLY_TYPEC_NONE;
 	case UFP_TYPEC_RDSTD_BIT:
 		return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
 	case UFP_TYPEC_RD1P5_BIT:
@@ -2229,7 +2221,7 @@
 		break;
 	}
 
-	return POWER_SUPPLY_TYPEC_NON_COMPLIANT;
+	return POWER_SUPPLY_TYPEC_NONE;
 }
 
 static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
@@ -2243,8 +2235,6 @@
 		return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
 	case DFP_RD_OPEN_BIT:
 		return POWER_SUPPLY_TYPEC_SINK;
-	case DFP_RA_OPEN_BIT:
-		return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
 	default:
 		break;
 	}
@@ -2252,20 +2242,12 @@
 	return POWER_SUPPLY_TYPEC_NONE;
 }
 
-int smblib_get_prop_typec_mode(struct smb_charger *chg,
-			       union power_supply_propval *val)
+static int smblib_get_prop_typec_mode(struct smb_charger *chg)
 {
-	if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
-		val->intval = POWER_SUPPLY_TYPEC_NONE;
-		return 0;
-	}
-
 	if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
-		val->intval = smblib_get_prop_dfp_mode(chg);
+		return smblib_get_prop_dfp_mode(chg);
 	else
-		val->intval = smblib_get_prop_ufp_mode(chg);
-
-	return 0;
+		return smblib_get_prop_ufp_mode(chg);
 }
 
 int smblib_get_prop_typec_power_role(struct smb_charger *chg,
@@ -2553,24 +2535,12 @@
 			      const union power_supply_propval *val)
 {
 	int rc;
-	bool orientation, cc_debounced, sink_attached, hvdcp;
+	bool orientation, sink_attached, hvdcp;
 	u8 stat;
 
 	if (!get_effective_result(chg->pd_allowed_votable))
 		return -EINVAL;
 
-	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
-		return rc;
-	}
-
-	cc_debounced = (bool)
-		(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
-	sink_attached = (bool)
-		(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
-	hvdcp = stat & QC_CHARGER_BIT;
-
 	chg->pd_active = val->intval;
 	if (chg->pd_active) {
 		vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
@@ -2622,6 +2592,14 @@
 		if (rc < 0)
 			smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
 	} else {
+		rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't read APSD status rc=%d\n",
+									rc);
+			return rc;
+		}
+
+		hvdcp = stat & QC_CHARGER_BIT;
 		vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
 		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
 		vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
@@ -2641,8 +2619,8 @@
 		 * and data could be interrupted. Non-legacy DCP could also draw
 		 * more, but it may impact compliance.
 		 */
-		if (!chg->typec_legacy_valid && cc_debounced &&
-							!sink_attached && hvdcp)
+		sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
+		if (!chg->typec_legacy_valid && !sink_attached && hvdcp)
 			schedule_work(&chg->legacy_detection_work);
 	}
 
@@ -2764,6 +2742,7 @@
 		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
 		return rc;
 	}
+
 	ccout = (stat & CC_ATTACHED_BIT) ?
 					(!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
 	ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
@@ -3600,6 +3579,7 @@
 	vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
 	vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
 	vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
 
 	/* reset hvdcp voters */
 	vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
@@ -3630,6 +3610,11 @@
 	chg->pd_hard_reset = 0;
 	chg->typec_legacy_valid = false;
 
+	/* reset back to 120mS tCC debounce */
+	rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
+
 	/* enable APSD CC trigger for next insertion */
 	rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
 				APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
@@ -3670,12 +3655,29 @@
 	if (rc < 0)
 		smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
 
+	mutex_lock(&chg->vconn_oc_lock);
+	if (!chg->vconn_en)
+		goto unlock;
+
+	smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+				 VCONN_EN_VALUE_BIT, 0);
+	chg->vconn_en = false;
+
+unlock:
+	mutex_unlock(&chg->vconn_oc_lock);
+
+	/* clear exit sink based on cc */
+	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+						EXIT_SNK_BASED_ON_CC_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
+				rc);
+
 	typec_sink_removal(chg);
 	smblib_update_usb_type(chg);
 }
 
-static void smblib_handle_typec_insertion(struct smb_charger *chg,
-							bool sink_attached)
+static void smblib_handle_typec_insertion(struct smb_charger *chg)
 {
 	int rc;
 
@@ -3687,45 +3689,37 @@
 		smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
 									rc);
 
-	if (sink_attached)
+	if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
 		typec_sink_insertion(chg);
 	else
 		typec_sink_removal(chg);
 }
 
-static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
-						bool rising, bool sink_attached)
+static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
 {
-	int rc;
-	union power_supply_propval pval = {0, };
+	if (chg->pr_swap_in_progress)
+		return;
 
-	if (rising) {
-		if (!chg->typec_present) {
-			chg->typec_present = true;
-			smblib_dbg(chg, PR_MISC,  "TypeC insertion\n");
-			smblib_handle_typec_insertion(chg, sink_attached);
-		}
-	} else {
-		if (chg->typec_present) {
-			chg->typec_present = false;
-			smblib_dbg(chg, PR_MISC,  "TypeC removal\n");
-			smblib_handle_typec_removal(chg);
-		}
+	chg->typec_mode = smblib_get_prop_typec_mode(chg);
+	if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
+		chg->typec_present = true;
+		smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
+			smblib_typec_mode_name[chg->typec_mode]);
+		smblib_handle_typec_insertion(chg);
+	} else if (chg->typec_present &&
+				chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+		chg->typec_present = false;
+		smblib_dbg(chg, PR_MISC, "TypeC removal\n");
+		smblib_handle_typec_removal(chg);
 	}
 
-	rc = smblib_get_prop_typec_mode(chg, &pval);
-	if (rc < 0)
-		smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
-
-	smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
-		   rising ? "rising" : "falling",
-		   smblib_typec_mode_name[pval.intval]);
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
+				smblib_typec_mode_name[chg->typec_mode]);
 }
 
 static void smblib_usb_typec_change(struct smb_charger *chg)
 {
 	int rc;
-	bool debounce_done, sink_attached;
 
 	rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
 							chg->typec_status, 5);
@@ -3734,12 +3728,7 @@
 		return;
 	}
 
-	debounce_done =
-		(bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
-	sink_attached =
-		(bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
-
-	smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
+	smblib_handle_typec_cc_state_change(chg);
 
 	if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
 		smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
@@ -3842,6 +3831,36 @@
 	return IRQ_HANDLED;
 }
 
+/**************
+ * Additional USB PSY getters/setters
+ * that call interrupt functions
+ ***************/
+
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	val->intval = chg->pr_swap_in_progress;
+	return 0;
+}
+
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	int rc;
+
+	chg->pr_swap_in_progress = val->intval;
+	/*
+	 * call the cc changed irq to handle real removals while
+	 * PR_SWAP was in progress
+	 */
+	smblib_usb_typec_change(chg);
+	rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
+			val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
+	return 0;
+}
+
 /***************
  * Work Queues *
  ***************/
@@ -4230,14 +4249,14 @@
 	chg->typec_legacy_valid = true;
 	vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
 	legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
-	rp_high = smblib_get_prop_ufp_mode(chg) ==
-						POWER_SUPPLY_TYPEC_SOURCE_HIGH;
+	rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
 	if (!legacy || !rp_high)
 		vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
 								false, 0);
 
 unlock:
 	chg->typec_en_dis_active = 0;
+	smblib_usb_typec_change(chg);
 	mutex_unlock(&chg->lock);
 }
 
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 0c8e661..f39f2c9 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -321,6 +321,8 @@
 	u8			typec_status[5];
 	bool			typec_legacy_valid;
 	int			fake_input_current_limited;
+	bool			pr_swap_in_progress;
+	int			typec_mode;
 
 	/* workaround flag */
 	u32			wa_flags;
@@ -454,8 +456,6 @@
 				union power_supply_propval *val);
 int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
 				union power_supply_propval *val);
-int smblib_get_prop_typec_mode(struct smb_charger *chg,
-				union power_supply_propval *val);
 int smblib_get_prop_typec_power_role(struct smb_charger *chg,
 				union power_supply_propval *val);
 int smblib_get_prop_pd_allowed(struct smb_charger *chg,
@@ -508,6 +508,10 @@
 int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
 int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
 int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua);
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+				const union power_supply_propval *val);
 
 int smblib_init(struct smb_charger *chg);
 int smblib_deinit(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index 167666a..d8671ab 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -486,11 +486,11 @@
 #define UFP_TYPEC_OPEN_OPEN_BIT			BIT(0)
 
 #define TYPE_C_STATUS_2_REG			(USBIN_BASE + 0x0C)
-#define DFP_TYPEC_MASK				0x8F
 #define DFP_RA_OPEN_BIT				BIT(7)
 #define TIMER_STAGE_BIT				BIT(6)
 #define EXIT_UFP_MODE_BIT			BIT(5)
 #define EXIT_DFP_MODE_BIT			BIT(4)
+#define DFP_TYPEC_MASK				GENMASK(3, 0)
 #define DFP_RD_OPEN_BIT				BIT(3)
 #define DFP_RD_RA_VCONN_BIT			BIT(2)
 #define DFP_RD_RD_BIT				BIT(1)
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index b92a482..a464a81 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -1416,6 +1416,7 @@
 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
 	POWER_SUPPLY_PROP_CHARGE_TYPE,
 	POWER_SUPPLY_PROP_PARALLEL_MODE,
+	POWER_SUPPLY_PROP_INPUT_SUSPEND,
 };
 
 static int smb1351_parallel_set_chg_suspend(struct smb1351_charger *chip,
@@ -1702,6 +1703,9 @@
 	case POWER_SUPPLY_PROP_PARALLEL_MODE:
 		val->intval = chip->parallel_mode;
 		break;
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		val->intval = chip->parallel_charger_suspended;
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index d5fff74..b2c0059 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -16,6 +16,7 @@
 #include <linux/regmap.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/iio/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/qpnp/qpnp-revid.h>
 #include <linux/of.h>
@@ -61,6 +62,15 @@
 #define CHGR_BATTOV_CFG_REG			(CHGR_BASE + 0x70)
 #define BATTOV_SETTING_MASK			GENMASK(7, 0)
 
+#define TEMP_COMP_STATUS_REG			(MISC_BASE + 0x07)
+#define SKIN_TEMP_RST_HOT_BIT			BIT(6)
+#define SKIN_TEMP_UB_HOT_BIT			BIT(5)
+#define SKIN_TEMP_LB_HOT_BIT			BIT(4)
+#define DIE_TEMP_TSD_HOT_BIT			BIT(3)
+#define DIE_TEMP_RST_HOT_BIT			BIT(2)
+#define DIE_TEMP_UB_HOT_BIT			BIT(1)
+#define DIE_TEMP_LB_HOT_BIT			BIT(0)
+
 #define BARK_BITE_WDOG_PET_REG			(MISC_BASE + 0x43)
 #define BARK_BITE_WDOG_PET_BIT			BIT(0)
 
@@ -115,12 +125,18 @@
 	int			irq;
 };
 
+struct smb_iio {
+	struct iio_channel	*temp_chan;
+	struct iio_channel	*temp_max_chan;
+};
+
 struct smb1355 {
 	struct device		*dev;
 	char			*name;
 	struct regmap		*regmap;
 
 	struct smb_params	param;
+	struct smb_iio		iio;
 
 	struct mutex		write_lock;
 
@@ -257,9 +273,13 @@
 	POWER_SUPPLY_PROP_CHARGING_ENABLED,
 	POWER_SUPPLY_PROP_PIN_ENABLED,
 	POWER_SUPPLY_PROP_INPUT_SUSPEND,
+	POWER_SUPPLY_PROP_CHARGER_TEMP,
+	POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
 	POWER_SUPPLY_PROP_VOLTAGE_MAX,
 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
 	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_PARALLEL_MODE,
+	POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
 };
 
 static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip,
@@ -305,6 +325,65 @@
 	return 0;
 }
 
+static int smb1355_get_prop_connector_health(struct smb1355 *chip)
+{
+	u8 temp;
+	int rc;
+
+	rc = smb1355_read(chip, TEMP_COMP_STATUS_REG, &temp);
+	if (rc < 0) {
+		pr_err("Couldn't read comp stat reg rc = %d\n", rc);
+		return POWER_SUPPLY_HEALTH_UNKNOWN;
+	}
+
+	if (temp & SKIN_TEMP_RST_HOT_BIT)
+		return POWER_SUPPLY_HEALTH_OVERHEAT;
+
+	if (temp & SKIN_TEMP_UB_HOT_BIT)
+		return POWER_SUPPLY_HEALTH_HOT;
+
+	if (temp & SKIN_TEMP_LB_HOT_BIT)
+		return POWER_SUPPLY_HEALTH_WARM;
+
+	return POWER_SUPPLY_HEALTH_COOL;
+}
+
+
+static int smb1355_get_prop_charger_temp(struct smb1355 *chip,
+				union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chip->iio.temp_chan ||
+		PTR_ERR(chip->iio.temp_chan) == -EPROBE_DEFER)
+		chip->iio.temp_chan = devm_iio_channel_get(chip->dev,
+						"charger_temp");
+
+	if (IS_ERR(chip->iio.temp_chan))
+		return PTR_ERR(chip->iio.temp_chan);
+
+	rc = iio_read_channel_processed(chip->iio.temp_chan, &val->intval);
+	val->intval /= 100;
+	return rc;
+}
+
+static int smb1355_get_prop_charger_temp_max(struct smb1355 *chip,
+				union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chip->iio.temp_max_chan ||
+		PTR_ERR(chip->iio.temp_max_chan) == -EPROBE_DEFER)
+		chip->iio.temp_max_chan = devm_iio_channel_get(chip->dev,
+							"charger_temp_max");
+	if (IS_ERR(chip->iio.temp_max_chan))
+		return PTR_ERR(chip->iio.temp_max_chan);
+
+	rc = iio_read_channel_processed(chip->iio.temp_max_chan, &val->intval);
+	val->intval /= 100;
+	return rc;
+}
+
 static int smb1355_parallel_get_prop(struct power_supply *psy,
 				     enum power_supply_property prop,
 				     union power_supply_propval *val)
@@ -327,6 +406,12 @@
 		if (rc >= 0)
 			val->intval = !(stat & DISABLE_CHARGING_BIT);
 		break;
+	case POWER_SUPPLY_PROP_CHARGER_TEMP:
+		rc = smb1355_get_prop_charger_temp(chip, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
+		rc = smb1355_get_prop_charger_temp_max(chip, val);
+		break;
 	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
 		rc = smb1355_get_parallel_charging(chip, &val->intval);
 		break;
@@ -344,6 +429,9 @@
 	case POWER_SUPPLY_PROP_PARALLEL_MODE:
 		val->intval = POWER_SUPPLY_PL_USBMID_USBMID;
 		break;
+	case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
+		val->intval = smb1355_get_prop_connector_health(chip);
+		break;
 	default:
 		pr_err_ratelimited("parallel psy get prop %d not supported\n",
 			prop);
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 83374bb..ca0a2c6 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -248,7 +248,7 @@
 		val->intval = chg->usb_psy_desc.type;
 		break;
 	case POWER_SUPPLY_PROP_TYPEC_MODE:
-		rc = smblib_get_prop_typec_mode(chg, val);
+		val->intval = chg->typec_mode;
 		break;
 	case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
 		rc = smblib_get_prop_typec_power_role(chg, val);
@@ -941,13 +941,6 @@
 		return rc;
 	}
 
-	rc = smblib_write(chg, THERMREG_SRC_CFG_REG,
-						THERMREG_SKIN_ADC_SRC_EN_BIT);
-	if (rc < 0) {
-		pr_err("Couldn't enable connector thermreg source rc=%d\n", rc);
-		return rc;
-	}
-
 	return 0;
 }
 
diff --git a/drivers/regulator/rpmh-regulator.c b/drivers/regulator/rpmh-regulator.c
index 4f5f86c..1ba8926 100644
--- a/drivers/regulator/rpmh-regulator.c
+++ b/drivers/regulator/rpmh-regulator.c
@@ -1187,6 +1187,9 @@
 	aggr_vreg->vreg_count = 0;
 
 	for_each_available_child_of_node(aggr_vreg->dev->of_node, node) {
+		/* Skip child nodes handled by other drivers. */
+		if (of_find_property(node, "compatible", NULL))
+			continue;
 		aggr_vreg->vreg_count++;
 	}
 
@@ -1202,6 +1205,10 @@
 
 	i = 0;
 	for_each_available_child_of_node(aggr_vreg->dev->of_node, node) {
+		/* Skip child nodes handled by other drivers. */
+		if (of_find_property(node, "compatible", NULL))
+			continue;
+
 		aggr_vreg->vreg[i].of_node = node;
 		aggr_vreg->vreg[i].aggr_vreg = aggr_vreg;
 
@@ -1623,6 +1630,7 @@
 		mutex_unlock(&aggr_vreg->lock);
 	}
 
+	of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 	platform_set_drvdata(pdev, aggr_vreg);
 
 	aggr_vreg_debug(aggr_vreg, "successfully probed; addr=0x%05X, type=%s\n",
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 643014f..4a6e086 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -721,6 +721,8 @@
 		return -EIO;
 	}
 
+	memset(&elreq, 0, sizeof(elreq));
+
 	elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev,
 		bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt,
 		DMA_TO_DEVICE);
@@ -786,10 +788,9 @@
 
 	if (atomic_read(&vha->loop_state) == LOOP_READY &&
 	    (ha->current_topology == ISP_CFG_F ||
-	    ((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) &&
-	    le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
-	    && req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
-		elreq.options == EXTERNAL_LOOPBACK) {
+	    (le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE &&
+	     req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
+	    elreq.options == EXTERNAL_LOOPBACK) {
 		type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
 		ql_dbg(ql_dbg_user, vha, 0x701e,
 		    "BSG request type: %s.\n", type);
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 45af34d..658e4d1 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -1131,7 +1131,7 @@
 
 	/* Mailbox registers. */
 	mbx_reg = &reg->mailbox0;
-	for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, dmp_reg++)
+	for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, mbx_reg++)
 		fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
 
 	/* Transfer sequence registers. */
@@ -2090,7 +2090,7 @@
 
 	/* Mailbox registers. */
 	mbx_reg = &reg->mailbox0;
-	for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, dmp_reg++)
+	for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, mbx_reg++)
 		fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
 
 	/* Transfer sequence registers. */
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 23698c9..a1b01d6 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4783,9 +4783,9 @@
 
 	memset(mcp->mb, 0 , sizeof(mcp->mb));
 	mcp->mb[0] = MBC_DIAGNOSTIC_ECHO;
-	mcp->mb[1] = mreq->options | BIT_6;	/* BIT_6 specifies 64bit address */
+	/* BIT_6 specifies 64bit address */
+	mcp->mb[1] = mreq->options | BIT_15 | BIT_6;
 	if (IS_CNA_CAPABLE(ha)) {
-		mcp->mb[1] |= BIT_15;
 		mcp->mb[2] = vha->fcoe_fcf_idx;
 	}
 	mcp->mb[16] = LSW(mreq->rcv_dma);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index f9b52a4..94630d4 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2420,10 +2420,10 @@
 
 	if (mem_only) {
 		if (pci_enable_device_mem(pdev))
-			goto probe_out;
+			return ret;
 	} else {
 		if (pci_enable_device(pdev))
-			goto probe_out;
+			return ret;
 	}
 
 	/* This may fail but that's ok */
@@ -2433,7 +2433,7 @@
 	if (!ha) {
 		ql_log_pci(ql_log_fatal, pdev, 0x0009,
 		    "Unable to allocate memory for ha.\n");
-		goto probe_out;
+		goto disable_device;
 	}
 	ql_dbg_pci(ql_dbg_init, pdev, 0x000a,
 	    "Memory allocated for ha=%p.\n", ha);
@@ -3039,7 +3039,7 @@
 	kfree(ha);
 	ha = NULL;
 
-probe_out:
+disable_device:
 	pci_disable_device(pdev);
 	return ret;
 }
diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c
index 36935c9..9c2c7fe6 100644
--- a/drivers/scsi/qla2xxx/qla_tmpl.c
+++ b/drivers/scsi/qla2xxx/qla_tmpl.c
@@ -371,7 +371,7 @@
 		goto done;
 	}
 
-	if (end <= start || start == 0 || end == 0) {
+	if (end < start || start == 0 || end == 0) {
 		ql_dbg(ql_dbg_misc, vha, 0xd023,
 		    "%s: unusable range (start=%x end=%x)\n", __func__,
 		    ent->t262.end_addr, ent->t262.start_addr);
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 1b283b2..db4e7bb 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -83,6 +83,8 @@
 	tristate "QCOM specific hooks to UFS controller platform driver"
 	depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM
 	select PHY_QCOM_UFS
+	select EXTCON
+	select EXTCON_GPIO
 	help
 	  This selects the QCOM specific additions to UFSHCD platform driver.
 	  UFS host on QCOM needs some vendor specific configuration before
diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index 814d1dc..0c86263 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -394,8 +394,8 @@
 	}
 
 
+	memset(&ice_set, 0, sizeof(ice_set));
 	if (qcom_host->ice.vops->config_start) {
-		memset(&ice_set, 0, sizeof(ice_set));
 
 		spin_lock_irqsave(
 			&qcom_host->ice_work_lock, flags);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index de6ecbd..7c5a1bc 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -327,6 +327,20 @@
 	return ret;
 }
 
+static int ufshcd_parse_extcon_info(struct ufs_hba *hba)
+{
+	struct extcon_dev *extcon;
+
+	extcon = extcon_get_edev_by_phandle(hba->dev, 0);
+	if (IS_ERR(extcon) && PTR_ERR(extcon) != -ENODEV)
+		return PTR_ERR(extcon);
+
+	if (!IS_ERR(extcon))
+		hba->extcon = extcon;
+
+	return 0;
+}
+
 #ifdef CONFIG_SMP
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -449,6 +463,9 @@
 	ufshcd_parse_pm_levels(hba);
 	ufshcd_parse_gear_limits(hba);
 	ufshcd_parse_cmd_timeout(hba);
+	err = ufshcd_parse_extcon_info(hba);
+	if (err)
+		goto dealloc_host;
 
 	if (!dev->dma_mask)
 		dev->dma_mask = &dev->coherent_dma_mask;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 77ba414..59222ea 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -534,7 +534,7 @@
 		*val = ' ';
 }
 
-#define UFSHCD_MAX_CMD_LOGGING	100
+#define UFSHCD_MAX_CMD_LOGGING	200
 
 #ifdef CONFIG_TRACEPOINTS
 static inline void ufshcd_add_command_trace(struct ufs_hba *hba,
@@ -610,7 +610,7 @@
 	ufshcd_cmd_log(hba, str, "dme", 0xff, cmd_id, 0xff);
 }
 
-static void ufshcd_cmd_log_print(struct ufs_hba *hba)
+static void ufshcd_print_cmd_log(struct ufs_hba *hba)
 {
 	int i;
 	int pos;
@@ -659,7 +659,7 @@
 {
 }
 
-static void ufshcd_cmd_log_print(struct ufs_hba *hba)
+static void ufshcd_print_cmd_log(struct ufs_hba *hba)
 {
 }
 #endif
@@ -3342,8 +3342,10 @@
 	/*
 	 * May get invoked from shutdown and IOCTL contexts.
 	 * In shutdown context, it comes in with lock acquired.
+	 * In error recovery context, it may come with lock acquired.
 	 */
-	if (!ufshcd_is_shutdown_ongoing(hba))
+
+	if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba))
 		down_read(&hba->lock);
 
 	/*
@@ -3377,7 +3379,7 @@
 out_put_tag:
 	ufshcd_put_dev_cmd_tag(hba, tag);
 	wake_up(&hba->dev_cmd.tag_wq);
-	if (!ufshcd_is_shutdown_ongoing(hba))
+	if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba))
 		up_read(&hba->lock);
 	return err;
 }
@@ -4334,6 +4336,7 @@
 		ufshcd_print_host_state(hba);
 		ufshcd_print_pwr_info(hba);
 		ufshcd_print_host_regs(hba);
+		ufshcd_print_cmd_log(hba);
 	}
 
 	ufshcd_save_tstamp_of_last_dme_cmd(hba);
@@ -6181,7 +6184,7 @@
 			ufshcd_print_host_state(hba);
 			ufshcd_print_pwr_info(hba);
 			ufshcd_print_tmrs(hba, hba->outstanding_tasks);
-			ufshcd_cmd_log_print(hba);
+			ufshcd_print_cmd_log(hba);
 			spin_lock_irqsave(hba->host->host_lock, flags);
 		}
 	}
@@ -6693,7 +6696,7 @@
 	hba = shost_priv(host);
 	tag = cmd->request->tag;
 
-	ufshcd_cmd_log_print(hba);
+	ufshcd_print_cmd_log(hba);
 	lrbp = &hba->lrb[tag];
 	err = ufshcd_issue_tm_cmd(hba, lrbp->lun, 0, UFS_LOGICAL_RESET, &resp);
 	if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
@@ -6965,6 +6968,23 @@
 	return err;
 }
 
+static int ufshcd_detect_device(struct ufs_hba *hba)
+{
+	int err = 0;
+
+	err = ufshcd_vops_full_reset(hba);
+	if (err)
+		dev_warn(hba->dev, "%s: full reset returned %d\n",
+			 __func__, err);
+
+	err = ufshcd_reset_device(hba);
+	if (err)
+		dev_warn(hba->dev, "%s: device reset failed. err %d\n",
+			 __func__, err);
+
+	return ufshcd_host_reset_and_restore(hba);
+}
+
 /**
  * ufshcd_reset_and_restore - reset and re-initialize host/device
  * @hba: per-adapter instance
@@ -6981,26 +7001,10 @@
 	int retries = MAX_HOST_RESET_RETRIES;
 
 	do {
-		err = ufshcd_vops_full_reset(hba);
-		if (err)
-			dev_warn(hba->dev, "%s: full reset returned %d\n",
-				 __func__, err);
-
-		err = ufshcd_reset_device(hba);
-		if (err)
-			dev_warn(hba->dev, "%s: device reset failed. err %d\n",
-				 __func__, err);
-
-		err = ufshcd_host_reset_and_restore(hba);
+		err = ufshcd_detect_device(hba);
 	} while (err && --retries);
 
 	/*
-	 * There is no point proceeding even after failing
-	 * to recover after multiple retries.
-	 */
-	if (err)
-		BUG();
-	/*
 	 * After reset the door-bell might be cleared, complete
 	 * outstanding requests in s/w here.
 	 */
@@ -7703,10 +7707,8 @@
 	 * If we failed to initialize the device or the device is not
 	 * present, turn off the power/clocks etc.
 	 */
-	if (ret && !ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress) {
+	if (ret && !ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress)
 		pm_runtime_put_sync(hba->dev);
-		ufshcd_hba_exit(hba);
-	}
 
 	trace_ufshcd_init(dev_name(hba->dev), ret,
 		ktime_to_us(ktime_sub(ktime_get(), start)),
@@ -7714,6 +7716,70 @@
 	return ret;
 }
 
+static void ufshcd_card_detect_handler(struct work_struct *work)
+{
+	struct ufs_hba *hba;
+
+	hba = container_of(work, struct ufs_hba, card_detect_work);
+	if (hba->card_detect_event &&
+	    (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)) {
+		dev_dbg(hba->dev, "%s: card detect notification received\n",
+			 __func__);
+		pm_runtime_get_sync(hba->dev);
+		ufshcd_detect_device(hba);
+		pm_runtime_put_sync(hba->dev);
+	} else {
+		dev_dbg(hba->dev, "%s: card removed notification received\n",
+			 __func__);
+		/* TODO: remove the scsi device instances */
+	}
+}
+
+static int ufshcd_card_detect_notifier(struct notifier_block *nb,
+				       unsigned long event, void *ptr)
+{
+	struct ufs_hba *hba = container_of(nb, struct ufs_hba, card_detect_nb);
+
+	hba->card_detect_event = event;
+	schedule_work(&hba->card_detect_work);
+
+	return NOTIFY_DONE;
+}
+
+static int ufshcd_extcon_register(struct ufs_hba *hba)
+{
+	int ret;
+
+	if (!hba->extcon)
+		return 0;
+
+	hba->card_detect_nb.notifier_call = ufshcd_card_detect_notifier;
+	ret = extcon_register_notifier(hba->extcon,
+				       EXTCON_MECHANICAL,
+				       &hba->card_detect_nb);
+	if (ret)
+		dev_err(hba->dev, "%s: extcon_register_notifier() failed, ret %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static int ufshcd_extcon_unregister(struct ufs_hba *hba)
+{
+	int ret;
+
+	if (!hba->extcon)
+		return 0;
+
+	ret = extcon_unregister_notifier(hba->extcon, EXTCON_MECHANICAL,
+					 &hba->card_detect_nb);
+	if (ret)
+		dev_err(hba->dev, "%s: extcon_unregister_notifier() failed, ret %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
 /**
  * ufshcd_async_scan - asynchronous execution for probing hba
  * @data: data pointer to pass to this function
@@ -7730,6 +7796,8 @@
 	ufshcd_hold_all(hba);
 	ufshcd_probe_hba(hba);
 	ufshcd_release_all(hba);
+
+	ufshcd_extcon_register(hba);
 }
 
 /**
@@ -8439,20 +8507,9 @@
 
 	err = ufshcd_vops_init(hba);
 	if (err)
-		goto out;
-
-	err = ufshcd_vops_setup_regulators(hba, true);
-	if (err)
-		goto out_exit;
-
-	goto out;
-
-out_exit:
-	ufshcd_vops_exit(hba);
-out:
-	if (err)
 		dev_err(hba->dev, "%s: variant %s init failed err %d\n",
 			__func__, ufshcd_get_var_name(hba), err);
+out:
 	return err;
 }
 
@@ -8461,8 +8518,6 @@
 	if (!hba->var || !hba->var->vops)
 		return;
 
-	ufshcd_vops_setup_regulators(hba, false);
-
 	ufshcd_vops_exit(hba);
 }
 
@@ -8521,6 +8576,7 @@
 static void ufshcd_hba_exit(struct ufs_hba *hba)
 {
 	if (hba->is_powered) {
+		ufshcd_extcon_unregister(hba);
 		ufshcd_variant_hba_exit(hba);
 		ufshcd_setup_vreg(hba, false);
 		if (ufshcd_is_clkscaling_supported(hba)) {
@@ -8825,10 +8881,8 @@
 		goto enable_gating;
 
 	/* UFS device & link must be active before we enter in this function */
-	if (!ufshcd_is_ufs_dev_active(hba) || !ufshcd_is_link_active(hba)) {
-		ret = -EINVAL;
-		goto enable_gating;
-	}
+	if (!ufshcd_is_ufs_dev_active(hba) || !ufshcd_is_link_active(hba))
+		goto set_vreg_lpm;
 
 	if (ufshcd_is_runtime_pm(pm_op)) {
 		if (ufshcd_can_autobkops_during_suspend(hba)) {
@@ -8864,6 +8918,7 @@
 	    ufshcd_is_hibern8_on_idle_allowed(hba))
 		hba->hibern8_on_idle.state = HIBERN8_ENTERED;
 
+set_vreg_lpm:
 	ufshcd_vreg_set_lpm(hba);
 
 disable_clks:
@@ -8966,6 +9021,9 @@
 	if (ret)
 		goto disable_vreg;
 
+	if (ufshcd_is_link_off(hba))
+		goto skip_dev_ops;
+
 	if (ufshcd_is_link_hibern8(hba)) {
 		ret = ufshcd_uic_hibern8_exit(hba);
 		if (!ret) {
@@ -9013,6 +9071,7 @@
 	if (hba->clk_scaling.is_allowed)
 		ufshcd_resume_clkscaling(hba);
 
+skip_dev_ops:
 	/* Schedule clock gating in case of no access to UFS device yet */
 	ufshcd_release_all(hba);
 	goto out;
@@ -10074,6 +10133,7 @@
 	/* Initialize work queues */
 	INIT_WORK(&hba->eh_work, ufshcd_err_handler);
 	INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler);
+	INIT_WORK(&hba->card_detect_work, ufshcd_card_detect_handler);
 
 	/* Initialize UIC command mutex */
 	mutex_init(&hba->uic_cmd_mutex);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index c61a753..a485885 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -57,6 +57,7 @@
 #include <linux/completion.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
+#include <linux/extcon.h>
 #include "unipro.h"
 
 #include <asm/irq.h>
@@ -724,6 +725,10 @@
  * @ufs_stats: ufshcd statistics to be used via debugfs
  * @debugfs_files: debugfs files associated with the ufs stats
  * @ufshcd_dbg_print: Bitmask for enabling debug prints
+ * @extcon: pointer to external connector device
+ * @card_detect_nb: card detector notifier registered with @extcon
+ * @card_detect_work: work to exectute the card detect function
+ * @card_detect_event: card detect event, 0 = removed, 1 = inserted
  * @vreg_info: UFS device voltage regulator information
  * @clk_list_head: UFS host controller clocks list node head
  * @pwr_info: holds current power mode
@@ -896,6 +901,11 @@
 	/* Bitmask for enabling debug prints */
 	u32 ufshcd_dbg_print;
 
+	struct extcon_dev *extcon;
+	struct notifier_block card_detect_nb;
+	struct work_struct card_detect_work;
+	unsigned long card_detect_event;
+
 	struct ufs_pa_layer_attr pwr_info;
 	struct ufs_pwr_mode_info max_pwr_info;
 
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index a72cb17..1b7b591 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -9,11 +9,13 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+#include <asm/dma-iommu.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/iommu.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
@@ -23,6 +25,7 @@
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/of_slimbus.h>
 #include <linux/timer.h>
 #include <linux/msm-sps.h>
@@ -1665,6 +1668,43 @@
 
 static DEVICE_ATTR(debug_mask, 0644, show_mask, set_mask);
 
+static const struct of_device_id ngd_slim_dt_match[] = {
+	{
+		.compatible = "qcom,slim-ngd",
+	},
+	{
+		.compatible = "qcom,iommu-slim-ctrl-cb",
+	},
+	{}
+};
+
+static int ngd_slim_iommu_probe(struct device *dev)
+{
+	struct platform_device *pdev;
+	struct msm_slim_ctrl *ctrl_dev;
+
+	if (unlikely(!dev->parent)) {
+		dev_err(dev, "%s no parent for this device\n", __func__);
+		return -EINVAL;
+	}
+
+	pdev = to_platform_device(dev->parent);
+	if (!pdev) {
+		dev_err(dev, "%s Parent platform device not found\n", __func__);
+		return -EINVAL;
+	}
+
+	ctrl_dev = platform_get_drvdata(pdev);
+	if (!ctrl_dev) {
+		dev_err(dev, "%s NULL controller device\n", __func__);
+		return -EINVAL;
+
+	}
+	ctrl_dev->iommu_desc.cb_dev = dev;
+	SLIM_INFO(ctrl_dev, "NGD IOMMU initialization complete\n");
+	return 0;
+}
+
 static int ngd_slim_probe(struct platform_device *pdev)
 {
 	struct msm_slim_ctrl *dev;
@@ -1676,6 +1716,10 @@
 	bool			slim_mdm = false;
 	const char		*ext_modem_id = NULL;
 
+	if (of_device_is_compatible(pdev->dev.of_node,
+				    "qcom,iommu-slim-ctrl-cb"))
+		return ngd_slim_iommu_probe(&pdev->dev);
+
 	slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						"slimbus_physical");
 	if (!slim_mem) {
@@ -1774,6 +1818,17 @@
 					"qcom,slim-mdm", &ext_modem_id);
 		if (!ret)
 			slim_mdm = true;
+
+		dev->iommu_desc.s1_bypass = of_property_read_bool(
+							pdev->dev.of_node,
+							"qcom,iommu-s1-bypass");
+		ret = of_platform_populate(pdev->dev.of_node, ngd_slim_dt_match,
+					   NULL, &pdev->dev);
+		if (ret) {
+			dev_err(dev->dev, "%s: Failed to of_platform_populate %d\n",
+				__func__, ret);
+			goto err_ctrl_failed;
+		}
 	} else {
 		dev->ctrl.nr = pdev->id;
 	}
@@ -1920,6 +1975,10 @@
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
 
 	ngd_slim_enable(dev, false);
+	if (!IS_ERR_OR_NULL(dev->iommu_desc.iommu_map)) {
+		arm_iommu_detach_device(dev->iommu_desc.cb_dev);
+		arm_iommu_release_mapping(dev->iommu_desc.iommu_map);
+	}
 	if (dev->sysfs_created)
 		sysfs_remove_file(&dev->dev->kobj,
 				&dev_attr_debug_mask.attr);
@@ -2091,13 +2150,6 @@
 	)
 };
 
-static const struct of_device_id ngd_slim_dt_match[] = {
-	{
-		.compatible = "qcom,slim-ngd",
-	},
-	{}
-};
-
 static struct platform_driver ngd_slim_driver = {
 	.probe = ngd_slim_probe,
 	.remove = ngd_slim_remove,
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index ef10e64..d8c5ea8 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -9,17 +9,21 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-#include <linux/pm_runtime.h>
-#include <linux/dma-mapping.h>
+#include <asm/dma-iommu.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/gcd.h>
+#include <linux/msm-sps.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/slimbus/slimbus.h>
-#include <linux/msm-sps.h>
-#include <linux/gcd.h>
 #include "slim-msm.h"
 
 /* Pipe Number Offset Mask */
 #define P_OFF_MASK 0x3FC
+#define MSM_SLIM_VA_START	(0x40000000)
+#define MSM_SLIM_VA_SIZE	(0xC0000000)
 
 int msm_slim_rx_enqueue(struct msm_slim_ctrl *dev, u32 *buf, u8 len)
 {
@@ -164,17 +168,61 @@
 	ep->sps = NULL;
 }
 
+static int msm_slim_iommu_attach(struct msm_slim_ctrl *ctrl_dev)
+{
+	struct dma_iommu_mapping *iommu_map;
+	dma_addr_t va_start = MSM_SLIM_VA_START;
+	size_t va_size = MSM_SLIM_VA_SIZE;
+	int bypass = 1;
+	struct device *dev;
+
+	if (unlikely(!ctrl_dev))
+		return -EINVAL;
+
+	if (!ctrl_dev->iommu_desc.cb_dev)
+		return 0;
+
+	dev = ctrl_dev->iommu_desc.cb_dev;
+	iommu_map = arm_iommu_create_mapping(&platform_bus_type,
+						va_start, va_size);
+	if (IS_ERR(iommu_map)) {
+		dev_err(dev, "%s iommu_create_mapping failure\n", __func__);
+		return PTR_ERR(iommu_map);
+	}
+
+	if (ctrl_dev->iommu_desc.s1_bypass) {
+		if (iommu_domain_set_attr(iommu_map->domain,
+					DOMAIN_ATTR_S1_BYPASS, &bypass)) {
+			dev_err(dev, "%s Can't bypass s1 translation\n",
+				__func__);
+			arm_iommu_release_mapping(iommu_map);
+			return -EIO;
+		}
+	}
+
+	if (arm_iommu_attach_device(dev, iommu_map)) {
+		dev_err(dev, "%s can't arm_iommu_attach_device\n", __func__);
+		arm_iommu_release_mapping(iommu_map);
+		return -EIO;
+	}
+	ctrl_dev->iommu_desc.iommu_map = iommu_map;
+	SLIM_INFO(ctrl_dev, "NGD IOMMU Attach complete\n");
+	return 0;
+}
+
 int msm_slim_sps_mem_alloc(
 		struct msm_slim_ctrl *dev, struct sps_mem_buffer *mem, u32 len)
 {
 	dma_addr_t phys;
+	struct device *dma_dev = dev->iommu_desc.cb_dev ?
+					dev->iommu_desc.cb_dev : dev->dev;
 
 	mem->size = len;
 	mem->min_size = 0;
-	mem->base = dma_alloc_coherent(dev->dev, mem->size, &phys, GFP_KERNEL);
+	mem->base = dma_alloc_coherent(dma_dev, mem->size, &phys, GFP_KERNEL);
 
 	if (!mem->base) {
-		dev_err(dev->dev, "dma_alloc_coherent(%d) failed\n", len);
+		dev_err(dma_dev, "dma_alloc_coherent(%d) failed\n", len);
 		return -ENOMEM;
 	}
 
@@ -387,6 +435,10 @@
 	if (pn >= dev->port_nums)
 		return -ENODEV;
 
+	ret = msm_slim_iommu_attach(dev);
+	if (ret)
+		return ret;
+
 	endpoint = &dev->pipes[pn];
 	ret = msm_slim_init_endpoint(dev, endpoint);
 	dev_dbg(dev->dev, "sps register bam error code:%x\n", ret);
@@ -435,9 +487,37 @@
 	return SLIM_P_INPROGRESS;
 }
 
+static int msm_slim_iommu_map(struct msm_slim_ctrl *dev, phys_addr_t iobuf,
+			      u32 len)
+{
+	int ret;
+
+	if (!dev->iommu_desc.cb_dev)
+		return 0;
+
+	ret = iommu_map(dev->iommu_desc.iommu_map->domain,
+			rounddown(iobuf, PAGE_SIZE),
+			rounddown(iobuf, PAGE_SIZE),
+			roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))),
+				PAGE_SIZE), IOMMU_READ | IOMMU_WRITE);
+	return ret;
+}
+
+static void msm_slim_iommu_unmap(struct msm_slim_ctrl *dev, phys_addr_t iobuf,
+				u32 len)
+{
+	if (!dev->iommu_desc.cb_dev)
+		return;
+
+	iommu_unmap(dev->iommu_desc.iommu_map->domain,
+		    rounddown(iobuf, PAGE_SIZE),
+		    roundup((len + (iobuf - rounddown(iobuf, PAGE_SIZE))),
+			    PAGE_SIZE));
+}
+
 static void msm_slim_port_cb(struct sps_event_notify *ev)
 {
-
+	struct msm_slim_ctrl *dev = ev->user;
 	struct completion *comp = ev->data.transfer.user;
 	struct sps_iovec *iovec = &ev->data.transfer.iovec;
 
@@ -450,6 +530,8 @@
 		pr_err("%s: ERR event %d\n",
 					__func__, ev->event_id);
 	}
+	if (dev)
+		msm_slim_iommu_unmap(dev, iovec->addr, iovec->size);
 	if (comp)
 		complete(comp);
 }
@@ -467,14 +549,19 @@
 	if (!dev->pipes[pn].connected)
 		return -ENOTCONN;
 
+	ret = msm_slim_iommu_map(dev, iobuf, len);
+	if (ret)
+		return ret;
+
 	sreg.options = (SPS_EVENT_DESC_DONE|SPS_EVENT_ERROR);
 	sreg.mode = SPS_TRIGGER_WAIT;
 	sreg.xfer_done = NULL;
 	sreg.callback = msm_slim_port_cb;
-	sreg.user = NULL;
+	sreg.user = dev;
 	ret = sps_register_event(dev->pipes[pn].sps, &sreg);
 	if (ret) {
 		dev_dbg(dev->dev, "sps register event error:%x\n", ret);
+		msm_slim_iommu_unmap(dev, iobuf, len);
 		return ret;
 	}
 	ret = sps_transfer_one(dev->pipes[pn].sps, iobuf, len, comp,
@@ -490,6 +577,8 @@
 				PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver));
 		/* Make sure that port registers are updated before returning */
 		mb();
+	} else {
+		msm_slim_iommu_unmap(dev, iobuf, len);
 	}
 
 	return ret;
@@ -1102,6 +1191,12 @@
 	}
 
 init_msgq:
+	ret = msm_slim_iommu_attach(dev);
+	if (ret) {
+		sps_deregister_bam_device(bam_handle);
+		return ret;
+	}
+
 	ret = msm_slim_init_rx_msgq(dev, pipe_reg);
 	if (ret)
 		dev_err(dev->dev, "msm_slim_init_rx_msgq failed 0x%x\n", ret);
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index ee0f625..5859c5f 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2017, 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
@@ -263,10 +263,17 @@
 	bool		in_progress;
 };
 
+struct msm_slim_iommu {
+	struct device			*cb_dev;
+	struct dma_iommu_mapping	*iommu_map;
+	bool				s1_bypass;
+};
+
 struct msm_slim_ctrl {
 	struct slim_controller  ctrl;
 	struct slim_framer	framer;
 	struct device		*dev;
+	struct msm_slim_iommu	iommu_desc;
 	void __iomem		*base;
 	struct resource		*slew_mem;
 	struct resource		*bam_mem;
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index ec85506..121fa34 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -43,6 +43,16 @@
 	  data required to configure LLCC so that clients can start using the
 	  LLCC slices.
 
+config QCOM_SDM670_LLCC
+	tristate "Qualcomm Technologies, Inc. SDM670 LLCC driver"
+	depends on QCOM_LLCC
+	help
+	  This provides Last level cache controller driver for SDM670.
+	  This driver provides data required to configure LLCC, so that clients
+	  can start using the LLCC slices.
+	  Say yes here to enable llcc driver for SDM670.
+
+
 config QCOM_LLCC_AMON
 	tristate "Qualcomm Technologies, Inc. LLCC Activity Monitor(AMON) driver"
 	depends on QCOM_LLCC
@@ -691,3 +701,5 @@
 	  This forces a watchdog bite when the device restarts due to a
 	  kernel panic. On certain MSM SoCs, this provides us
 	  additional debugging information.
+
+source "drivers/soc/qcom/memshare/Kconfig"
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 4c59ca6..64fb7a0 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,8 +1,11 @@
 KASAN_SANITIZE_scm.o := n
+KCOV_INSTRUMENT_scm.o := n
+
 obj-$(CONFIG_QCOM_CPUSS_DUMP) += cpuss_dump.o
 obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
 obj-$(CONFIG_QCOM_LLCC) += llcc-core.o llcc-slice.o
 obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
+obj-$(CONFIG_QCOM_SDM670_LLCC) += llcc-sdm670.o
 obj-$(CONFIG_QCOM_LLCC_AMON) += llcc-amon.o
 obj-$(CONFIG_QPNP_PBS) += qpnp-pbs.o
 obj-$(CONFIG_QCOM_PM)	+=	spm.o
@@ -53,6 +56,7 @@
 obj-$(CONFIG_MSM_SYSMON_GLINK_COMM) += sysmon-glink.o sysmon-qmi.o
 obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o icnss_utils.o
 
+obj-$(CONFIG_MEM_SHARE_QMI_SERVICE)		+= memshare/
 obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o
 obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o
 obj-$(CONFIG_MSM_PIL)   +=      peripheral-loader.o
diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c
index 42f146d..21b2034 100644
--- a/drivers/soc/qcom/dcc_v2.c
+++ b/drivers/soc/qcom/dcc_v2.c
@@ -431,7 +431,7 @@
 				link = 0;
 			}
 
-			prev_off  = off;
+			prev_off  = off + entry->len - 1;
 			prev_addr = addr;
 			}
 		}
@@ -1143,8 +1143,16 @@
 
 	mutex_lock(&drvdata->mutex);
 
-	if (kstrtoul(buf, 16, &loop_cnt))
+	if (kstrtoul(buf, 16, &loop_cnt)) {
 		ret = -EINVAL;
+		goto err;
+	}
+
+	if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
+		dev_err(dev, "Select link list to program using curr_list\n");
+		ret = -EINVAL;
+		goto err;
+	}
 
 	entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
 	if (!entry) {
@@ -1154,6 +1162,7 @@
 
 	entry->loop_cnt = min_t(uint32_t, loop_cnt, MAX_LOOP_CNT);
 	entry->index = drvdata->nr_config[drvdata->curr_list]++;
+	entry->desc_type = DCC_LOOP_TYPE;
 	INIT_LIST_HEAD(&entry->list);
 	list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);
 
@@ -1221,12 +1230,13 @@
 
 	nval = sscanf(buf, "%x %x %d", &addr, &write_val, &apb_bus);
 
-	if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
-		dev_err(dev, "Select link list to program using curr_list\n");
-		return -EINVAL;
+	if (nval <= 1 || nval > 3) {
+		ret = -EINVAL;
+		goto err;
 	}
 
-	if (nval <= 1 || nval > 3) {
+	if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
+		dev_err(dev, "Select link list to program using curr_list\n");
 		ret = -EINVAL;
 		goto err;
 	}
diff --git a/drivers/soc/qcom/early_random.c b/drivers/soc/qcom/early_random.c
index 5156bc1..06601dd 100644
--- a/drivers/soc/qcom/early_random.c
+++ b/drivers/soc/qcom/early_random.c
@@ -56,9 +56,18 @@
 					&desc);
 
 	if (!ret) {
+		u64 bytes_received = desc.ret[0];
+
+		if (bytes_received != SZ_512)
+			pr_warn("Did not receive the expected number of bytes from PRNG: %llu\n",
+				bytes_received);
+
 		dmac_inv_range(random_buffer, random_buffer +
 						RANDOM_BUFFER_SIZE);
-		add_hwgenerator_randomness(random_buffer, SZ_512, SZ_512 << 3);
+		bytes_received = (bytes_received <= RANDOM_BUFFER_SIZE) ?
+					bytes_received : RANDOM_BUFFER_SIZE;
+		add_hwgenerator_randomness(random_buffer, bytes_received,
+					   bytes_received << 3);
 	}
 }
 
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index fd4c604..dcf6654 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -4095,7 +4095,7 @@
 	xprt_ptr = kzalloc(sizeof(*xprt_ptr), GFP_KERNEL);
 	if (!xprt_ptr)
 		return ERR_PTR(-ENOMEM);
-	if_ptr = kmalloc(sizeof(*if_ptr), GFP_KERNEL);
+	if_ptr = kzalloc(sizeof(*if_ptr), GFP_KERNEL);
 	if (!if_ptr) {
 		kfree(xprt_ptr);
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 453faa8..94dffa5 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -869,7 +869,7 @@
 
 	rcu_id = srcu_read_lock(&einfo->use_ref);
 
-	if (unlikely(!einfo->rx_fifo)) {
+	if (unlikely(!einfo->rx_fifo) && atomic_ctx) {
 		if (!get_rx_fifo(einfo)) {
 			srcu_read_unlock(&einfo->use_ref, rcu_id);
 			return;
@@ -2388,7 +2388,7 @@
 	einfo->tx_fifo = smem_alloc(SMEM_GLINK_NATIVE_XPRT_FIFO_0,
 							einfo->tx_fifo_size,
 							einfo->remote_proc_id,
-							SMEM_ITEM_CACHED_FLAG);
+							0);
 	if (!einfo->tx_fifo) {
 		pr_err("%s: smem alloc of tx fifo failed\n", __func__);
 		rc = -ENOMEM;
diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c
index e02c07a..c44aa93 100644
--- a/drivers/soc/qcom/glink_spi_xprt.c
+++ b/drivers/soc/qcom/glink_spi_xprt.c
@@ -111,7 +111,7 @@
  * @xprt_cfg:			The transport configuration for the glink core
  *				assocaited with this edge.
  * @subsys_name:		Name of the remote subsystem in the edge.
- * @spi_dev:			Pointer to the connectingSPI Device.
+ * @spi_ops:			Function pointers for ops provided by spi.
  * @fifo_size:			Size of the FIFO at the remote end.
  * @tx_fifo_start:		Base Address of the TX FIFO.
  * @tx_fifo_end:		End Address of the TX FIFO.
@@ -147,7 +147,7 @@
 	struct glink_transport_if xprt_if;
 	struct glink_core_transport_cfg xprt_cfg;
 	char subsys_name[GLINK_NAME_SIZE];
-	struct spi_device *spi_dev;
+	struct wcd_spi_ops spi_ops;
 
 	uint32_t fifo_size;
 	uint32_t tx_fifo_start;
@@ -286,11 +286,14 @@
 {
 	struct wcd_spi_msg spi_msg;
 
+	if (unlikely(!einfo->spi_ops.read_dev))
+		return -EINVAL;
+
 	memset(&spi_msg, 0, sizeof(spi_msg));
 	spi_msg.data = dst;
 	spi_msg.remote_addr = (uint32_t)(size_t)src;
 	spi_msg.len = (size_t)size;
-	return wcd_spi_data_read(einfo->spi_dev, &spi_msg);
+	return einfo->spi_ops.read_dev(einfo->spi_ops.spi_dev, &spi_msg);
 }
 
 /**
@@ -310,11 +313,14 @@
 {
 	struct wcd_spi_msg spi_msg;
 
+	if (unlikely(!einfo->spi_ops.write_dev))
+		return -EINVAL;
+
 	memset(&spi_msg, 0, sizeof(spi_msg));
 	spi_msg.data = src;
 	spi_msg.remote_addr = (uint32_t)(size_t)dst;
 	spi_msg.len = (size_t)size;
-	return wcd_spi_data_write(einfo->spi_dev, &spi_msg);
+	return einfo->spi_ops.write_dev(einfo->spi_ops.spi_dev, &spi_msg);
 }
 
 /**
@@ -1796,27 +1802,20 @@
 {
 	struct edge_info *einfo = dev_get_drvdata(dev);
 	struct glink_cmpnt *cmpnt = &einfo->cmpnt;
-	struct device *sdev;
-	struct spi_device *spi_dev;
+	int rc = -EINVAL;
 
 	switch (event) {
 	case WDSP_EVENT_PRE_BOOTUP:
 		if (cmpnt && cmpnt->master_dev &&
 		    cmpnt->master_ops &&
-		    cmpnt->master_ops->get_dev_for_cmpnt)
-			sdev = cmpnt->master_ops->get_dev_for_cmpnt(
-				cmpnt->master_dev, WDSP_CMPNT_TRANSPORT);
-		else
-			sdev = NULL;
+		    cmpnt->master_ops->get_devops_for_cmpnt)
+			rc = cmpnt->master_ops->get_devops_for_cmpnt(
+				cmpnt->master_dev, WDSP_CMPNT_TRANSPORT,
+				&einfo->spi_ops);
 
-		if (!sdev) {
+		if (rc)
 			dev_err(dev, "%s: Failed to get transport device\n",
 				__func__);
-			break;
-		}
-
-		spi_dev = to_spi_device(sdev);
-		einfo->spi_dev = spi_dev;
 		break;
 	case WDSP_EVENT_POST_BOOTUP:
 		einfo->in_ssr = false;
diff --git a/drivers/soc/qcom/icnss_utils.c b/drivers/soc/qcom/icnss_utils.c
index a7a0ffa..6974146 100644
--- a/drivers/soc/qcom/icnss_utils.c
+++ b/drivers/soc/qcom/icnss_utils.c
@@ -12,11 +12,13 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <soc/qcom/icnss.h>
 
 #define ICNSS_MAX_CH_NUM 45
 
 static DEFINE_MUTEX(unsafe_channel_list_lock);
 static DEFINE_SPINLOCK(dfs_nol_info_lock);
+static int driver_load_cnt;
 
 static struct icnss_unsafe_channel_list {
 	u16 unsafe_ch_count;
@@ -124,3 +126,15 @@
 	return len;
 }
 EXPORT_SYMBOL(icnss_wlan_get_dfs_nol);
+
+void icnss_increment_driver_load_cnt(void)
+{
+	++driver_load_cnt;
+}
+EXPORT_SYMBOL(icnss_increment_driver_load_cnt);
+
+int icnss_get_driver_load_cnt(void)
+{
+	return driver_load_cnt;
+}
+EXPORT_SYMBOL(icnss_get_driver_load_cnt);
diff --git a/drivers/soc/qcom/llcc-sdm670.c b/drivers/soc/qcom/llcc-sdm670.c
new file mode 100644
index 0000000..68ad755
--- /dev/null
+++ b/drivers/soc/qcom/llcc-sdm670.c
@@ -0,0 +1,103 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/soc/qcom/llcc-qcom.h>
+
+/*
+ * SCT entry contains of the following parameters
+ * name: Name of the client's use case for which the llcc slice is used
+ * uid: Unique id for the client's use case
+ * slice_id: llcc slice id for each client
+ * max_cap: The maximum capacity of the cache slice provided in KB
+ * priority: Priority of the client used to select victim line for replacement
+ * fixed_size: Determine of the slice has a fixed capacity
+ * bonus_ways: Bonus ways to be used by any slice, bonus way is used only if
+ *             it't not a reserved way.
+ * res_ways: Reserved ways for the cache slice, the reserved ways cannot be used
+ *           by any other client than the one its assigned to.
+ * cache_mode: Each slice operates as a cache, this controls the mode of the
+ *             slice normal or TCM
+ * probe_target_ways: Determines what ways to probe for access hit. When
+ *                    configured to 1 only bonus and reseved ways are probed.
+ *                    when configured to 0 all ways in llcc are probed.
+ * dis_cap_alloc: Disable capacity based allocation for a client
+ * retain_on_pc: If this bit is set and client has maitained active vote
+ *               then the ways assigned to this client are not flushed on power
+ *               collapse.
+ * activate_on_init: Activate the slice immidiately after the SCT is programmed
+ */
+#define SCT_ENTRY(n, uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \
+	{					\
+		.name = n,			\
+		.usecase_id = uid,		\
+		.slice_id = sid,		\
+		.max_cap = mc,			\
+		.priority = p,			\
+		.fixed_size = fs,		\
+		.bonus_ways = bway,		\
+		.res_ways = rway,		\
+		.cache_mode = cmod,		\
+		.probe_target_ways = ptw,	\
+		.dis_cap_alloc = dca,		\
+		.retain_on_pc = rp,		\
+		.activate_on_init = a,		\
+	}
+
+static struct llcc_slice_config sdm670_data[] =  {
+	SCT_ENTRY("cpuss", 1, 1, 512, 1, 1, 0xF,  0x0, 0, 0, 0, 1, 1),
+	SCT_ENTRY("vidsc0", 2, 2, 64,  2, 1, 0xF,  0x0, 0, 0, 0, 1, 0),
+	SCT_ENTRY("vidsc1", 3, 3, 64,  2, 1, 0xF,  0x0, 0, 0, 0, 1, 0),
+	SCT_ENTRY("rotator", 4, 4, 384, 2, 1, 0xF,  0x0, 0, 0, 0, 1, 0),
+	SCT_ENTRY("modem",  8, 8, 512, 1, 0, 0xF,  0x0, 0, 0, 0, 1, 0),
+	SCT_ENTRY("gpuhtw", 11, 11, 128, 1, 1, 0xF,  0x0, 0, 0, 0, 1, 0),
+	SCT_ENTRY("gpu",    12, 12, 384, 1, 1, 0xF,  0x0, 0, 0, 0, 1, 0),
+};
+
+static int sdm670_qcom_llcc_probe(struct platform_device *pdev)
+{
+	return qcom_llcc_probe(pdev, sdm670_data,
+				 ARRAY_SIZE(sdm670_data));
+}
+
+static const struct of_device_id sdm670_qcom_llcc_of_match[] = {
+	{ .compatible = "qcom,sdm670-llcc", },
+	{ },
+};
+
+static struct platform_driver sdm670_qcom_llcc_driver = {
+	.driver = {
+		.name = "sdm670-llcc",
+		.owner = THIS_MODULE,
+		.of_match_table = sdm670_qcom_llcc_of_match,
+	},
+	.probe = sdm670_qcom_llcc_probe,
+	.remove = qcom_llcc_remove,
+};
+
+static int __init sdm670_init_qcom_llcc_init(void)
+{
+	return platform_driver_register(&sdm670_qcom_llcc_driver);
+}
+module_init(sdm670_init_qcom_llcc_init);
+
+static void __exit sdm670_exit_qcom_llcc_exit(void)
+{
+	platform_driver_unregister(&sdm670_qcom_llcc_driver);
+}
+module_exit(sdm670_exit_qcom_llcc_exit);
+
+MODULE_DESCRIPTION("QTI sdm670 LLCC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/memshare/Kconfig b/drivers/soc/qcom/memshare/Kconfig
new file mode 100644
index 0000000..7eb1415
--- /dev/null
+++ b/drivers/soc/qcom/memshare/Kconfig
@@ -0,0 +1,9 @@
+config MEM_SHARE_QMI_SERVICE
+       depends on MSM_QMI_INTERFACE
+       bool "Shared Heap for external processors"
+       help
+		Memory Share Kernel Qualcomm Messaging Interface Service
+		receives requests from Modem Processor Sub System
+		for heap alloc/free from Application Processor
+		Sub System and send a response back to client with
+		proper handle/address.
diff --git a/drivers/soc/qcom/memshare/Makefile b/drivers/soc/qcom/memshare/Makefile
new file mode 100644
index 0000000..cf49fbc
--- /dev/null
+++ b/drivers/soc/qcom/memshare/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MEM_SHARE_QMI_SERVICE) := heap_mem_ext_v01.o msm_memshare.o
\ No newline at end of file
diff --git a/drivers/soc/qcom/memshare/heap_mem_ext_v01.c b/drivers/soc/qcom/memshare/heap_mem_ext_v01.c
new file mode 100644
index 0000000..afe9a87
--- /dev/null
+++ b/drivers/soc/qcom/memshare/heap_mem_ext_v01.c
@@ -0,0 +1,472 @@
+/* Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/qmi_encdec.h>
+#include <soc/qcom/msm_qmi_interface.h>
+#include "heap_mem_ext_v01.h"
+
+struct elem_info mem_alloc_req_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct mem_alloc_req_msg_v01,
+					num_bytes),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_alloc_req_msg_v01,
+					block_alignment_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_alloc_req_msg_v01,
+					block_alignment),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info mem_alloc_resp_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_2_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint16_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct mem_alloc_resp_msg_v01,
+					resp),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_alloc_resp_msg_v01,
+					handle_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint64_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_alloc_resp_msg_v01,
+					handle),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct mem_alloc_resp_msg_v01,
+					num_bytes_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct mem_alloc_resp_msg_v01,
+					num_bytes),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info mem_free_req_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint64_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct mem_free_req_msg_v01,
+					handle),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info mem_free_resp_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_2_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint16_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct mem_free_resp_msg_v01,
+					resp),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info dhms_mem_alloc_addr_info_type_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint64_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+		.offset         = offsetof(struct
+					dhms_mem_alloc_addr_info_type_v01,
+					phy_addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+		.offset         = offsetof(struct
+					dhms_mem_alloc_addr_info_type_v01,
+					num_bytes),
+	},
+		{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info mem_alloc_generic_req_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct mem_alloc_generic_req_msg_v01,
+					num_bytes),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct mem_alloc_generic_req_msg_v01,
+					client_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct mem_alloc_generic_req_msg_v01,
+					proc_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x04,
+		.offset         = offsetof(struct mem_alloc_generic_req_msg_v01,
+					sequence_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_alloc_generic_req_msg_v01,
+					alloc_contiguous_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_alloc_generic_req_msg_v01,
+					alloc_contiguous),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct mem_alloc_generic_req_msg_v01,
+					block_alignment_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct mem_alloc_generic_req_msg_v01,
+					block_alignment),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info mem_alloc_generic_resp_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct	qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+						mem_alloc_generic_resp_msg_v01,
+					resp),
+		.ei_array		= get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+						mem_alloc_generic_resp_msg_v01,
+					sequence_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+						mem_alloc_generic_resp_msg_v01,
+					sequence_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+						mem_alloc_generic_resp_msg_v01,
+					dhms_mem_alloc_addr_info_valid),
+	},
+	{
+		.data_type	    = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+						mem_alloc_generic_resp_msg_v01,
+					dhms_mem_alloc_addr_info_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = MAX_ARR_CNT_V01,
+		.elem_size      = sizeof(struct
+					dhms_mem_alloc_addr_info_type_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+						mem_alloc_generic_resp_msg_v01,
+					dhms_mem_alloc_addr_info),
+		.ei_array       = dhms_mem_alloc_addr_info_type_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info mem_free_generic_req_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct mem_free_generic_req_msg_v01,
+					dhms_mem_alloc_addr_info_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = MAX_ARR_CNT_V01,
+		.elem_size      = sizeof(struct
+					dhms_mem_alloc_addr_info_type_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct mem_free_generic_req_msg_v01,
+					dhms_mem_alloc_addr_info),
+		.ei_array		= dhms_mem_alloc_addr_info_type_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_free_generic_req_msg_v01,
+					client_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_free_generic_req_msg_v01,
+					client_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct mem_free_generic_req_msg_v01,
+					proc_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct mem_free_generic_req_msg_v01,
+					proc_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info mem_free_generic_resp_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct	qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+						mem_free_generic_resp_msg_v01,
+					resp),
+		.ei_array		= get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info mem_query_size_req_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct mem_query_size_req_msg_v01,
+					client_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_query_size_req_msg_v01,
+					proc_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_query_size_req_msg_v01,
+					proc_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info mem_query_size_resp_msg_data_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct	qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+						mem_query_size_rsp_msg_v01,
+					resp),
+		.ei_array		= get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint8_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_query_size_rsp_msg_v01,
+					size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(uint32_t),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct mem_query_size_rsp_msg_v01,
+					size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
diff --git a/drivers/soc/qcom/memshare/heap_mem_ext_v01.h b/drivers/soc/qcom/memshare/heap_mem_ext_v01.h
new file mode 100644
index 0000000..cfe3e49
--- /dev/null
+++ b/drivers/soc/qcom/memshare/heap_mem_ext_v01.h
@@ -0,0 +1,356 @@
+/* Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef HEAP_MEM_EXT_SERVICE_01_H
+#define HEAP_MEM_EXT_SERVICE_01_H
+
+#include <soc/qcom/msm_qmi_interface.h>
+
+#define MEM_ALLOC_REQ_MAX_MSG_LEN_V01 255
+#define MEM_FREE_REQ_MAX_MSG_LEN_V01 255
+#define MAX_ARR_CNT_V01 64
+
+struct dhms_mem_alloc_addr_info_type_v01 {
+	uint64_t phy_addr;
+	uint32_t num_bytes;
+};
+
+enum dhms_mem_proc_id_v01 {
+	/* To force a 32 bit signed enum.  Do not change or use */
+	DHMS_MEM_PROC_ID_MIN_ENUM_VAL_V01 = -2147483647,
+	/* Request from MPSS processor */
+	DHMS_MEM_PROC_MPSS_V01 = 0,
+	/* Request from ADSP processor */
+	DHMS_MEM_PROC_ADSP_V01 = 1,
+	/* Request from WCNSS processor */
+	DHMS_MEM_PROC_WCNSS_V01 = 2,
+	/* To force a 32 bit signed enum.  Do not change or use */
+	DHMS_MEM_PROC_ID_MAX_ENUM_VAL_V01 = 2147483647
+};
+
+enum dhms_mem_client_id_v01 {
+	/*To force a 32 bit signed enum.  Do not change or use*/
+	DHMS_MEM_CLIENT_ID_MIN_ENUM_VAL_V01 = -2147483647,
+	/*  Request from GPS Client    */
+	DHMS_MEM_CLIENT_GPS_V01 = 0,
+	/* Invalid Client */
+	DHMS_MEM_CLIENT_INVALID = 1000,
+	/* To force a 32 bit signed enum.  Do not change or use */
+	DHMS_MEM_CLIENT_ID_MAX_ENUM_VAL_V01 = 2147483647
+};
+
+enum dhms_mem_block_align_enum_v01 {
+	/* To force a 32 bit signed enum.  Do not change or use
+	 */
+	DHMS_MEM_BLOCK_ALIGN_ENUM_MIN_ENUM_VAL_V01 = -2147483647,
+	/* Align allocated memory by 2 bytes  */
+	DHMS_MEM_BLOCK_ALIGN_2_V01 = 0,
+	/* Align allocated memory by 4 bytes  */
+	DHMS_MEM_BLOCK_ALIGN_4_V01 = 1,
+	/**<  Align allocated memory by 8 bytes */
+	DHMS_MEM_BLOCK_ALIGN_8_V01 = 2,
+	/**<  Align allocated memory by 16 bytes */
+	DHMS_MEM_BLOCK_ALIGN_16_V01 = 3,
+	/**<  Align allocated memory by 32 bytes */
+	DHMS_MEM_BLOCK_ALIGN_32_V01 = 4,
+	/**<  Align allocated memory by 64 bytes */
+	DHMS_MEM_BLOCK_ALIGN_64_V01 = 5,
+	/**<  Align allocated memory by 128 bytes */
+	DHMS_MEM_BLOCK_ALIGN_128_V01 = 6,
+	/**<  Align allocated memory by 256 bytes */
+	DHMS_MEM_BLOCK_ALIGN_256_V01 = 7,
+	/**<  Align allocated memory by 512 bytes */
+	DHMS_MEM_BLOCK_ALIGN_512_V01 = 8,
+	/**<  Align allocated memory by 1024 bytes */
+	DHMS_MEM_BLOCK_ALIGN_1K_V01 = 9,
+	/**<  Align allocated memory by 2048 bytes */
+	DHMS_MEM_BLOCK_ALIGN_2K_V01 = 10,
+	/**<  Align allocated memory by 4096 bytes */
+	DHMS_MEM_BLOCK_ALIGN_4K_V01 = 11,
+	DHMS_MEM_BLOCK_ALIGN_ENUM_MAX_ENUM_VAL_V01 = 2147483647
+	/* To force a 32 bit signed enum.  Do not change or use
+	 */
+};
+
+/* Request Message; This command is used for getting
+ * the multiple physically contiguous
+ * memory blocks from the server memory subsystem
+ */
+struct mem_alloc_req_msg_v01 {
+
+	/* Mandatory */
+	/*requested size*/
+	uint32_t num_bytes;
+
+	/* Optional */
+	/* Must be set to true if block_alignment
+	 * is being passed
+	 */
+	uint8_t block_alignment_valid;
+	/* The block alignment for the memory block to be allocated
+	 */
+	enum dhms_mem_block_align_enum_v01 block_alignment;
+};  /* Message */
+
+/* Response Message; This command is used for getting
+ * the multiple physically contiguous memory blocks
+ * from the server memory subsystem
+ */
+struct mem_alloc_resp_msg_v01 {
+
+	/* Mandatory */
+	/*  Result Code */
+	/* The result of the requested memory operation
+	 */
+	enum qmi_result_type_v01 resp;
+	/* Optional */
+	/*  Memory Block Handle
+	 */
+	/* Must be set to true if handle is being passed
+	 */
+	uint8_t handle_valid;
+	/* The physical address of the memory allocated on the HLOS
+	 */
+	uint64_t handle;
+	/* Optional */
+	/* Memory block size */
+	/* Must be set to true if num_bytes is being passed
+	 */
+	uint8_t num_bytes_valid;
+	/* The number of bytes actually allocated for the request.
+	 * This value can be smaller than the size requested in
+	 * QMI_DHMS_MEM_ALLOC_REQ_MSG.
+	 */
+	uint32_t num_bytes;
+};  /* Message */
+
+/* Request Message; This command is used for releasing
+ * the multiple physically contiguous
+ * memory blocks to the server memory subsystem
+ */
+struct mem_free_req_msg_v01 {
+
+	/* Mandatory */
+	/* Physical address of memory to be freed
+	 */
+	uint32_t handle;
+};  /* Message */
+
+/* Response Message; This command is used for releasing
+ * the multiple physically contiguous
+ * memory blocks to the server memory subsystem
+ */
+struct mem_free_resp_msg_v01 {
+
+	/* Mandatory */
+	/* Result of the requested memory operation, todo,
+	 * need to check the async operation for free
+	 */
+	enum qmi_result_type_v01 resp;
+};  /* Message */
+
+/* Request Message; This command is used for getting
+ * the multiple physically contiguous
+ * memory blocks from the server memory subsystem
+ */
+struct mem_alloc_generic_req_msg_v01 {
+
+	/* Mandatory */
+	/*requested size*/
+	uint32_t num_bytes;
+
+	/* Mandatory */
+	/* client id */
+	enum dhms_mem_client_id_v01 client_id;
+
+	/* Mandatory */
+	/* Peripheral Id*/
+	enum dhms_mem_proc_id_v01 proc_id;
+
+	/* Mandatory */
+	/* Sequence id */
+	uint32_t sequence_id;
+
+	/* Optional */
+	/*  alloc_contiguous */
+	/* Must be set to true if alloc_contiguous is being passed */
+	uint8_t alloc_contiguous_valid;
+
+	/* Alloc_contiguous is used to identify that clients are requesting
+	 * for contiguous or non contiguous memory, default is contiguous
+	 * 0 = non contiguous else contiguous
+	 */
+	uint8_t alloc_contiguous;
+
+	/* Optional */
+	/* Must be set to true if block_alignment
+	 * is being passed
+	 */
+	uint8_t block_alignment_valid;
+
+	/* The block alignment for the memory block to be allocated
+	 */
+	enum dhms_mem_block_align_enum_v01 block_alignment;
+
+};  /* Message */
+
+/* Response Message; This command is used for getting
+ * the multiple physically contiguous memory blocks
+ * from the server memory subsystem
+ */
+struct mem_alloc_generic_resp_msg_v01 {
+
+	/* Mandatory */
+	/*  Result Code */
+	/* The result of the requested memory operation
+	 */
+	struct qmi_response_type_v01 resp;
+
+	/* Optional */
+	/* Sequence ID */
+	/* Must be set to true if sequence_id is being passed */
+	uint8_t sequence_id_valid;
+
+
+	/* Mandatory */
+	/* Sequence id */
+	uint32_t sequence_id;
+
+	/* Optional */
+	/*  Memory Block Handle
+	 */
+	/* Must be set to true if handle is being passed
+	 */
+	uint8_t dhms_mem_alloc_addr_info_valid;
+
+	/* Optional */
+	/* Handle Size */
+	uint32_t dhms_mem_alloc_addr_info_len;
+
+	/* Optional */
+	/* The physical address of the memory allocated on the HLOS
+	 */
+	struct dhms_mem_alloc_addr_info_type_v01
+		dhms_mem_alloc_addr_info[MAX_ARR_CNT_V01];
+
+};  /* Message */
+
+/* Request Message; This command is used for releasing
+ * the multiple physically contiguous
+ * memory blocks to the server memory subsystem
+ */
+struct mem_free_generic_req_msg_v01 {
+
+	/* Mandatory */
+	/* Must be set to # of  elments in array*/
+	uint32_t dhms_mem_alloc_addr_info_len;
+
+	/* Mandatory */
+	/* Physical address and size of the memory allocated
+	 * on the HLOS to be freed.
+	 */
+	struct dhms_mem_alloc_addr_info_type_v01
+			dhms_mem_alloc_addr_info[MAX_ARR_CNT_V01];
+
+	/* Optional */
+	/* Client ID */
+	/* Must be set to true if client_id is being passed */
+	uint8_t client_id_valid;
+
+	/* Optional */
+	/* Client Id */
+	enum dhms_mem_client_id_v01 client_id;
+
+	/* Optional */
+	/* Proc ID */
+	/* Must be set to true if proc_id is being passed */
+	uint8_t proc_id_valid;
+
+	/* Optional */
+	/* Peripheral */
+	enum dhms_mem_proc_id_v01 proc_id;
+
+};  /* Message */
+
+/* Response Message; This command is used for releasing
+ * the multiple physically contiguous
+ * memory blocks to the server memory subsystem
+ */
+struct mem_free_generic_resp_msg_v01 {
+
+	/*
+	 * Mandatory
+	 * Result of the requested memory operation, todo,
+	 * need to check the async operation for free
+	 */
+	struct qmi_response_type_v01 resp;
+
+};  /* Message */
+
+struct mem_query_size_req_msg_v01 {
+
+	/* Mandatory */
+	enum dhms_mem_client_id_v01 client_id;
+
+	/*
+	 * Optional
+	 * Proc ID
+	 * proc_id_valid must be set to true if proc_id is being passed
+	 */
+	uint8_t proc_id_valid;
+
+	enum dhms_mem_proc_id_v01 proc_id;
+};  /* Message */
+
+struct mem_query_size_rsp_msg_v01 {
+
+	/*
+	 * Mandatory
+	 * Result Code
+	 */
+	struct qmi_response_type_v01 resp;
+
+	/*
+	 * Optional
+	 * size_valid must be set to true if size is being passed
+	 */
+	uint8_t size_valid;
+
+	uint32_t size;
+};  /* Message */
+
+
+extern struct elem_info mem_alloc_req_msg_data_v01_ei[];
+extern struct elem_info mem_alloc_resp_msg_data_v01_ei[];
+extern struct elem_info mem_free_req_msg_data_v01_ei[];
+extern struct elem_info mem_free_resp_msg_data_v01_ei[];
+extern struct elem_info mem_alloc_generic_req_msg_data_v01_ei[];
+extern struct elem_info mem_alloc_generic_resp_msg_data_v01_ei[];
+extern struct elem_info mem_free_generic_req_msg_data_v01_ei[];
+extern struct elem_info mem_free_generic_resp_msg_data_v01_ei[];
+extern struct elem_info mem_query_size_req_msg_data_v01_ei[];
+extern struct elem_info mem_query_size_resp_msg_data_v01_ei[];
+
+/*Service Message Definition*/
+#define MEM_ALLOC_REQ_MSG_V01 0x0020
+#define MEM_ALLOC_RESP_MSG_V01 0x0020
+#define MEM_FREE_REQ_MSG_V01 0x0021
+#define MEM_FREE_RESP_MSG_V01 0x0021
+#define MEM_ALLOC_GENERIC_REQ_MSG_V01 0x0022
+#define MEM_ALLOC_GENERIC_RESP_MSG_V01 0x0022
+#define MEM_FREE_GENERIC_REQ_MSG_V01 0x0023
+#define MEM_FREE_GENERIC_RESP_MSG_V01 0x0023
+#define MEM_QUERY_SIZE_REQ_MSG_V01	0x0024
+#define MEM_QUERY_SIZE_RESP_MSG_V01	0x0024
+
+#endif
diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c
new file mode 100644
index 0000000..7298f30
--- /dev/null
+++ b/drivers/soc/qcom/memshare/msm_memshare.c
@@ -0,0 +1,1074 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/notifier.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/msm_qmi_interface.h>
+#include <soc/qcom/scm.h>
+#include "msm_memshare.h"
+#include "heap_mem_ext_v01.h"
+
+#include <soc/qcom/secure_buffer.h>
+#include <soc/qcom/ramdump.h>
+
+/* Macros */
+#define MEMSHARE_DEV_NAME "memshare"
+#define MEMSHARE_CHILD_DEV_NAME "memshare_child"
+static unsigned long(attrs);
+
+static struct qmi_handle *mem_share_svc_handle;
+static void mem_share_svc_recv_msg(struct work_struct *work);
+static DECLARE_DELAYED_WORK(work_recv_msg, mem_share_svc_recv_msg);
+static struct workqueue_struct *mem_share_svc_workqueue;
+static uint64_t bootup_request;
+static bool ramdump_event;
+static void *memshare_ramdump_dev[MAX_CLIENTS];
+static struct device *memshare_dev[MAX_CLIENTS];
+
+/* Memshare Driver Structure */
+struct memshare_driver {
+	struct device *dev;
+	struct mutex mem_share;
+	struct mutex mem_free;
+	struct work_struct memshare_init_work;
+};
+
+struct memshare_child {
+	struct device *dev;
+};
+
+static struct memshare_driver *memsh_drv;
+static struct memshare_child *memsh_child;
+static struct mem_blocks memblock[MAX_CLIENTS];
+static uint32_t num_clients;
+static struct msg_desc mem_share_svc_alloc_req_desc = {
+	.max_msg_len = MEM_ALLOC_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_ALLOC_REQ_MSG_V01,
+	.ei_array = mem_alloc_req_msg_data_v01_ei,
+};
+
+static struct msg_desc mem_share_svc_alloc_resp_desc = {
+	.max_msg_len = MEM_ALLOC_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_ALLOC_RESP_MSG_V01,
+	.ei_array = mem_alloc_resp_msg_data_v01_ei,
+};
+
+static struct msg_desc mem_share_svc_free_req_desc = {
+	.max_msg_len = MEM_FREE_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_FREE_REQ_MSG_V01,
+	.ei_array = mem_free_req_msg_data_v01_ei,
+};
+
+static struct msg_desc mem_share_svc_free_resp_desc = {
+	.max_msg_len = MEM_FREE_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_FREE_RESP_MSG_V01,
+	.ei_array = mem_free_resp_msg_data_v01_ei,
+};
+
+static struct msg_desc mem_share_svc_alloc_generic_req_desc = {
+	.max_msg_len = MEM_ALLOC_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_ALLOC_GENERIC_REQ_MSG_V01,
+	.ei_array = mem_alloc_generic_req_msg_data_v01_ei,
+};
+
+static struct msg_desc mem_share_svc_alloc_generic_resp_desc = {
+	.max_msg_len = MEM_ALLOC_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_ALLOC_GENERIC_RESP_MSG_V01,
+	.ei_array = mem_alloc_generic_resp_msg_data_v01_ei,
+};
+
+static struct msg_desc mem_share_svc_free_generic_req_desc = {
+	.max_msg_len = MEM_FREE_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_FREE_GENERIC_REQ_MSG_V01,
+	.ei_array = mem_free_generic_req_msg_data_v01_ei,
+};
+
+static struct msg_desc mem_share_svc_free_generic_resp_desc = {
+	.max_msg_len = MEM_FREE_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_FREE_GENERIC_RESP_MSG_V01,
+	.ei_array = mem_free_generic_resp_msg_data_v01_ei,
+};
+
+static struct msg_desc mem_share_svc_size_query_req_desc = {
+	.max_msg_len = MEM_FREE_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_QUERY_SIZE_REQ_MSG_V01,
+	.ei_array = mem_query_size_req_msg_data_v01_ei,
+};
+
+static struct msg_desc mem_share_svc_size_query_resp_desc = {
+	.max_msg_len = MEM_FREE_REQ_MAX_MSG_LEN_V01,
+	.msg_id = MEM_QUERY_SIZE_RESP_MSG_V01,
+	.ei_array = mem_query_size_resp_msg_data_v01_ei,
+};
+
+/*
+ *  This API creates ramdump dev handlers
+ *  for each of the memshare clients.
+ *  These dev handlers will be used for
+ *  extracting the ramdump for loaned memory
+ *  segments.
+ */
+
+static int mem_share_configure_ramdump(int client)
+{
+	char client_name[18];
+	const char *clnt = NULL;
+
+	switch (client) {
+	case 0:
+		clnt = "GPS";
+		break;
+	case 1:
+		clnt = "FTM";
+		break;
+	case 2:
+		clnt = "DIAG";
+		break;
+	default:
+		pr_err("memshare: no memshare clients registered\n");
+		return -EINVAL;
+	}
+
+	snprintf(client_name, sizeof(client_name),
+		"memshare_%s", clnt);
+	if (memshare_dev[client]) {
+		memshare_ramdump_dev[client] =
+			create_ramdump_device(client_name,
+				memshare_dev[client]);
+	} else {
+		pr_err("memshare:%s: invalid memshare device\n", __func__);
+		return -ENODEV;
+	}
+	if (IS_ERR_OR_NULL(memshare_ramdump_dev[client])) {
+		pr_err("memshare: %s: Unable to create memshare ramdump device\n",
+				__func__);
+		memshare_ramdump_dev[client] = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int check_client(int client_id, int proc, int request)
+{
+	int i = 0, rc;
+	int found = DHMS_MEM_CLIENT_INVALID;
+
+	for (i = 0; i < MAX_CLIENTS; i++) {
+		if (memblock[i].client_id == client_id &&
+				memblock[i].peripheral == proc) {
+			found = i;
+			break;
+		}
+	}
+	if ((found == DHMS_MEM_CLIENT_INVALID) && !request) {
+		pr_debug("memshare: No registered client, adding a new client\n");
+		/* Add a new client */
+		for (i = 0; i < MAX_CLIENTS; i++) {
+			if (memblock[i].client_id == DHMS_MEM_CLIENT_INVALID) {
+				memblock[i].client_id = client_id;
+				memblock[i].allotted = 0;
+				memblock[i].guarantee = 0;
+				memblock[i].peripheral = proc;
+				found = i;
+
+				if (!memblock[i].file_created) {
+					rc = mem_share_configure_ramdump(i);
+					if (rc)
+						pr_err("memshare: %s, Cannot create ramdump for client: %d\n",
+							__func__, client_id);
+					else
+						memblock[i].file_created = 1;
+				}
+
+				break;
+			}
+		}
+	}
+
+	return found;
+}
+
+static void free_client(int id)
+{
+	memblock[id].phy_addr = 0;
+	memblock[id].virtual_addr = 0;
+	memblock[id].allotted = 0;
+	memblock[id].guarantee = 0;
+	memblock[id].sequence_id = -1;
+	memblock[id].memory_type = MEMORY_CMA;
+
+}
+
+static void fill_alloc_response(struct mem_alloc_generic_resp_msg_v01 *resp,
+						int id, int *flag)
+{
+	resp->sequence_id_valid = 1;
+	resp->sequence_id = memblock[id].sequence_id;
+	resp->dhms_mem_alloc_addr_info_valid = 1;
+	resp->dhms_mem_alloc_addr_info_len = 1;
+	resp->dhms_mem_alloc_addr_info[0].phy_addr = memblock[id].phy_addr;
+	resp->dhms_mem_alloc_addr_info[0].num_bytes = memblock[id].size;
+	if (!*flag) {
+		resp->resp.result = QMI_RESULT_SUCCESS_V01;
+		resp->resp.error = QMI_ERR_NONE_V01;
+	} else {
+		resp->resp.result = QMI_RESULT_FAILURE_V01;
+		resp->resp.error = QMI_ERR_NO_MEMORY_V01;
+	}
+
+}
+
+static void initialize_client(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_CLIENTS; i++) {
+		memblock[i].allotted = 0;
+		memblock[i].size = 0;
+		memblock[i].guarantee = 0;
+		memblock[i].phy_addr = 0;
+		memblock[i].virtual_addr = 0;
+		memblock[i].client_id = DHMS_MEM_CLIENT_INVALID;
+		memblock[i].peripheral = -1;
+		memblock[i].sequence_id = -1;
+		memblock[i].memory_type = MEMORY_CMA;
+		memblock[i].free_memory = 0;
+		memblock[i].hyp_mapping = 0;
+		memblock[i].file_created = 0;
+	}
+	attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
+}
+
+/*
+ *  mem_share_do_ramdump() function initializes the
+ *  ramdump segments with the physical address and
+ *  size of the memshared clients. Extraction of ramdump
+ *  is skipped if memshare client is not allotted
+ *  This calls the ramdump api in extracting the
+ *  ramdump in elf format.
+ */
+
+static int mem_share_do_ramdump(void)
+{
+	int i = 0, ret;
+	char *client_name = NULL;
+
+	for (i = 0; i < num_clients; i++) {
+
+		struct ramdump_segment *ramdump_segments_tmp = NULL;
+
+		switch (i) {
+		case 0:
+			client_name = "GPS";
+			break;
+		case 1:
+			client_name = "FTM";
+			break;
+		case 2:
+			client_name = "DIAG";
+			break;
+		default:
+			pr_err("memshare: no memshare clients registered\n");
+			return -EINVAL;
+		}
+
+		if (!memblock[i].allotted) {
+			pr_err("memshare:%s memblock is not allotted\n",
+			client_name);
+			continue;
+		}
+
+		ramdump_segments_tmp = kcalloc(1,
+			sizeof(struct ramdump_segment),
+			GFP_KERNEL);
+		if (!ramdump_segments_tmp)
+			return -ENOMEM;
+
+		ramdump_segments_tmp[0].size = memblock[i].size;
+		ramdump_segments_tmp[0].address = memblock[i].phy_addr;
+
+		pr_debug("memshare: %s:%s client:id: %d:size = %d\n",
+		__func__, client_name, i, memblock[i].size);
+
+		ret = do_elf_ramdump(memshare_ramdump_dev[i],
+					ramdump_segments_tmp, 1);
+		kfree(ramdump_segments_tmp);
+		if (ret < 0) {
+			pr_err("memshare: Unable to dump: %d\n", ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+					void *_cmd)
+{
+	int i;
+	int ret;
+	u32 source_vmlist[2] = {VMID_HLOS, VMID_MSS_MSA};
+	int dest_vmids[1] = {VMID_HLOS};
+	int dest_perms[1] = {PERM_READ|PERM_WRITE|PERM_EXEC};
+	struct notif_data *notifdata = NULL;
+
+	mutex_lock(&memsh_drv->mem_share);
+
+	switch (code) {
+
+	case SUBSYS_BEFORE_SHUTDOWN:
+		bootup_request++;
+		break;
+
+	case SUBSYS_RAMDUMP_NOTIFICATION:
+		ramdump_event = 1;
+		break;
+
+	case SUBSYS_BEFORE_POWERUP:
+		if (_cmd) {
+			notifdata = (struct notif_data *) _cmd;
+		} else {
+			ramdump_event = 0;
+			break;
+		}
+
+		if (notifdata->enable_ramdump && ramdump_event) {
+			pr_debug("memshare: %s, Ramdump collection is enabled\n",
+					__func__);
+			ret = mem_share_do_ramdump();
+			if (ret)
+				pr_err("memshare: Ramdump collection failed\n");
+			ramdump_event = 0;
+		}
+		break;
+
+	case SUBSYS_AFTER_POWERUP:
+		pr_debug("memshare: Modem has booted up\n");
+		for (i = 0; i < MAX_CLIENTS; i++) {
+			if (memblock[i].free_memory > 0 &&
+					bootup_request >= 2) {
+				memblock[i].free_memory -= 1;
+				pr_debug("memshare: free_memory count: %d for client id: %d\n",
+					memblock[i].free_memory,
+					memblock[i].client_id);
+			}
+
+			if (memblock[i].free_memory == 0) {
+				if (memblock[i].peripheral ==
+					DHMS_MEM_PROC_MPSS_V01 &&
+					!memblock[i].guarantee &&
+					memblock[i].allotted) {
+					pr_debug("memshare: hypervisor unmapping  for client id: %d\n",
+						memblock[i].client_id);
+					ret = hyp_assign_phys(
+							memblock[i].phy_addr,
+							memblock[i].size,
+							source_vmlist,
+							2, dest_vmids,
+							dest_perms, 1);
+					if (ret &&
+						memblock[i].hyp_mapping == 1) {
+						/*
+						 * This is an error case as hyp
+						 * mapping was successful
+						 * earlier but during unmap
+						 * it lead to failure.
+						 */
+						pr_err("memshare: %s, failed to unmap the region\n",
+							__func__);
+						memblock[i].hyp_mapping = 1;
+					} else {
+						memblock[i].hyp_mapping = 0;
+					}
+					dma_free_attrs(memsh_drv->dev,
+						memblock[i].size,
+						memblock[i].virtual_addr,
+						memblock[i].phy_addr,
+						attrs);
+					free_client(i);
+				}
+			}
+		}
+		bootup_request++;
+		break;
+
+	default:
+		break;
+	}
+
+	mutex_unlock(&memsh_drv->mem_share);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nb = {
+	.notifier_call = modem_notifier_cb,
+};
+
+static void shared_hyp_mapping(int client_id)
+{
+	int ret;
+	u32 source_vmlist[1] = {VMID_HLOS};
+	int dest_vmids[2] = {VMID_HLOS, VMID_MSS_MSA};
+	int dest_perms[2] = {PERM_READ|PERM_WRITE,
+				PERM_READ|PERM_WRITE};
+
+	if (client_id == DHMS_MEM_CLIENT_INVALID) {
+		pr_err("memshare: %s, Invalid Client\n", __func__);
+		return;
+	}
+
+	ret = hyp_assign_phys(memblock[client_id].phy_addr,
+			memblock[client_id].size,
+			source_vmlist, 1, dest_vmids,
+			dest_perms, 2);
+
+	if (ret != 0) {
+		pr_err("memshare: hyp_assign_phys failed size=%u err=%d\n",
+				memblock[client_id].size, ret);
+		return;
+	}
+	memblock[client_id].hyp_mapping = 1;
+}
+
+static int handle_alloc_req(void *req_h, void *req, void *conn_h)
+{
+	struct mem_alloc_req_msg_v01 *alloc_req;
+	struct mem_alloc_resp_msg_v01 alloc_resp;
+	int rc = 0;
+
+	mutex_lock(&memsh_drv->mem_share);
+	alloc_req = (struct mem_alloc_req_msg_v01 *)req;
+	pr_debug("memshare: %s: Received Alloc Request: alloc_req->num_bytes = %d\n",
+		__func__, alloc_req->num_bytes);
+	if (!memblock[GPS].size) {
+		memset(&alloc_resp, 0, sizeof(alloc_resp));
+		alloc_resp.resp = QMI_RESULT_FAILURE_V01;
+		rc = memshare_alloc(memsh_drv->dev, alloc_req->num_bytes,
+					&memblock[GPS]);
+	}
+	alloc_resp.num_bytes_valid = 1;
+	alloc_resp.num_bytes =  alloc_req->num_bytes;
+	alloc_resp.handle_valid = 1;
+	alloc_resp.handle = memblock[GPS].phy_addr;
+	if (rc) {
+		alloc_resp.resp = QMI_RESULT_FAILURE_V01;
+		memblock[GPS].size = 0;
+	} else {
+		alloc_resp.resp = QMI_RESULT_SUCCESS_V01;
+	}
+
+	mutex_unlock(&memsh_drv->mem_share);
+
+	pr_debug("memshare: %s, alloc_resp.num_bytes :%d, alloc_resp.resp :%lx\n",
+			  __func__, alloc_resp.num_bytes,
+			  (unsigned long int)alloc_resp.resp);
+	rc = qmi_send_resp_from_cb(mem_share_svc_handle, conn_h, req_h,
+			&mem_share_svc_alloc_resp_desc, &alloc_resp,
+			sizeof(alloc_resp));
+	if (rc < 0)
+		pr_err("memshare: %s, Error sending the alloc request: %d\n",
+					__func__, rc);
+
+	return rc;
+}
+
+static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h)
+{
+	struct mem_alloc_generic_req_msg_v01 *alloc_req;
+	struct mem_alloc_generic_resp_msg_v01 *alloc_resp;
+	int rc, resp = 0;
+	int client_id;
+
+	mutex_lock(&memsh_drv->mem_share);
+	alloc_req = (struct mem_alloc_generic_req_msg_v01 *)req;
+	pr_debug("memshare: alloc request client id: %d proc _id: %d\n",
+			alloc_req->client_id, alloc_req->proc_id);
+	alloc_resp = kzalloc(sizeof(*alloc_resp),
+					GFP_KERNEL);
+	if (!alloc_resp) {
+		mutex_unlock(&memsh_drv->mem_share);
+		return -ENOMEM;
+	}
+	alloc_resp->resp.result = QMI_RESULT_FAILURE_V01;
+	alloc_resp->resp.error = QMI_ERR_NO_MEMORY_V01;
+	client_id = check_client(alloc_req->client_id, alloc_req->proc_id,
+								CHECK);
+
+	if (client_id >= MAX_CLIENTS) {
+		pr_err("memshare: %s client not found, requested client: %d, proc_id: %d\n",
+				__func__, alloc_req->client_id,
+				alloc_req->proc_id);
+		kfree(alloc_resp);
+		alloc_resp = NULL;
+		mutex_unlock(&memsh_drv->mem_share);
+		return -EINVAL;
+	}
+
+	memblock[client_id].free_memory += 1;
+	pr_debug("memshare: %s, free memory count for client id: %d = %d",
+		__func__, memblock[client_id].client_id,
+			memblock[client_id].free_memory);
+	if (!memblock[client_id].allotted) {
+		rc = memshare_alloc(memsh_drv->dev, alloc_req->num_bytes,
+					&memblock[client_id]);
+		if (rc) {
+			pr_err("memshare: %s,Unable to allocate memory for requested client\n",
+							__func__);
+			resp = 1;
+		}
+		if (!resp) {
+			memblock[client_id].allotted = 1;
+			memblock[client_id].size = alloc_req->num_bytes;
+			memblock[client_id].peripheral = alloc_req->proc_id;
+		}
+	}
+	memblock[client_id].sequence_id = alloc_req->sequence_id;
+
+	fill_alloc_response(alloc_resp, client_id, &resp);
+	/*
+	 * Perform the Hypervisor mapping in order to avoid XPU viloation
+	 * to the allocated region for Modem Clients
+	 */
+	if (!memblock[client_id].hyp_mapping &&
+		memblock[client_id].allotted)
+		shared_hyp_mapping(client_id);
+	mutex_unlock(&memsh_drv->mem_share);
+	pr_debug("memshare: alloc_resp.num_bytes :%d, alloc_resp.resp.result :%lx\n",
+			  alloc_resp->dhms_mem_alloc_addr_info[0].num_bytes,
+			  (unsigned long int)alloc_resp->resp.result);
+	rc = qmi_send_resp_from_cb(mem_share_svc_handle, conn_h, req_h,
+			&mem_share_svc_alloc_generic_resp_desc, alloc_resp,
+			sizeof(alloc_resp));
+
+	if (rc < 0)
+		pr_err("memshare: %s, Error sending the alloc request: %d\n",
+							__func__, rc);
+
+	kfree(alloc_resp);
+	alloc_resp = NULL;
+	return rc;
+}
+
+static int handle_free_req(void *req_h, void *req, void *conn_h)
+{
+	struct mem_free_req_msg_v01 *free_req;
+	struct mem_free_resp_msg_v01 free_resp;
+	int rc;
+
+	mutex_lock(&memsh_drv->mem_free);
+	if (!memblock[GPS].guarantee) {
+		free_req = (struct mem_free_req_msg_v01 *)req;
+		pr_debug("memshare: %s: Received Free Request\n", __func__);
+		memset(&free_resp, 0, sizeof(free_resp));
+		dma_free_coherent(memsh_drv->dev, memblock[GPS].size,
+			memblock[GPS].virtual_addr,
+				free_req->handle);
+	}
+	free_resp.resp = QMI_RESULT_SUCCESS_V01;
+	mutex_unlock(&memsh_drv->mem_free);
+	rc = qmi_send_resp_from_cb(mem_share_svc_handle, conn_h, req_h,
+			&mem_share_svc_free_resp_desc, &free_resp,
+			sizeof(free_resp));
+	if (rc < 0)
+		pr_err("memshare: %s, Error sending the free request: %d\n",
+					__func__, rc);
+
+	return rc;
+}
+
+static int handle_free_generic_req(void *req_h, void *req, void *conn_h)
+{
+	struct mem_free_generic_req_msg_v01 *free_req;
+	struct mem_free_generic_resp_msg_v01 free_resp;
+	int rc;
+	int flag = 0;
+	uint32_t client_id;
+
+	mutex_lock(&memsh_drv->mem_free);
+	free_req = (struct mem_free_generic_req_msg_v01 *)req;
+	pr_debug("memshare: %s: Received Free Request\n", __func__);
+	memset(&free_resp, 0, sizeof(free_resp));
+	free_resp.resp.error = QMI_ERR_INTERNAL_V01;
+	free_resp.resp.result = QMI_RESULT_FAILURE_V01;
+	pr_debug("memshare: Client id: %d proc id: %d\n", free_req->client_id,
+				free_req->proc_id);
+	client_id = check_client(free_req->client_id, free_req->proc_id, FREE);
+	if (client_id == DHMS_MEM_CLIENT_INVALID) {
+		pr_err("memshare: %s, Invalid client request to free memory\n",
+					__func__);
+		flag = 1;
+	} else if (!memblock[client_id].guarantee &&
+					memblock[client_id].allotted) {
+		pr_debug("memshare: %s: size: %d",
+				__func__, memblock[client_id].size);
+		dma_free_attrs(memsh_drv->dev, memblock[client_id].size,
+			memblock[client_id].virtual_addr,
+			memblock[client_id].phy_addr,
+			attrs);
+		free_client(client_id);
+	} else {
+		pr_err("memshare: %s, Request came for a guaranteed client cannot free up the memory\n",
+						__func__);
+	}
+
+	if (flag) {
+		free_resp.resp.result = QMI_RESULT_FAILURE_V01;
+		free_resp.resp.error = QMI_ERR_INVALID_ID_V01;
+	} else {
+		free_resp.resp.result = QMI_RESULT_SUCCESS_V01;
+		free_resp.resp.error = QMI_ERR_NONE_V01;
+	}
+
+	mutex_unlock(&memsh_drv->mem_free);
+	rc = qmi_send_resp_from_cb(mem_share_svc_handle, conn_h, req_h,
+		&mem_share_svc_free_generic_resp_desc, &free_resp,
+		sizeof(free_resp));
+
+	if (rc < 0)
+		pr_err("memshare: %s, Error sending the free request: %d\n",
+					__func__, rc);
+
+	return rc;
+}
+
+static int handle_query_size_req(void *req_h, void *req, void *conn_h)
+{
+	int rc, client_id;
+	struct mem_query_size_req_msg_v01 *query_req;
+	struct mem_query_size_rsp_msg_v01 *query_resp;
+
+	mutex_lock(&memsh_drv->mem_share);
+	query_req = (struct mem_query_size_req_msg_v01 *)req;
+	query_resp = kzalloc(sizeof(*query_resp),
+					GFP_KERNEL);
+	if (!query_resp) {
+		mutex_unlock(&memsh_drv->mem_share);
+		return -ENOMEM;
+	}
+	pr_debug("memshare: query request client id: %d proc _id: %d\n",
+		query_req->client_id, query_req->proc_id);
+	client_id = check_client(query_req->client_id, query_req->proc_id,
+								CHECK);
+
+	if (client_id >= MAX_CLIENTS) {
+		pr_err("memshare: %s client not found, requested client: %d, proc_id: %d\n",
+				__func__, query_req->client_id,
+				query_req->proc_id);
+		kfree(query_resp);
+		query_resp = NULL;
+		mutex_unlock(&memsh_drv->mem_share);
+		return -EINVAL;
+	}
+
+	if (memblock[client_id].size) {
+		query_resp->size_valid = 1;
+		query_resp->size = memblock[client_id].size;
+	} else {
+		query_resp->size_valid = 1;
+		query_resp->size = 0;
+	}
+	query_resp->resp.result = QMI_RESULT_SUCCESS_V01;
+	query_resp->resp.error = QMI_ERR_NONE_V01;
+	mutex_unlock(&memsh_drv->mem_share);
+
+	pr_debug("memshare: query_resp.size :%d, query_resp.resp.result :%lx\n",
+			  query_resp->size,
+			  (unsigned long int)query_resp->resp.result);
+	rc = qmi_send_resp_from_cb(mem_share_svc_handle, conn_h, req_h,
+			&mem_share_svc_size_query_resp_desc, query_resp,
+			sizeof(query_resp));
+
+	if (rc < 0)
+		pr_err("memshare: %s, Error sending the query request: %d\n",
+							__func__, rc);
+
+	kfree(query_resp);
+	query_resp = NULL;
+	return rc;
+}
+
+static int mem_share_svc_connect_cb(struct qmi_handle *handle,
+			       void *conn_h)
+{
+	if (mem_share_svc_handle != handle || !conn_h)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mem_share_svc_disconnect_cb(struct qmi_handle *handle,
+				  void *conn_h)
+{
+	if (mem_share_svc_handle != handle || !conn_h)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mem_share_svc_req_desc_cb(unsigned int msg_id,
+				struct msg_desc **req_desc)
+{
+	int rc;
+
+	pr_debug("memshare: %s\n", __func__);
+	switch (msg_id) {
+	case MEM_ALLOC_REQ_MSG_V01:
+		*req_desc = &mem_share_svc_alloc_req_desc;
+		rc = sizeof(struct mem_alloc_req_msg_v01);
+		break;
+
+	case MEM_FREE_REQ_MSG_V01:
+		*req_desc = &mem_share_svc_free_req_desc;
+		rc = sizeof(struct mem_free_req_msg_v01);
+		break;
+
+	case MEM_ALLOC_GENERIC_REQ_MSG_V01:
+		*req_desc = &mem_share_svc_alloc_generic_req_desc;
+		rc = sizeof(struct mem_alloc_generic_req_msg_v01);
+		break;
+
+	case MEM_FREE_GENERIC_REQ_MSG_V01:
+		*req_desc = &mem_share_svc_free_generic_req_desc;
+		rc = sizeof(struct mem_free_generic_req_msg_v01);
+		break;
+
+	case MEM_QUERY_SIZE_REQ_MSG_V01:
+		*req_desc = &mem_share_svc_size_query_req_desc;
+		rc = sizeof(struct mem_query_size_req_msg_v01);
+		break;
+
+	default:
+		rc = -ENOTSUPP;
+		break;
+	}
+	return rc;
+}
+
+static int mem_share_svc_req_cb(struct qmi_handle *handle, void *conn_h,
+			void *req_h, unsigned int msg_id, void *req)
+{
+	int rc;
+
+	pr_debug("memshare: %s\n", __func__);
+	if (mem_share_svc_handle != handle || !conn_h)
+		return -EINVAL;
+
+	switch (msg_id) {
+	case MEM_ALLOC_REQ_MSG_V01:
+		rc = handle_alloc_req(req_h, req, conn_h);
+		break;
+
+	case MEM_FREE_REQ_MSG_V01:
+		rc = handle_free_req(req_h, req, conn_h);
+		break;
+
+	case MEM_ALLOC_GENERIC_REQ_MSG_V01:
+		rc = handle_alloc_generic_req(req_h, req, conn_h);
+		break;
+
+	case MEM_FREE_GENERIC_REQ_MSG_V01:
+		rc = handle_free_generic_req(req_h, req, conn_h);
+		break;
+
+	case MEM_QUERY_SIZE_REQ_MSG_V01:
+		rc = handle_query_size_req(req_h, req, conn_h);
+		break;
+
+	default:
+		rc = -ENOTSUPP;
+		break;
+	}
+	return rc;
+}
+
+static void mem_share_svc_recv_msg(struct work_struct *work)
+{
+	int rc;
+
+	pr_debug("memshare: %s\n", __func__);
+	do {
+		rc = qmi_recv_msg(mem_share_svc_handle);
+		pr_debug("memshare: %s: Notified about a Receive Event",
+			__func__);
+	} while (!rc);
+
+	if (rc != -ENOMSG)
+		pr_err("memshare: %s: Error = %d while receiving message\n",
+			__func__, rc);
+}
+
+static void qmi_mem_share_svc_ntfy(struct qmi_handle *handle,
+		enum qmi_event_type event, void *priv)
+{
+	pr_debug("memshare: %s\n", __func__);
+
+	if (event == QMI_RECV_MSG)
+		queue_delayed_work(mem_share_svc_workqueue,
+				   &work_recv_msg, 0);
+}
+
+static struct qmi_svc_ops_options mem_share_svc_ops_options = {
+	.version = 1,
+	.service_id = MEM_SHARE_SERVICE_SVC_ID,
+	.service_vers = MEM_SHARE_SERVICE_VERS,
+	.service_ins = MEM_SHARE_SERVICE_INS_ID,
+	.connect_cb = mem_share_svc_connect_cb,
+	.disconnect_cb = mem_share_svc_disconnect_cb,
+	.req_desc_cb = mem_share_svc_req_desc_cb,
+	.req_cb = mem_share_svc_req_cb,
+};
+
+int memshare_alloc(struct device *dev,
+					unsigned int block_size,
+					struct mem_blocks *pblk)
+{
+	pr_debug("memshare: %s", __func__);
+
+	if (!pblk) {
+		pr_err("memshare: %s: Failed memory block allocation\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	pblk->virtual_addr = dma_alloc_attrs(dev, block_size,
+						&pblk->phy_addr, GFP_KERNEL,
+						attrs);
+	if (pblk->virtual_addr == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void memshare_init_worker(struct work_struct *work)
+{
+	int rc;
+
+	mem_share_svc_workqueue =
+		create_singlethread_workqueue("mem_share_svc");
+	if (!mem_share_svc_workqueue)
+		return;
+
+	mem_share_svc_handle = qmi_handle_create(qmi_mem_share_svc_ntfy, NULL);
+	if (!mem_share_svc_handle) {
+		pr_err("memshare: %s: Creating mem_share_svc qmi handle failed\n",
+			__func__);
+		destroy_workqueue(mem_share_svc_workqueue);
+		return;
+	}
+	rc = qmi_svc_register(mem_share_svc_handle, &mem_share_svc_ops_options);
+	if (rc < 0) {
+		pr_err("memshare: %s: Registering mem share svc failed %d\n",
+			__func__, rc);
+		qmi_handle_destroy(mem_share_svc_handle);
+		destroy_workqueue(mem_share_svc_workqueue);
+		return;
+	}
+	pr_debug("memshare: memshare_init successful\n");
+}
+
+static int memshare_child_probe(struct platform_device *pdev)
+{
+	int rc;
+	uint32_t size, client_id;
+	const char *name;
+	struct memshare_child *drv;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(struct memshare_child),
+							GFP_KERNEL);
+
+	if (!drv)
+		return -ENOMEM;
+
+	drv->dev = &pdev->dev;
+	memsh_child = drv;
+	platform_set_drvdata(pdev, memsh_child);
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,peripheral-size",
+						&size);
+	if (rc) {
+		pr_err("memshare: %s, Error reading size of clients, rc: %d\n",
+				__func__, rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,client-id",
+						&client_id);
+	if (rc) {
+		pr_err("memshare: %s, Error reading client id, rc: %d\n",
+				__func__, rc);
+		return rc;
+	}
+
+	memblock[num_clients].guarantee = of_property_read_bool(
+							pdev->dev.of_node,
+							"qcom,allocate-boot-time");
+
+	rc = of_property_read_string(pdev->dev.of_node, "label",
+						&name);
+	if (rc) {
+		pr_err("memshare: %s, Error reading peripheral info for client, rc: %d\n",
+					__func__, rc);
+		return rc;
+	}
+
+	if (strcmp(name, "modem") == 0)
+		memblock[num_clients].peripheral = DHMS_MEM_PROC_MPSS_V01;
+	else if (strcmp(name, "adsp") == 0)
+		memblock[num_clients].peripheral = DHMS_MEM_PROC_ADSP_V01;
+	else if (strcmp(name, "wcnss") == 0)
+		memblock[num_clients].peripheral = DHMS_MEM_PROC_WCNSS_V01;
+
+	memblock[num_clients].size = size;
+	memblock[num_clients].client_id = client_id;
+
+  /*
+   *	Memshare allocation for guaranteed clients
+   */
+	if (memblock[num_clients].guarantee) {
+		rc = memshare_alloc(memsh_child->dev,
+				memblock[num_clients].size,
+				&memblock[num_clients]);
+		if (rc) {
+			pr_err("memshare: %s, Unable to allocate memory for guaranteed clients, rc: %d\n",
+							__func__, rc);
+			return rc;
+		}
+		memblock[num_clients].allotted = 1;
+	}
+
+	/*
+	 *  call for creating ramdump dev handlers for
+	 *  memshare clients
+	 */
+
+	memshare_dev[num_clients] = &pdev->dev;
+
+	if (!memblock[num_clients].file_created) {
+		rc = mem_share_configure_ramdump(num_clients);
+		if (rc)
+			pr_err("memshare: %s, cannot collect dumps for client id: %d\n",
+					__func__,
+					memblock[num_clients].client_id);
+		else
+			memblock[num_clients].file_created = 1;
+	}
+
+	num_clients++;
+
+	return 0;
+}
+
+static int memshare_probe(struct platform_device *pdev)
+{
+	int rc;
+	struct memshare_driver *drv;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(struct memshare_driver),
+							GFP_KERNEL);
+
+	if (!drv)
+		return -ENOMEM;
+
+	/* Memory allocation has been done successfully */
+	mutex_init(&drv->mem_free);
+	mutex_init(&drv->mem_share);
+
+	INIT_WORK(&drv->memshare_init_work, memshare_init_worker);
+	schedule_work(&drv->memshare_init_work);
+
+	drv->dev = &pdev->dev;
+	memsh_drv = drv;
+	platform_set_drvdata(pdev, memsh_drv);
+	initialize_client();
+	num_clients = 0;
+
+	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL,
+				&pdev->dev);
+
+	if (rc) {
+		pr_err("memshare: %s, error populating the devices\n",
+			__func__);
+		return rc;
+	}
+
+	subsys_notif_register_notifier("modem", &nb);
+	pr_debug("memshare: %s, Memshare inited\n", __func__);
+
+	return 0;
+}
+
+static int memshare_remove(struct platform_device *pdev)
+{
+	if (!memsh_drv)
+		return 0;
+
+	qmi_svc_unregister(mem_share_svc_handle);
+	flush_workqueue(mem_share_svc_workqueue);
+	qmi_handle_destroy(mem_share_svc_handle);
+	destroy_workqueue(mem_share_svc_workqueue);
+
+	return 0;
+}
+
+static int memshare_child_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id memshare_match_table[] = {
+	{
+		.compatible = "qcom,memshare",
+	},
+	{}
+};
+
+static const struct of_device_id memshare_match_table1[] = {
+	{
+		.compatible = "qcom,memshare-peripheral",
+	},
+	{}
+};
+
+
+static struct platform_driver memshare_pdriver = {
+	.probe          = memshare_probe,
+	.remove         = memshare_remove,
+	.driver = {
+		.name   = MEMSHARE_DEV_NAME,
+		.owner  = THIS_MODULE,
+		.of_match_table = memshare_match_table,
+	},
+};
+
+static struct platform_driver memshare_pchild = {
+	.probe          = memshare_child_probe,
+	.remove         = memshare_child_remove,
+	.driver = {
+		.name   = MEMSHARE_CHILD_DEV_NAME,
+		.owner  = THIS_MODULE,
+		.of_match_table = memshare_match_table1,
+	},
+};
+
+module_platform_driver(memshare_pdriver);
+module_platform_driver(memshare_pchild);
+
+MODULE_DESCRIPTION("Mem Share QMI Service Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/memshare/msm_memshare.h b/drivers/soc/qcom/memshare/msm_memshare.h
new file mode 100644
index 0000000..f3b594a
--- /dev/null
+++ b/drivers/soc/qcom/memshare/msm_memshare.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_MEM_SHARE_H
+#define _LINUX_MEM_SHARE_H
+
+#define MEM_SHARE_SERVICE_SVC_ID 0x00000034
+#define MEM_SHARE_SERVICE_INS_ID 1
+#define MEM_SHARE_SERVICE_VERS 1
+
+#define MEMORY_CMA	1
+#define MEMORY_NON_CMA	0
+#define MAX_CLIENTS 10
+#define GPS	0
+#define CHECK	0
+#define FREE	1
+
+struct mem_blocks {
+	/* Client Id information */
+	uint32_t client_id;
+	/* Peripheral associated with client */
+	uint32_t peripheral;
+	/* Sequence Id */
+	uint32_t sequence_id;
+	/* CMA or Non-CMA region */
+	uint32_t memory_type;
+	/* Guaranteed Memory */
+	uint32_t guarantee;
+	/* Memory alloted or not */
+	uint32_t allotted;
+	/* Size required for client */
+	uint32_t size;
+	/*
+	 * start address of the memory block reserved by server memory
+	 * subsystem to client
+	 */
+	phys_addr_t phy_addr;
+	/* Virtual address for the physical address allocated */
+	void *virtual_addr;
+	/* Release memory only when XPU is released*/
+	uint8_t free_memory;
+	/* Need Hypervisor mapping*/
+	uint8_t hyp_mapping;
+	/* Status flag which checks if ramdump file is created*/
+	int file_created;
+
+};
+
+int memshare_alloc(struct device *dev,
+					unsigned int block_size,
+					struct mem_blocks *pblk);
+void memshare_free(unsigned int block_size,
+					struct mem_blocks *pblk);
+#endif /* _LINUX_MEM_SHARE_H */
diff --git a/drivers/soc/qcom/msm-core.c b/drivers/soc/qcom/msm-core.c
index 4ec791c..f8103de 100644
--- a/drivers/soc/qcom/msm-core.c
+++ b/drivers/soc/qcom/msm-core.c
@@ -293,23 +293,27 @@
 	struct cpu_static_info *sp, *clear_sp;
 	int cpumask, cluster;
 	bool pdata_valid[NR_CPUS] = {0};
+	bool cpu_found = false;
 
 	get_user(cpumask, &argp->cpumask);
 	get_user(cluster, &argp->cluster);
 
 	pr_debug("%s: cpumask %d, cluster: %d\n", __func__, cpumask,
 					cluster);
-	for (i = 0; i < MAX_CORES_PER_CLUSTER; i++, cpumask >>= 1) {
+	for (i = 0; cpumask > 0; i++, cpumask >>= 1) {
 		if (!(cpumask & 0x01))
 			continue;
 
 		for_each_possible_cpu(cpu) {
-			if ((cpu_topology[cpu].core_id != i) &&
+			if ((cpu_topology[cpu].core_id != i) ||
 				(cpu_topology[cpu].cluster_id != cluster))
 				continue;
 
+			cpu_found = true;
 			break;
 		}
+		if (cpu_found)
+			break;
 	}
 
 	if ((cpu < 0) || (cpu >= num_possible_cpus()))
@@ -346,7 +350,7 @@
 	 */
 	get_user(cpumask, &argp->cpumask);
 	spin_lock(&update_lock);
-	for (i = 0; i < MAX_CORES_PER_CLUSTER; i++, cpumask >>= 1) {
+	for (i = 0; cpumask > 0; i++, cpumask >>= 1) {
 		if (!(cpumask & 0x01))
 			continue;
 		for_each_possible_cpu(cpu) {
@@ -396,6 +400,7 @@
 	struct sched_params __user *argp = (struct sched_params __user *)arg;
 	int i, cpu = num_possible_cpus();
 	int cluster, cpumask;
+	bool cpu_found = false;
 
 	if (!argp)
 		return -EINVAL;
@@ -416,8 +421,11 @@
 				(cpu_topology[cpu].cluster_id != cluster)))
 					continue;
 
+				cpu_found = true;
 				break;
 			}
+			if (cpu_found)
+				break;
 		}
 		if (cpu >= num_possible_cpus())
 			break;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 144b1a1..b331e74 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -272,6 +272,9 @@
 	int ret = 0;
 	bool valid = true;
 
+	if (!cmd)
+		return ret;
+
 	if (vec_a == 0 && vec_b == 0)
 		valid = false;
 
@@ -670,7 +673,30 @@
 	return ret;
 }
 
+static void bcm_commit_single_req(struct msm_bus_node_device_type *cur_bcm,
+					uint64_t vec_a, uint64_t vec_b)
+{
+	struct msm_bus_node_device_type *cur_rsc = NULL;
+	struct rpmh_client *cur_mbox = NULL;
+	struct tcs_cmd *cmd_active = NULL;
 
+	if (!cur_bcm->node_info->num_rsc_devs)
+		return;
+
+	cmd_active = kzalloc(sizeof(struct tcs_cmd), GFP_KERNEL);
+
+	if (!cmd_active)
+		return;
+
+	cur_rsc = to_msm_bus_node(cur_bcm->node_info->rsc_devs[0]);
+	cur_mbox = cur_rsc->rscdev->mbox;
+
+	tcs_cmd_gen(cur_bcm, cmd_active, vec_a, vec_b, true);
+	rpmh_write_single(cur_mbox, RPMH_ACTIVE_ONLY_STATE,
+					cmd_active->addr, cmd_active->data);
+
+	kfree(cmd_active);
+}
 
 void *msm_bus_realloc_devmem(struct device *dev, void *p, size_t old_size,
 					size_t new_size, gfp_t flags)
@@ -733,29 +759,22 @@
 
 static int msm_bus_enable_node_qos_clk(struct msm_bus_node_device_type *node)
 {
-	struct msm_bus_node_device_type *bus_node = NULL;
 	int i;
 	int ret;
 	long rounded_rate;
 
-	if (!node || (!to_msm_bus_node(node->node_info->bus_device))) {
-		ret = -ENXIO;
-		goto exit_enable_node_qos_clk;
-	}
-	bus_node = to_msm_bus_node(node->node_info->bus_device);
-
-	for (i = 0; i < bus_node->num_node_qos_clks; i++) {
-		if (!bus_node->node_qos_clks[i].enable_only_clk) {
+	for (i = 0; i < node->num_node_qos_clks; i++) {
+		if (!node->node_qos_clks[i].enable_only_clk) {
 			rounded_rate =
 				clk_round_rate(
-					bus_node->node_qos_clks[i].clk, 1);
-			ret = setrate_nodeclk(&bus_node->node_qos_clks[i],
+					node->node_qos_clks[i].clk, 1);
+			ret = setrate_nodeclk(&node->node_qos_clks[i],
 								rounded_rate);
 			if (ret)
 				MSM_BUS_DBG("%s: Failed set rate clk,node %d\n",
 					__func__, node->node_info->id);
 		}
-		ret = enable_nodeclk(&bus_node->node_qos_clks[i],
+		ret = enable_nodeclk(&node->node_qos_clks[i],
 					node->node_info->bus_device);
 		if (ret) {
 			MSM_BUS_DBG("%s: Failed to set Qos Clks ret %d\n",
@@ -763,12 +782,85 @@
 			msm_bus_disable_node_qos_clk(node);
 			goto exit_enable_node_qos_clk;
 		}
-
 	}
 exit_enable_node_qos_clk:
 	return ret;
 }
 
+static int msm_bus_vote_qos_bcms(struct msm_bus_node_device_type *node)
+{
+	struct msm_bus_node_device_type *cur_dev = NULL;
+	struct msm_bus_node_device_type *cur_bcm = NULL;
+	int i;
+	struct device *dev = NULL;
+
+	if (!node || (!to_msm_bus_node(node->node_info->bus_device)))
+		return -ENXIO;
+
+	cur_dev = node;
+
+	for (i = 0; i < cur_dev->num_qos_bcms; i++) {
+		dev = bus_find_device(&msm_bus_type, NULL,
+				(void *) &cur_dev->qos_bcms[i].qos_bcm_id,
+					msm_bus_device_match_adhoc);
+
+		if (!dev) {
+			MSM_BUS_ERR("Can't find dev node for %d",
+					cur_dev->qos_bcms[i].qos_bcm_id);
+			return -ENODEV;
+		}
+
+		cur_bcm = to_msm_bus_node(dev);
+		if (cur_bcm->node_vec[ACTIVE_CTX].vec_a != 0 ||
+			cur_bcm->node_vec[ACTIVE_CTX].vec_b != 0 ||
+			cur_bcm->node_vec[DUAL_CTX].vec_a != 0 ||
+			cur_bcm->node_vec[DUAL_CTX].vec_b != 0)
+			return 0;
+
+		bcm_commit_single_req(cur_bcm,
+					cur_dev->qos_bcms[i].vec.vec_a,
+					cur_dev->qos_bcms[i].vec.vec_b);
+	}
+
+	return 0;
+}
+
+static int msm_bus_rm_vote_qos_bcms(struct msm_bus_node_device_type *node)
+{
+	struct msm_bus_node_device_type *cur_dev = NULL;
+	struct msm_bus_node_device_type *cur_bcm = NULL;
+	int i;
+	struct device *dev = NULL;
+
+	if (!node || (!to_msm_bus_node(node->node_info->bus_device)))
+		return -ENXIO;
+
+	cur_dev = node;
+
+	for (i = 0; i < cur_dev->num_qos_bcms; i++) {
+		dev = bus_find_device(&msm_bus_type, NULL,
+				(void *) &cur_dev->qos_bcms[i].qos_bcm_id,
+					msm_bus_device_match_adhoc);
+
+		if (!dev) {
+			MSM_BUS_ERR("Can't find dev node for %d",
+					cur_dev->qos_bcms[i].qos_bcm_id);
+			return -ENODEV;
+		}
+
+		cur_bcm = to_msm_bus_node(dev);
+		if (cur_bcm->node_vec[ACTIVE_CTX].vec_a != 0 ||
+			cur_bcm->node_vec[ACTIVE_CTX].vec_b != 0 ||
+			cur_bcm->node_vec[DUAL_CTX].vec_a != 0 ||
+			cur_bcm->node_vec[DUAL_CTX].vec_b != 0)
+			return 0;
+
+		bcm_commit_single_req(cur_bcm, 0, 0);
+	}
+
+	return 0;
+}
+
 int msm_bus_enable_limiter(struct msm_bus_node_device_type *node_dev,
 				int enable, uint64_t lim_bw)
 {
@@ -847,12 +939,11 @@
 			bus_node_info->fabdev->noc_ops.qos_init) {
 			int ret = 0;
 
-			if (node_dev->ap_owned &&
-				(node_dev->node_info->qos_params.mode) != -1) {
-
+			if (node_dev->ap_owned) {
 				if (bus_node_info->fabdev->bypass_qos_prg)
 					goto exit_init_qos;
 
+				ret = msm_bus_vote_qos_bcms(node_dev);
 				ret = msm_bus_enable_node_qos_clk(node_dev);
 				if (ret < 0) {
 					MSM_BUS_DBG("Can't Enable QoS clk %d\n",
@@ -868,6 +959,7 @@
 					bus_node_info->fabdev->qos_off,
 					bus_node_info->fabdev->qos_freq);
 				ret = msm_bus_disable_node_qos_clk(node_dev);
+				ret = msm_bus_rm_vote_qos_bcms(node_dev);
 				node_dev->node_info->defer_qos = false;
 			}
 		} else
@@ -1136,18 +1228,27 @@
 	node_info->is_fab_dev = pdata_node_info->is_fab_dev;
 	node_info->is_bcm_dev = pdata_node_info->is_bcm_dev;
 	node_info->is_rsc_dev = pdata_node_info->is_rsc_dev;
-	node_info->qos_params.mode = pdata_node_info->qos_params.mode;
-	node_info->qos_params.prio1 = pdata_node_info->qos_params.prio1;
-	node_info->qos_params.prio0 = pdata_node_info->qos_params.prio0;
-	node_info->qos_params.reg_prio1 = pdata_node_info->qos_params.reg_prio1;
-	node_info->qos_params.reg_prio0 = pdata_node_info->qos_params.reg_prio0;
-	node_info->qos_params.prio_lvl = pdata_node_info->qos_params.prio_lvl;
-	node_info->qos_params.prio_rd = pdata_node_info->qos_params.prio_rd;
-	node_info->qos_params.prio_wr = pdata_node_info->qos_params.prio_wr;
-	node_info->qos_params.gp = pdata_node_info->qos_params.gp;
-	node_info->qos_params.thmp = pdata_node_info->qos_params.thmp;
-	node_info->qos_params.ws = pdata_node_info->qos_params.ws;
-	node_info->qos_params.bw_buffer = pdata_node_info->qos_params.bw_buffer;
+	node_info->qos_params.prio_dflt = pdata_node_info->qos_params.prio_dflt;
+	node_info->qos_params.limiter.bw =
+				pdata_node_info->qos_params.limiter.bw;
+	node_info->qos_params.limiter.sat =
+				pdata_node_info->qos_params.limiter.sat;
+	node_info->qos_params.limiter_en =
+				pdata_node_info->qos_params.limiter_en;
+	node_info->qos_params.reg.low_prio =
+				pdata_node_info->qos_params.reg.low_prio;
+	node_info->qos_params.reg.hi_prio =
+				pdata_node_info->qos_params.reg.hi_prio;
+	node_info->qos_params.reg.bw =
+				pdata_node_info->qos_params.reg.bw;
+	node_info->qos_params.reg.sat =
+				pdata_node_info->qos_params.reg.sat;
+	node_info->qos_params.reg_mode.read =
+				pdata_node_info->qos_params.reg_mode.read;
+	node_info->qos_params.reg_mode.write =
+				pdata_node_info->qos_params.reg_mode.write;
+	node_info->qos_params.urg_fwd_en =
+				pdata_node_info->qos_params.urg_fwd_en;
 	node_info->agg_params.buswidth = pdata_node_info->agg_params.buswidth;
 	node_info->agg_params.agg_scheme =
 					pdata_node_info->agg_params.agg_scheme;
@@ -1299,7 +1400,7 @@
 	struct device *bus_dev = NULL;
 	struct msm_bus_node_device_type *bus_node = NULL;
 	struct msm_bus_node_info_type *node_info = NULL;
-	int ret = 0;
+	int ret = 0, i = 0;
 
 	/**
 	* Init here so we can use devm calls
@@ -1328,6 +1429,23 @@
 	bus_node->node_info = node_info;
 	bus_node->ap_owned = pdata->ap_owned;
 	bus_node->dirty = false;
+	bus_node->num_qos_bcms = pdata->num_qos_bcms;
+	if (bus_node->num_qos_bcms) {
+		bus_node->qos_bcms = devm_kzalloc(bus_dev,
+					(sizeof(struct qos_bcm_type) *
+					bus_node->num_qos_bcms), GFP_KERNEL);
+		if (!bus_node->qos_bcms)
+			goto exit_device_init;
+		for (i = 0; i < bus_node->num_qos_bcms; i++) {
+			bus_node->qos_bcms[i].qos_bcm_id =
+					pdata->qos_bcms[i].qos_bcm_id;
+			bus_node->qos_bcms[i].vec.vec_a =
+					pdata->qos_bcms[i].vec.vec_a;
+			bus_node->qos_bcms[i].vec.vec_b =
+					pdata->qos_bcms[i].vec.vec_b;
+		}
+	}
+
 	bus_dev->of_node = pdata->of_node;
 
 	if (msm_bus_copy_node_info(pdata, bus_dev) < 0) {
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c
index c501e80..996c719 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -32,15 +32,46 @@
 
 #define NOC_QOS_REG_BASE(b, o)		((b) + (o))
 
-#define NOC_QOS_PRIORITYn_ADDR(b, o, n, d)	\
+#define NOC_QOS_MAINCTL_LOWn_ADDR(b, o, n, d)	\
 	(NOC_QOS_REG_BASE(b, o) + 0x8 + (d) * (n))
-enum noc_qos_id_priorityn {
-	NOC_QOS_PRIORITYn_RMSK		= 0x0000000f,
-	NOC_QOS_PRIORITYn_MAXn		= 32,
-	NOC_QOS_PRIORITYn_P1_BMSK	= 0xc,
-	NOC_QOS_PRIORITYn_P1_SHFT	= 0x2,
-	NOC_QOS_PRIORITYn_P0_BMSK	= 0x3,
-	NOC_QOS_PRIORITYn_P0_SHFT	= 0x0,
+enum noc_qos_id_mainctl_lown {
+	NOC_QOS_MCTL_DFLT_PRIOn_BMSK	= 0x00000070,
+	NOC_QOS_MCTL_DFLT_PRIOn_SHFT	= 0x4,
+	NOC_QOS_MCTL_URGFWD_ENn_BMSK	= 0x00000008,
+	NOC_QOS_MCTL_URGFWD_ENn_SHFT	= 0x3,
+	NOC_QOS_MCTL_LIMIT_ENn_BMSK	= 0x00000001,
+	NOC_QOS_MCTL_LIMIT_ENn_SHFT	= 0x0,
+};
+
+#define NOC_QOS_LIMITBWn_ADDR(b, o, n, d)	\
+	(NOC_QOS_REG_BASE(b, o) + 0x18 + (d) * (n))
+enum noc_qos_id_limitbwn {
+	NOC_QOS_LIMITBW_BWn_BMSK	= 0x000007FF,
+	NOC_QOS_LIMITBW_BWn_SHFT	= 0x0,
+	NOC_QOS_LIMITBW_SATn_BMSK	= 0x03FF0000,
+	NOC_QOS_LIMITBW_SATn_SHFT	= 0x11,
+};
+
+#define NOC_QOS_REGUL0CTLn_ADDR(b, o, n, d)	\
+	(NOC_QOS_REG_BASE(b, o) + 0x40 + (d) * (n))
+enum noc_qos_id_regul0ctln {
+	NOC_QOS_REGUL0CTL_HI_PRIOn_BMSK	= 0x00007000,
+	NOC_QOS_REGUL0CTL_HI_PRIOn_SHFT	= 0x8,
+	NOC_QOS_REGUL0CTL_LW_PRIOn_BMSK	= 0x00000700,
+	NOC_QOS_REGUL0CTL_LW_PRIOn_SHFT	= 0xC,
+	NOC_QOS_REGUL0CTL_WRENn_BMSK	= 0x00000002,
+	NOC_QOS_REGUL0CTL_WRENn_SHFT	= 0x1,
+	NOC_QOS_REGUL0CTL_RDENn_BMSK	= 0x00000001,
+	NOC_QOS_REGUL0CTL_RDENn_SHFT	= 0x0,
+};
+
+#define NOC_QOS_REGUL0BWn_ADDR(b, o, n, d)	\
+	(NOC_QOS_REG_BASE(b, o) + 0x48 + (d) * (n))
+enum noc_qos_id_regul0bwbwn {
+	NOC_QOS_REGUL0BW_BWn_BMSK	= 0x000007FF,
+	NOC_QOS_REGUL0BW_BWn_SHFT	= 0x0,
+	NOC_QOS_REGUL0BW_SATn_BMSK	= 0x03FF0000,
+	NOC_QOS_REGUL0BW_SATn_SHFT	= 0x11,
 };
 
 #define NOC_QOS_MODEn_ADDR(b, o, n, d) \
@@ -100,14 +131,6 @@
 /**
  * Calculate the max BW in Bytes/s for a given time-base.
  */
-static uint32_t noc_bw_ceil(long int bw_field, uint32_t qos_freq_khz)
-{
-	uint64_t bw_temp = 2 * qos_freq_khz * bw_field;
-	uint32_t scale = 1000 * BW_SCALE;
-
-	noc_div(&bw_temp, scale);
-	return bw_temp * 1000000;
-}
 #define MAX_BW(timebase) noc_bw_ceil(MAX_BW_FIELD, (timebase))
 
 /**
@@ -129,190 +152,147 @@
 }
 #define MAX_WS(bw, timebase) noc_ws((bw), MAX_SAT_FIELD, (timebase))
 
-/* Calculate bandwidth field value for requested bandwidth  */
-static uint32_t noc_bw_field(uint64_t bw_bps, uint32_t qos_freq_khz)
-{
-	uint32_t bw_field = 0;
-
-	if (bw_bps) {
-		uint32_t rem;
-		uint64_t bw_capped = min_t(uint64_t, bw_bps,
-						MAX_BW(qos_freq_khz));
-		uint64_t bwc = bw_capped * BW_SCALE;
-		uint64_t qf = 2 * qos_freq_khz * 1000;
-
-		rem = noc_div(&bwc, qf);
-		bw_field = (uint32_t)max_t(unsigned long, bwc, MIN_BW_FIELD);
-		bw_field = (uint32_t)min_t(unsigned long, bw_field,
-								MAX_BW_FIELD);
-	}
-
-	MSM_BUS_DBG("NOC: bw_field: %u\n", bw_field);
-	return bw_field;
-}
-
-static uint32_t noc_sat_field(uint64_t bw, uint32_t ws, uint32_t qos_freq)
-{
-	uint32_t sat_field = 0;
-
-	if (bw) {
-		/* Limit to max bw and scale bw to 100 KB increments */
-		uint64_t tbw, tscale;
-		uint64_t bw_scaled = min_t(uint64_t, bw, MAX_BW(qos_freq));
-		uint32_t rem = noc_div(&bw_scaled, 100000);
-
-		/**
-		 *	SATURATION =
-		 *	(BW [MBps] * integration window [us] *
-		 *		time base frequency [MHz]) / (256 * 16)
-		 */
-		tbw = bw_scaled * ws * qos_freq;
-		tscale = BW_SCALE * SAT_SCALE * 1000000LL;
-		rem = noc_div(&tbw, tscale);
-		sat_field = (uint32_t)max_t(unsigned long, tbw, MIN_SAT_FIELD);
-		sat_field = (uint32_t)min_t(unsigned long, sat_field,
-							MAX_SAT_FIELD);
-	}
-
-	MSM_BUS_DBG("NOC: sat_field: %d\n", sat_field);
-	return sat_field;
-}
-
-static void noc_set_qos_mode(void __iomem *base, uint32_t qos_off,
-		uint32_t mport, uint32_t qos_delta, uint8_t mode,
-		uint8_t perm_mode)
-{
-	if (mode < NOC_QOS_MODE_MAX &&
-		((1 << mode) & perm_mode)) {
-		uint32_t reg_val;
-
-		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
-			mport, qos_delta)) & NOC_QOS_MODEn_RMSK;
-		writel_relaxed(((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) |
-			(mode & NOC_QOS_MODEn_MODE_BMSK)),
-			NOC_QOS_MODEn_ADDR(base, qos_off, mport, qos_delta));
-	}
-	/* Ensure qos mode is set before exiting */
-	wmb();
-}
-
-static void noc_set_qos_priority(void __iomem *base, uint32_t qos_off,
+static void noc_set_qos_dflt_prio(void __iomem *base, uint32_t qos_off,
 		uint32_t mport, uint32_t qos_delta,
-		struct msm_bus_noc_qos_priority *priority)
+		uint32_t prio)
 {
 	uint32_t reg_val, val;
 
-	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport,
-		qos_delta)) & NOC_QOS_PRIORITYn_RMSK;
-	val = priority->p1 << NOC_QOS_PRIORITYn_P1_SHFT;
-	writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P1_BMSK))) |
-		(val & NOC_QOS_PRIORITYn_P1_BMSK)),
-		NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, qos_delta));
+	reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport,
+		qos_delta));
+	val = prio << NOC_QOS_MCTL_DFLT_PRIOn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_MCTL_DFLT_PRIOn_BMSK))) |
+		(val & NOC_QOS_MCTL_DFLT_PRIOn_BMSK)),
+		NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta));
 
-	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport,
-								qos_delta))
-		& NOC_QOS_PRIORITYn_RMSK;
-	writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P0_BMSK))) |
-		(priority->p0 & NOC_QOS_PRIORITYn_P0_BMSK)),
-		NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, qos_delta));
 	/* Ensure qos priority is set before exiting */
 	wmb();
 }
 
-static void msm_bus_noc_set_qos_bw(void __iomem *base, uint32_t qos_off,
-		uint32_t qos_freq, uint32_t mport, uint32_t qos_delta,
-		uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw)
+static void noc_set_qos_limiter(void __iomem *base, uint32_t qos_off,
+		uint32_t mport, uint32_t qos_delta,
+		struct msm_bus_noc_limiter *lim, uint32_t lim_en)
 {
-	uint32_t reg_val, val, mode;
+	uint32_t reg_val, val;
 
-	if (!qos_freq) {
-		MSM_BUS_DBG("Zero QoS Freq\n");
-		return;
-	}
+	reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport,
+		qos_delta));
 
-	/* If Limiter or Regulator modes are not supported, bw not available*/
-	if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
-		NOC_QOS_PERM_MODE_REGULATOR)) {
-		uint32_t bw_val = noc_bw_field(qbw->bw, qos_freq);
-		uint32_t sat_val = noc_sat_field(qbw->bw, qbw->ws,
-			qos_freq);
+	writel_relaxed((reg_val & (~(NOC_QOS_MCTL_LIMIT_ENn_BMSK))),
+		NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta));
 
-		MSM_BUS_DBG("NOC: BW: perm_mode: %d bw_val: %d, sat_val: %d\n",
-			perm_mode, bw_val, sat_val);
-		/*
-		 * If in Limiter/Regulator mode, first go to fixed mode.
-		 * Clear QoS accumulator
-		 **/
-		mode = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
-			mport, qos_delta)) & NOC_QOS_MODEn_MODE_BMSK;
-		if (mode == NOC_QOS_MODE_REGULATOR || mode ==
-			NOC_QOS_MODE_LIMITER) {
-			reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(
-				base, qos_off, mport, qos_delta));
-			val = NOC_QOS_MODE_FIXED;
-			writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
-				| (val & NOC_QOS_MODEn_MODE_BMSK),
-				NOC_QOS_MODEn_ADDR(base, qos_off, mport,
-								qos_delta));
-		}
+	/* Ensure we disable limiter before config*/
+	wmb();
 
-		reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(base, qos_off, mport,
-								qos_delta));
-		val = bw_val << NOC_QOS_BWn_BW_SHFT;
-		writel_relaxed(((reg_val & (~(NOC_QOS_BWn_BW_BMSK))) |
-			(val & NOC_QOS_BWn_BW_BMSK)),
-			NOC_QOS_BWn_ADDR(base, qos_off, mport, qos_delta));
+	reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
+		qos_delta));
+	val = lim->bw << NOC_QOS_LIMITBW_BWn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_BWn_BMSK))) |
+		(val & NOC_QOS_LIMITBW_BWn_BMSK)),
+		NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
 
-		MSM_BUS_DBG("NOC: BW: Wrote value: 0x%x\n", ((reg_val &
-			(~NOC_QOS_BWn_BW_BMSK)) | (val &
-			NOC_QOS_BWn_BW_BMSK)));
+	reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
+		qos_delta));
+	val = lim->sat << NOC_QOS_LIMITBW_SATn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_SATn_BMSK))) |
+		(val & NOC_QOS_LIMITBW_SATn_BMSK)),
+		NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
 
-		reg_val = readl_relaxed(NOC_QOS_SATn_ADDR(base, qos_off,
-			mport, qos_delta));
-		val = sat_val << NOC_QOS_SATn_SAT_SHFT;
-		writel_relaxed(((reg_val & (~(NOC_QOS_SATn_SAT_BMSK))) |
-			(val & NOC_QOS_SATn_SAT_BMSK)),
-			NOC_QOS_SATn_ADDR(base, qos_off, mport, qos_delta));
+	/* Ensure qos limiter settings in place before possibly enabling */
+	wmb();
 
-		MSM_BUS_DBG("NOC: SAT: Wrote value: 0x%x\n", ((reg_val &
-			(~NOC_QOS_SATn_SAT_BMSK)) | (val &
-			NOC_QOS_SATn_SAT_BMSK)));
+	reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport,
+		qos_delta));
+	val = lim_en << NOC_QOS_MCTL_LIMIT_ENn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_MCTL_LIMIT_ENn_BMSK))) |
+		(val & NOC_QOS_MCTL_LIMIT_ENn_BMSK)),
+		NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta));
 
-		/* Set mode back to what it was initially */
-		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
-			mport, qos_delta));
-		writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
-			| (mode & NOC_QOS_MODEn_MODE_BMSK),
-			NOC_QOS_MODEn_ADDR(base, qos_off, mport, qos_delta));
-		/* Ensure that all writes for bandwidth registers have
-		 * completed before returning
-		 */
-		wmb();
-	}
+	wmb();
 }
 
-uint8_t msm_bus_noc_get_qos_mode(void __iomem *base, uint32_t qos_off,
-	uint32_t mport, uint32_t qos_delta, uint32_t mode, uint32_t perm_mode)
+static void noc_set_qos_regulator(void __iomem *base, uint32_t qos_off,
+		uint32_t mport, uint32_t qos_delta,
+		struct msm_bus_noc_regulator *reg,
+		struct msm_bus_noc_regulator_mode *reg_mode)
 {
-	if (perm_mode == NOC_QOS_MODES_ALL_PERM)
-		return readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
-			mport, qos_delta)) & NOC_QOS_MODEn_MODE_BMSK;
-	else
-		return 31 - __CLZ(mode &
-			NOC_QOS_MODES_ALL_PERM);
+	uint32_t reg_val, val;
+
+	reg_val = readl_relaxed(NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport,
+		qos_delta)) & (NOC_QOS_REGUL0CTL_WRENn_BMSK |
+						NOC_QOS_REGUL0CTL_RDENn_BMSK);
+
+	writel_relaxed((reg_val & (~(NOC_QOS_REGUL0CTL_WRENn_BMSK |
+						NOC_QOS_REGUL0CTL_RDENn_BMSK))),
+		NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport, qos_delta));
+
+	/* Ensure qos regulator is disabled before configuring */
+	wmb();
+
+	reg_val = readl_relaxed(NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport,
+		qos_delta)) & NOC_QOS_REGUL0CTL_HI_PRIOn_BMSK;
+	val = reg->hi_prio << NOC_QOS_REGUL0CTL_HI_PRIOn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_REGUL0CTL_HI_PRIOn_BMSK))) |
+		(val & NOC_QOS_REGUL0CTL_HI_PRIOn_BMSK)),
+		NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport, qos_delta));
+
+	reg_val = readl_relaxed(NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport,
+		qos_delta)) & NOC_QOS_REGUL0CTL_LW_PRIOn_BMSK;
+	val = reg->low_prio << NOC_QOS_REGUL0CTL_LW_PRIOn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_REGUL0CTL_LW_PRIOn_BMSK))) |
+		(val & NOC_QOS_REGUL0CTL_LW_PRIOn_BMSK)),
+		NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport, qos_delta));
+
+	reg_val = readl_relaxed(NOC_QOS_REGUL0BWn_ADDR(base, qos_off, mport,
+		qos_delta)) & NOC_QOS_REGUL0BW_BWn_BMSK;
+	val = reg->bw << NOC_QOS_REGUL0BW_BWn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_REGUL0BW_BWn_BMSK))) |
+		(val & NOC_QOS_REGUL0BW_BWn_BMSK)),
+		NOC_QOS_REGUL0BWn_ADDR(base, qos_off, mport, qos_delta));
+
+	reg_val = readl_relaxed(NOC_QOS_REGUL0BWn_ADDR(base, qos_off, mport,
+		qos_delta)) & NOC_QOS_REGUL0BW_SATn_BMSK;
+	val = reg->sat << NOC_QOS_REGUL0BW_SATn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_REGUL0BW_SATn_BMSK))) |
+		(val & NOC_QOS_REGUL0BW_SATn_BMSK)),
+		NOC_QOS_REGUL0BWn_ADDR(base, qos_off, mport, qos_delta));
+
+	/* Ensure regulator is configured before possibly enabling */
+	wmb();
+
+	reg_val = readl_relaxed(NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport,
+		qos_delta));
+	val = reg_mode->write << NOC_QOS_REGUL0CTL_WRENn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_REGUL0CTL_WRENn_BMSK))) |
+		(val & NOC_QOS_REGUL0CTL_WRENn_BMSK)),
+		NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport, qos_delta));
+
+	reg_val = readl_relaxed(NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport,
+		qos_delta));
+	val = reg_mode->read << NOC_QOS_REGUL0CTL_RDENn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_REGUL0CTL_RDENn_BMSK))) |
+		(val & NOC_QOS_REGUL0CTL_RDENn_BMSK)),
+		NOC_QOS_REGUL0CTLn_ADDR(base, qos_off, mport, qos_delta));
+
+	/* Ensure regulator is ready before exiting */
+	wmb();
 }
 
-void msm_bus_noc_get_qos_priority(void __iomem *base, uint32_t qos_off,
-	uint32_t mport, uint32_t qos_delta,
-	struct msm_bus_noc_qos_priority *priority)
+static void noc_set_qos_forwarding(void __iomem *base, uint32_t qos_off,
+		uint32_t mport, uint32_t qos_delta,
+		bool urg_fwd_en)
 {
-	priority->p1 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off,
-		mport, qos_delta)) & NOC_QOS_PRIORITYn_P1_BMSK) >>
-		NOC_QOS_PRIORITYn_P1_SHFT;
+	uint32_t reg_val, val;
 
-	priority->p0 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off,
-		mport, qos_delta)) & NOC_QOS_PRIORITYn_P0_BMSK) >>
-		NOC_QOS_PRIORITYn_P0_SHFT;
+	reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport,
+		qos_delta));
+	val = (urg_fwd_en ? 1:0) << NOC_QOS_MCTL_URGFWD_ENn_SHFT;
+	writel_relaxed(((reg_val & (~(NOC_QOS_MCTL_URGFWD_ENn_BMSK))) |
+		(val & NOC_QOS_MCTL_URGFWD_ENn_BMSK)),
+		NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta));
+
+	/* Ensure qos priority is set before exiting */
+	wmb();
 }
 
 void msm_bus_noc_get_qos_bw(void __iomem *base, uint32_t qos_off,
@@ -336,28 +316,16 @@
 	}
 }
 
-static bool msm_bus_noc_update_bw_reg(int mode)
-{
-	bool ret = false;
-
-	if ((mode == NOC_QOS_MODE_LIMITER) ||
-			(mode == NOC_QOS_MODE_REGULATOR))
-		ret = true;
-
-	return ret;
-}
-
 static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info,
 				void __iomem *qos_base,
 				uint32_t qos_off, uint32_t qos_delta,
 				uint32_t qos_freq)
 {
-	struct msm_bus_noc_qos_priority prio;
+	struct msm_bus_noc_qos_params *qos_params;
 	int ret = 0;
 	int i;
 
-	prio.p1 = info->node_info->qos_params.prio1;
-	prio.p0 = info->node_info->qos_params.prio0;
+	qos_params = &info->node_info->qos_params;
 
 	if (!info->node_info->qport) {
 		MSM_BUS_DBG("No QoS Ports to init\n");
@@ -366,224 +334,38 @@
 	}
 
 	for (i = 0; i < info->node_info->num_qports; i++) {
-		if (info->node_info->qos_params.mode != NOC_QOS_MODE_BYPASS) {
-			noc_set_qos_priority(qos_base, qos_off,
-					info->node_info->qport[i], qos_delta,
-					&prio);
-
-			if (info->node_info->qos_params.mode !=
-							NOC_QOS_MODE_FIXED) {
-				struct msm_bus_noc_qos_bw qbw;
-
-				qbw.ws = info->node_info->qos_params.ws;
-				qbw.bw = 0;
-				msm_bus_noc_set_qos_bw(qos_base, qos_off,
-					qos_freq,
+		noc_set_qos_dflt_prio(qos_base, qos_off,
 					info->node_info->qport[i],
 					qos_delta,
-					info->node_info->qos_params.mode,
-					&qbw);
-			}
-		}
+					qos_params->prio_dflt);
 
-		noc_set_qos_mode(qos_base, qos_off, info->node_info->qport[i],
-				qos_delta, info->node_info->qos_params.mode,
-				(1 << info->node_info->qos_params.mode));
+		noc_set_qos_limiter(qos_base, qos_off,
+					info->node_info->qport[i],
+					qos_delta,
+					&qos_params->limiter,
+					qos_params->limiter_en);
+
+		noc_set_qos_regulator(qos_base, qos_off,
+					info->node_info->qport[i],
+					qos_delta,
+					&qos_params->reg,
+					&qos_params->reg_mode);
+
+		noc_set_qos_forwarding(qos_base, qos_off,
+					info->node_info->qport[i],
+					qos_delta,
+					qos_params->urg_fwd_en);
 	}
 err_qos_init:
 	return ret;
 }
 
-static int msm_bus_noc_set_bw(struct msm_bus_node_device_type *dev,
-				void __iomem *qos_base,
-				uint32_t qos_off, uint32_t qos_delta,
-				uint32_t qos_freq)
-{
-	int ret = 0;
-	uint64_t bw = 0;
-	int i;
-	struct msm_bus_node_info_type *info = dev->node_info;
-
-	if (info && info->num_qports &&
-		((info->qos_params.mode == NOC_QOS_MODE_REGULATOR) ||
-		(info->qos_params.mode ==
-			NOC_QOS_MODE_LIMITER))) {
-		struct msm_bus_noc_qos_bw qos_bw;
-
-		bw = msm_bus_div64(info->num_qports,
-				dev->node_bw[ACTIVE_CTX].sum_ab);
-
-		for (i = 0; i < info->num_qports; i++) {
-			if (!info->qport) {
-				MSM_BUS_DBG("No qos ports to update!\n");
-				break;
-			}
-
-			qos_bw.bw = bw;
-			qos_bw.ws = info->qos_params.ws;
-			msm_bus_noc_set_qos_bw(qos_base, qos_off, qos_freq,
-				info->qport[i], qos_delta,
-				(1 << info->qos_params.mode), &qos_bw);
-			MSM_BUS_DBG("NOC: QoS: Update mas_bw: ws: %u\n",
-				qos_bw.ws);
-		}
-	}
-	return ret;
-}
-
-static int msm_bus_noc_set_lim_mode(struct msm_bus_node_device_type *info,
-				void __iomem *qos_base, uint32_t qos_off,
-				uint32_t qos_delta, uint32_t qos_freq,
-				u64 lim_bw)
-{
-	int i;
-
-	if (info && info->node_info->num_qports) {
-		struct msm_bus_noc_qos_bw qos_bw;
-
-		if (lim_bw != info->node_info->lim_bw) {
-			for (i = 0; i < info->node_info->num_qports; i++) {
-				qos_bw.bw = lim_bw;
-				qos_bw.ws = info->node_info->qos_params.ws;
-					msm_bus_noc_set_qos_bw(qos_base,
-					qos_off, qos_freq,
-					info->node_info->qport[i], qos_delta,
-					(1 << NOC_QOS_MODE_LIMITER), &qos_bw);
-			}
-			info->node_info->lim_bw = lim_bw;
-		}
-
-		for (i = 0; i < info->node_info->num_qports; i++) {
-			noc_set_qos_mode(qos_base, qos_off,
-					info->node_info->qport[i],
-					qos_delta,
-					NOC_QOS_MODE_LIMITER,
-					(1 << NOC_QOS_MODE_LIMITER));
-		}
-	}
-
-	return 0;
-}
-
-static int msm_bus_noc_set_reg_mode(struct msm_bus_node_device_type *info,
-				void __iomem *qos_base, uint32_t qos_off,
-				uint32_t qos_delta, uint32_t qos_freq,
-				u64 lim_bw)
-{
-	int i;
-
-	if (info && info->node_info->num_qports) {
-		struct msm_bus_noc_qos_priority prio;
-		struct msm_bus_noc_qos_bw qos_bw;
-
-		for (i = 0; i < info->node_info->num_qports; i++) {
-			prio.p1 =
-				info->node_info->qos_params.reg_prio1;
-			prio.p0 =
-				info->node_info->qos_params.reg_prio0;
-			noc_set_qos_priority(qos_base, qos_off,
-					info->node_info->qport[i],
-					qos_delta,
-					&prio);
-		}
-
-		if (lim_bw != info->node_info->lim_bw) {
-			for (i = 0; i < info->node_info->num_qports; i++) {
-				qos_bw.bw = lim_bw;
-				qos_bw.ws = info->node_info->qos_params.ws;
-				msm_bus_noc_set_qos_bw(qos_base, qos_off,
-					qos_freq,
-					info->node_info->qport[i], qos_delta,
-					(1 << NOC_QOS_MODE_REGULATOR), &qos_bw);
-			}
-			info->node_info->lim_bw = lim_bw;
-		}
-
-		for (i = 0; i < info->node_info->num_qports; i++) {
-			noc_set_qos_mode(qos_base, qos_off,
-					info->node_info->qport[i],
-					qos_delta,
-					NOC_QOS_MODE_REGULATOR,
-					(1 << NOC_QOS_MODE_REGULATOR));
-		}
-	}
-	return 0;
-}
-
-static int msm_bus_noc_set_def_mode(struct msm_bus_node_device_type *info,
-				void __iomem *qos_base, uint32_t qos_off,
-				uint32_t qos_delta, uint32_t qos_freq,
-				u64 lim_bw)
-{
-	int i;
-
-	for (i = 0; i < info->node_info->num_qports; i++) {
-		if (info->node_info->qos_params.mode ==
-						NOC_QOS_MODE_FIXED) {
-			struct msm_bus_noc_qos_priority prio;
-
-			prio.p1 =
-				info->node_info->qos_params.prio1;
-			prio.p0 =
-				info->node_info->qos_params.prio0;
-			noc_set_qos_priority(qos_base, qos_off,
-					info->node_info->qport[i],
-					qos_delta, &prio);
-		}
-		noc_set_qos_mode(qos_base, qos_off,
-			info->node_info->qport[i],
-			qos_delta,
-			info->node_info->qos_params.mode,
-			(1 << info->node_info->qos_params.mode));
-	}
-	return 0;
-}
-
-static int msm_bus_noc_limit_mport(struct msm_bus_node_device_type *info,
-				void __iomem *qos_base, uint32_t qos_off,
-				uint32_t qos_delta, uint32_t qos_freq,
-				int enable_lim, u64 lim_bw)
-{
-	int ret = 0;
-
-	if (!(info && info->node_info->num_qports)) {
-		MSM_BUS_ERR("Invalid Node info or no Qports to program");
-		ret = -ENXIO;
-		goto exit_limit_mport;
-	}
-
-	if (lim_bw) {
-		switch (enable_lim) {
-		case THROTTLE_REG:
-			msm_bus_noc_set_reg_mode(info, qos_base, qos_off,
-						qos_delta, qos_freq, lim_bw);
-			break;
-		case THROTTLE_ON:
-			msm_bus_noc_set_lim_mode(info, qos_base, qos_off,
-						qos_delta, qos_freq, lim_bw);
-			break;
-		default:
-			msm_bus_noc_set_def_mode(info, qos_base, qos_off,
-						qos_delta, qos_freq, lim_bw);
-			break;
-		}
-	} else
-		msm_bus_noc_set_def_mode(info, qos_base, qos_off,
-					qos_delta, qos_freq, lim_bw);
-
-exit_limit_mport:
-	return ret;
-}
-
 int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev)
 {
 	if (!bus_dev)
 		return -ENODEV;
 
 	bus_dev->fabdev->noc_ops.qos_init = msm_bus_noc_qos_init;
-	bus_dev->fabdev->noc_ops.set_bw = msm_bus_noc_set_bw;
-	bus_dev->fabdev->noc_ops.limit_mport = msm_bus_noc_limit_mport;
-	bus_dev->fabdev->noc_ops.update_bw_reg = msm_bus_noc_update_bw_reg;
 
 	return 0;
 }
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_of.c b/drivers/soc/qcom/msm_bus/msm_bus_of.c
index fd72ae6..34ba05f 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_of.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_of.c
@@ -113,9 +113,9 @@
 			int index = i * 2;
 
 			usecase_lat[i].fal_ns = (uint64_t)
-				KBTOB(be32_to_cpu(vec_arr[index]));
+				be32_to_cpu(vec_arr[index]);
 			usecase_lat[i].idle_t_ns = (uint64_t)
-				KBTOB(be32_to_cpu(vec_arr[index + 1]));
+				be32_to_cpu(vec_arr[index + 1]);
 		}
 
 		pdata->usecase_lat = usecase_lat;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
index 5710bca..42a6f58 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
@@ -31,31 +31,6 @@
 #define DEFAULT_VRAIL_COMP	100
 #define DEFAULT_AGG_SCHEME	AGG_SCHEME_LEG
 
-static int get_qos_mode(struct platform_device *pdev,
-			struct device_node *node, const char *qos_mode)
-{
-	static char const *qos_names[] = {"fixed", "limiter",
-						"bypass", "regulator"};
-	int i = 0;
-	int ret = -1;
-
-	if (!qos_mode)
-		goto exit_get_qos_mode;
-
-	for (i = 0; i < ARRAY_SIZE(qos_names); i++) {
-		if (!strcmp(qos_mode, qos_names[i]))
-			break;
-	}
-	if (i == ARRAY_SIZE(qos_names))
-		dev_err(&pdev->dev, "Cannot match mode qos %s using Bypass",
-				qos_mode);
-	else
-		ret = i;
-
-exit_get_qos_mode:
-	return ret;
-}
-
 static int *get_arr(struct platform_device *pdev,
 		struct device_node *node, const char *prop,
 		int *nports)
@@ -210,7 +185,6 @@
 		fab_dev->qos_freq = DEFAULT_QOS_FREQ;
 	}
 
-
 	return fab_dev;
 
 fab_dev_err:
@@ -224,54 +198,48 @@
 		struct platform_device * const pdev,
 		struct msm_bus_node_info_type *node_info)
 {
-	const char *qos_mode = NULL;
-	unsigned int ret;
-	unsigned int temp;
+	const uint32_t *vec_arr = NULL;
+	int len;
 
-	ret = of_property_read_string(dev_node, "qcom,qos-mode", &qos_mode);
+	of_property_read_u32(dev_node, "qcom,prio",
+					&node_info->qos_params.prio_dflt);
 
-	if (ret)
-		node_info->qos_params.mode = -1;
-	else
-		node_info->qos_params.mode = get_qos_mode(pdev, dev_node,
-								qos_mode);
+	vec_arr = of_get_property(dev_node, "qcom,lim-params", &len);
+	if (vec_arr != NULL && len == sizeof(uint32_t) * 2) {
+		node_info->qos_params.limiter.bw = be32_to_cpu(vec_arr[0]);
+		node_info->qos_params.limiter.sat = be32_to_cpu(vec_arr[1]);
+	} else {
+		node_info->qos_params.limiter.bw = 0;
+		node_info->qos_params.limiter.sat = 0;
+	}
 
-	of_property_read_u32(dev_node, "qcom,prio-lvl",
-					&node_info->qos_params.prio_lvl);
+	node_info->qos_params.limiter_en = of_property_read_bool(dev_node,
+						"qcom,lim-en");
 
-	of_property_read_u32(dev_node, "qcom,prio1",
-						&node_info->qos_params.prio1);
+	vec_arr = of_get_property(dev_node, "qcom,qos-reg-params", &len);
+	if (vec_arr != NULL && len == sizeof(uint32_t) * 4) {
+		node_info->qos_params.reg.low_prio = be32_to_cpu(vec_arr[0]);
+		node_info->qos_params.reg.hi_prio = be32_to_cpu(vec_arr[1]);
+		node_info->qos_params.reg.bw = be32_to_cpu(vec_arr[2]);
+		node_info->qos_params.reg.sat = be32_to_cpu(vec_arr[3]);
+	} else {
+		node_info->qos_params.reg.low_prio = 0;
+		node_info->qos_params.reg.hi_prio = 0;
+		node_info->qos_params.reg.bw = 0;
+		node_info->qos_params.reg.sat = 0;
+	}
 
-	of_property_read_u32(dev_node, "qcom,prio0",
-						&node_info->qos_params.prio0);
+	vec_arr = of_get_property(dev_node, "qcom,qos-reg-mode", &len);
+	if (vec_arr != NULL && len == sizeof(uint32_t) * 2) {
+		node_info->qos_params.reg_mode.read = be32_to_cpu(vec_arr[0]);
+		node_info->qos_params.reg_mode.write = be32_to_cpu(vec_arr[1]);
+	} else {
+		node_info->qos_params.reg_mode.read = 0;
+		node_info->qos_params.reg_mode.write = 0;
+	}
 
-	of_property_read_u32(dev_node, "qcom,reg-prio1",
-					&node_info->qos_params.reg_prio1);
-
-	of_property_read_u32(dev_node, "qcom,reg-prio0",
-					&node_info->qos_params.reg_prio0);
-
-	of_property_read_u32(dev_node, "qcom,prio-rd",
-					&node_info->qos_params.prio_rd);
-
-	of_property_read_u32(dev_node, "qcom,prio-wr",
-						&node_info->qos_params.prio_wr);
-
-	of_property_read_u32(dev_node, "qcom,gp",
-						&node_info->qos_params.gp);
-
-	of_property_read_u32(dev_node, "qcom,thmp",
-						&node_info->qos_params.thmp);
-
-	of_property_read_u32(dev_node, "qcom,ws",
-						&node_info->qos_params.ws);
-
-	ret = of_property_read_u32(dev_node, "qcom,bw_buffer", &temp);
-
-	if (ret)
-		node_info->qos_params.bw_buffer = 0;
-	else
-		node_info->qos_params.bw_buffer = KBTOB(temp);
+	node_info->qos_params.urg_fwd_en = of_property_read_bool(dev_node,
+						"qcom,forwarding");
 
 }
 
@@ -308,13 +276,9 @@
 		char gdsc_string[MAX_REG_NAME];
 
 		(*clk_arr)[idx].clk = of_clk_get_by_name(dev_node, clk_name);
+		if (IS_ERR_OR_NULL((*clk_arr)[idx].clk))
+			goto exit_of_parse_clk_array;
 
-		if (IS_ERR_OR_NULL((*clk_arr)[idx].clk)) {
-			dev_err(&pdev->dev,
-				"Failed to get clk %s for bus%d ", clk_name,
-									id);
-			continue;
-		}
 		if (strnstr(clk_name, "no-rate", strlen(clk_name)))
 			(*clk_arr)[idx].enable_only_clk = true;
 
@@ -532,6 +496,10 @@
 {
 	bool enable_only;
 	bool setrate_only;
+	int num_elems = 0, num_bcms = 0, i = 0, ret = 0;
+	uint32_t *vec_arr = NULL;
+	struct qos_bcm_type *qos_bcms = NULL;
+	struct device_node *qos_clk_node = NULL;
 
 	node_device->node_info = get_node_info_data(dev_node, pdev);
 	if (IS_ERR_OR_NULL(node_device->node_info)) {
@@ -566,8 +534,6 @@
 	}
 
 	if (node_device->node_info->is_fab_dev) {
-		struct device_node *qos_clk_node;
-
 		dev_dbg(&pdev->dev, "Dev %d\n", node_device->node_info->id);
 
 		if (!node_device->node_info->virt_dev) {
@@ -615,6 +581,48 @@
 			of_node_put(qos_clk_node);
 		}
 	} else {
+		num_elems = of_property_count_elems_of_size(dev_node,
+					"qcom,node-qos-bcms", sizeof(uint32_t));
+
+		if (num_elems > 0) {
+			if (num_elems % 3 != 0) {
+				pr_err("Error: Length-error on getting vectors\n");
+				return -ENODATA;
+			}
+
+			vec_arr = devm_kzalloc(&pdev->dev, (sizeof(uint32_t) *
+							num_elems), GFP_KERNEL);
+			if (!vec_arr)
+				return -ENOMEM;
+
+			ret = of_property_read_u32_array(dev_node,
+						"qcom,node-qos-bcms", vec_arr,
+								num_elems);
+			if (ret) {
+				pr_err("Error: problem reading qos-bcm vectors\n");
+				return ret;
+			}
+			num_bcms = num_elems / 3;
+			node_device->num_qos_bcms = num_bcms;
+
+			qos_bcms = devm_kzalloc(&pdev->dev,
+						(sizeof(struct qos_bcm_type) *
+						num_bcms), GFP_KERNEL);
+			if (!qos_bcms)
+				return -ENOMEM;
+
+			for (i = 0; i < num_bcms; i++) {
+				int index = i * 3;
+
+				qos_bcms[i].qos_bcm_id = vec_arr[index];
+				qos_bcms[i].vec.vec_a =
+					(uint64_t)KBTOB(vec_arr[index + 1]);
+				qos_bcms[i].vec.vec_b =
+					(uint64_t)KBTOB(vec_arr[index + 2]);
+			}
+			node_device->qos_bcms = qos_bcms;
+		}
+
 		enable_only = of_property_read_bool(dev_node,
 							"qcom,enable-only-clk");
 		node_device->clk[DUAL_CTX].enable_only_clk = enable_only;
@@ -632,6 +640,20 @@
 								setrate_only;
 		}
 
+		qos_clk_node = of_get_child_by_name(dev_node,
+						"qcom,node-qos-clks");
+
+		if (qos_clk_node) {
+			if (msm_bus_of_parse_clk_array(qos_clk_node, dev_node,
+						pdev,
+						&node_device->node_qos_clks,
+						&node_device->num_node_qos_clks,
+						node_device->node_info->id)) {
+				dev_dbg(&pdev->dev, "Bypass QoS programming");
+				node_device->fabdev->bypass_qos_prg = true;
+			}
+			of_node_put(qos_clk_node);
+		}
 		node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node,
 							"node_clk");
 
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
index cd5281a..17657e5 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
@@ -19,6 +19,7 @@
 #include <linux/msm-bus.h>
 #include <linux/msm_bus_rules.h>
 #include "msm_bus_core.h"
+#include "msm_bus_noc.h"
 
 #define VCD_MAX_CNT 16
 
@@ -75,6 +76,11 @@
 	uint64_t query_vec_b;
 };
 
+struct qos_bcm_type {
+	int qos_bcm_id;
+	struct nodevector vec;
+};
+
 struct msm_bus_rsc_device_type {
 	struct rpmh_client *mbox;
 	struct list_head bcm_clist[VCD_MAX_CNT];
@@ -106,19 +112,30 @@
 	bool bypass_qos_prg;
 };
 
-struct qos_params_type {
-	int mode;
-	unsigned int prio_lvl;
-	unsigned int prio_rd;
-	unsigned int prio_wr;
-	unsigned int prio1;
-	unsigned int prio0;
-	unsigned int reg_prio1;
-	unsigned int reg_prio0;
-	unsigned int gp;
-	unsigned int thmp;
-	unsigned int ws;
-	u64 bw_buffer;
+struct msm_bus_noc_limiter {
+	uint32_t bw;
+	uint32_t sat;
+};
+
+struct msm_bus_noc_regulator {
+	uint32_t low_prio;
+	uint32_t hi_prio;
+	uint32_t bw;
+	uint32_t sat;
+};
+
+struct msm_bus_noc_regulator_mode {
+	uint32_t read;
+	uint32_t write;
+};
+
+struct msm_bus_noc_qos_params {
+	uint32_t prio_dflt;
+	struct msm_bus_noc_limiter limiter;
+	bool limiter_en;
+	struct msm_bus_noc_regulator reg;
+	struct msm_bus_noc_regulator_mode reg_mode;
+	bool urg_fwd_en;
 };
 
 struct node_util_levels_type {
@@ -143,7 +160,7 @@
 	int num_ports;
 	int num_qports;
 	int *qport;
-	struct qos_params_type qos_params;
+	struct msm_bus_noc_qos_params qos_params;
 	unsigned int num_connections;
 	unsigned int num_blist;
 	unsigned int num_bcm_devs;
@@ -185,6 +202,8 @@
 	struct nodeclk bus_qos_clk;
 	uint32_t num_node_qos_clks;
 	struct nodeclk *node_qos_clks;
+	uint32_t num_qos_bcms;
+	struct qos_bcm_type *qos_bcms;
 	unsigned int ap_owned;
 	struct device_node *of_node;
 	struct device dev;
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 1f28712..91c9441 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -38,6 +38,8 @@
 
 #include <linux/uaccess.h>
 #include <asm/setup.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/trace_msm_pil_event.h>
 
 #include "peripheral-loader.h"
 
@@ -834,6 +836,7 @@
 		goto release_fw;
 	}
 
+	trace_pil_event("before_init_image", desc);
 	if (desc->ops->init_image)
 		ret = desc->ops->init_image(desc, fw->data, fw->size);
 	if (ret) {
@@ -841,6 +844,7 @@
 		goto err_boot;
 	}
 
+	trace_pil_event("before_mem_setup", desc);
 	if (desc->ops->mem_setup)
 		ret = desc->ops->mem_setup(desc, priv->region_start,
 				priv->region_end - priv->region_start);
@@ -856,6 +860,7 @@
 		 * Also for secure boot devices, modem memory has to be released
 		 * after MBA is booted
 		 */
+		trace_pil_event("before_assign_mem", desc);
 		if (desc->modem_ssr) {
 			ret = pil_assign_mem_to_linux(desc, priv->region_start,
 				(priv->region_end - priv->region_start));
@@ -874,6 +879,7 @@
 		hyp_assign = true;
 	}
 
+	trace_pil_event("before_load_seg", desc);
 	list_for_each_entry(seg, &desc->priv->segs, list) {
 		ret = pil_load_seg(desc, seg);
 		if (ret)
@@ -881,6 +887,7 @@
 	}
 
 	if (desc->subsys_vmid > 0) {
+		trace_pil_event("before_reclaim_mem", desc);
 		ret =  pil_reclaim_mem(desc, priv->region_start,
 				(priv->region_end - priv->region_start),
 				desc->subsys_vmid);
@@ -892,11 +899,13 @@
 		hyp_assign = false;
 	}
 
+	trace_pil_event("before_auth_reset", desc);
 	ret = desc->ops->auth_and_reset(desc);
 	if (ret) {
 		pil_err(desc, "Failed to bring out of reset(rc:%d)\n", ret);
 		goto err_auth_and_reset;
 	}
+	trace_pil_event("reset_done", desc);
 	pil_info(desc, "Brought out of reset\n");
 	desc->modem_ssr = false;
 err_auth_and_reset:
@@ -925,13 +934,13 @@
 						priv->region_start),
 					VMID_HLOS);
 			}
+			if (desc->clear_fw_region && priv->region_start)
+				pil_clear_segment(desc);
 			dma_free_attrs(desc->dev, priv->region_size,
 					priv->region, priv->region_start,
 					desc->attrs);
 			priv->region = NULL;
 		}
-		if (desc->clear_fw_region && priv->region_start)
-			pil_clear_segment(desc);
 		pil_release_mmap(desc);
 	}
 	return ret;
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index b71ce6b..20b9769 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -26,6 +26,7 @@
 #include <linux/highmem.h>
 #include <soc/qcom/scm.h>
 #include <soc/qcom/secure_buffer.h>
+#include <trace/events/trace_msm_pil_event.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
@@ -513,6 +514,7 @@
 	u32 debug_val;
 	int ret;
 
+	trace_pil_func(__func__);
 	if (drv->mba_dp_phys)
 		start_addr = drv->mba_dp_phys;
 
@@ -612,6 +614,7 @@
 	const u8 *data;
 	struct device *dma_dev = md->mba_mem_dev_fixed ?: &md->mba_mem_dev;
 
+	trace_pil_func(__func__);
 	fw_name_p = drv->non_elf_image ? fw_name_legacy : fw_name;
 	ret = request_firmware(&fw, fw_name_p, pil->dev);
 	if (ret) {
@@ -674,7 +677,15 @@
 
 	/* Load the MBA image into memory */
 	count = fw->size;
-	memcpy(mba_dp_virt, data, count);
+	if (count <= SZ_1M) {
+		/* Ensures memcpy is done for max 1MB fw size */
+		memcpy(mba_dp_virt, data, count);
+	} else {
+		dev_err(pil->dev, "%s fw image loading into memory is failed due to fw size overflow\n",
+			__func__);
+		ret = -EINVAL;
+		goto err_mba_data;
+	}
 	/* Ensure memcpy of the MBA memory is done before loading the DP */
 	wmb();
 
@@ -734,6 +745,7 @@
 	struct device *dma_dev = drv->mba_mem_dev_fixed ?: &drv->mba_mem_dev;
 	unsigned long attrs = 0;
 
+	trace_pil_func(__func__);
 	dma_dev->coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
 	attrs |= DMA_ATTR_SKIP_ZEROING;
 	attrs |= DMA_ATTR_STRONGLY_ORDERED;
diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c
index b41a173..49dd0be 100644
--- a/drivers/soc/qcom/pil-q6v5.c
+++ b/drivers/soc/qcom/pil-q6v5.c
@@ -20,6 +20,7 @@
 #include <linux/of.h>
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
+#include <trace/events/trace_msm_pil_event.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
@@ -425,6 +426,7 @@
 	u32 val;
 	int i;
 
+	trace_pil_func(__func__);
 	/* Override the ACC value if required */
 	if (drv->override_acc)
 		writel_relaxed(QDSP6SS_ACC_OVERRIDE_VAL,
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
index 5d860a3..e45f61e 100644
--- a/drivers/soc/qcom/qdsp6v2/apr.c
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -515,19 +515,19 @@
 			mutex_unlock(&svc->m_lock);
 			return NULL;
 		}
-		if (!svc->port_cnt && !svc->svc_cnt)
+		if (!svc->svc_cnt)
 			clnt->svc_cnt++;
 		svc->port_cnt++;
 		svc->port_fn[temp_port] = svc_fn;
 		svc->port_priv[temp_port] = priv;
+		svc->svc_cnt++;
 	} else {
 		if (!svc->fn) {
-			if (!svc->port_cnt && !svc->svc_cnt)
+			if (!svc->svc_cnt)
 				clnt->svc_cnt++;
 			svc->fn = svc_fn;
-			if (svc->port_cnt)
-				svc->svc_cnt++;
 			svc->priv = priv;
+			svc->svc_cnt++;
 		}
 	}
 
@@ -747,28 +747,28 @@
 		return -EINVAL;
 
 	mutex_lock(&svc->m_lock);
+	if (!svc->svc_cnt) {
+		pr_err("%s: svc already deregistered. svc = %pK\n",
+			__func__, svc);
+		mutex_unlock(&svc->m_lock);
+		return -EINVAL;
+	}
+
 	dest_id = svc->dest_id;
 	client_id = svc->client_id;
 	clnt = &client[dest_id][client_id];
 
-	if (svc->port_cnt > 0 || svc->svc_cnt > 0) {
+	if (svc->svc_cnt > 0) {
 		if (svc->port_cnt)
 			svc->port_cnt--;
-		else if (svc->svc_cnt)
-			svc->svc_cnt--;
-		if (!svc->port_cnt && !svc->svc_cnt) {
+		svc->svc_cnt--;
+		if (!svc->svc_cnt) {
 			client[dest_id][client_id].svc_cnt--;
-			svc->need_reset = 0x0;
-		}
-	} else if (client[dest_id][client_id].svc_cnt > 0) {
-		client[dest_id][client_id].svc_cnt--;
-		if (!client[dest_id][client_id].svc_cnt) {
-			svc->need_reset = 0x0;
 			pr_debug("%s: service is reset %pK\n", __func__, svc);
 		}
 	}
 
-	if (!svc->port_cnt && !svc->svc_cnt) {
+	if (!svc->svc_cnt) {
 		svc->priv = NULL;
 		svc->id = 0;
 		svc->fn = NULL;
@@ -887,8 +887,10 @@
 		 * recovery notifications during initial boot
 		 * up since everything is expected to be down.
 		 */
-		if (is_initial_boot)
+		if (is_initial_boot) {
+			is_initial_boot = false;
 			break;
+		}
 		if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN)
 			apr_modem_down(opcode);
 		else
@@ -908,7 +910,12 @@
 	return NOTIFY_OK;
 }
 
-static struct notifier_block service_nb = {
+static struct notifier_block adsp_service_nb = {
+	.notifier_call  = apr_notifier_service_cb,
+	.priority = 0,
+};
+
+static struct notifier_block modem_service_nb = {
 	.notifier_call  = apr_notifier_service_cb,
 	.priority = 0,
 };
@@ -938,9 +945,9 @@
 
 	is_initial_boot = true;
 	subsys_notif_register("apr_adsp", AUDIO_NOTIFIER_ADSP_DOMAIN,
-			      &service_nb);
+			      &adsp_service_nb);
 	subsys_notif_register("apr_modem", AUDIO_NOTIFIER_MODEM_DOMAIN,
-			      &service_nb);
+			      &modem_service_nb);
 
 	return 0;
 }
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 40aac6a..92a97fae 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -97,8 +97,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&apr_ch->w_lock, flags);
-	rc = glink_tx(apr_ch->handle, pkt_priv, data, len,
-			GLINK_TX_REQ_INTENT | GLINK_TX_ATOMIC);
+	rc = glink_tx(apr_ch->handle, pkt_priv, data, len, GLINK_TX_ATOMIC);
 	spin_unlock_irqrestore(&apr_ch->w_lock, flags);
 
 	if (rc)
diff --git a/drivers/soc/qcom/qdsp6v2/audio_notifier.c b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
index 414c123..2320fea 100644
--- a/drivers/soc/qcom/qdsp6v2/audio_notifier.c
+++ b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
@@ -626,9 +626,11 @@
 	 * If pdr registration failed, register clients on next service
 	 * Do in late init to ensure that SSR subsystem is initialized
 	 */
+	mutex_lock(&notifier_mutex);
 	if (!audio_notifer_is_service_enabled(AUDIO_NOTIFIER_PDR_SERVICE))
 		audio_notifer_reg_all_clients();
 
+	mutex_unlock(&notifier_mutex);
 	return 0;
 }
 late_initcall(audio_notifier_late_init);
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index b4713ac..fcb3731 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2017, 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
@@ -134,6 +134,7 @@
 #define R3_STR "r3"
 #define R4_STR "r4"
 #define R5_STR "r5"
+#define R6_STR "r6"
 
 #endif
 
@@ -481,6 +482,7 @@
 	register u32 r3 asm("r3") = w3;
 	register u32 r4 asm("r4") = w4;
 	register u32 r5 asm("r5") = w5;
+	register u32 r6 asm("r6") = 0;
 
 	do {
 		asm volatile(
@@ -494,13 +496,14 @@
 			__asmeq("%7", R3_STR)
 			__asmeq("%8", R4_STR)
 			__asmeq("%9", R5_STR)
+			__asmeq("%10", R6_STR)
 #ifdef REQUIRES_SEC
 			".arch_extension sec\n"
 #endif
 			"smc	#0\n"
 			: "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
 			: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
-			 "r" (r5));
+			 "r" (r5), "r" (r6));
 
 	} while (r0 == SCM_INTERRUPTED);
 
diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c
index 44192ff..5b0129e 100644
--- a/drivers/soc/qcom/smp2p_sleepstate.c
+++ b/drivers/soc/qcom/smp2p_sleepstate.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, 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
@@ -46,6 +46,7 @@
 
 static struct notifier_block sleepstate_pm_nb = {
 	.notifier_call = sleepstate_pm_notifier,
+	.priority = INT_MAX,
 };
 
 static int smp2p_sleepstate_probe(struct platform_device *pdev)
diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c
index 21f3580..55cb604 100644
--- a/drivers/soc/qcom/subsystem_restart.c
+++ b/drivers/soc/qcom/subsystem_restart.c
@@ -35,6 +35,7 @@
 #include <soc/qcom/subsystem_restart.h>
 #include <soc/qcom/subsystem_notif.h>
 #include <soc/qcom/sysmon.h>
+#include <trace/events/trace_msm_pil_event.h>
 
 #include <asm/current.h>
 
@@ -534,8 +535,10 @@
 		notif_data.no_auth = dev->desc->no_auth;
 		notif_data.pdev = pdev;
 
+		trace_pil_notif("before_send_notif", notif, dev->desc->fw_name);
 		subsys_notif_queue_notification(dev->notify, notif,
 								&notif_data);
+		trace_pil_notif("after_send_notif", notif, dev->desc->fw_name);
 	}
 }
 
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index d8c5a8f..f4f4c36 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -24,7 +24,7 @@
 
 static int setup_wakeup(uint64_t sleep_val)
 {
-	struct tcs_cmd cmd[3] = { { 0 } };
+	struct tcs_cmd cmd[2] = { { 0 } };
 
 	cmd[0].data = (sleep_val >> 32) & PDC_TIME_UPPER_MASK;
 	cmd[0].data |= 1 << PDC_TIME_VALID_SHIFT;
diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c
index 034ddd3..c8bb13d 100644
--- a/drivers/soc/qcom/wcd-dsp-glink.c
+++ b/drivers/soc/qcom/wcd-dsp-glink.c
@@ -21,6 +21,7 @@
 #include <linux/list.h>
 #include <linux/cdev.h>
 #include <linux/platform_device.h>
+#include <linux/vmalloc.h>
 #include <soc/qcom/glink.h>
 #include "sound/wcd-dsp-glink.h"
 
@@ -29,6 +30,10 @@
 #define WDSP_MAX_READ_SIZE (4 * 1024)
 #define WDSP_MAX_NO_OF_INTENTS (20)
 #define WDSP_MAX_NO_OF_CHANNELS (10)
+#define WDSP_WRITE_PKT_SIZE (sizeof(struct wdsp_write_pkt))
+#define WDSP_REG_PKT_SIZE (sizeof(struct wdsp_reg_pkt))
+#define WDSP_CMD_PKT_SIZE (sizeof(struct wdsp_cmd_pkt))
+#define WDSP_CH_CFG_SIZE (sizeof(struct wdsp_glink_ch_cfg))
 
 #define MINOR_NUMBER_COUNT 1
 #define WDSP_EDGE "wdsp"
@@ -183,7 +188,7 @@
 		return;
 	}
 	/* Free tx pkt */
-	kfree(pkt_priv);
+	vfree(pkt_priv);
 }
 
 /*
@@ -201,7 +206,7 @@
 		return;
 	}
 	/* Free tx pkt */
-	kfree(pkt_priv);
+	vfree(pkt_priv);
 }
 
 /*
@@ -519,9 +524,10 @@
  * and register with glink
  * wpriv:     Wdsp_glink private structure.
  * pkt:       Glink registration packet contains glink channel information.
+ * pkt_size:  Size of the pkt.
  */
 static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
-				   struct wdsp_reg_pkt *pkt)
+				   struct wdsp_reg_pkt *pkt, size_t pkt_size)
 {
 	int ret = 0, i, j;
 	struct glink_link_info link_info;
@@ -530,14 +536,23 @@
 	u8 no_of_channels;
 	u8 *payload;
 	u32 ch_size, ch_cfg_size;
+	size_t size = WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE;
 
+	mutex_lock(&wpriv->glink_mutex);
+	if (wpriv->ch) {
+		dev_err(wpriv->dev, "%s: glink ch memory is already allocated\n",
+			 __func__);
+		ret = -EINVAL;
+		goto done;
+	}
 	payload = (u8 *)pkt->payload;
 	no_of_channels = pkt->no_of_channels;
 
 	if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) {
-		dev_info(wpriv->dev, "%s: no_of_channels = %d are limited to %d\n",
-			 __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
-		no_of_channels = WDSP_MAX_NO_OF_CHANNELS;
+		dev_err(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n",
+			__func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
+		ret = -EINVAL;
+		goto done;
 	}
 	ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *),
 		     GFP_KERNEL);
@@ -551,20 +566,34 @@
 	for (i = 0; i < no_of_channels; i++) {
 		ch_cfg = (struct wdsp_glink_ch_cfg *)payload;
 
+		size += WDSP_CH_CFG_SIZE;
+		if (size > pkt_size) {
+			dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
+				__func__, size, pkt_size);
+			ret = -EINVAL;
+			goto err_ch_mem;
+		}
 		if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) {
 			dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
 				__func__, ch_cfg->no_of_intents);
 			ret = -EINVAL;
 			goto err_ch_mem;
 		}
+		size += (sizeof(u32) * ch_cfg->no_of_intents);
+		if (size > pkt_size) {
+			dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
+				__func__, size, pkt_size);
+			ret = -EINVAL;
+			goto err_ch_mem;
+		}
 
 		ch_cfg_size = sizeof(struct wdsp_glink_ch_cfg) +
 					(sizeof(u32) * ch_cfg->no_of_intents);
 		ch_size = sizeof(struct wdsp_glink_ch) +
 					(sizeof(u32) * ch_cfg->no_of_intents);
 
-		dev_dbg(wpriv->dev, "%s: channels = %d, ch_cfg_size %d",
-			 __func__, no_of_channels, ch_cfg_size);
+		dev_dbg(wpriv->dev, "%s: channels: %d ch_cfg_size: %d, size: %zd, pkt_size: %zd",
+			 __func__, no_of_channels, ch_cfg_size, size, pkt_size);
 
 		ch[i] = kzalloc(ch_size, GFP_KERNEL);
 		if (!ch[i]) {
@@ -611,6 +640,7 @@
 	wpriv->no_of_channels = 0;
 
 done:
+	mutex_unlock(&wpriv->glink_mutex);
 	return ret;
 }
 
@@ -650,7 +680,7 @@
 			 * there won't be any tx_done notification to
 			 * free the buffer.
 			 */
-			kfree(tx_buf);
+			vfree(tx_buf);
 		}
 	} else {
 		mutex_unlock(&tx_buf->ch->mutex);
@@ -660,7 +690,7 @@
 		 * Free tx_buf here as there won't be any tx_done
 		 * notification in this case also.
 		 */
-		kfree(tx_buf);
+		vfree(tx_buf);
 	}
 }
 
@@ -753,6 +783,7 @@
 	struct wdsp_cmd_pkt *cpkt;
 	struct wdsp_glink_tx_buf *tx_buf;
 	struct wdsp_glink_priv *wpriv;
+	size_t pkt_max_size;
 
 	wpriv = (struct wdsp_glink_priv *)file->private_data;
 	if (!wpriv) {
@@ -761,7 +792,7 @@
 		goto done;
 	}
 
-	if ((count < sizeof(struct wdsp_write_pkt)) ||
+	if ((count < WDSP_WRITE_PKT_SIZE) ||
 	    (count > WDSP_MAX_WRITE_SIZE)) {
 		dev_err(wpriv->dev, "%s: Invalid count = %zd\n",
 			__func__, count);
@@ -771,8 +802,8 @@
 
 	dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count);
 
-	tx_buf_size = WDSP_MAX_WRITE_SIZE + sizeof(struct wdsp_glink_tx_buf);
-	tx_buf = kzalloc(tx_buf_size, GFP_KERNEL);
+	tx_buf_size = count + sizeof(struct wdsp_glink_tx_buf);
+	tx_buf = vzalloc(tx_buf_size);
 	if (!tx_buf) {
 		ret = -ENOMEM;
 		goto done;
@@ -789,19 +820,20 @@
 	wpkt = (struct wdsp_write_pkt *)tx_buf->buf;
 	switch (wpkt->pkt_type) {
 	case WDSP_REG_PKT:
-		if (count <= (sizeof(struct wdsp_write_pkt) +
-			      sizeof(struct wdsp_reg_pkt))) {
+		if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE +
+			     WDSP_CH_CFG_SIZE)) {
 			dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
 				__func__, count);
 			ret = -EINVAL;
 			goto free_buf;
 		}
 		ret = wdsp_glink_ch_info_init(wpriv,
-					(struct wdsp_reg_pkt *)wpkt->payload);
+					(struct wdsp_reg_pkt *)wpkt->payload,
+					count);
 		if (ret < 0)
 			dev_err(wpriv->dev, "%s: glink register failed, ret = %d\n",
 				__func__, ret);
-		kfree(tx_buf);
+		vfree(tx_buf);
 		break;
 	case WDSP_READY_PKT:
 		ret = wait_event_timeout(wpriv->link_state_wait,
@@ -815,11 +847,10 @@
 			goto free_buf;
 		}
 		ret = 0;
-		kfree(tx_buf);
+		vfree(tx_buf);
 		break;
 	case WDSP_CMD_PKT:
-		if (count <= (sizeof(struct wdsp_write_pkt) +
-			      sizeof(struct wdsp_cmd_pkt))) {
+		if (count <= (WDSP_WRITE_PKT_SIZE + WDSP_CMD_PKT_SIZE)) {
 			dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
 				__func__, count);
 			ret = -EINVAL;
@@ -835,10 +866,18 @@
 			goto free_buf;
 		}
 		mutex_unlock(&wpriv->glink_mutex);
-
 		cpkt = (struct wdsp_cmd_pkt *)wpkt->payload;
-		dev_dbg(wpriv->dev, "%s: requested ch_name: %s\n", __func__,
-			 cpkt->ch_name);
+		pkt_max_size =  sizeof(struct wdsp_write_pkt) +
+					sizeof(struct wdsp_cmd_pkt) +
+					cpkt->payload_size;
+		if (count < pkt_max_size) {
+			dev_err(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n",
+				__func__, count, pkt_max_size);
+			ret = -EINVAL;
+			goto free_buf;
+		}
+		dev_dbg(wpriv->dev, "%s: requested ch_name: %s, pkt_size: %zd\n",
+			__func__, cpkt->ch_name, pkt_max_size);
 		for (i = 0; i < wpriv->no_of_channels; i++) {
 			if (wpriv->ch && wpriv->ch[i] &&
 				(!strcmp(cpkt->ch_name,
@@ -873,13 +912,13 @@
 	default:
 		dev_err(wpriv->dev, "%s: Invalid packet type\n", __func__);
 		ret = -EINVAL;
-		kfree(tx_buf);
+		vfree(tx_buf);
 		break;
 	}
 	goto done;
 
 free_buf:
-	kfree(tx_buf);
+	vfree(tx_buf);
 
 done:
 	return ret;
diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig
index a4c2f0c..e1ca532 100644
--- a/drivers/soundwire/Kconfig
+++ b/drivers/soundwire/Kconfig
@@ -9,7 +9,7 @@
 
 if SOUNDWIRE
 config SOUNDWIRE_WCD_CTRL
-	depends on WCD9335_CODEC || WCD934X_CODEC
+	depends on WCD9XXX_CODEC_CORE
 	tristate "QTI WCD CODEC Soundwire controller"
 	default n
 	help
diff --git a/drivers/soundwire/soundwire.c b/drivers/soundwire/soundwire.c
index 68655a5..f0c7aa9 100644
--- a/drivers/soundwire/soundwire.c
+++ b/drivers/soundwire/soundwire.c
@@ -68,6 +68,27 @@
 }
 
 /**
+ * swr_remove_device - remove a soundwire device
+ * @swr_dev: soundwire device to remove
+ *
+ * Remove a soundwire device. Go through the soundwire
+ * device list that master has and remove swr_dev from
+ * it.
+ */
+void swr_remove_device(struct swr_device *swr_dev)
+{
+	struct swr_device *swr_dev_loop, *safe;
+
+	list_for_each_entry_safe(swr_dev_loop, safe,
+				 &swr_dev->master->devices,
+				 dev_list) {
+		if (swr_dev == swr_dev_loop)
+			list_del(&swr_dev_loop->dev_list);
+	}
+}
+EXPORT_SYMBOL(swr_remove_device);
+
+/**
  * swr_new_device - instantiate a new soundwire device
  * @master: Controller to which device is connected
  * @info: Describes the soundwire device
@@ -128,47 +149,6 @@
 EXPORT_SYMBOL(swr_new_device);
 
 /**
- * swr_startup_devices - perform additional initialization for child devices
- *
- * @swr_dev: pointer to soundwire slave device
- *
- * Performs any additional initialization needed for a soundwire slave device.
- * This is a optional functionality defined by slave devices.
- * Removes the slave node from the list, in case there is any failure.
- */
-int swr_startup_devices(struct swr_device *swr_dev)
-{
-	struct swr_driver *swr_drv;
-	struct device *dev;
-	int ret = 0;
-
-	if (!swr_dev)
-		return -EINVAL;
-
-	dev = &swr_dev->dev;
-	if (!dev)
-		return -EINVAL;
-
-	swr_drv = to_swr_driver(dev->driver);
-	if (!swr_drv)
-		return -EINVAL;
-
-	if (swr_drv->startup) {
-		ret = swr_drv->startup(swr_dev);
-		if (ret)
-			goto out;
-
-		dev_dbg(&swr_dev->dev,
-			"%s: startup complete for device %lx\n",
-			__func__, swr_dev->addr);
-	}
-
-out:
-	return ret;
-}
-EXPORT_SYMBOL(swr_startup_devices);
-
-/**
  * of_register_swr_devices - register child devices on to the soundwire bus
  * @master: pointer to soundwire master device
  *
@@ -202,14 +182,15 @@
 		}
 		info.addr = addr;
 		info.of_node = of_node_get(node);
+		master->num_dev++;
 		swr = swr_new_device(master, &info);
 		if (!swr) {
 			dev_err(&master->dev, "of_swr: Register failed %s\n",
 				node->full_name);
 			of_node_put(node);
+			master->num_dev--;
 			continue;
 		}
-		master->num_dev++;
 	}
 	return 0;
 }
@@ -605,7 +586,7 @@
 	dev = &swr_dev->dev;
 	sdrv = to_swr_driver(dev->driver);
 	if (!sdrv)
-		return -EINVAL;
+		return 0;
 
 	if (sdrv->device_up)
 		return sdrv->device_up(to_swr_device(dev));
@@ -633,7 +614,7 @@
 	dev = &swr_dev->dev;
 	sdrv = to_swr_driver(dev->driver);
 	if (!sdrv)
-		return -EINVAL;
+		return 0;
 
 	if (sdrv->device_down)
 		return sdrv->device_down(to_swr_device(dev));
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index ce2a367..e338d58 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -223,6 +223,12 @@
 static struct dentry *debugfs_reg_dump;
 static unsigned int read_data;
 
+
+static bool swrm_is_msm_variant(int val)
+{
+	return (val == SWRM_VERSION_1_3);
+}
+
 static int swrm_debug_open(struct inode *inode, struct file *file)
 {
 	file->private_data = inode->i_private;
@@ -513,8 +519,17 @@
 			__func__, val, ret);
 		goto err;
 	}
-	if (cmd_id == 0xF)
-		wait_for_completion_timeout(&swrm->broadcast, (2 * HZ/10));
+	if (cmd_id == 0xF) {
+		/*
+		 * sleep for 10ms for MSM soundwire variant to allow broadcast
+		 * command to complete.
+		 */
+		if (swrm_is_msm_variant(swrm->version))
+			usleep_range(10000, 10100);
+		else
+			wait_for_completion_timeout(&swrm->broadcast,
+						    (2 * HZ/10));
+	}
 err:
 	return ret;
 }
@@ -1355,7 +1370,6 @@
 {
 	struct swr_mstr_ctrl *swrm;
 	struct swr_ctrl_platform_data *pdata;
-	struct swr_device *swr_dev, *safe;
 	int ret;
 
 	/* Allocate soundwire master driver structure */
@@ -1454,9 +1468,6 @@
 		goto err_mstr_fail;
 	}
 
-	if (pdev->dev.of_node)
-		of_register_swr_devices(&swrm->master);
-
 	/* Add devices registered with board-info as the
 	 * controller will be up now
 	 */
@@ -1471,16 +1482,13 @@
 		mutex_unlock(&swrm->mlock);
 		goto err_mstr_fail;
 	}
+	swrm->version = swrm->read(swrm->handle, SWRM_COMP_HW_VERSION);
 
-	/* Enumerate slave devices */
-	list_for_each_entry_safe(swr_dev, safe, &swrm->master.devices,
-				 dev_list) {
-		ret = swr_startup_devices(swr_dev);
-		if (ret)
-			list_del(&swr_dev->dev_list);
-	}
 	mutex_unlock(&swrm->mlock);
 
+	if (pdev->dev.of_node)
+		of_register_swr_devices(&swrm->master);
+
 	dbgswrm = swrm;
 	debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
 	if (!IS_ERR(debugfs_swrm_dent)) {
diff --git a/drivers/soundwire/swr-wcd-ctrl.h b/drivers/soundwire/swr-wcd-ctrl.h
index 8992318..b7a3eda 100644
--- a/drivers/soundwire/swr-wcd-ctrl.h
+++ b/drivers/soundwire/swr-wcd-ctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -23,6 +23,10 @@
 
 #define SWR_MSTR_PORT_LEN	8 /* Number of master ports */
 
+#define SWRM_VERSION_1_0 0x01010000
+#define SWRM_VERSION_1_2 0x01030000
+#define SWRM_VERSION_1_3 0x01040000
+
 enum {
 	SWR_MSTR_PAUSE,
 	SWR_MSTR_RESUME,
@@ -88,6 +92,7 @@
 	int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
 			void *data), void *swr_handle, int type);
 	int irq;
+	int version;
 	int num_enum_slaves;
 	int slave_status;
 	struct swr_mstr_port *mstr_port;
diff --git a/drivers/soundwire/swrm_registers.h b/drivers/soundwire/swrm_registers.h
index c6923f3..50c3ecf 100644
--- a/drivers/soundwire/swrm_registers.h
+++ b/drivers/soundwire/swrm_registers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
 
 #define SWRM_BASE_ADDRESS				0x00
 
+#define SWRM_COMP_HW_VERSION                     SWRM_BASE_ADDRESS
 #define SWRM_COMP_CFG_ADDR			(SWRM_BASE_ADDRESS+0x00000004)
 #define SWRM_COMP_CFG_RMSK				0x3
 #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_BMSK		0x2
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 08eb00a..ad3eb187 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -110,14 +110,6 @@
 	return spi;
 }
 
-static int get_sclk(u32 speed_hz, unsigned long *sclk_freq)
-{
-	u32 root_freq[] = { 19200000 };
-
-	*sclk_freq = root_freq[0];
-	return 0;
-}
-
 static int do_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas)
 {
 	unsigned long sclk_freq;
@@ -131,14 +123,20 @@
 	clk_sel &= ~CLK_SEL_MSK;
 	m_clk_cfg &= ~CLK_DIV_MSK;
 
-	idx = get_sclk(speed_hz, &sclk_freq);
-	if (idx < 0)
-		return -EINVAL;
+	ret = geni_se_clk_freq_match(&mas->spi_rsc, speed_hz, &idx,
+					&sclk_freq, true);
+	if (ret) {
+		dev_err(mas->dev, "%s: Failed(%d) to find src clk for 0x%x\n",
+						__func__, ret, speed_hz);
+		return ret;
+	}
 
 	div = ((sclk_freq / SPI_OVERSAMPLING) / speed_hz);
 	if (!div)
 		return -EINVAL;
 
+	dev_dbg(mas->dev, "%s: req %u sclk %lu, idx %d, div %d\n", __func__,
+						speed_hz, sclk_freq, idx, div);
 	clk_sel |= (idx & CLK_SEL_MSK);
 	m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
 	ret = clk_set_rate(rsc->se_clk, sclk_freq);
@@ -362,13 +360,13 @@
 	reinit_completion(&mas->xfer_done);
 	/* Speed and bits per word can be overridden per transfer */
 	if (xfer->speed_hz != mas->cur_speed_hz) {
+		mas->cur_speed_hz = xfer->speed_hz;
 		ret = do_spi_clk_cfg(mas->cur_speed_hz, mas);
 		if (ret) {
 			dev_err(mas->dev, "%s:Err setting clks:%d\n",
 								__func__, ret);
 			goto geni_transfer_one_exit;
 		}
-		mas->cur_speed_hz = xfer->speed_hz;
 	}
 
 	setup_fifo_xfer(xfer, mas, slv->mode, spi);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 9cc85ee..bfd4b7a 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -576,10 +576,16 @@
 	int last = pa->max_apid >> 5;
 	u32 status, enable;
 	int i, id, apid;
+	/* status based dispatch */
+	bool acc_valid = false;
+	u32 irq_status = 0;
 
 	for (i = first; i <= last; ++i) {
 		status = readl_relaxed(pa->acc_status +
 				      pa->ver_ops->owner_acc_status(pa->ee, i));
+		if (status)
+			acc_valid = true;
+
 		while (status) {
 			id = ffs(status) - 1;
 			status &= ~BIT(id);
@@ -595,6 +601,28 @@
 				periph_interrupt(pa, apid, show);
 		}
 	}
+
+	/* ACC_STATUS is empty but IRQ fired check IRQ_STATUS */
+	if (!acc_valid) {
+		for (i = pa->min_apid; i <= pa->max_apid; i++) {
+			/* skip if APPS is not irq owner */
+			if (pa->apid_data[i].irq_owner != pa->ee)
+				continue;
+
+			irq_status = readl_relaxed(pa->intr +
+						pa->ver_ops->irq_status(i));
+			if (irq_status) {
+				enable = readl_relaxed(pa->intr +
+						pa->ver_ops->acc_enable(i));
+				if (enable & SPMI_PIC_ACC_ENABLE_BIT) {
+					dev_dbg(&pa->spmic->dev,
+						"Dispatching IRQ for apid=%d status=%x\n",
+						i, irq_status);
+					periph_interrupt(pa, i, show);
+				}
+			}
+		}
+	}
 }
 
 static void pmic_arb_chained_irq(struct irq_desc *desc)
diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c
index be6e985..a6d1cc8 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pack.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pack.c
@@ -387,18 +387,10 @@
 	struct lov_mds_md *lmmk = NULL;
 	int rc, lmmk_size, lmm_size;
 	int lum_size;
-	mm_segment_t seg;
 
 	if (!lsm)
 		return -ENODATA;
 
-	/*
-	 * "Switch to kernel segment" to allow copying from kernel space by
-	 * copy_{to,from}_user().
-	 */
-	seg = get_fs();
-	set_fs(KERNEL_DS);
-
 	/* we only need the header part from user space to get lmm_magic and
 	 * lmm_stripe_count, (the header part is common to v1 and v3)
 	 */
@@ -478,6 +470,5 @@
 out_free:
 	kfree(lmmk);
 out:
-	set_fs(seg);
 	return rc;
 }
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index cae4dea..077344c 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1182,15 +1182,28 @@
 	if (cmd->unknown_data_length) {
 		cmd->data_length = size;
 	} else if (size != cmd->data_length) {
-		pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
+		pr_warn_ratelimited("TARGET_CORE[%s]: Expected Transfer Length:"
 			" %u does not match SCSI CDB Length: %u for SAM Opcode:"
 			" 0x%02x\n", cmd->se_tfo->get_fabric_name(),
 				cmd->data_length, size, cmd->t_task_cdb[0]);
 
-		if (cmd->data_direction == DMA_TO_DEVICE &&
-		    cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
-			pr_err("Rejecting underflow/overflow WRITE data\n");
-			return TCM_INVALID_CDB_FIELD;
+		if (cmd->data_direction == DMA_TO_DEVICE) {
+			if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
+				pr_err_ratelimited("Rejecting underflow/overflow"
+						   " for WRITE data CDB\n");
+				return TCM_INVALID_CDB_FIELD;
+			}
+			/*
+			 * Some fabric drivers like iscsi-target still expect to
+			 * always reject overflow writes.  Reject this case until
+			 * full fabric driver level support for overflow writes
+			 * is introduced tree-wide.
+			 */
+			if (size > cmd->data_length) {
+				pr_err_ratelimited("Rejecting overflow for"
+						   " WRITE control CDB\n");
+				return TCM_INVALID_CDB_FIELD;
+			}
 		}
 		/*
 		 * Reject READ_* or WRITE_* with overflow/underflow for
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 355d013..cd5bde3 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -118,6 +118,10 @@
 static DEFINE_MUTEX(cooling_cpufreq_lock);
 
 static unsigned int cpufreq_dev_count;
+static int8_t cpuhp_registered;
+static struct work_struct cpuhp_register_work;
+static struct cpumask cpus_pending_online;
+static DEFINE_MUTEX(core_isolate_lock);
 
 static DEFINE_MUTEX(cooling_list_lock);
 static LIST_HEAD(cpufreq_dev_list);
@@ -212,6 +216,49 @@
 }
 EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level);
 
+static int cpufreq_hp_offline(unsigned int offline_cpu)
+{
+	struct cpufreq_cooling_device *cpufreq_dev;
+
+	mutex_lock(&cooling_list_lock);
+	list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+		if (!cpumask_test_cpu(offline_cpu, &cpufreq_dev->allowed_cpus))
+			continue;
+
+		mutex_lock(&core_isolate_lock);
+		if (cpufreq_dev->cpufreq_state == cpufreq_dev->max_level)
+			sched_unisolate_cpu_unlocked(offline_cpu);
+		mutex_unlock(&core_isolate_lock);
+		break;
+	}
+	mutex_unlock(&cooling_list_lock);
+
+	return 0;
+}
+
+static int cpufreq_hp_online(unsigned int online_cpu)
+{
+	struct cpufreq_cooling_device *cpufreq_dev;
+	int ret = 0;
+
+	mutex_lock(&cooling_list_lock);
+	list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+		if (!cpumask_test_cpu(online_cpu, &cpufreq_dev->allowed_cpus))
+			continue;
+
+		mutex_lock(&core_isolate_lock);
+		if (cpufreq_dev->cpufreq_state == cpufreq_dev->max_level) {
+			cpumask_set_cpu(online_cpu, &cpus_pending_online);
+			ret = NOTIFY_BAD;
+		}
+		mutex_unlock(&core_isolate_lock);
+		break;
+	}
+	mutex_unlock(&cooling_list_lock);
+
+	return ret;
+}
+
 /**
  * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
  * @nb:	struct notifier_block * with callback info.
@@ -611,6 +658,9 @@
 	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
 	unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus);
 	unsigned int clip_freq;
+	unsigned long prev_state;
+	struct device *cpu_dev;
+	int ret = 0;
 
 	/* Request state should be less than max_level */
 	if (WARN_ON(state > cpufreq_device->max_level))
@@ -620,13 +670,34 @@
 	if (cpufreq_device->cpufreq_state == state)
 		return 0;
 
+	mutex_lock(&core_isolate_lock);
+	prev_state = cpufreq_device->cpufreq_state;
 	cpufreq_device->cpufreq_state = state;
 	/* If state is the last, isolate the CPU */
-	if (state == cpufreq_device->max_level)
-		return sched_isolate_cpu(cpu);
-	else if (state < cpufreq_device->max_level)
-		sched_unisolate_cpu(cpu);
-
+	if (state == cpufreq_device->max_level) {
+		if (cpu_online(cpu))
+			sched_isolate_cpu(cpu);
+		mutex_unlock(&core_isolate_lock);
+		return ret;
+	} else if ((prev_state == cpufreq_device->max_level)
+			&& (state < cpufreq_device->max_level)) {
+		if (cpumask_test_and_clear_cpu(cpu, &cpus_pending_online)) {
+			cpu_dev = get_cpu_device(cpu);
+			mutex_unlock(&core_isolate_lock);
+			/*
+			 * Unlock before calling the device_online.
+			 * Else, this will lead to deadlock, since the hp
+			 * online callback will be blocked on this mutex.
+			 */
+			ret = device_online(cpu_dev);
+			if (ret)
+				pr_err("CPU:%d online error:%d\n", cpu, ret);
+			goto update_frequency;
+		} else
+			sched_unisolate_cpu(cpu);
+	}
+	mutex_unlock(&core_isolate_lock);
+update_frequency:
 	clip_freq = cpufreq_device->freq_table[state];
 	cpufreq_device->clipped_freq = clip_freq;
 
@@ -878,6 +949,16 @@
 	return max;
 }
 
+static void register_cdev(struct work_struct *work)
+{
+	int ret = 0;
+
+	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+				"cpu_cooling/no-sched",	cpufreq_hp_online,
+				cpufreq_hp_offline);
+	if (ret < 0)
+		pr_err("Error registering for hotpug callback:%d\n", ret);
+}
 /**
  * __cpufreq_cooling_register - helper function to create cpufreq cooling device
  * @np: a valid struct device_node to the cooling device device tree node
@@ -1025,6 +1106,12 @@
 	if (!cpufreq_dev_count++)
 		cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
 					  CPUFREQ_POLICY_NOTIFIER);
+	if (!cpuhp_registered) {
+		cpuhp_registered = 1;
+		cpumask_clear(&cpus_pending_online);
+		INIT_WORK(&cpuhp_register_work, register_cdev);
+		queue_work(system_wq, &cpuhp_register_work);
+	}
 	mutex_unlock(&cooling_cpufreq_lock);
 
 	goto put_policy;
diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c
index 57cdd49..e1f22a3 100644
--- a/drivers/thermal/qcom-spmi-temp-alarm.c
+++ b/drivers/thermal/qcom-spmi-temp-alarm.c
@@ -22,6 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/thermal.h>
+#include "thermal_core.h"
 
 #define QPNP_TM_REG_TYPE		0x04
 #define QPNP_TM_REG_SUBTYPE		0x05
@@ -188,7 +189,7 @@
 {
 	struct qpnp_tm_chip *chip = data;
 
-	thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED);
+	of_thermal_handle_trip(chip->tz_dev);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
index f6e1b86..38d5b93 100644
--- a/drivers/thermal/qcom/Kconfig
+++ b/drivers/thermal/qcom/Kconfig
@@ -40,3 +40,12 @@
 	  The virtual sensor information includes the underlying thermal
 	  sensors to query for temperature and the aggregation logic to
 	  determine the virtual sensor temperature.
+
+config QTI_REG_COOLING_DEVICE
+	bool "QTI Regulator cooling device"
+	depends on THERMAL_OF && MSM_QMP
+	help
+	  This enables the Regulator cooling device. This cooling device
+	  will be used by QTI chipset to place a floor voltage restriction at
+	  low temperatures. The regulator cooling device will message the AOP
+	  using mail box to establish the floor voltage.
diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 2ba487d..2ba84c6 100644
--- a/drivers/thermal/qcom/Makefile
+++ b/drivers/thermal/qcom/Makefile
@@ -3,3 +3,4 @@
 obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o
 obj-$(CONFIG_QTI_THERMAL_LIMITS_DCVS) += msm_lmh_dcvs.o lmh_dbg.o
 obj-$(CONFIG_QTI_VIRTUAL_SENSOR) += qti_virtual_sensor.o
+obj-$(CONFIG_QTI_REG_COOLING_DEVICE) += regulator_cooling.o
diff --git a/drivers/thermal/qcom/qti_virtual_sensor.c b/drivers/thermal/qcom/qti_virtual_sensor.c
index 3064c74..923680a 100644
--- a/drivers/thermal/qcom/qti_virtual_sensor.c
+++ b/drivers/thermal/qcom/qti_virtual_sensor.c
@@ -29,7 +29,7 @@
 		.logic = VIRT_MAXIMUM,
 	},
 	{
-		.virt_zone_name = "silver-virt-max-usr",
+		.virt_zone_name = "silv-virt-max-step",
 		.num_sensors = 4,
 		.sensor_names = {"cpu0-silver-usr",
 				"cpu1-silver-usr",
@@ -38,7 +38,7 @@
 		.logic = VIRT_MAXIMUM,
 	},
 	{
-		.virt_zone_name = "gold-virt-max-usr",
+		.virt_zone_name = "gold-virt-max-step",
 		.num_sensors = 4,
 		.sensor_names = {"cpu0-gold-usr",
 				"cpu1-gold-usr",
diff --git a/drivers/thermal/qcom/regulator_cooling.c b/drivers/thermal/qcom/regulator_cooling.c
new file mode 100644
index 0000000..3cbf198
--- /dev/null
+++ b/drivers/thermal/qcom/regulator_cooling.c
@@ -0,0 +1,224 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mailbox_client.h>
+
+#define REG_CDEV_DRIVER "reg-cooling-device"
+#define REG_MSG_FORMAT "{class:volt_flr, event:zero_temp, res:%s, value:%s}"
+#define REG_CDEV_MAX_STATE 1
+#define MBOX_TOUT_MS 1000
+#define REG_MSG_MAX_LEN 100
+
+struct reg_cooling_device {
+	struct thermal_cooling_device	*cdev;
+	unsigned int			min_state;
+	const char			*resource_name;
+	struct mbox_chan		*qmp_chan;
+	struct mbox_client		*client;
+};
+
+struct aop_msg {
+	uint32_t len;
+	void *msg;
+};
+
+enum regulator_rail_type {
+	REG_COOLING_CX,
+	REG_COOLING_MX,
+	REG_COOLING_EBI,
+	REG_COOLING_NR,
+};
+
+static char *regulator_rail[REG_COOLING_NR] = {
+	"cx",
+	"mx",
+	"ebi",
+};
+
+static int aop_send_msg(struct reg_cooling_device *reg_dev, int min_state)
+{
+	char msg_buf[REG_MSG_MAX_LEN] = {0};
+	int ret = 0;
+	struct aop_msg msg;
+
+	if (!reg_dev->qmp_chan) {
+		pr_err("mbox not initialized for resource:%s\n",
+				reg_dev->resource_name);
+		return -EINVAL;
+	}
+
+	ret = snprintf(msg_buf, REG_MSG_MAX_LEN, REG_MSG_FORMAT,
+			reg_dev->resource_name,
+			(min_state == REG_CDEV_MAX_STATE) ? "off" : "on");
+	if (ret >= REG_MSG_MAX_LEN) {
+		pr_err("Message too long for resource:%s\n",
+				reg_dev->resource_name);
+		return -E2BIG;
+	}
+	msg.len = REG_MSG_MAX_LEN;
+	msg.msg = msg_buf;
+	ret = mbox_send_message(reg_dev->qmp_chan, &msg);
+
+	return (ret < 0) ? ret : 0;
+}
+
+static int reg_get_max_state(struct thermal_cooling_device *cdev,
+				unsigned long *state)
+{
+	*state = REG_CDEV_MAX_STATE;
+	return 0;
+}
+
+static int reg_get_min_state(struct thermal_cooling_device *cdev,
+				unsigned long *state)
+{
+	struct reg_cooling_device *reg_dev = cdev->devdata;
+
+	*state = reg_dev->min_state;
+	return 0;
+}
+
+static int reg_send_min_state(struct thermal_cooling_device *cdev,
+				unsigned long state)
+{
+	struct reg_cooling_device *reg_dev = cdev->devdata;
+	int ret = 0;
+
+	if (state > REG_CDEV_MAX_STATE)
+		state = REG_CDEV_MAX_STATE;
+
+	if (reg_dev->min_state == state)
+		return ret;
+
+	ret = aop_send_msg(reg_dev, state);
+	if (ret) {
+		pr_err("regulator:%s switching to floor %lu error. err:%d\n",
+			reg_dev->resource_name, state, ret);
+	} else {
+		pr_debug("regulator:%s switched to %lu from %d\n",
+			reg_dev->resource_name, state, reg_dev->min_state);
+		reg_dev->min_state = state;
+	}
+
+	return ret;
+}
+
+static int reg_get_cur_state(struct thermal_cooling_device *cdev,
+				unsigned long *state)
+{
+	*state = 0;
+	return 0;
+}
+
+static int reg_send_cur_state(struct thermal_cooling_device *cdev,
+				unsigned long state)
+{
+	return 0;
+}
+
+static struct thermal_cooling_device_ops reg_dev_ops = {
+	.get_max_state = reg_get_max_state,
+	.get_cur_state = reg_get_cur_state,
+	.set_cur_state = reg_send_cur_state,
+	.set_min_state = reg_send_min_state,
+	.get_min_state = reg_get_min_state,
+};
+
+static int reg_init_mbox(struct platform_device *pdev,
+			struct reg_cooling_device *reg_dev)
+{
+	reg_dev->client = devm_kzalloc(&pdev->dev, sizeof(*reg_dev->client),
+					GFP_KERNEL);
+	if (!reg_dev->client)
+		return -ENOMEM;
+
+	reg_dev->client->dev = &pdev->dev;
+	reg_dev->client->tx_block = true;
+	reg_dev->client->tx_tout = MBOX_TOUT_MS;
+	reg_dev->client->knows_txdone = false;
+
+	reg_dev->qmp_chan = mbox_request_channel(reg_dev->client, 0);
+	if (IS_ERR(reg_dev->qmp_chan)) {
+		dev_err(&pdev->dev, "Mbox request failed. err:%ld\n",
+				PTR_ERR(reg_dev->qmp_chan));
+		return PTR_ERR(reg_dev->qmp_chan);
+	}
+
+	return 0;
+}
+
+static int reg_dev_probe(struct platform_device *pdev)
+{
+	int ret = 0, idx = 0;
+	struct reg_cooling_device *reg_dev = NULL;
+
+	reg_dev = devm_kzalloc(&pdev->dev, sizeof(*reg_dev), GFP_KERNEL);
+	if (!reg_dev)
+		return -ENOMEM;
+
+	ret = reg_init_mbox(pdev, reg_dev);
+	if (ret)
+		return ret;
+
+	ret = of_property_read_string(pdev->dev.of_node,
+			"qcom,reg-resource-name",
+			&reg_dev->resource_name);
+	if (ret) {
+		dev_err(&pdev->dev, "Error reading resource name. err:%d\n",
+			ret);
+		goto mbox_free;
+	}
+
+	for (idx = 0; idx < REG_COOLING_NR; idx++) {
+		if (!strcmp(reg_dev->resource_name, regulator_rail[idx]))
+			break;
+	}
+	if (idx == REG_COOLING_NR) {
+		dev_err(&pdev->dev, "Invalid regulator resource name:%s\n",
+				reg_dev->resource_name);
+		ret = -EINVAL;
+		goto mbox_free;
+	}
+	reg_dev->min_state = REG_CDEV_MAX_STATE;
+	reg_dev->cdev = thermal_of_cooling_device_register(
+				pdev->dev.of_node,
+				(char *)reg_dev->resource_name,
+				reg_dev, &reg_dev_ops);
+	if (IS_ERR(reg_dev->cdev))
+		goto mbox_free;
+
+	return ret;
+
+mbox_free:
+	mbox_free_channel(reg_dev->qmp_chan);
+
+	return ret;
+}
+
+static const struct of_device_id reg_dev_of_match[] = {
+	{.compatible = "qcom,rpmh-reg-cdev", },
+	{}
+};
+
+static struct platform_driver reg_dev_driver = {
+	.driver = {
+		.name = REG_CDEV_DRIVER,
+		.of_match_table = reg_dev_of_match,
+	},
+	.probe = reg_dev_probe,
+};
+builtin_platform_driver(reg_dev_driver);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index b137c4e..68d9feb 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -418,8 +418,9 @@
 		thermal_zone_device_set_polling(thermal_passive_wq,
 						tz, tz->passive_delay);
 	else if (tz->polling_delay)
-		thermal_zone_device_set_polling(system_freezable_wq,
-						tz, tz->polling_delay);
+		thermal_zone_device_set_polling(
+				system_freezable_power_efficient_wq,
+				tz, tz->polling_delay);
 	else
 		thermal_zone_device_set_polling(NULL, tz, 0);
 
@@ -1424,9 +1425,26 @@
 	if (ret)
 		return ret;
 
-	/* lower default 0, upper default max_state */
-	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
-	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
+	/*
+	 * If upper or lower has a MACRO to define the mitigation state,
+	 * based on the MACRO determine the default state to use or the
+	 * offset from the max_state.
+	 */
+	if (upper > (THERMAL_MAX_LIMIT - max_state)) {
+		/* upper default max_state */
+		if (upper == THERMAL_NO_LIMIT)
+			upper = max_state;
+		else
+			upper = max_state - (THERMAL_MAX_LIMIT - upper);
+	}
+
+	if (lower > (THERMAL_MAX_LIMIT - max_state)) {
+		/* lower default 0 */
+		if (lower == THERMAL_NO_LIMIT)
+			lower = 0;
+		else
+			lower =  max_state - (THERMAL_MAX_LIMIT - lower);
+	}
 
 	if (lower > upper || upper > max_state)
 		return -EINVAL;
@@ -2117,7 +2135,7 @@
 	/* Bind cooling devices for this zone */
 	bind_tz(tz);
 
-	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
+	INIT_DEFERRABLE_WORK(&(tz->poll_queue), thermal_zone_device_check);
 
 	thermal_zone_device_reset(tz);
 	/* Update the new thermal zone and mark it as already updated. */
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index d386346..91d2ddd 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -1381,9 +1381,9 @@
 static void __exit ifx_spi_exit(void)
 {
 	/* unregister */
+	spi_unregister_driver(&ifx_spi_driver);
 	tty_unregister_driver(tty_drv);
 	put_tty_driver(tty_drv);
-	spi_unregister_driver(&ifx_spi_driver);
 	unregister_reboot_notifier(&ifx_modem_reboot_notifier_block);
 }
 
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 4b26252..ee84f89 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1976,12 +1976,14 @@
 
 	dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
 
-	ret = sci_request_irq(s);
-	if (unlikely(ret < 0))
-		return ret;
-
 	sci_request_dma(port);
 
+	ret = sci_request_irq(s);
+	if (unlikely(ret < 0)) {
+		sci_free_dma(port);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -2012,8 +2014,8 @@
 	}
 #endif
 
-	sci_free_dma(port);
 	sci_free_irq(s);
+	sci_free_dma(port);
 }
 
 static int sci_sck_calc(struct sci_port *s, unsigned int bps,
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 6d23eed..1c31e8a 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -294,7 +294,8 @@
 {
 	struct ci_hdrc *ci = s->private;
 
-	seq_printf(s, "%s\n", ci_role(ci)->name);
+	if (ci->role != CI_ROLE_END)
+		seq_printf(s, "%s\n", ci_role(ci)->name);
 
 	return 0;
 }
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index c9e80ad..6a15b72 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1987,6 +1987,7 @@
 int ci_hdrc_gadget_init(struct ci_hdrc *ci)
 {
 	struct ci_role_driver *rdrv;
+	int ret;
 
 	if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
 		return -ENXIO;
@@ -1999,7 +2000,10 @@
 	rdrv->stop	= udc_id_switch_for_host;
 	rdrv->irq	= udc_irq;
 	rdrv->name	= "gadget";
-	ci->roles[CI_ROLE_GADGET] = rdrv;
 
-	return udc_start(ci);
+	ret = udc_start(ci);
+	if (!ret)
+		ci->roles[CI_ROLE_GADGET] = rdrv;
+
+	return ret;
 }
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 009193c..b042152 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -590,6 +590,7 @@
  * @dbg_ep_events: different events counter for endpoint
  * @dbg_ep_events_diff: differential events counter for endpoint
  * @dbg_ep_events_ts: timestamp for previous event counters
+ * @fifo_depth: allocated TXFIFO depth
  */
 struct dwc3_ep {
 	struct usb_ep		endpoint;
@@ -644,6 +645,7 @@
 	struct dwc3_ep_events	dbg_ep_events;
 	struct dwc3_ep_events	dbg_ep_events_diff;
 	struct timespec		dbg_ep_events_ts;
+	int			fifo_depth;
 };
 
 enum dwc3_phy {
@@ -905,7 +907,6 @@
  * @pending_events: true when we have pending IRQs to be handled
  * @needs_fifo_resize: not all users might want fifo resizing, flag it
  * @pullups_connected: true when Run/Stop bit is set
- * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
  * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
  * @start_config_issued: true when StartConfig command has been issued
  * @three_stage_setup: set if we perform a three phase setup
@@ -947,6 +948,7 @@
  * @vbus_draw: current to be drawn from USB
  * @index: dwc3 instance's number
  * @dwc_ipc_log_ctxt: dwc3 ipc log context
+ * @last_fifo_depth: total TXFIFO depth of all enabled USB IN/INT endpoints
  * @imod_interval: set the interrupt moderation interval in 250ns
  *			increments or 0 to disable.
  */
@@ -1082,7 +1084,6 @@
 	unsigned		pending_events:1;
 	unsigned		needs_fifo_resize:1;
 	unsigned		pullups_connected:1;
-	unsigned		resize_fifos:1;
 	unsigned		setup_packet_pending:1;
 	unsigned		three_stage_setup:1;
 	unsigned		usb3_lpm_capable:1;
@@ -1142,6 +1143,7 @@
 	wait_queue_head_t	wait_linkstate;
 	unsigned int		index;
 	void			*dwc_ipc_log_ctxt;
+	int			last_fifo_depth;
 	struct dwc3_gadget_events	dbg_gadget_events;
 };
 
@@ -1297,7 +1299,7 @@
 /* prototypes */
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
-int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep);
 
 /* check whether we are on the DWC_usb3 core */
 static inline bool dwc3_is_usb3(struct dwc3 *dwc)
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index a7105af..260092c 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -324,7 +324,7 @@
 	struct dwc3		*dwc = s->private;
 	unsigned long		flags;
 	u32			mode = 0;
-	char			buf[32];
+	char buf[32] = {};
 
 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 		return -EFAULT;
@@ -404,7 +404,7 @@
 	struct dwc3		*dwc = s->private;
 	unsigned long		flags;
 	u32			testmode = 0;
-	char			buf[32];
+	char			buf[32] = {};
 
 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 		return -EFAULT;
@@ -511,7 +511,7 @@
 	struct dwc3		*dwc = s->private;
 	unsigned long		flags;
 	enum dwc3_link_state	state = 0;
-	char			buf[32];
+	char			buf[32] = {};
 
 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 		return -EFAULT;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 228d8af..a496468 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -69,6 +69,11 @@
 module_param(cpu_to_affin, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(cpu_to_affin, "affin usb irq to this cpu");
 
+/* override for USB speed */
+static int override_usb_speed;
+module_param(override_usb_speed, int, 0644);
+MODULE_PARM_DESC(override_usb_speed, "override for USB speed");
+
 /* XHCI registers */
 #define USB3_HCSPARAMS1		(0x4)
 #define USB3_PORTSC		(0x420)
@@ -143,6 +148,29 @@
 	ORIENTATION_CC2,
 };
 
+enum msm_usb_irq {
+	HS_PHY_IRQ,
+	PWR_EVNT_IRQ,
+	DP_HS_PHY_IRQ,
+	DM_HS_PHY_IRQ,
+	SS_PHY_IRQ,
+	USB_MAX_IRQ
+};
+
+struct usb_irq {
+	char *name;
+	int irq;
+	bool enable;
+};
+
+static const struct usb_irq usb_irq_info[USB_MAX_IRQ] = {
+	{"hs_phy_irq", 0},
+	{"pwr_event_irq", 0},
+	{"dp_hs_phy_irq", 0},
+	{"dm_hs_phy_irq", 0},
+	{"ss_phy_irq", 0},
+};
+
 /* Input bits to state machine (mdwc->inputs) */
 
 #define ID			0
@@ -184,8 +212,7 @@
 	int			vbus_retry_count;
 	bool			resume_pending;
 	atomic_t                pm_suspended;
-	int			hs_phy_irq;
-	int			ss_phy_irq;
+	struct usb_irq		wakeup_irq[USB_MAX_IRQ];
 	struct work_struct	resume_work;
 	struct work_struct	restart_usb_work;
 	bool			in_restart;
@@ -205,6 +232,7 @@
 	bool			vbus_active;
 	bool			suspend;
 	bool			disable_host_mode_pm;
+	bool			use_pdc_interrupts;
 	enum dwc3_id_state	id_state;
 	unsigned long		lpm_flags;
 #define MDWC3_SS_PHY_SUSPEND		BIT(0)
@@ -225,7 +253,6 @@
 
 	struct notifier_block	host_nb;
 
-	int			pwr_event_irq;
 	atomic_t                in_p3;
 	unsigned int		lpm_to_suspend_delay;
 	bool			init;
@@ -255,6 +282,15 @@
 static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc);
 static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA);
 static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event);
+
+static inline bool is_valid_usb_speed(struct dwc3 *dwc, int speed)
+{
+
+	return (((speed == USB_SPEED_FULL) || (speed == USB_SPEED_HIGH) ||
+		(speed == USB_SPEED_SUPER) || (speed == USB_SPEED_SUPER_PLUS))
+		&& (speed <= dwc->maximum_speed));
+}
+
 /**
  *
  * Read register with debug info.
@@ -264,7 +300,7 @@
  *
  * @return u32
  */
-static inline u32 dwc3_msm_read_reg(void *base, u32 offset)
+static inline u32 dwc3_msm_read_reg(void __iomem *base, u32 offset)
 {
 	u32 val = ioread32(base + offset);
 	return val;
@@ -279,11 +315,11 @@
  *
  * @return u32
  */
-static inline u32 dwc3_msm_read_reg_field(void *base,
+static inline u32 dwc3_msm_read_reg_field(void __iomem *base,
 					  u32 offset,
 					  const u32 mask)
 {
-	u32 shift = find_first_bit((void *)&mask, 32);
+	u32 shift = ffs(mask);
 	u32 val = ioread32(base + offset);
 
 	val &= mask;		/* clear other bits */
@@ -300,7 +336,7 @@
  * @val - value to write.
  *
  */
-static inline void dwc3_msm_write_reg(void *base, u32 offset, u32 val)
+static inline void dwc3_msm_write_reg(void __iomem *base, u32 offset, u32 val)
 {
 	iowrite32(val, base + offset);
 }
@@ -314,7 +350,7 @@
  * @val - value to write.
  *
  */
-static inline void dwc3_msm_write_reg_field(void *base, u32 offset,
+static inline void dwc3_msm_write_reg_field(void __iomem *base, u32 offset,
 					    const u32 mask, u32 val)
 {
 	u32 shift = find_first_bit((void *)&mask, 32);
@@ -334,7 +370,7 @@
  * @val - value to write.
  *
  */
-static inline void dwc3_msm_write_readback(void *base, u32 offset,
+static inline void dwc3_msm_write_readback(void __iomem *base, u32 offset,
 					    const u32 mask, u32 val)
 {
 	u32 write_val, tmp = ioread32(base + offset);
@@ -581,8 +617,8 @@
 	list_add_tail(&req->list, &dep->started_list);
 
 	/* First, prepare a normal TRB, point to the fake buffer */
-	trb = &dep->trb_pool[dep->trb_enqueue & DWC3_TRB_NUM];
-	dep->trb_enqueue++;
+	trb = &dep->trb_pool[dep->trb_enqueue];
+	dwc3_ep_inc_enq(dep);
 	memset(trb, 0, sizeof(*trb));
 
 	req->trb = trb;
@@ -593,8 +629,8 @@
 	req->trb_dma = dwc3_trb_dma_offset(dep, trb);
 
 	/* Second, prepare a Link TRB that points to the first TRB*/
-	trb_link = &dep->trb_pool[dep->trb_enqueue & DWC3_TRB_NUM];
-	dep->trb_enqueue++;
+	trb_link = &dep->trb_pool[dep->trb_enqueue];
+	dwc3_ep_inc_enq(dep);
 	memset(trb_link, 0, sizeof(*trb_link));
 
 	trb_link->bpl = lower_32_bits(req->trb_dma);
@@ -832,8 +868,8 @@
 		 * n + 1 TRBs as per GSI h/w requirement. n Xfer TRBs + 1
 		 * LINK TRB.
 		 */
-		ch_info->xfer_ring_len = (request->num_bufs + 1) * 0x10;
-		last_trb_index = request->num_bufs + 1;
+		ch_info->xfer_ring_len = (request->num_bufs + 2) * 0x10;
+		last_trb_index = request->num_bufs + 2;
 	}
 
 	/* Store last 16 bits of LINK TRB address as per GSI hw requirement */
@@ -905,13 +941,13 @@
 }
 
 /*
-* Rings Doorbell for IN GSI Channel
+* Rings Doorbell for GSI Channel
 *
 * @usb_ep - pointer to usb_ep instance.
 * @request - pointer to GSI request. This is used to pass in the
 * address of the GSI doorbell obtained from IPA driver
 */
-static void gsi_ring_in_db(struct usb_ep *ep, struct usb_gsi_request *request)
+static void gsi_ring_db(struct usb_ep *ep, struct usb_gsi_request *request)
 {
 	void __iomem *gsi_dbl_address_lsb;
 	void __iomem *gsi_dbl_address_msb;
@@ -919,10 +955,11 @@
 	u64 dbl_addr = *((u64 *)request->buf_base_addr);
 	u32 dbl_lo_addr = (dbl_addr & 0xFFFFFFFF);
 	u32 dbl_hi_addr = (dbl_addr >> 32);
-	u32 num_trbs = (request->num_bufs * 2 + 2);
 	struct dwc3_ep *dep = to_dwc3_ep(ep);
 	struct dwc3	*dwc = dep->dwc;
 	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+	int num_trbs = (dep->direction) ? (2 * (request->num_bufs) + 2)
+					: (request->num_bufs + 2);
 
 	gsi_dbl_address_lsb = devm_ioremap_nocache(mdwc->dev,
 					dbl_lo_addr, sizeof(u32));
@@ -935,8 +972,8 @@
 		dev_dbg(mdwc->dev, "Failed to get GSI DBL address MSB\n");
 
 	offset = dwc3_trb_dma_offset(dep, &dep->trb_pool[num_trbs-1]);
-	dev_dbg(mdwc->dev, "Writing link TRB addr: %pa to %p (%x)\n",
-	&offset, gsi_dbl_address_lsb, dbl_lo_addr);
+	dev_dbg(mdwc->dev, "Writing link TRB addr: %pa to %p (%x) for ep:%s\n",
+		&offset, gsi_dbl_address_lsb, dbl_lo_addr, ep->name);
 
 	writel_relaxed(offset, gsi_dbl_address_lsb);
 	writel_relaxed(0, gsi_dbl_address_msb);
@@ -1006,7 +1043,7 @@
 	struct dwc3		*dwc = dep->dwc;
 	struct dwc3_trb *trb;
 	int num_trbs = (dep->direction) ? (2 * (req->num_bufs) + 2)
-					: (req->num_bufs + 1);
+					: (req->num_bufs + 2);
 
 	dep->trb_dma_pool = dma_pool_create(ep->name, dwc->sysdev,
 					num_trbs * sizeof(struct dwc3_trb),
@@ -1067,26 +1104,43 @@
 
 			trb = &dep->trb_pool[i];
 			memset(trb, 0, sizeof(*trb));
-			trb->bpl = lower_32_bits(buffer_addr);
-			trb->bph = 0;
-			trb->size = req->buf_len;
-			trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_IOC
-					| DWC3_TRB_CTRL_CSP
-					| DWC3_TRB_CTRL_ISP_IMI;
-			buffer_addr += req->buf_len;
-
-			/* Set up the Link TRB at the end */
-			if (i == (num_trbs - 1)) {
+			/* Setup LINK TRB to start with TRB ring */
+			if (i == 0) {
 				trb->bpl = dwc3_trb_dma_offset(dep,
-							&dep->trb_pool[0]);
+							&dep->trb_pool[1]);
+				trb->ctrl = DWC3_TRBCTL_LINK_TRB;
+			} else if (i == (num_trbs - 1)) {
+				/* Set up the Link TRB at the end */
+				trb->bpl = dwc3_trb_dma_offset(dep,
+						&dep->trb_pool[0]);
 				trb->bph = (1 << 23) | (1 << 21)
 						| (ep->ep_intr_num << 16);
-				trb->size = 0;
 				trb->ctrl = DWC3_TRBCTL_LINK_TRB
 						| DWC3_TRB_CTRL_HWO;
+			} else {
+				trb->bpl = lower_32_bits(buffer_addr);
+				trb->size = req->buf_len;
+				buffer_addr += req->buf_len;
+				trb->ctrl = DWC3_TRBCTL_NORMAL
+					| DWC3_TRB_CTRL_IOC
+					| DWC3_TRB_CTRL_CSP
+					| DWC3_TRB_CTRL_ISP_IMI;
 			}
 		}
 	}
+
+	pr_debug("%s: Initialized TRB Ring for %s\n", __func__, dep->name);
+	trb = &dep->trb_pool[0];
+	if (trb) {
+		for (i = 0; i < num_trbs; i++) {
+			pr_debug("TRB(%d): ADDRESS:%lx bpl:%x bph:%x size:%x ctrl:%x\n",
+				i, (unsigned long)dwc3_trb_dma_offset(dep,
+				&dep->trb_pool[i]), trb->bpl, trb->bph,
+				trb->size, trb->ctrl);
+			trb++;
+		}
+	}
+
 	return 0;
 }
 
@@ -1127,7 +1181,8 @@
 	struct dwc3_gadget_ep_cmd_params params;
 	const struct usb_endpoint_descriptor *desc = ep->desc;
 	const struct usb_ss_ep_comp_descriptor *comp_desc = ep->comp_desc;
-	u32			reg;
+	u32 reg;
+	int ret;
 
 	memset(&params, 0x00, sizeof(params));
 
@@ -1175,6 +1230,10 @@
 
 	/* Set XferRsc Index for GSI EP */
 	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		ret = dwc3_gadget_resize_tx_fifos(dwc, dep);
+		if (ret)
+			return;
+
 		memset(&params, 0x00, sizeof(params));
 		params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
 		dwc3_send_gadget_ep_cmd(dep,
@@ -1327,10 +1386,10 @@
 		ch_info = (struct gsi_channel_info *)op_data;
 		gsi_get_channel_info(ep, ch_info);
 		break;
-	case GSI_EP_OP_RING_IN_DB:
+	case GSI_EP_OP_RING_DB:
 		request = (struct usb_gsi_request *)op_data;
-		dev_dbg(mdwc->dev, "RING IN EP DB\n");
-		gsi_ring_in_db(ep, request);
+		dbg_print(0xFF, "RING_DB", 0, ep->name);
+		gsi_ring_db(ep, request);
 		break;
 	case GSI_EP_OP_UPDATEXFER:
 		request = (struct usb_gsi_request *)op_data;
@@ -1580,7 +1639,7 @@
 	int ret = 0;
 
 	if (assert) {
-		disable_irq(mdwc->pwr_event_irq);
+		disable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
 		/* Using asynchronous block reset to the hardware */
 		dev_dbg(mdwc->dev, "block_reset ASSERT\n");
 		clk_disable_unprepare(mdwc->utmi_clk);
@@ -1600,7 +1659,7 @@
 		clk_prepare_enable(mdwc->core_clk);
 		clk_prepare_enable(mdwc->sleep_clk);
 		clk_prepare_enable(mdwc->utmi_clk);
-		enable_irq(mdwc->pwr_event_irq);
+		enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
 	}
 
 	return ret;
@@ -1995,12 +2054,93 @@
 static void msm_dwc3_perf_vote_update(struct dwc3_msm *mdwc,
 						bool perf_mode);
 
+static void configure_usb_wakeup_interrupt(struct dwc3_msm *mdwc,
+	struct usb_irq *uirq, unsigned int polarity, bool enable)
+{
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+
+	if (uirq && enable && !uirq->enable) {
+		dbg_event(0xFF, "PDC_IRQ_EN", uirq->irq);
+		dbg_event(0xFF, "PDC_IRQ_POL", polarity);
+		/* clear any pending interrupt */
+		irq_set_irqchip_state(uirq->irq, IRQCHIP_STATE_PENDING, 0);
+		irq_set_irq_type(uirq->irq, polarity);
+		enable_irq_wake(uirq->irq);
+		enable_irq(uirq->irq);
+		uirq->enable = true;
+	}
+
+	if (uirq && !enable && uirq->enable) {
+		dbg_event(0xFF, "PDC_IRQ_DIS", uirq->irq);
+		disable_irq_wake(uirq->irq);
+		disable_irq_nosync(uirq->irq);
+		uirq->enable = false;
+	}
+}
+
+static void enable_usb_pdc_interrupt(struct dwc3_msm *mdwc, bool enable)
+{
+	if (!enable)
+		goto disable_usb_irq;
+
+	if (mdwc->hs_phy->flags & PHY_LS_MODE) {
+		configure_usb_wakeup_interrupt(mdwc,
+			&mdwc->wakeup_irq[DM_HS_PHY_IRQ],
+			IRQ_TYPE_EDGE_FALLING, enable);
+	} else if (mdwc->hs_phy->flags & PHY_HSFS_MODE) {
+		configure_usb_wakeup_interrupt(mdwc,
+			&mdwc->wakeup_irq[DP_HS_PHY_IRQ],
+			IRQ_TYPE_EDGE_FALLING, enable);
+	} else {
+		configure_usb_wakeup_interrupt(mdwc,
+			&mdwc->wakeup_irq[DP_HS_PHY_IRQ],
+			IRQ_TYPE_EDGE_RISING, true);
+		configure_usb_wakeup_interrupt(mdwc,
+			&mdwc->wakeup_irq[DM_HS_PHY_IRQ],
+			IRQ_TYPE_EDGE_RISING, true);
+	}
+
+	configure_usb_wakeup_interrupt(mdwc,
+		&mdwc->wakeup_irq[SS_PHY_IRQ],
+		IRQF_TRIGGER_HIGH | IRQ_TYPE_LEVEL_HIGH, enable);
+	return;
+
+disable_usb_irq:
+	configure_usb_wakeup_interrupt(mdwc,
+			&mdwc->wakeup_irq[DP_HS_PHY_IRQ], 0, enable);
+	configure_usb_wakeup_interrupt(mdwc,
+			&mdwc->wakeup_irq[DM_HS_PHY_IRQ], 0, enable);
+	configure_usb_wakeup_interrupt(mdwc,
+			&mdwc->wakeup_irq[SS_PHY_IRQ], 0, enable);
+}
+
+static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc,
+		struct usb_irq *uirq, bool enable)
+{
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+
+	if (uirq && enable && !uirq->enable) {
+		dbg_event(0xFF, "IRQ_EN", uirq->irq);
+		enable_irq_wake(uirq->irq);
+		enable_irq(uirq->irq);
+		uirq->enable = true;
+	}
+
+	if (uirq && !enable && uirq->enable) {
+		dbg_event(0xFF, "IRQ_DIS", uirq->irq);
+		disable_irq_wake(uirq->irq);
+		disable_irq_nosync(uirq->irq);
+		uirq->enable = true;
+	}
+}
+
 static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
 {
 	int ret;
 	bool can_suspend_ssphy;
 	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 	struct dwc3_event_buffer *evt;
+	struct usb_irq *uirq;
 
 	if (atomic_read(&dwc->in_lpm)) {
 		dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__);
@@ -2066,7 +2206,7 @@
 		dbg_event(0xFF, "pend evt", 0);
 
 	/* disable power event irq, hs and ss phy irq is used as wake up src */
-	disable_irq(mdwc->pwr_event_irq);
+	disable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
 
 	dwc3_set_phy_speed_flags(mdwc);
 	/* Suspend HS PHY */
@@ -2152,11 +2292,13 @@
 	 * case of host bus suspend and device bus suspend.
 	 */
 	if (mdwc->vbus_active || mdwc->in_host_mode) {
-		enable_irq_wake(mdwc->hs_phy_irq);
-		enable_irq(mdwc->hs_phy_irq);
-		if (mdwc->ss_phy_irq) {
-			enable_irq_wake(mdwc->ss_phy_irq);
-			enable_irq(mdwc->ss_phy_irq);
+		if (mdwc->use_pdc_interrupts) {
+			enable_usb_pdc_interrupt(mdwc, true);
+		} else {
+			uirq = &mdwc->wakeup_irq[HS_PHY_IRQ];
+			configure_nonpdc_usb_interrupt(mdwc, uirq, true);
+			uirq = &mdwc->wakeup_irq[SS_PHY_IRQ];
+			configure_nonpdc_usb_interrupt(mdwc, uirq, true);
 		}
 		mdwc->lpm_flags |= MDWC3_ASYNC_IRQ_WAKE_CAPABILITY;
 	}
@@ -2170,6 +2312,7 @@
 	int ret;
 	long core_clk_rate;
 	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+	struct usb_irq *uirq;
 
 	dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
 
@@ -2287,7 +2430,7 @@
 	atomic_set(&dwc->in_lpm, 0);
 
 	/* enable power evt irq for IN P3 detection */
-	enable_irq(mdwc->pwr_event_irq);
+	enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
 
 	/* Disable HSPHY auto suspend */
 	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
@@ -2297,11 +2440,13 @@
 
 	/* Disable wakeup capable for HS_PHY IRQ & SS_PHY_IRQ if enabled */
 	if (mdwc->lpm_flags & MDWC3_ASYNC_IRQ_WAKE_CAPABILITY) {
-		disable_irq_wake(mdwc->hs_phy_irq);
-		disable_irq_nosync(mdwc->hs_phy_irq);
-		if (mdwc->ss_phy_irq) {
-			disable_irq_wake(mdwc->ss_phy_irq);
-			disable_irq_nosync(mdwc->ss_phy_irq);
+		if (mdwc->use_pdc_interrupts) {
+			enable_usb_pdc_interrupt(mdwc, false);
+		} else {
+			uirq = &mdwc->wakeup_irq[HS_PHY_IRQ];
+			configure_nonpdc_usb_interrupt(mdwc, uirq, false);
+			uirq = &mdwc->wakeup_irq[SS_PHY_IRQ];
+			configure_nonpdc_usb_interrupt(mdwc, uirq, false);
 		}
 		mdwc->lpm_flags &= ~MDWC3_ASYNC_IRQ_WAKE_CAPABILITY;
 	}
@@ -2395,6 +2540,12 @@
 		if (dwc->maximum_speed > dwc->max_hw_supp_speed)
 			dwc->maximum_speed = dwc->max_hw_supp_speed;
 
+		if (override_usb_speed &&
+				is_valid_usb_speed(dwc, override_usb_speed)) {
+			dwc->maximum_speed = override_usb_speed;
+			dbg_event(0xFF, "override_speed", override_usb_speed);
+		}
+
 		dbg_event(0xFF, "speed", dwc->maximum_speed);
 
 		ret = extcon_get_property(edev, extcon_id,
@@ -2925,9 +3076,10 @@
 	struct resource *res;
 	void __iomem *tcsr;
 	bool host_mode;
-	int ret = 0;
+	int ret = 0, i;
 	int ext_hub_reset_gpio;
 	u32 val;
+	unsigned long irq_type;
 
 	mdwc = devm_kzalloc(&pdev->dev, sizeof(*mdwc), GFP_KERNEL);
 	if (!mdwc)
@@ -2977,64 +3129,41 @@
 		mdwc->lpm_to_suspend_delay = 0;
 	}
 
-	/*
-	 * DWC3 has separate IRQ line for OTG events (ID/BSV) and for
-	 * DP and DM linestate transitions during low power mode.
-	 */
-	mdwc->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
-	if (mdwc->hs_phy_irq < 0) {
-		dev_err(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
-		ret = -EINVAL;
-		goto err;
-	} else {
-		irq_set_status_flags(mdwc->hs_phy_irq, IRQ_NOAUTOEN);
-		ret = devm_request_threaded_irq(&pdev->dev, mdwc->hs_phy_irq,
-					msm_dwc3_pwr_irq,
-					msm_dwc3_pwr_irq_thread,
-					IRQF_TRIGGER_RISING | IRQF_EARLY_RESUME
-					| IRQF_ONESHOT, "hs_phy_irq", mdwc);
-		if (ret) {
-			dev_err(&pdev->dev, "irqreq hs_phy_irq failed: %d\n",
-					ret);
-			goto err;
-		}
-	}
+	memcpy(mdwc->wakeup_irq, usb_irq_info, sizeof(usb_irq_info));
+	for (i = 0; i < USB_MAX_IRQ; i++) {
+		irq_type = IRQF_TRIGGER_RISING | IRQF_EARLY_RESUME |
+						IRQF_ONESHOT;
+		mdwc->wakeup_irq[i].irq = platform_get_irq_byname(pdev,
+					mdwc->wakeup_irq[i].name);
+		if (mdwc->wakeup_irq[i].irq < 0) {
+			/* pwr_evnt_irq is only mandatory irq */
+			if (!strcmp(mdwc->wakeup_irq[i].name,
+						"pwr_event_irq")) {
+				dev_err(&pdev->dev, "get_irq for %s failed\n\n",
+						mdwc->wakeup_irq[i].name);
+				ret = -EINVAL;
+				goto err;
+			}
+			mdwc->wakeup_irq[i].irq = 0;
+		} else {
+			irq_set_status_flags(mdwc->wakeup_irq[i].irq,
+						IRQ_NOAUTOEN);
+			/* ss_phy_irq is level trigger interrupt */
+			if (!strcmp(mdwc->wakeup_irq[i].name, "ss_phy_irq"))
+				irq_type = IRQF_TRIGGER_HIGH | IRQF_ONESHOT |
+					IRQ_TYPE_LEVEL_HIGH | IRQF_EARLY_RESUME;
 
-	mdwc->ss_phy_irq = platform_get_irq_byname(pdev, "ss_phy_irq");
-	if (mdwc->ss_phy_irq < 0) {
-		dev_dbg(&pdev->dev, "pget_irq for ss_phy_irq failed\n");
-	} else {
-		irq_set_status_flags(mdwc->ss_phy_irq, IRQ_NOAUTOEN);
-		ret = devm_request_threaded_irq(&pdev->dev, mdwc->ss_phy_irq,
+			ret = devm_request_threaded_irq(&pdev->dev,
+					mdwc->wakeup_irq[i].irq,
 					msm_dwc3_pwr_irq,
 					msm_dwc3_pwr_irq_thread,
-					IRQF_TRIGGER_HIGH | IRQ_TYPE_LEVEL_HIGH
-					| IRQF_EARLY_RESUME | IRQF_ONESHOT,
-					"ss_phy_irq", mdwc);
-		if (ret) {
-			dev_err(&pdev->dev, "irqreq ss_phy_irq failed: %d\n",
-					ret);
-			goto err;
-		}
-	}
-
-	mdwc->pwr_event_irq = platform_get_irq_byname(pdev, "pwr_event_irq");
-	if (mdwc->pwr_event_irq < 0) {
-		dev_err(&pdev->dev, "pget_irq for pwr_event_irq failed\n");
-		ret = -EINVAL;
-		goto err;
-	} else {
-		/* will be enabled in dwc3_msm_resume() */
-		irq_set_status_flags(mdwc->pwr_event_irq, IRQ_NOAUTOEN);
-		ret = devm_request_threaded_irq(&pdev->dev, mdwc->pwr_event_irq,
-					msm_dwc3_pwr_irq,
-					msm_dwc3_pwr_irq_thread,
-					IRQF_TRIGGER_RISING | IRQF_EARLY_RESUME,
-					"msm_dwc3", mdwc);
-		if (ret) {
-			dev_err(&pdev->dev, "irqreq pwr_event_irq failed: %d\n",
-					ret);
-			goto err;
+					irq_type,
+					mdwc->wakeup_irq[i].name, mdwc);
+			if (ret) {
+				dev_err(&pdev->dev, "irq req %s failed: %d\n\n",
+						mdwc->wakeup_irq[i].name, ret);
+				goto err;
+			}
 		}
 	}
 
@@ -3115,7 +3244,7 @@
 		 * by interrupt
 		 */
 		if (dbm_l1_lpm_interrupt(mdwc->dbm)) {
-			if (!mdwc->pwr_event_irq) {
+			if (!mdwc->wakeup_irq[PWR_EVNT_IRQ].irq) {
 				dev_err(&pdev->dev,
 					"need pwr_event_irq exiting L1\n");
 				ret = -EINVAL;
@@ -3147,7 +3276,8 @@
 
 	mdwc->disable_host_mode_pm = of_property_read_bool(node,
 				"qcom,disable-host-mode-pm");
-
+	mdwc->use_pdc_interrupts = of_property_read_bool(node,
+				"qcom,use-pdc-interrupts");
 	dwc3_set_notifier(&dwc3_msm_notify_event);
 
 	ret = dwc3_msm_init_iommu(mdwc);
@@ -3349,10 +3479,15 @@
 	if (!IS_ERR_OR_NULL(mdwc->vbus_reg))
 		regulator_disable(mdwc->vbus_reg);
 
-	disable_irq(mdwc->hs_phy_irq);
-	if (mdwc->ss_phy_irq)
-		disable_irq(mdwc->ss_phy_irq);
-	disable_irq(mdwc->pwr_event_irq);
+	if (mdwc->wakeup_irq[HS_PHY_IRQ].irq)
+		disable_irq(mdwc->wakeup_irq[HS_PHY_IRQ].irq);
+	if (mdwc->wakeup_irq[DP_HS_PHY_IRQ].irq)
+		disable_irq(mdwc->wakeup_irq[DP_HS_PHY_IRQ].irq);
+	if (mdwc->wakeup_irq[DM_HS_PHY_IRQ].irq)
+		disable_irq(mdwc->wakeup_irq[DM_HS_PHY_IRQ].irq);
+	if (mdwc->wakeup_irq[SS_PHY_IRQ].irq)
+		disable_irq(mdwc->wakeup_irq[SS_PHY_IRQ].irq);
+	disable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
 
 	clk_disable_unprepare(mdwc->utmi_clk);
 	clk_set_rate(mdwc->core_clk, 19200000);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index b062d58..ec9ffc1 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -588,8 +588,9 @@
 {
 	enum usb_device_state state = dwc->gadget.state;
 	u32 cfg;
-	int ret;
+	int ret, num;
 	u32 reg;
+	struct dwc3_ep	*dep;
 
 	cfg = le16_to_cpu(ctrl->wValue);
 
@@ -598,6 +599,24 @@
 		return -EINVAL;
 
 	case USB_STATE_ADDRESS:
+		/* Read ep0IN related TXFIFO size */
+		dwc->last_fifo_depth = (dwc3_readl(dwc->regs,
+					DWC3_GTXFIFOSIZ(0)) & 0xFFFF);
+		/* Clear existing allocated TXFIFO for all IN eps except ep0 */
+		for (num = 0; num < dwc->num_in_eps; num++) {
+			dep = dwc->eps[(num << 1) | 1];
+			if (num) {
+				dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), 0);
+				dep->fifo_depth = 0;
+			} else {
+				dep->fifo_depth = dwc->last_fifo_depth;
+			}
+
+			dev_dbg(dwc->dev, "%s(): %s dep->fifo_depth:%x\n",
+					__func__, dep->name, dep->fifo_depth);
+			dbg_event(0xFF, "fifo_reset", dep->number);
+		}
+
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
 		/* if the cfg matches and the cfg is non zero */
 		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
@@ -619,9 +638,6 @@
 			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 			reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
 			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-
-			dwc->resize_fifos = true;
-			dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");
 		}
 		break;
 
@@ -1080,12 +1096,6 @@
 {
 	int ret;
 
-	if (dwc->resize_fifos) {
-		dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
-		dwc3_gadget_resize_tx_fifos(dwc);
-		dwc->resize_fifos = 0;
-	}
-
 	ret = dwc3_ep0_start_control_status(dep);
 	if (WARN_ON_ONCE(ret))
 		dbg_event(dep->number, "ECTRLSTATUS", ret);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index df0427c..7d8566f 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -164,12 +164,12 @@
 		*index = 0;
 }
 
-static void dwc3_ep_inc_enq(struct dwc3_ep *dep)
+void dwc3_ep_inc_enq(struct dwc3_ep *dep)
 {
 	dwc3_ep_inc_trb(&dep->trb_enqueue);
 }
 
-static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
+void dwc3_ep_inc_deq(struct dwc3_ep *dep)
 {
 	dwc3_ep_inc_trb(&dep->trb_dequeue);
 }
@@ -195,88 +195,64 @@
  *
  * Unfortunately, due to many variables that's not always the case.
  */
-int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
-	int		last_fifo_depth = 0;
-	int		ram1_depth;
-	int		fifo_size;
-	int		mdwidth;
-	int		num;
-	int		num_eps;
-	int		max_packet = 1024;
-	struct usb_composite_dev *cdev = get_gadget_data(&dwc->gadget);
+	int		fifo_size, mdwidth, max_packet = 1024;
+	int		tmp, mult = 1;
 
-	if (!(cdev && cdev->config) || !dwc->needs_fifo_resize)
+	if (!dwc->needs_fifo_resize)
 		return 0;
 
-	num_eps = dwc->num_in_eps;
-	ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
-	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+	/* resize IN endpoints excepts ep0 */
+	if (!usb_endpoint_dir_in(dep->endpoint.desc) ||
+			dep->endpoint.ep_num == 0)
+		return 0;
 
-	/* MDWIDTH is represented in bits, we need it in bytes */
-	mdwidth >>= 3;
-	last_fifo_depth = (dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)) & 0xFFFF);
-	dev_dbg(dwc->dev, "%s: num eps:%d max_packet:%d last_fifo_depth:%04x\n",
-				__func__, num_eps, max_packet, last_fifo_depth);
-
-	/* Don't resize ep0IN TxFIFO, start with ep1IN only. */
-	for (num = 1; num < num_eps; num++) {
-		/* bit0 indicates direction; 1 means IN ep */
-		struct dwc3_ep	*dep = dwc->eps[(num << 1) | 1];
-		int		mult = 1;
-		int		tmp;
-
-		tmp = max_packet + mdwidth;
-		/*
-		 * Interfaces like MBIM or ECM is having multiple data
-		 * interfaces. SET_CONFIG() happens before set_alt with
-		 * data interface 1 which results into calling this API
-		 * before GSI endpoint enabled. This results no txfifo
-		 * resize with GSI endpoint causing low throughput. Hence
-		 * use mult as 3 for GSI IN endpoint always irrespective
-		 * USB speed.
-		 */
-		if (dep->endpoint.ep_type == EP_TYPE_GSI ||
-				dep->endpoint.endless)
-			mult = 3;
-
-		if (!(dep->flags & DWC3_EP_ENABLED)) {
-			dev_dbg(dwc->dev, "ep%dIn not enabled", num);
-			goto resize_fifo;
-		}
-
-		if (((dep->endpoint.maxburst > 1) &&
-				usb_endpoint_xfer_bulk(dep->endpoint.desc))
-				|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
-			mult = 3;
-
-resize_fifo:
-		tmp *= mult;
-		tmp += mdwidth;
-
-		fifo_size = DIV_ROUND_UP(tmp, mdwidth);
-
-		fifo_size |= (last_fifo_depth << 16);
-
-		dev_dbg(dwc->dev, "%s: Fifo Addr %04x Size %d",
-				dep->name, last_fifo_depth, fifo_size & 0xffff);
-
-		last_fifo_depth += (fifo_size & 0xffff);
-		if (dwc->tx_fifo_size &&
-				(last_fifo_depth >= dwc->tx_fifo_size)) {
-			/*
-			 * Fifo size allocated exceeded available RAM size.
-			 * Hence return error.
-			 */
-			dev_err(dwc->dev, "Fifosize(%d) > available RAM(%d)\n",
-					last_fifo_depth, dwc->tx_fifo_size);
-			return -ENOMEM;
-		}
-
-		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
-
+	/* Don't resize already resized IN endpoint */
+	if (dep->fifo_depth) {
+		dev_dbg(dwc->dev, "%s fifo_depth:%d is already set\n",
+				dep->endpoint.name, dep->fifo_depth);
+		return 0;
 	}
 
+	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+	/* MDWIDTH is represented in bits, we need it in bytes */
+	mdwidth >>= 3;
+
+	if (dep->endpoint.ep_type == EP_TYPE_GSI || dep->endpoint.endless)
+		mult = 3;
+
+	if (((dep->endpoint.maxburst > 1) &&
+			usb_endpoint_xfer_bulk(dep->endpoint.desc))
+			|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
+		mult = 3;
+
+	tmp = ((max_packet + mdwidth) * mult) + mdwidth;
+	fifo_size = DIV_ROUND_UP(tmp, mdwidth);
+	dep->fifo_depth = fifo_size;
+	fifo_size |= (dwc->last_fifo_depth << 16);
+	dwc->last_fifo_depth += (fifo_size & 0xffff);
+
+	dev_dbg(dwc->dev, "%s ep_num:%d last_fifo_depth:%04x fifo_depth:%d\n",
+		dep->endpoint.name, dep->endpoint.ep_num, dwc->last_fifo_depth,
+		dep->fifo_depth);
+
+	dbg_event(0xFF, "resize_fifo", dep->number);
+	dbg_event(0xFF, "fifo_depth", dep->fifo_depth);
+	/* Check fifo size allocation doesn't exceed available RAM size. */
+	if (dwc->tx_fifo_size &&
+		((dwc->last_fifo_depth * mdwidth) >= dwc->tx_fifo_size)) {
+		dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n",
+			(dwc->last_fifo_depth * mdwidth), dwc->tx_fifo_size,
+			dep->endpoint.name, fifo_size);
+		dwc->last_fifo_depth -= (fifo_size & 0xffff);
+		dep->fifo_depth = 0;
+		WARN_ON(1);
+		return -ENOMEM;
+	}
+
+	dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->endpoint.ep_num),
+							fifo_size);
 	return 0;
 }
 
@@ -691,6 +667,17 @@
 	dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
 
 	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		dep->endpoint.desc = desc;
+		dep->comp_desc = comp_desc;
+		dep->type = usb_endpoint_type(desc);
+		ret = dwc3_gadget_resize_tx_fifos(dwc, dep);
+		if (ret) {
+			dep->endpoint.desc = NULL;
+			dep->comp_desc = NULL;
+			dep->type = 0;
+			return ret;
+		}
+
 		ret = dwc3_gadget_start_config(dwc, dep);
 		if (ret) {
 			dev_err(dwc->dev, "start_config() failed for %s\n",
@@ -710,9 +697,6 @@
 		struct dwc3_trb	*trb_st_hw;
 		struct dwc3_trb	*trb_link;
 
-		dep->endpoint.desc = desc;
-		dep->comp_desc = comp_desc;
-		dep->type = usb_endpoint_type(desc);
 		dep->flags |= DWC3_EP_ENABLED;
 
 		reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
@@ -901,6 +885,7 @@
 
 	req->epnum	= dep->number;
 	req->dep	= dep;
+	req->request.dma = DMA_ERROR_CODE;
 
 	dep->allocated_requests++;
 
@@ -2986,9 +2971,6 @@
 	dwc3_stop_active_transfers(dwc);
 	dwc3_clear_stall_all_ep(dwc);
 
-	/* bus reset issued due to missing status stage of a control transfer */
-	dwc->resize_fifos = 0;
-
 	/* Reset device address to zero */
 	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
 	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index e973ad3..8d0a5eb 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -98,6 +98,8 @@
 void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
 irqreturn_t dwc3_interrupt(int irq, void *_dwc);
 void dwc3_bh_work(struct work_struct *w);
+void dwc3_ep_inc_enq(struct dwc3_ep *dep);
+void dwc3_ep_inc_deq(struct dwc3_ep *dep);
 
 static inline dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
 		struct dwc3_trb *trb)
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 6b2c137..5396557 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -22,6 +22,7 @@
 static struct class *android_class;
 static struct device *android_device;
 static int index;
+static int gadget_index;
 
 struct device *create_function_device(char *name)
 {
@@ -1425,21 +1426,21 @@
 	spin_unlock_irqrestore(&cdev->lock, flags);
 
 	if (status[0]) {
-		kobject_uevent_env(&android_device->kobj,
+		kobject_uevent_env(&gi->dev->kobj,
 					KOBJ_CHANGE, connected);
 		pr_info("%s: sent uevent %s\n", __func__, connected[0]);
 		uevent_sent = true;
 	}
 
 	if (status[1]) {
-		kobject_uevent_env(&android_device->kobj,
+		kobject_uevent_env(&gi->dev->kobj,
 					KOBJ_CHANGE, configured);
 		pr_info("%s: sent uevent %s\n", __func__, configured[0]);
 		uevent_sent = true;
 	}
 
 	if (status[2]) {
-		kobject_uevent_env(&android_device->kobj,
+		kobject_uevent_env(&gi->dev->kobj,
 					KOBJ_CHANGE, disconnected);
 		pr_info("%s: sent uevent %s\n", __func__, disconnected[0]);
 		uevent_sent = true;
@@ -1600,23 +1601,28 @@
 {
 	struct device_attribute **attrs;
 	struct device_attribute *attr;
+	char str[10];
 
 	INIT_WORK(&gi->work, android_work);
-	android_device = device_create(android_class, NULL,
-				MKDEV(0, 0), NULL, "android0");
-	if (IS_ERR(android_device))
-		return PTR_ERR(android_device);
+	snprintf(str, sizeof(str), "android%d", gadget_index - 1);
+	pr_debug("Creating android device %s\n", str);
+	gi->dev = device_create(android_class, NULL,
+				MKDEV(0, 0), NULL, str);
+	if (IS_ERR(gi->dev))
+		return PTR_ERR(gi->dev);
 
-	dev_set_drvdata(android_device, gi);
+	dev_set_drvdata(gi->dev, gi);
+	if (gadget_index == 1)
+		android_device = gi->dev;
 
 	attrs = android_usb_attributes;
 	while ((attr = *attrs++)) {
 		int err;
 
-		err = device_create_file(android_device, attr);
+		err = device_create_file(gi->dev, attr);
 		if (err) {
-			device_destroy(android_device->class,
-				       android_device->devt);
+			device_destroy(gi->dev->class,
+				       gi->dev->devt);
 			return err;
 		}
 	}
@@ -1624,15 +1630,15 @@
 	return 0;
 }
 
-static void android_device_destroy(void)
+static void android_device_destroy(struct device *dev)
 {
 	struct device_attribute **attrs;
 	struct device_attribute *attr;
 
 	attrs = android_usb_attributes;
 	while ((attr = *attrs++))
-		device_remove_file(android_device, attr);
-	device_destroy(android_device->class, android_device->devt);
+		device_remove_file(dev, attr);
+	device_destroy(dev->class, dev->devt);
 }
 #else
 static inline int android_device_create(struct gadget_info *gi)
@@ -1640,7 +1646,7 @@
 	return 0;
 }
 
-static inline void android_device_destroy(void)
+static inline void android_device_destroy(struct device *dev)
 {
 }
 #endif
@@ -1696,6 +1702,8 @@
 	if (!gi->composite.gadget_driver.function)
 		goto err;
 
+	gadget_index++;
+	pr_debug("Creating gadget index %d\n", gadget_index);
 	if (android_device_create(gi) < 0)
 		goto err;
 
@@ -1708,8 +1716,14 @@
 
 static void gadgets_drop(struct config_group *group, struct config_item *item)
 {
+	struct gadget_info *gi;
+
+	gi = container_of(to_config_group(item), struct gadget_info, group);
 	config_item_put(item);
-	android_device_destroy();
+	if (gi->dev) {
+		android_device_destroy(gi->dev);
+		gi->dev = NULL;
+	}
 }
 
 static struct configfs_group_operations gadgets_ops = {
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 12e94d5..4df2dc6 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -40,6 +40,7 @@
 
 static struct workqueue_struct *ipa_usb_wq;
 
+static void gsi_rndis_ipa_reset_trigger(struct gsi_data_port *d_port);
 static void ipa_disconnect_handler(struct gsi_data_port *d_port);
 static int gsi_ctrl_send_notification(struct f_gsi *gsi);
 static int gsi_alloc_trb_buffer(struct f_gsi *gsi);
@@ -472,6 +473,7 @@
 	usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
 				GSI_EP_OP_SET_CLR_BLOCK_DBL);
 
+	/* GSI channel DBL address for USB IN endpoint */
 	dbl_register_addr = gsi->d_port.in_db_reg_phs_addr_msb;
 	dbl_register_addr = dbl_register_addr << 32;
 	dbl_register_addr =
@@ -481,11 +483,18 @@
 	req.buf_base_addr = &dbl_register_addr;
 
 	req.num_bufs = gsi->d_port.in_request.num_bufs;
-	usb_gsi_ep_op(gsi->d_port.in_ep, &req, GSI_EP_OP_RING_IN_DB);
+	usb_gsi_ep_op(gsi->d_port.in_ep, &req, GSI_EP_OP_RING_DB);
 
 	if (gsi->d_port.out_ep) {
-		usb_gsi_ep_op(gsi->d_port.out_ep, &gsi->d_port.out_request,
-			GSI_EP_OP_UPDATEXFER);
+		/* GSI channel DBL address for USB OUT endpoint */
+		dbl_register_addr = gsi->d_port.out_db_reg_phs_addr_msb;
+		dbl_register_addr = dbl_register_addr << 32;
+		dbl_register_addr = dbl_register_addr |
+					gsi->d_port.out_db_reg_phs_addr_lsb;
+		/* use temp request to pass 64 bit dbl reg addr and num_bufs */
+		req.buf_base_addr = &dbl_register_addr;
+		req.num_bufs = gsi->d_port.out_request.num_bufs;
+		usb_gsi_ep_op(gsi->d_port.out_ep, &req, GSI_EP_OP_RING_DB);
 	}
 }
 
@@ -503,14 +512,11 @@
 		 */
 		usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
 				GSI_EP_OP_SET_CLR_BLOCK_DBL);
-		gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc;
 		usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_DISABLE);
 	}
 
-	if (gsi->d_port.out_ep) {
-		gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc;
+	if (gsi->d_port.out_ep)
 		usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_DISABLE);
-	}
 
 	gsi->d_port.net_ready_trigger = false;
 }
@@ -616,6 +622,7 @@
 	struct device *dev;
 	struct device *gad_dev;
 	struct f_gsi *gsi = d_port_to_gsi(d_port);
+	bool block_db;
 
 	event = read_event(d_port);
 
@@ -676,28 +683,6 @@
 				break;
 			}
 
-			/*
-			 * Update desc and reconfigure USB GSI OUT and IN
-			 * endpoint for RNDIS Adaptor enable case.
-			 */
-			if (d_port->out_ep && !d_port->out_ep->desc &&
-					gsi->out_ep_desc_backup) {
-				d_port->out_ep->desc = gsi->out_ep_desc_backup;
-				d_port->out_ep->ep_intr_num = 1;
-				log_event_dbg("%s: OUT ep_op_config", __func__);
-				usb_gsi_ep_op(d_port->out_ep,
-					&d_port->out_request, GSI_EP_OP_CONFIG);
-			}
-
-			if (d_port->in_ep && !d_port->in_ep->desc &&
-					gsi->in_ep_desc_backup) {
-				d_port->in_ep->desc = gsi->in_ep_desc_backup;
-				d_port->in_ep->ep_intr_num = 2;
-				log_event_dbg("%s: IN ep_op_config", __func__);
-				usb_gsi_ep_op(d_port->in_ep,
-					&d_port->in_request, GSI_EP_OP_CONFIG);
-			}
-
 			ipa_connect_channels(d_port);
 			ipa_data_path_enable(d_port);
 			d_port->sm_state = STATE_CONNECTED;
@@ -759,7 +744,15 @@
 			if (event == EVT_HOST_NRDY) {
 				log_event_dbg("%s: ST_CON_HOST_NRDY\n",
 								__func__);
-				ipa_disconnect_handler(d_port);
+				block_db = true;
+				/* stop USB ringing doorbell to GSI(OUT_EP) */
+				usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
+						GSI_EP_OP_SET_CLR_BLOCK_DBL);
+				gsi_rndis_ipa_reset_trigger(d_port);
+				usb_gsi_ep_op(d_port->in_ep, NULL,
+						GSI_EP_OP_ENDXFER);
+				usb_gsi_ep_op(d_port->out_ep, NULL,
+						GSI_EP_OP_ENDXFER);
 			}
 
 			ipa_disconnect_work_handler(d_port);
@@ -1046,7 +1039,7 @@
 	log_event_dbg("%s: cpkt size:%d", __func__, cpkt->len);
 	if (qti_packet_debug)
 		print_hex_dump(KERN_DEBUG, "READ:", DUMP_PREFIX_OFFSET, 16, 1,
-			buf, min_t(int, 30, cpkt->len), false);
+			cpkt->buf, min_t(int, 30, cpkt->len), false);
 
 	ret = copy_to_user(buf, cpkt->buf, cpkt->len);
 	if (ret) {
@@ -1119,7 +1112,7 @@
 	c_port->copied_from_modem++;
 	if (qti_packet_debug)
 		print_hex_dump(KERN_DEBUG, "WRITE:", DUMP_PREFIX_OFFSET, 16, 1,
-			buf, min_t(int, 30, count), false);
+			cpkt->buf, min_t(int, 30, count), false);
 
 	spin_lock_irqsave(&c_port->lock, flags);
 	list_add_tail(&cpkt->list, &c_port->cpkt_resp_q);
@@ -1385,6 +1378,17 @@
 	rndis_signal_connect(gsi->params);
 }
 
+static void gsi_rndis_ipa_reset_trigger(struct gsi_data_port *d_port)
+{
+	unsigned long flags;
+	struct f_gsi *gsi = d_port_to_gsi(d_port);
+
+	log_event_dbg("%s: setting net_ready_trigger\n", __func__);
+	spin_lock_irqsave(&d_port->lock, flags);
+	d_port->net_ready_trigger = false;
+	spin_unlock_irqrestore(&d_port->lock, flags);
+}
+
 void gsi_rndis_flow_ctrl_enable(bool enable, struct rndis_params *param)
 {
 	struct f_gsi *gsi = param->v;
@@ -2618,7 +2622,7 @@
 		info.in_req_num_buf = num_in_bufs;
 		gsi->d_port.out_aggr_size = GSI_ECM_AGGR_SIZE;
 		info.out_req_buf_len = GSI_OUT_ECM_BUF_LEN;
-		info.out_req_num_buf = GSI_ECM_NUM_OUT_BUFFERS;
+		info.out_req_num_buf = num_out_bufs;
 		info.notify_buf_len = GSI_CTRL_NOTIFY_BUFF_LEN;
 
 		/* export host's Ethernet address in CDC format */
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index 43aae8f..0fe3665 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -37,8 +37,7 @@
 
 #define GSI_NUM_IN_BUFFERS 15
 #define GSI_IN_BUFF_SIZE 2048
-#define GSI_NUM_OUT_BUFFERS 15
-#define GSI_ECM_NUM_OUT_BUFFERS 31
+#define GSI_NUM_OUT_BUFFERS 14
 #define GSI_OUT_AGGR_SIZE 24576
 
 #define GSI_IN_RNDIS_AGGR_SIZE 9216
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index cca261e..0b758236 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -395,7 +395,11 @@
 /* Caller must hold fsg->lock */
 static void wakeup_thread(struct fsg_common *common)
 {
-	smp_wmb();	/* ensure the write of bh->state is complete */
+	/*
+	 * Ensure the reading of thread_wakeup_needed
+	 * and the writing of bh->state are completed
+	 */
+	smp_mb();
 	/* Tell the main thread that something has happened */
 	common->thread_wakeup_needed = 1;
 	if (common->thread_task)
@@ -645,7 +649,12 @@
 	}
 	__set_current_state(TASK_RUNNING);
 	common->thread_wakeup_needed = 0;
-	smp_rmb();	/* ensure the latest bh->state is visible */
+
+	/*
+	 * Ensure the writing of thread_wakeup_needed
+	 * and the reading of bh->state are completed
+	 */
+	smp_mb();
 	return rc;
 }
 
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
index 17f6f60..40a7acf 100644
--- a/drivers/usb/gadget/function/f_qdss.c
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -474,6 +474,7 @@
 {
 	struct f_qdss *qdss;
 	int status;
+	unsigned long flags;
 
 	qdss = container_of(work, struct f_qdss, disconnect_w);
 	pr_debug("usb_qdss_disconnect_work\n");
@@ -496,6 +497,14 @@
 		status = set_qdss_data_connection(qdss, 0);
 		if (status)
 			pr_err("qdss_disconnect error");
+
+		spin_lock_irqsave(&qdss->lock, flags);
+		if (qdss->endless_req) {
+			usb_ep_free_request(qdss->port.data,
+					qdss->endless_req);
+			qdss->endless_req = NULL;
+		}
+		spin_unlock_irqrestore(&qdss->lock, flags);
 	}
 
 	/*
@@ -528,6 +537,8 @@
 {
 	struct f_qdss *qdss;
 	int status;
+	struct usb_request *req = NULL;
+	unsigned long flags;
 
 	qdss = container_of(work, struct f_qdss, connect_w);
 
@@ -548,8 +559,13 @@
 	if (qdss->ch.notify)
 		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT,
 						NULL, &qdss->ch);
+	spin_lock_irqsave(&qdss->lock, flags);
+	req = qdss->endless_req;
+	spin_unlock_irqrestore(&qdss->lock, flags);
+	if (!req)
+		return;
 
-	status = usb_ep_queue(qdss->port.data, qdss->endless_req, GFP_ATOMIC);
+	status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC);
 	if (status)
 		pr_err("%s: usb_ep_queue error (%d)\n", __func__, status);
 }
@@ -849,9 +865,11 @@
 		return;
 	}
 
-	usb_ep_dequeue(qdss->port.data, qdss->endless_req);
-	usb_ep_free_request(qdss->port.data, qdss->endless_req);
-	qdss->endless_req = NULL;
+	if (qdss->endless_req) {
+		usb_ep_dequeue(qdss->port.data, qdss->endless_req);
+		usb_ep_free_request(qdss->port.data, qdss->endless_req);
+		qdss->endless_req = NULL;
+	}
 	gadget = qdss->gadget;
 	ch->app_conn = 0;
 	spin_unlock_irqrestore(&qdss_lock, flags);
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index fc85994..1633d4a 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -880,7 +880,7 @@
 				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 
 		req->num_mapped_sgs = 0;
-	} else {
+	} else if (req->dma != DMA_ERROR_CODE) {
 		dma_unmap_single(dev, req->dma, req->length,
 				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 	}
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 47b2817..32aa45e 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -385,10 +385,6 @@
 	int i;
 
 	ret = 0;
-	virt_dev = xhci->devs[slot_id];
-	if (!virt_dev)
-		return -ENODEV;
-
 	cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
 	if (!cmd) {
 		xhci_dbg(xhci, "Couldn't allocate command structure.\n");
@@ -396,6 +392,13 @@
 	}
 
 	spin_lock_irqsave(&xhci->lock, flags);
+	virt_dev = xhci->devs[slot_id];
+	if (!virt_dev) {
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		xhci_free_command(xhci, cmd);
+		return -ENODEV;
+	}
+
 	for (i = LAST_EP_INDEX; i > 0; i--) {
 		if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) {
 			struct xhci_command *command;
@@ -412,6 +415,7 @@
 					i, suspend);
 			if (ret) {
 				spin_unlock_irqrestore(&xhci->lock, flags);
+				xhci_free_command(xhci, command);
 				goto err_cmd_queue;
 			}
 		}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 8c06e6a..5643613 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -34,6 +34,10 @@
 module_param(usb_compliance_mode, bool, 0644);
 MODULE_PARM_DESC(usb_compliance_mode, "Start USB stack for USB3.1 compliance testing");
 
+static bool disable_usb_pd;
+module_param(disable_usb_pd, bool, 0644);
+MODULE_PARM_DESC(disable_usb_pd, "Disable USB PD for USB3.1 compliance testing");
+
 enum usbpd_state {
 	PE_UNKNOWN,
 	PE_ERROR_RECOVERY,
@@ -594,6 +598,8 @@
 
 static void pd_send_hard_reset(struct usbpd *pd)
 {
+	union power_supply_propval val = {0};
+
 	usbpd_dbg(&pd->dev, "send hard reset");
 
 	/* Force CC logic to source/sink to keep Rp/Rd unchanged */
@@ -601,6 +607,7 @@
 	pd->hard_reset_count++;
 	pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
 	pd->in_pr_swap = false;
+	power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val);
 }
 
 static void kick_sm(struct usbpd *pd, int ms)
@@ -744,6 +751,15 @@
 		break;
 
 	/* Source states */
+	case PE_SRC_DISABLED:
+		/* are we still connected? */
+		if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+			pd->current_pr = PR_NONE;
+			kick_sm(pd, 0);
+		}
+
+		break;
+
 	case PE_SRC_STARTUP:
 		if (pd->current_dr == DR_NONE) {
 			pd->current_dr = DR_DFP;
@@ -787,6 +803,9 @@
 		if (pd->in_pr_swap) {
 			kick_sm(pd, SWAP_SOURCE_START_TIME);
 			pd->in_pr_swap = false;
+			val.intval = 0;
+			power_supply_set_property(pd->usb_psy,
+					POWER_SUPPLY_PROP_PR_SWAP, &val);
 			break;
 		}
 
@@ -869,6 +888,10 @@
 
 	case PE_SRC_HARD_RESET:
 	case PE_SNK_HARD_RESET:
+		/* are we still connected? */
+		if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE)
+			pd->current_pr = PR_NONE;
+
 		/* hard reset may sleep; handle it in the workqueue */
 		kick_sm(pd, 0);
 		break;
@@ -910,7 +933,7 @@
 			break;
 		}
 
-		if (!val.intval)
+		if (!val.intval || disable_usb_pd)
 			break;
 
 		pd_reset_protocol(pd);
@@ -1572,7 +1595,6 @@
 		memset(&pd->received_pdos, 0, sizeof(pd->received_pdos));
 		rx_msg_cleanup(pd);
 
-		val.intval = 0;
 		power_supply_set_property(pd->usb_psy,
 				POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
 
@@ -1602,6 +1624,10 @@
 			usleep_range(ERROR_RECOVERY_TIME * USEC_PER_MSEC,
 				(ERROR_RECOVERY_TIME + 5) * USEC_PER_MSEC);
 
+		val.intval = 0;
+		power_supply_set_property(pd->usb_psy,
+				POWER_SUPPLY_PROP_PR_SWAP, &val);
+
 		/* set due to dual_role class "mode" change */
 		if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
 			val.intval = pd->forced_pr;
@@ -1637,6 +1663,10 @@
 				POWER_SUPPLY_PROP_VOLTAGE_MIN, &val);
 
 		pd->in_pr_swap = false;
+		val.intval = 0;
+		power_supply_set_property(pd->usb_psy,
+				POWER_SUPPLY_PROP_PR_SWAP, &val);
+
 		pd->in_explicit_contract = false;
 		pd->selected_pdo = pd->requested_pdo = 0;
 		pd->rdo = 0;
@@ -1897,6 +1927,9 @@
 
 	case PE_SNK_WAIT_FOR_CAPABILITIES:
 		pd->in_pr_swap = false;
+		val.intval = 0;
+		power_supply_set_property(pd->usb_psy,
+				POWER_SUPPLY_PROP_PR_SWAP, &val);
 
 		if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) {
 			val.intval = 0;
@@ -1916,15 +1949,6 @@
 					POWER_SUPPLY_PROP_PD_ACTIVE, &val);
 		} else if (pd->hard_reset_count < 3) {
 			usbpd_set_state(pd, PE_SNK_HARD_RESET);
-		} else if (pd->pd_connected) {
-			usbpd_info(&pd->dev, "Sink hard reset count exceeded, forcing reconnect\n");
-
-			val.intval = 0;
-			power_supply_set_property(pd->usb_psy,
-					POWER_SUPPLY_PROP_PD_IN_HARD_RESET,
-					&val);
-
-			usbpd_set_state(pd, PE_ERROR_RECOVERY);
 		} else {
 			usbpd_dbg(&pd->dev, "Sink hard reset count exceeded, disabling PD\n");
 
@@ -2072,6 +2096,9 @@
 			}
 
 			pd->in_pr_swap = true;
+			val.intval = 1;
+			power_supply_set_property(pd->usb_psy,
+					POWER_SUPPLY_PROP_PR_SWAP, &val);
 			usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
 			break;
 		} else if (IS_CTRL(rx_msg, MSG_VCONN_SWAP)) {
@@ -2215,6 +2242,9 @@
 
 	case PE_PRS_SRC_SNK_TRANSITION_TO_OFF:
 		pd->in_pr_swap = true;
+		val.intval = 1;
+		power_supply_set_property(pd->usb_psy,
+				POWER_SUPPLY_PROP_PR_SWAP, &val);
 		pd->in_explicit_contract = false;
 
 		if (pd->vbus_enabled) {
@@ -2255,6 +2285,9 @@
 		}
 
 		pd->in_pr_swap = true;
+		val.intval = 1;
+		power_supply_set_property(pd->usb_psy,
+				POWER_SUPPLY_PROP_PR_SWAP, &val);
 		usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
 		break;
 
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index d2c4876..b1b74ff 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -245,4 +245,13 @@
 	  Synopsys DWC3 USB IPs on MSM SOCs. This driver expects to configure the
 	  PHY with a dedicated register I/O memory region.
 
+config MSM_HSUSB_PHY
+	tristate "MSM HSUSB PHY Driver"
+	depends on ARCH_QCOM
+	select USB_PHY
+	help
+	  Enable this to support the HSUSB PHY on MSM chips. This driver supports
+	  the high-speed PHY which is usually paired with either the ChipIdea or
+	  Synopsys DWC3 USB IPs on MSM SOCs. This driver expects to configure the
+	  PHY with a dedicated register I/O memory region.
 endmenu
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index ce98866..5b748a6 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -30,3 +30,4 @@
 obj-$(CONFIG_KEYSTONE_USB_PHY)		+= phy-keystone.o
 obj-$(CONFIG_USB_MSM_SSPHY_QMP)     	+= phy-msm-ssusb-qmp.o
 obj-$(CONFIG_MSM_QUSB_PHY)              += phy-msm-qusb.o phy-msm-qusb-v2.o
+obj-$(CONFIG_MSM_HSUSB_PHY)		+= phy-msm-snps-hs.o
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 4f0a455..1210188e 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -48,7 +48,6 @@
 #define DPSE_INTERRUPT			BIT(0)
 
 #define QUSB2PHY_PORT_TUNE1		0x23c
-#define QUSB2PHY_TEST1			0x24C
 
 #define QUSB2PHY_PLL_CORE_INPUT_OVERRIDE 0x0a8
 #define CORE_PLL_RATE			BIT(0)
@@ -94,6 +93,7 @@
 	int			*qusb_phy_host_init_seq;
 
 	u32			tune_val;
+	u32			phy_auto_resume_offset;
 	int			efuse_bit_pos;
 	int			efuse_num_of_bits;
 
@@ -551,14 +551,15 @@
 				CORE_RESET | CORE_RESET_MUX,
 				qphy->base + QUSB2PHY_PLL_CORE_INPUT_OVERRIDE);
 
-			/* enable phy auto-resume */
-			writel_relaxed(0x91,
-					qphy->base + QUSB2PHY_TEST1);
-			/* flush the previous write before next write */
-			wmb();
-			writel_relaxed(0x90,
-				qphy->base + QUSB2PHY_TEST1);
-
+			if (qphy->phy_auto_resume_offset) {
+				/* enable phy auto-resume */
+				writel_relaxed(0x91,
+				qphy->base + qphy->phy_auto_resume_offset);
+				/* flush the previous write before next write */
+				wmb();
+				writel_relaxed(0x90,
+				qphy->base + qphy->phy_auto_resume_offset);
+			}
 			dev_dbg(phy->dev, "%s: intr_mask = %x\n",
 			__func__, intr_mask);
 
@@ -916,6 +917,12 @@
 		return ret;
 	}
 
+	ret = of_property_read_u32(dev->of_node, "qcom,phy-auto-resume-offset",
+			&qphy->phy_auto_resume_offset);
+	if (ret)
+		dev_dbg(dev, "error reading qcom,phy-auto-resume-offset %d\n",
+				ret);
+
 	qphy->vdd = devm_regulator_get(dev, "vdd");
 	if (IS_ERR(qphy->vdd)) {
 		dev_err(dev, "unable to get vdd supply\n");
diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c
new file mode 100644
index 0000000..2d18faf
--- /dev/null
+++ b/drivers/usb/phy/phy-msm-snps-hs.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/usb/phy.h>
+#include <linux/reset.h>
+
+#define USB2_PHY_USB_PHY_UTMI_CTRL0		(0x3c)
+#define SLEEPM					BIT(0)
+
+#define USB2_PHY_USB_PHY_UTMI_CTRL5		(0x50)
+#define ATERESET				BIT(0)
+#define POR					BIT(1)
+
+#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0	(0x54)
+#define VATESTENB_MASK				(0x3 << 0)
+#define RETENABLEN				BIT(3)
+#define FSEL_MASK				(0x7 << 4)
+#define FSEL_DEFAULT				(0x3 << 4)
+
+#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1	(0x58)
+#define VBUSVLDEXTSEL0				BIT(4)
+#define PLLBTUNE				BIT(5)
+
+#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2	(0x5c)
+#define VREGBYPASS				BIT(0)
+
+#define USB2_PHY_USB_PHY_HS_PHY_CTRL1		(0x60)
+#define VBUSVLDEXT0				BIT(0)
+
+#define USB2_PHY_USB_PHY_HS_PHY_CTRL2		(0x64)
+#define USB2_SUSPEND_N				BIT(2)
+#define USB2_SUSPEND_N_SEL			BIT(3)
+
+#define USB2_PHY_USB_PHY_HS_PHY_TEST0		(0x80)
+#define TESTDATAIN_MASK				(0xff << 0)
+
+#define USB2_PHY_USB_PHY_HS_PHY_TEST1		(0x84)
+#define TESTDATAOUTSEL				BIT(4)
+#define TOGGLE_2WR				BIT(6)
+
+#define USB2_PHY_USB_PHY_CFG0			(0x94)
+#define UTMI_PHY_CMN_CTRL_OVERRIDE_EN		BIT(1)
+
+#define USB2_PHY_USB_PHY_REFCLK_CTRL		(0xa0)
+#define REFCLK_SEL_MASK				(0x3 << 0)
+#define REFCLK_SEL_DEFAULT			(0x2 << 0)
+
+#define USB_HSPHY_3P3_VOL_MIN			3050000 /* uV */
+#define USB_HSPHY_3P3_VOL_MAX			3300000 /* uV */
+#define USB_HSPHY_3P3_HPM_LOAD			16000	/* uA */
+#define USB_HSPHY_3P3_VOL_FSHOST		3150000 /* uV */
+
+#define USB_HSPHY_1P8_VOL_MIN			1800000 /* uV */
+#define USB_HSPHY_1P8_VOL_MAX			1800000 /* uV */
+#define USB_HSPHY_1P8_HPM_LOAD			19000	/* uA */
+
+struct msm_hsphy {
+	struct usb_phy		phy;
+	void __iomem		*base;
+
+	struct clk		*ref_clk_src;
+	struct clk		*cfg_ahb_clk;
+	struct reset_control	*phy_reset;
+
+	struct regulator	*vdd;
+	struct regulator	*vdda33;
+	struct regulator	*vdda18;
+	int			vdd_levels[3]; /* none, low, high */
+
+	bool			clocks_enabled;
+	bool			power_enabled;
+	bool			suspended;
+	bool			cable_connected;
+
+	/* emulation targets specific */
+	void __iomem		*emu_phy_base;
+	int			*emu_init_seq;
+	int			emu_init_seq_len;
+	int			*emu_dcm_reset_seq;
+	int			emu_dcm_reset_seq_len;
+};
+
+static void msm_hsphy_enable_clocks(struct msm_hsphy *phy, bool on)
+{
+	dev_dbg(phy->phy.dev, "%s(): clocks_enabled:%d on:%d\n",
+			__func__, phy->clocks_enabled, on);
+
+	if (!phy->clocks_enabled && on) {
+		clk_prepare_enable(phy->ref_clk_src);
+
+		if (phy->cfg_ahb_clk)
+			clk_prepare_enable(phy->cfg_ahb_clk);
+
+		phy->clocks_enabled = true;
+	}
+
+	if (phy->clocks_enabled && !on) {
+		if (phy->cfg_ahb_clk)
+			clk_disable_unprepare(phy->cfg_ahb_clk);
+
+		clk_disable_unprepare(phy->ref_clk_src);
+		phy->clocks_enabled = false;
+	}
+
+}
+static int msm_hsphy_config_vdd(struct msm_hsphy *phy, int high)
+{
+	int min, ret;
+
+	min = high ? 1 : 0; /* low or none? */
+	ret = regulator_set_voltage(phy->vdd, phy->vdd_levels[min],
+				    phy->vdd_levels[2]);
+	if (ret) {
+		dev_err(phy->phy.dev, "unable to set voltage for hsusb vdd\n");
+		return ret;
+	}
+
+	dev_dbg(phy->phy.dev, "%s: min_vol:%d max_vol:%d\n", __func__,
+		phy->vdd_levels[min], phy->vdd_levels[2]);
+
+	return ret;
+}
+
+static int msm_hsphy_enable_power(struct msm_hsphy *phy, bool on)
+{
+	int ret = 0;
+
+	dev_dbg(phy->phy.dev, "%s turn %s regulators. power_enabled:%d\n",
+			__func__, on ? "on" : "off", phy->power_enabled);
+
+	if (phy->power_enabled == on) {
+		dev_dbg(phy->phy.dev, "PHYs' regulators are already ON.\n");
+		return 0;
+	}
+
+	if (!on)
+		goto disable_vdda33;
+
+	ret = msm_hsphy_config_vdd(phy, true);
+	if (ret) {
+		dev_err(phy->phy.dev, "Unable to config VDD:%d\n",
+							ret);
+		goto err_vdd;
+	}
+
+	ret = regulator_enable(phy->vdd);
+	if (ret) {
+		dev_err(phy->phy.dev, "Unable to enable VDD\n");
+		goto unconfig_vdd;
+	}
+
+	ret = regulator_set_load(phy->vdda18, USB_HSPHY_1P8_HPM_LOAD);
+	if (ret < 0) {
+		dev_err(phy->phy.dev, "Unable to set HPM of vdda18:%d\n", ret);
+		goto disable_vdd;
+	}
+
+	ret = regulator_set_voltage(phy->vdda18, USB_HSPHY_1P8_VOL_MIN,
+						USB_HSPHY_1P8_VOL_MAX);
+	if (ret) {
+		dev_err(phy->phy.dev,
+				"Unable to set voltage for vdda18:%d\n", ret);
+		goto put_vdda18_lpm;
+	}
+
+	ret = regulator_enable(phy->vdda18);
+	if (ret) {
+		dev_err(phy->phy.dev, "Unable to enable vdda18:%d\n", ret);
+		goto unset_vdda18;
+	}
+
+	ret = regulator_set_load(phy->vdda33, USB_HSPHY_3P3_HPM_LOAD);
+	if (ret < 0) {
+		dev_err(phy->phy.dev, "Unable to set HPM of vdda33:%d\n", ret);
+		goto disable_vdda18;
+	}
+
+	ret = regulator_set_voltage(phy->vdda33, USB_HSPHY_3P3_VOL_MIN,
+						USB_HSPHY_3P3_VOL_MAX);
+	if (ret) {
+		dev_err(phy->phy.dev,
+				"Unable to set voltage for vdda33:%d\n", ret);
+		goto put_vdda33_lpm;
+	}
+
+	ret = regulator_enable(phy->vdda33);
+	if (ret) {
+		dev_err(phy->phy.dev, "Unable to enable vdda33:%d\n", ret);
+		goto unset_vdd33;
+	}
+
+	phy->power_enabled = true;
+
+	pr_debug("%s(): HSUSB PHY's regulators are turned ON.\n", __func__);
+	return ret;
+
+disable_vdda33:
+	ret = regulator_disable(phy->vdda33);
+	if (ret)
+		dev_err(phy->phy.dev, "Unable to disable vdda33:%d\n", ret);
+
+unset_vdd33:
+	ret = regulator_set_voltage(phy->vdda33, 0, USB_HSPHY_3P3_VOL_MAX);
+	if (ret)
+		dev_err(phy->phy.dev,
+			"Unable to set (0) voltage for vdda33:%d\n", ret);
+
+put_vdda33_lpm:
+	ret = regulator_set_load(phy->vdda33, 0);
+	if (ret < 0)
+		dev_err(phy->phy.dev, "Unable to set (0) HPM of vdda33\n");
+
+disable_vdda18:
+	ret = regulator_disable(phy->vdda18);
+	if (ret)
+		dev_err(phy->phy.dev, "Unable to disable vdda18:%d\n", ret);
+
+unset_vdda18:
+	ret = regulator_set_voltage(phy->vdda18, 0, USB_HSPHY_1P8_VOL_MAX);
+	if (ret)
+		dev_err(phy->phy.dev,
+			"Unable to set (0) voltage for vdda18:%d\n", ret);
+
+put_vdda18_lpm:
+	ret = regulator_set_load(phy->vdda18, 0);
+	if (ret < 0)
+		dev_err(phy->phy.dev, "Unable to set LPM of vdda18\n");
+
+disable_vdd:
+	if (ret)
+		dev_err(phy->phy.dev, "Unable to disable vdd:%d\n",
+								ret);
+
+unconfig_vdd:
+	ret = msm_hsphy_config_vdd(phy, false);
+	if (ret)
+		dev_err(phy->phy.dev, "Unable unconfig VDD:%d\n",
+								ret);
+err_vdd:
+	phy->power_enabled = false;
+	dev_dbg(phy->phy.dev, "HSUSB PHY's regulators are turned OFF.\n");
+	return ret;
+}
+
+static void msm_usb_write_readback(void __iomem *base, u32 offset,
+					const u32 mask, u32 val)
+{
+	u32 write_val, tmp = readl_relaxed(base + offset);
+
+	tmp &= ~mask;		/* retain other bits */
+	write_val = tmp | val;
+
+	writel_relaxed(write_val, base + offset);
+
+	/* Read back to see if val was written */
+	tmp = readl_relaxed(base + offset);
+	tmp &= mask;		/* clear other bits */
+
+	if (tmp != val)
+		pr_err("%s: write: %x to QSCRATCH: %x FAILED\n",
+			__func__, val, offset);
+}
+
+static void msm_hsphy_reset(struct msm_hsphy *phy)
+{
+	int ret;
+
+	ret = reset_control_assert(phy->phy_reset);
+	if (ret)
+		dev_err(phy->phy.dev, "%s: phy_reset assert failed\n",
+								__func__);
+	usleep_range(100, 150);
+
+	ret = reset_control_deassert(phy->phy_reset);
+	if (ret)
+		dev_err(phy->phy.dev, "%s: phy_reset deassert failed\n",
+							__func__);
+}
+
+static void hsusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt,
+		unsigned long delay)
+{
+	int i;
+
+	pr_debug("Seq count:%d\n", cnt);
+	for (i = 0; i < cnt; i = i+2) {
+		pr_debug("write 0x%02x to 0x%02x\n", seq[i], seq[i+1]);
+		writel_relaxed(seq[i], base + seq[i+1]);
+		if (delay)
+			usleep_range(delay, (delay + 2000));
+	}
+}
+
+static int msm_hsphy_emu_init(struct usb_phy *uphy)
+{
+	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
+	int ret;
+
+	dev_dbg(uphy->dev, "%s\n", __func__);
+
+	ret = msm_hsphy_enable_power(phy, true);
+	if (ret)
+		return ret;
+
+	msm_hsphy_enable_clocks(phy, true);
+	msm_hsphy_reset(phy);
+
+	if (phy->emu_init_seq) {
+		hsusb_phy_write_seq(phy->base,
+			phy->emu_init_seq,
+			phy->emu_init_seq_len, 10000);
+
+		/* Wait for 5ms as per QUSB2 RUMI sequence */
+		usleep_range(5000, 7000);
+
+		if (phy->emu_dcm_reset_seq)
+			hsusb_phy_write_seq(phy->emu_phy_base,
+					phy->emu_dcm_reset_seq,
+					phy->emu_dcm_reset_seq_len, 10000);
+	}
+
+	return 0;
+}
+
+static int msm_hsphy_init(struct usb_phy *uphy)
+{
+	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
+	int ret;
+
+	dev_dbg(uphy->dev, "%s\n", __func__);
+
+	ret = msm_hsphy_enable_power(phy, true);
+	if (ret)
+		return ret;
+
+	msm_hsphy_enable_clocks(phy, true);
+	msm_hsphy_reset(phy);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0,
+	UTMI_PHY_CMN_CTRL_OVERRIDE_EN, UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
+				POR, POR);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0,
+				FSEL_MASK, 0);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
+				PLLBTUNE, PLLBTUNE);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_REFCLK_CTRL,
+				REFCLK_SEL_MASK, REFCLK_SEL_DEFAULT);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
+				VBUSVLDEXTSEL0, VBUSVLDEXTSEL0);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1,
+				VBUSVLDEXT0, VBUSVLDEXT0);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2,
+				VREGBYPASS, VREGBYPASS);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
+				ATERESET, ATERESET);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_TEST1,
+				TESTDATAOUTSEL, TESTDATAOUTSEL);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_TEST1,
+				TOGGLE_2WR, TOGGLE_2WR);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0,
+				VATESTENB_MASK, 0);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_TEST0,
+				TESTDATAIN_MASK, 0);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
+				USB2_SUSPEND_N_SEL, USB2_SUSPEND_N_SEL);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
+				USB2_SUSPEND_N, USB2_SUSPEND_N);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
+				SLEEPM, SLEEPM);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
+				POR, 0);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
+				USB2_SUSPEND_N_SEL, 0);
+
+	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0,
+	UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0);
+
+	return 0;
+}
+
+static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend)
+{
+	return 0;
+}
+
+static int msm_hsphy_notify_connect(struct usb_phy *uphy,
+				    enum usb_device_speed speed)
+{
+	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
+
+	phy->cable_connected = true;
+
+	return 0;
+}
+
+static int msm_hsphy_notify_disconnect(struct usb_phy *uphy,
+				       enum usb_device_speed speed)
+{
+	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
+
+	phy->cable_connected = false;
+
+	return 0;
+}
+
+static int msm_hsphy_probe(struct platform_device *pdev)
+{
+	struct msm_hsphy *phy;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret = 0, size = 0;
+
+
+	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+	if (!phy) {
+		ret = -ENOMEM;
+		goto err_ret;
+	}
+
+	phy->phy.dev = dev;
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"hsusb_phy_base");
+	if (!res) {
+		dev_err(dev, "missing memory base resource\n");
+		ret = -ENODEV;
+		goto err_ret;
+	}
+
+	phy->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(phy->base)) {
+		dev_err(dev, "ioremap failed\n");
+		ret = -ENODEV;
+		goto err_ret;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+							"emu_phy_base");
+	if (res) {
+		phy->emu_phy_base = devm_ioremap_resource(dev, res);
+		if (IS_ERR(phy->emu_phy_base)) {
+			dev_dbg(dev, "couldn't ioremap emu_phy_base\n");
+			phy->emu_phy_base = NULL;
+		}
+	}
+
+	/* ref_clk_src is needed irrespective of SE_CLK or DIFF_CLK usage */
+	phy->ref_clk_src = devm_clk_get(dev, "ref_clk_src");
+	if (IS_ERR(phy->ref_clk_src)) {
+		dev_dbg(dev, "clk get failed for ref_clk_src\n");
+		ret = PTR_ERR(phy->ref_clk_src);
+		return ret;
+	}
+
+	if (of_property_match_string(pdev->dev.of_node,
+				"clock-names", "cfg_ahb_clk") >= 0) {
+		phy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb_clk");
+		if (IS_ERR(phy->cfg_ahb_clk)) {
+			ret = PTR_ERR(phy->cfg_ahb_clk);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev,
+				"clk get failed for cfg_ahb_clk ret %d\n", ret);
+			return ret;
+		}
+	}
+
+	phy->phy_reset = devm_reset_control_get(dev, "phy_reset");
+	if (IS_ERR(phy->phy_reset))
+		return PTR_ERR(phy->phy_reset);
+
+	of_get_property(dev->of_node, "qcom,emu-init-seq", &size);
+	if (size) {
+		phy->emu_init_seq = devm_kzalloc(dev,
+						size, GFP_KERNEL);
+		if (phy->emu_init_seq) {
+			phy->emu_init_seq_len =
+				(size / sizeof(*phy->emu_init_seq));
+			if (phy->emu_init_seq_len % 2) {
+				dev_err(dev, "invalid emu_init_seq_len\n");
+				return -EINVAL;
+			}
+
+			of_property_read_u32_array(dev->of_node,
+				"qcom,emu-init-seq",
+				phy->emu_init_seq,
+				phy->emu_init_seq_len);
+		} else {
+			dev_dbg(dev,
+			"error allocating memory for emu_init_seq\n");
+		}
+	}
+
+	size = 0;
+	of_get_property(dev->of_node, "qcom,emu-dcm-reset-seq", &size);
+	if (size) {
+		phy->emu_dcm_reset_seq = devm_kzalloc(dev,
+						size, GFP_KERNEL);
+		if (phy->emu_dcm_reset_seq) {
+			phy->emu_dcm_reset_seq_len =
+				(size / sizeof(*phy->emu_dcm_reset_seq));
+			if (phy->emu_dcm_reset_seq_len % 2) {
+				dev_err(dev, "invalid emu_dcm_reset_seq_len\n");
+				return -EINVAL;
+			}
+
+			of_property_read_u32_array(dev->of_node,
+				"qcom,emu-dcm-reset-seq",
+				phy->emu_dcm_reset_seq,
+				phy->emu_dcm_reset_seq_len);
+		} else {
+			dev_dbg(dev,
+			"error allocating memory for emu_dcm_reset_seq\n");
+		}
+	}
+
+	ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level",
+					 (u32 *) phy->vdd_levels,
+					 ARRAY_SIZE(phy->vdd_levels));
+	if (ret) {
+		dev_err(dev, "error reading qcom,vdd-voltage-level property\n");
+		goto err_ret;
+	}
+
+
+	phy->vdd = devm_regulator_get(dev, "vdd");
+	if (IS_ERR(phy->vdd)) {
+		dev_err(dev, "unable to get vdd supply\n");
+		ret = PTR_ERR(phy->vdd);
+		goto err_ret;
+	}
+
+	phy->vdda33 = devm_regulator_get(dev, "vdda33");
+	if (IS_ERR(phy->vdda33)) {
+		dev_err(dev, "unable to get vdda33 supply\n");
+		ret = PTR_ERR(phy->vdda33);
+		goto err_ret;
+	}
+
+	phy->vdda18 = devm_regulator_get(dev, "vdda18");
+	if (IS_ERR(phy->vdda18)) {
+		dev_err(dev, "unable to get vdda18 supply\n");
+		ret = PTR_ERR(phy->vdda18);
+		goto err_ret;
+	}
+
+	platform_set_drvdata(pdev, phy);
+
+	if (phy->emu_init_seq)
+		phy->phy.init			= msm_hsphy_emu_init;
+	else
+		phy->phy.init			= msm_hsphy_init;
+	phy->phy.set_suspend		= msm_hsphy_set_suspend;
+	phy->phy.notify_connect		= msm_hsphy_notify_connect;
+	phy->phy.notify_disconnect	= msm_hsphy_notify_disconnect;
+	phy->phy.type			= USB_PHY_TYPE_USB2;
+
+	ret = usb_add_phy_dev(&phy->phy);
+	if (ret)
+		return ret;
+
+	return 0;
+
+err_ret:
+	return ret;
+}
+
+static int msm_hsphy_remove(struct platform_device *pdev)
+{
+	struct msm_hsphy *phy = platform_get_drvdata(pdev);
+
+	if (!phy)
+		return 0;
+
+	usb_remove_phy(&phy->phy);
+	clk_disable_unprepare(phy->ref_clk_src);
+
+	msm_hsphy_enable_clocks(phy, false);
+	msm_hsphy_enable_power(phy, false);
+
+	kfree(phy);
+
+	return 0;
+}
+
+static const struct of_device_id msm_usb_id_table[] = {
+	{
+		.compatible = "qcom,usb-hsphy-snps-femto",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, msm_usb_id_table);
+
+static struct platform_driver msm_hsphy_driver = {
+	.probe		= msm_hsphy_probe,
+	.remove		= msm_hsphy_remove,
+	.driver = {
+		.name	= "msm-usb-hsphy",
+		.of_match_table = of_match_ptr(msm_usb_id_table),
+	},
+};
+
+module_platform_driver(msm_hsphy_driver);
+
+MODULE_DESCRIPTION("MSM USB HS PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 702040f..0e60614 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -335,8 +335,8 @@
 				st->global_error = 1;
 		}
 	}
-	st->va += PAGE_SIZE * nr;
-	st->index += nr;
+	st->va += XEN_PAGE_SIZE * nr;
+	st->index += nr / XEN_PFN_PER_PAGE;
 
 	return 0;
 }
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 2924bddb..07e46b7 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -713,7 +713,7 @@
 		bdev->bd_contains = NULL;
 		bdev->bd_super = NULL;
 		bdev->bd_inode = inode;
-		bdev->bd_block_size = (1 << inode->i_blkbits);
+		bdev->bd_block_size = i_blocksize(inode);
 		bdev->bd_part_count = 0;
 		bdev->bd_invalidated = 0;
 		inode->i_mode = S_IFBLK;
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 5909ae8..e46e7fb 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3984,6 +3984,7 @@
 				    info->space_info_kobj, "%s",
 				    alloc_name(found->flags));
 	if (ret) {
+		percpu_counter_destroy(&found->total_bytes_pinned);
 		kfree(found);
 		return ret;
 	}
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 3a14c87..3286a6e 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2842,7 +2842,7 @@
 		if (!ret)
 			ret = btrfs_prealloc_file_range(inode, mode,
 					range->start,
-					range->len, 1 << inode->i_blkbits,
+					range->len, i_blocksize(inode),
 					offset + len, &alloc_hint);
 		else
 			btrfs_free_reserved_data_space(inode, range->start,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index be4da91..bddbae7 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7435,8 +7435,8 @@
 	int found = false;
 	void **pagep = NULL;
 	struct page *page = NULL;
-	int start_idx;
-	int end_idx;
+	unsigned long start_idx;
+	unsigned long end_idx;
 
 	start_idx = start >> PAGE_SHIFT;
 
diff --git a/fs/buffer.c b/fs/buffer.c
index b205a62..5d8f496 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2353,7 +2353,7 @@
 			    loff_t pos, loff_t *bytes)
 {
 	struct inode *inode = mapping->host;
-	unsigned blocksize = 1 << inode->i_blkbits;
+	unsigned int blocksize = i_blocksize(inode);
 	struct page *page;
 	void *fsdata;
 	pgoff_t index, curidx;
@@ -2433,8 +2433,8 @@
 			get_block_t *get_block, loff_t *bytes)
 {
 	struct inode *inode = mapping->host;
-	unsigned blocksize = 1 << inode->i_blkbits;
-	unsigned zerofrom;
+	unsigned int blocksize = i_blocksize(inode);
+	unsigned int zerofrom;
 	int err;
 
 	err = cont_expand_zero(file, mapping, pos, bytes);
@@ -2796,7 +2796,7 @@
 	struct buffer_head map_bh;
 	int err;
 
-	blocksize = 1 << inode->i_blkbits;
+	blocksize = i_blocksize(inode);
 	length = offset & (blocksize - 1);
 
 	/* Block boundary? Nothing to do */
@@ -2874,7 +2874,7 @@
 	struct buffer_head *bh;
 	int err;
 
-	blocksize = 1 << inode->i_blkbits;
+	blocksize = i_blocksize(inode);
 	length = offset & (blocksize - 1);
 
 	/* Block boundary? Nothing to do */
@@ -2986,7 +2986,7 @@
 	struct inode *inode = mapping->host;
 	tmp.b_state = 0;
 	tmp.b_blocknr = 0;
-	tmp.b_size = 1 << inode->i_blkbits;
+	tmp.b_size = i_blocksize(inode);
 	get_block(inode, block, &tmp, 0);
 	return tmp.b_blocknr;
 }
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 18dc18f..900ffaf 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -745,7 +745,7 @@
 	struct pagevec pvec;
 	int done = 0;
 	int rc = 0;
-	unsigned wsize = 1 << inode->i_blkbits;
+	unsigned int wsize = i_blocksize(inode);
 	struct ceph_osd_request *req = NULL;
 	int do_sync = 0;
 	loff_t snap_size, i_size;
diff --git a/fs/direct-io.c b/fs/direct-io.c
index fb9aa16..c60756e 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -587,7 +587,7 @@
 /*
  * Call into the fs to map some more disk blocks.  We record the current number
  * of available blocks at sdio->blocks_available.  These are in units of the
- * fs blocksize, (1 << inode->i_blkbits).
+ * fs blocksize, i_blocksize(inode).
  *
  * The fs is allowed to map lots of blocks at once.  If it wants to do that,
  * it uses the passed inode-relative block number as the file offset, as usual.
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 9fbf92c..e57d463 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3413,13 +3413,13 @@
 	struct ext4_sb_info *sbi;
 	struct ext4_extent_header *eh;
 	struct ext4_map_blocks split_map;
-	struct ext4_extent zero_ex;
+	struct ext4_extent zero_ex1, zero_ex2;
 	struct ext4_extent *ex, *abut_ex;
 	ext4_lblk_t ee_block, eof_block;
 	unsigned int ee_len, depth, map_len = map->m_len;
 	int allocated = 0, max_zeroout = 0;
 	int err = 0;
-	int split_flag = 0;
+	int split_flag = EXT4_EXT_DATA_VALID2;
 
 	ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical"
 		"block %llu, max_blocks %u\n", inode->i_ino,
@@ -3436,7 +3436,10 @@
 	ex = path[depth].p_ext;
 	ee_block = le32_to_cpu(ex->ee_block);
 	ee_len = ext4_ext_get_actual_len(ex);
-	zero_ex.ee_len = 0;
+	zero_ex1.ee_len = 0;
+	zero_ex2.ee_len = 0;
+	zero_ex1.ee_start_lo = 0;
+	zero_ex2.ee_start_lo = 0;
 
 	trace_ext4_ext_convert_to_initialized_enter(inode, map, ex);
 
@@ -3576,62 +3579,52 @@
 	if (ext4_encrypted_inode(inode))
 		max_zeroout = 0;
 
-	/* If extent is less than s_max_zeroout_kb, zeroout directly */
-	if (max_zeroout && (ee_len <= max_zeroout)) {
-		err = ext4_ext_zeroout(inode, ex);
-		if (err)
-			goto out;
-		zero_ex.ee_block = ex->ee_block;
-		zero_ex.ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex));
-		ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex));
-
-		err = ext4_ext_get_access(handle, inode, path + depth);
-		if (err)
-			goto out;
-		ext4_ext_mark_initialized(ex);
-		ext4_ext_try_to_merge(handle, inode, path, ex);
-		err = ext4_ext_dirty(handle, inode, path + path->p_depth);
-		goto out;
-	}
-
 	/*
-	 * four cases:
+	 * five cases:
 	 * 1. split the extent into three extents.
-	 * 2. split the extent into two extents, zeroout the first half.
-	 * 3. split the extent into two extents, zeroout the second half.
+	 * 2. split the extent into two extents, zeroout the head of the first
+	 *    extent.
+	 * 3. split the extent into two extents, zeroout the tail of the second
+	 *    extent.
 	 * 4. split the extent into two extents with out zeroout.
+	 * 5. no splitting needed, just possibly zeroout the head and / or the
+	 *    tail of the extent.
 	 */
 	split_map.m_lblk = map->m_lblk;
 	split_map.m_len = map->m_len;
 
-	if (max_zeroout && (allocated > map->m_len)) {
+	if (max_zeroout && (allocated > split_map.m_len)) {
 		if (allocated <= max_zeroout) {
-			/* case 3 */
-			zero_ex.ee_block =
-					 cpu_to_le32(map->m_lblk);
-			zero_ex.ee_len = cpu_to_le16(allocated);
-			ext4_ext_store_pblock(&zero_ex,
-				ext4_ext_pblock(ex) + map->m_lblk - ee_block);
-			err = ext4_ext_zeroout(inode, &zero_ex);
+			/* case 3 or 5 */
+			zero_ex1.ee_block =
+				 cpu_to_le32(split_map.m_lblk +
+					     split_map.m_len);
+			zero_ex1.ee_len =
+				cpu_to_le16(allocated - split_map.m_len);
+			ext4_ext_store_pblock(&zero_ex1,
+				ext4_ext_pblock(ex) + split_map.m_lblk +
+				split_map.m_len - ee_block);
+			err = ext4_ext_zeroout(inode, &zero_ex1);
 			if (err)
 				goto out;
-			split_map.m_lblk = map->m_lblk;
 			split_map.m_len = allocated;
-		} else if (map->m_lblk - ee_block + map->m_len < max_zeroout) {
-			/* case 2 */
-			if (map->m_lblk != ee_block) {
-				zero_ex.ee_block = ex->ee_block;
-				zero_ex.ee_len = cpu_to_le16(map->m_lblk -
+		}
+		if (split_map.m_lblk - ee_block + split_map.m_len <
+								max_zeroout) {
+			/* case 2 or 5 */
+			if (split_map.m_lblk != ee_block) {
+				zero_ex2.ee_block = ex->ee_block;
+				zero_ex2.ee_len = cpu_to_le16(split_map.m_lblk -
 							ee_block);
-				ext4_ext_store_pblock(&zero_ex,
+				ext4_ext_store_pblock(&zero_ex2,
 						      ext4_ext_pblock(ex));
-				err = ext4_ext_zeroout(inode, &zero_ex);
+				err = ext4_ext_zeroout(inode, &zero_ex2);
 				if (err)
 					goto out;
 			}
 
+			split_map.m_len += split_map.m_lblk - ee_block;
 			split_map.m_lblk = ee_block;
-			split_map.m_len = map->m_lblk - ee_block + map->m_len;
 			allocated = map->m_len;
 		}
 	}
@@ -3642,8 +3635,11 @@
 		err = 0;
 out:
 	/* If we have gotten a failure, don't zero out status tree */
-	if (!err)
-		err = ext4_zeroout_es(inode, &zero_ex);
+	if (!err) {
+		err = ext4_zeroout_es(inode, &zero_ex1);
+		if (!err)
+			err = ext4_zeroout_es(inode, &zero_ex2);
+	}
 	return err ? err : allocated;
 }
 
@@ -4893,6 +4889,8 @@
 
 	/* Zero out partial block at the edges of the range */
 	ret = ext4_zero_partial_blocks(handle, inode, offset, len);
+	if (ret >= 0)
+		ext4_update_inode_fsync_trans(handle, inode, 1);
 
 	if (file->f_flags & O_SYNC)
 		ext4_handle_sync(handle);
@@ -5579,6 +5577,7 @@
 		ext4_handle_sync(handle);
 	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
 	ext4_mark_inode_dirty(handle, inode);
+	ext4_update_inode_fsync_trans(handle, inode, 1);
 
 out_stop:
 	ext4_journal_stop(handle);
@@ -5752,6 +5751,8 @@
 	up_write(&EXT4_I(inode)->i_data_sem);
 	if (IS_SYNC(inode))
 		ext4_handle_sync(handle);
+	if (ret >= 0)
+		ext4_update_inode_fsync_trans(handle, inode, 1);
 
 out_stop:
 	ext4_journal_stop(handle);
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 2a822d3..9e77c08 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -432,47 +432,27 @@
 		num = min_t(pgoff_t, end - index, PAGEVEC_SIZE);
 		nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
 					  (pgoff_t)num);
-		if (nr_pages == 0) {
-			if (whence == SEEK_DATA)
-				break;
-
-			BUG_ON(whence != SEEK_HOLE);
-			/*
-			 * If this is the first time to go into the loop and
-			 * offset is not beyond the end offset, it will be a
-			 * hole at this offset
-			 */
-			if (lastoff == startoff || lastoff < endoff)
-				found = 1;
+		if (nr_pages == 0)
 			break;
-		}
-
-		/*
-		 * If this is the first time to go into the loop and
-		 * offset is smaller than the first page offset, it will be a
-		 * hole at this offset.
-		 */
-		if (lastoff == startoff && whence == SEEK_HOLE &&
-		    lastoff < page_offset(pvec.pages[0])) {
-			found = 1;
-			break;
-		}
 
 		for (i = 0; i < nr_pages; i++) {
 			struct page *page = pvec.pages[i];
 			struct buffer_head *bh, *head;
 
 			/*
-			 * If the current offset is not beyond the end of given
-			 * range, it will be a hole.
+			 * If current offset is smaller than the page offset,
+			 * there is a hole at this offset.
 			 */
-			if (lastoff < endoff && whence == SEEK_HOLE &&
-			    page->index > end) {
+			if (whence == SEEK_HOLE && lastoff < endoff &&
+			    lastoff < page_offset(pvec.pages[i])) {
 				found = 1;
 				*offset = lastoff;
 				goto out;
 			}
 
+			if (page->index > end)
+				goto out;
+
 			lock_page(page);
 
 			if (unlikely(page->mapping != inode->i_mapping)) {
@@ -512,20 +492,18 @@
 			unlock_page(page);
 		}
 
-		/*
-		 * The no. of pages is less than our desired, that would be a
-		 * hole in there.
-		 */
-		if (nr_pages < num && whence == SEEK_HOLE) {
-			found = 1;
-			*offset = lastoff;
+		/* The no. of pages is less than our desired, we are done. */
+		if (nr_pages < num)
 			break;
-		}
 
 		index = pvec.pages[i - 1]->index + 1;
 		pagevec_release(&pvec);
 	} while (index <= end);
 
+	if (whence == SEEK_HOLE && lastoff < endoff) {
+		found = 1;
+		*offset = lastoff;
+	}
 out:
 	pagevec_release(&pvec);
 	return found;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 42723b2..de47a29 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2218,7 +2218,7 @@
 {
 	struct inode *inode = mpd->inode;
 	int err;
-	ext4_lblk_t blocks = (i_size_read(inode) + (1 << inode->i_blkbits) - 1)
+	ext4_lblk_t blocks = (i_size_read(inode) + i_blocksize(inode) - 1)
 							>> inode->i_blkbits;
 
 	do {
@@ -3478,14 +3478,14 @@
 		 * writes need zeroing either because they can race with page
 		 * faults or because they use partial blocks.
 		 */
-		if (round_down(offset, 1<<inode->i_blkbits) >= inode->i_size &&
+		if (round_down(offset, i_blocksize(inode)) >= inode->i_size &&
 		    ext4_aligned_io(inode, offset, count))
 			get_block_func = ext4_dio_get_block;
 		else
 			get_block_func = ext4_dax_get_block;
 		dio_flags = DIO_LOCKING;
 	} else if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) ||
-		   round_down(offset, 1 << inode->i_blkbits) >= inode->i_size) {
+		   round_down(offset, i_blocksize(inode)) >= inode->i_size) {
 		get_block_func = ext4_dio_get_block;
 		dio_flags = DIO_LOCKING | DIO_SKIP_HOLES;
 	} else if (is_sync_kiocb(iocb)) {
@@ -3979,6 +3979,7 @@
 
 int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
 {
+#if 0
 	struct super_block *sb = inode->i_sb;
 	ext4_lblk_t first_block, stop_block;
 	struct address_space *mapping = inode->i_mapping;
@@ -4099,6 +4100,8 @@
 
 	inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
 	ext4_mark_inode_dirty(handle, inode);
+	if (ret >= 0)
+		ext4_update_inode_fsync_trans(handle, inode, 1);
 out_stop:
 	ext4_journal_stop(handle);
 out_dio:
@@ -4107,6 +4110,12 @@
 out_mutex:
 	inode_unlock(inode);
 	return ret;
+#else
+	/*
+	 * Disabled as per b/28760453
+	 */
+	return -EOPNOTSUPP;
+#endif
 }
 
 int ext4_inode_attach_jinode(struct inode *inode)
@@ -5101,7 +5110,7 @@
 	 * do. We do the check mainly to optimize the common PAGE_SIZE ==
 	 * blocksize case
 	 */
-	if (offset > PAGE_SIZE - (1 << inode->i_blkbits))
+	if (offset > PAGE_SIZE - i_blocksize(inode))
 		return;
 	while (1) {
 		page = find_lock_page(inode->i_mapping,
@@ -5496,8 +5505,9 @@
 	/* No extended attributes present */
 	if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
 	    header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
-		memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
-			new_extra_isize);
+		memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
+		       EXT4_I(inode)->i_extra_isize, 0,
+		       new_extra_isize - EXT4_I(inode)->i_extra_isize);
 		EXT4_I(inode)->i_extra_isize = new_extra_isize;
 		return 0;
 	}
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index f9eee77..df8168f 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -838,7 +838,7 @@
 	inode = page->mapping->host;
 	sb = inode->i_sb;
 	ngroups = ext4_get_groups_count(sb);
-	blocksize = 1 << inode->i_blkbits;
+	blocksize = i_blocksize(inode);
 	blocks_per_page = PAGE_SIZE / blocksize;
 
 	groups_per_page = blocks_per_page >> 1;
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 6fc14de..578f8c3 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -187,7 +187,7 @@
 	if (PageUptodate(page))
 		return 0;
 
-	blocksize = 1 << inode->i_blkbits;
+	blocksize = i_blocksize(inode);
 	if (!page_has_buffers(page))
 		create_empty_buffers(page, blocksize, 0);
 
diff --git a/fs/iomap.c b/fs/iomap.c
index 814ae8f..798c291 100644
--- a/fs/iomap.c
+++ b/fs/iomap.c
@@ -419,8 +419,8 @@
 iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
 		struct iomap_ops *ops)
 {
-	unsigned blocksize = (1 << inode->i_blkbits);
-	unsigned off = pos & (blocksize - 1);
+	unsigned int blocksize = i_blocksize(inode);
+	unsigned int off = pos & (blocksize - 1);
 
 	/* Block boundary? Nothing to do */
 	if (!off)
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 85671f7..14be95b 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -758,7 +758,7 @@
 				sb->s_blocksize - offset : toread;
 
 		tmp_bh.b_state = 0;
-		tmp_bh.b_size = 1 << inode->i_blkbits;
+		tmp_bh.b_size = i_blocksize(inode);
 		err = jfs_get_block(inode, blk, &tmp_bh, 0);
 		if (err)
 			return err;
@@ -798,7 +798,7 @@
 				sb->s_blocksize - offset : towrite;
 
 		tmp_bh.b_state = 0;
-		tmp_bh.b_size = 1 << inode->i_blkbits;
+		tmp_bh.b_size = i_blocksize(inode);
 		err = jfs_get_block(inode, blk, &tmp_bh, 1);
 		if (err)
 			goto out;
diff --git a/fs/mpage.c b/fs/mpage.c
index 802b481..1193d43 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -151,7 +151,7 @@
 			SetPageUptodate(page);    
 			return;
 		}
-		create_empty_buffers(page, 1 << inode->i_blkbits, 0);
+		create_empty_buffers(page, i_blocksize(inode), 0);
 	}
 	head = page_buffers(page);
 	page_bh = head;
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index 0780ff8..3e396db 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -23,7 +23,7 @@
 {
 	struct nfsd4_layout_seg *seg = &args->lg_seg;
 	struct super_block *sb = inode->i_sb;
-	u32 block_size = (1 << inode->i_blkbits);
+	u32 block_size = i_blocksize(inode);
 	struct pnfs_block_extent *bex;
 	struct iomap iomap;
 	u32 device_generation = 0;
@@ -180,7 +180,7 @@
 	int nr_iomaps;
 
 	nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout,
-			lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits);
+			lcp->lc_up_len, &iomaps, i_blocksize(inode));
 	if (nr_iomaps < 0)
 		return nfserrno(nr_iomaps);
 
@@ -372,7 +372,7 @@
 	int nr_iomaps;
 
 	nr_iomaps = nfsd4_scsi_decode_layoutupdate(lcp->lc_up_layout,
-			lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits);
+			lcp->lc_up_len, &iomaps, i_blocksize(inode));
 	if (nr_iomaps < 0)
 		return nfserrno(nr_iomaps);
 
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 650226f..022d958 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1783,6 +1783,12 @@
 			opdesc->op_get_currentstateid(cstate, &op->u);
 		op->status = opdesc->op_func(rqstp, cstate, &op->u);
 
+		/* Only from SEQUENCE */
+		if (cstate->status == nfserr_replay_cache) {
+			dprintk("%s NFS4.1 replay from cache\n", __func__);
+			status = op->status;
+			goto out;
+		}
 		if (!op->status) {
 			if (opdesc->op_set_currentstateid)
 				opdesc->op_set_currentstateid(cstate, &op->u);
@@ -1793,14 +1799,7 @@
 			if (need_wrongsec_check(rqstp))
 				op->status = check_nfsd_access(current_fh->fh_export, rqstp);
 		}
-
 encode_op:
-		/* Only from SEQUENCE */
-		if (cstate->status == nfserr_replay_cache) {
-			dprintk("%s NFS4.1 replay from cache\n", __func__);
-			status = op->status;
-			goto out;
-		}
 		if (op->status == nfserr_replay_me) {
 			op->replay = &cstate->replay_owner->so_replay;
 			nfsd4_encode_replay(&resp->xdr, op);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 2ee80e1..4e7a56a 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2793,9 +2793,16 @@
 	}
 #endif /* CONFIG_NFSD_PNFS */
 	if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
-		status = nfsd4_encode_bitmap(xdr, NFSD_SUPPATTR_EXCLCREAT_WORD0,
-						  NFSD_SUPPATTR_EXCLCREAT_WORD1,
-						  NFSD_SUPPATTR_EXCLCREAT_WORD2);
+		u32 supp[3];
+
+		supp[0] = nfsd_suppattrs0(minorversion);
+		supp[1] = nfsd_suppattrs1(minorversion);
+		supp[2] = nfsd_suppattrs2(minorversion);
+		supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0;
+		supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1;
+		supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2;
+
+		status = nfsd4_encode_bitmap(xdr, supp[0], supp[1], supp[2]);
 		if (status)
 			goto out;
 	}
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c
index d5c23da..c21e0b4 100644
--- a/fs/nilfs2/btnode.c
+++ b/fs/nilfs2/btnode.c
@@ -50,7 +50,7 @@
 		brelse(bh);
 		BUG();
 	}
-	memset(bh->b_data, 0, 1 << inode->i_blkbits);
+	memset(bh->b_data, 0, i_blocksize(inode));
 	bh->b_bdev = inode->i_sb->s_bdev;
 	bh->b_blocknr = blocknr;
 	set_buffer_mapped(bh);
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index c7f4fef..7ffe71a 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -51,7 +51,7 @@
 {
 	struct nilfs_root *root = NILFS_I(inode)->i_root;
 
-	inode_add_bytes(inode, (1 << inode->i_blkbits) * n);
+	inode_add_bytes(inode, i_blocksize(inode) * n);
 	if (root)
 		atomic64_add(n, &root->blocks_count);
 }
@@ -60,7 +60,7 @@
 {
 	struct nilfs_root *root = NILFS_I(inode)->i_root;
 
-	inode_sub_bytes(inode, (1 << inode->i_blkbits) * n);
+	inode_sub_bytes(inode, i_blocksize(inode) * n);
 	if (root)
 		atomic64_sub(n, &root->blocks_count);
 }
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c
index d56d3a5..98835ed 100644
--- a/fs/nilfs2/mdt.c
+++ b/fs/nilfs2/mdt.c
@@ -57,7 +57,7 @@
 	set_buffer_mapped(bh);
 
 	kaddr = kmap_atomic(bh->b_page);
-	memset(kaddr + bh_offset(bh), 0, 1 << inode->i_blkbits);
+	memset(kaddr + bh_offset(bh), 0, i_blocksize(inode));
 	if (init_block)
 		init_block(inode, bh, kaddr);
 	flush_dcache_page(bh->b_page);
@@ -501,7 +501,7 @@
 	struct nilfs_mdt_info *mi = NILFS_MDT(inode);
 
 	mi->mi_entry_size = entry_size;
-	mi->mi_entries_per_block = (1 << inode->i_blkbits) / entry_size;
+	mi->mi_entries_per_block = i_blocksize(inode) / entry_size;
 	mi->mi_first_entry_offset = DIV_ROUND_UP(header_size, entry_size);
 }
 
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index bedcae2..7d18d62 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -723,7 +723,7 @@
 
 		lock_page(page);
 		if (!page_has_buffers(page))
-			create_empty_buffers(page, 1 << inode->i_blkbits, 0);
+			create_empty_buffers(page, i_blocksize(inode), 0);
 		unlock_page(page);
 
 		bh = head = page_buffers(page);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index c5c5b97..f2961b1 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -599,7 +599,7 @@
 	int ret = 0;
 	struct buffer_head *head, *bh, *wait[2], **wait_bh = wait;
 	unsigned int block_end, block_start;
-	unsigned int bsize = 1 << inode->i_blkbits;
+	unsigned int bsize = i_blocksize(inode);
 
 	if (!page_has_buffers(page))
 		create_empty_buffers(page, bsize, 0);
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 000c234..0db6f83 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -808,7 +808,7 @@
 	/* We know that zero_from is block aligned */
 	for (block_start = zero_from; block_start < zero_to;
 	     block_start = block_end) {
-		block_end = block_start + (1 << inode->i_blkbits);
+		block_end = block_start + i_blocksize(inode);
 
 		/*
 		 * block_start is block-aligned.  Bump it by one to force
diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c
index 06af81f..9b96b99 100644
--- a/fs/orangefs/orangefs-utils.c
+++ b/fs/orangefs/orangefs-utils.c
@@ -306,7 +306,7 @@
 		break;
 	case S_IFDIR:
 		inode->i_size = PAGE_SIZE;
-		orangefs_inode->blksize = (1 << inode->i_blkbits);
+		orangefs_inode->blksize = i_blocksize(inode);
 		spin_lock(&inode->i_lock);
 		inode_set_bytes(inode, inode->i_size);
 		spin_unlock(&inode->i_lock);
@@ -316,7 +316,7 @@
 		if (new) {
 			inode->i_size = (loff_t)strlen(new_op->
 			    downcall.resp.getattr.link_target);
-			orangefs_inode->blksize = (1 << inode->i_blkbits);
+			orangefs_inode->blksize = i_blocksize(inode);
 			ret = strscpy(orangefs_inode->link_target,
 			    new_op->downcall.resp.getattr.link_target,
 			    ORANGEFS_NAME_MAX);
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 2f8c5c9..b396eb0 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -189,7 +189,7 @@
 	int ret = 0;
 
 	th.t_trans_id = 0;
-	blocksize = 1 << inode->i_blkbits;
+	blocksize = i_blocksize(inode);
 
 	if (logit) {
 		reiserfs_write_lock(s);
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 58b2ded..bd4c727 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -524,7 +524,7 @@
 	 * referenced in convert_tail_for_hole() that may be called from
 	 * reiserfs_get_block()
 	 */
-	bh_result->b_size = (1 << inode->i_blkbits);
+	bh_result->b_size = i_blocksize(inode);
 
 	ret = reiserfs_get_block(inode, iblock, bh_result,
 				 create | GET_BLOCK_NO_DANGLE);
diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c
index 17761c5..843fcd2 100644
--- a/fs/sdcardfs/lookup.c
+++ b/fs/sdcardfs/lookup.c
@@ -199,7 +199,8 @@
 
 	ret_dentry = d_splice_alias(inode, dentry);
 	dentry = ret_dentry ?: dentry;
-	update_derived_permission_lock(dentry);
+	if (!IS_ERR(dentry))
+		update_derived_permission_lock(dentry);
 out:
 	return ret_dentry;
 }
diff --git a/fs/stat.c b/fs/stat.c
index bc045c7..068fdbc 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -31,7 +31,7 @@
 	stat->atime = inode->i_atime;
 	stat->mtime = inode->i_mtime;
 	stat->ctime = inode->i_ctime;
-	stat->blksize = (1 << inode->i_blkbits);
+	stat->blksize = i_blocksize(inode);
 	stat->blocks = inode->i_blocks;
 }
 
@@ -454,6 +454,7 @@
 		inode->i_bytes -= 512;
 	}
 }
+EXPORT_SYMBOL(__inode_add_bytes);
 
 void inode_add_bytes(struct inode *inode, loff_t bytes)
 {
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index aad4640..129b18a 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1214,7 +1214,7 @@
 {
 	int err;
 	struct udf_inode_info *iinfo;
-	int bsize = 1 << inode->i_blkbits;
+	int bsize = i_blocksize(inode);
 
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	      S_ISLNK(inode->i_mode)))
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 67e085d..a81b970 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -81,7 +81,8 @@
 			ufs_error (sb, "ufs_free_fragments",
 				   "bit already cleared for fragment %u", i);
 	}
-	
+
+	inode_sub_bytes(inode, count << uspi->s_fshift);
 	fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
 	uspi->cs_total.cs_nffree += count;
 	fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
@@ -183,6 +184,7 @@
 			ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
 		}
 		ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
+		inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
 		if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 			ufs_clusteracct (sb, ucpi, blkno, 1);
 
@@ -494,6 +496,20 @@
 	return 0;
 }		
 
+static bool try_add_frags(struct inode *inode, unsigned frags)
+{
+	unsigned size = frags * i_blocksize(inode);
+	spin_lock(&inode->i_lock);
+	__inode_add_bytes(inode, size);
+	if (unlikely((u32)inode->i_blocks != inode->i_blocks)) {
+		__inode_sub_bytes(inode, size);
+		spin_unlock(&inode->i_lock);
+		return false;
+	}
+	spin_unlock(&inode->i_lock);
+	return true;
+}
+
 static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
 			     unsigned oldcount, unsigned newcount)
 {
@@ -530,6 +546,9 @@
 	for (i = oldcount; i < newcount; i++)
 		if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
 			return 0;
+
+	if (!try_add_frags(inode, count))
+		return 0;
 	/*
 	 * Block can be extended
 	 */
@@ -647,6 +666,7 @@
 			ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
 		i = uspi->s_fpb - count;
 
+		inode_sub_bytes(inode, i << uspi->s_fshift);
 		fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
 		uspi->cs_total.cs_nffree += i;
 		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
@@ -657,6 +677,8 @@
 	result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
 	if (result == INVBLOCK)
 		return 0;
+	if (!try_add_frags(inode, count))
+		return 0;
 	for (i = 0; i < count; i++)
 		ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
 	
@@ -716,6 +738,8 @@
 		return INVBLOCK;
 	ucpi->c_rotor = result;
 gotit:
+	if (!try_add_frags(inode, uspi->s_fpb))
+		return 0;
 	blkno = ufs_fragstoblks(result);
 	ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
 	if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 190d64b..a2760a2 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -235,7 +235,8 @@
 
 	p = ufs_get_direct_data_ptr(uspi, ufsi, block);
 	tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p),
-				new_size, err, locked_page);
+				new_size - (lastfrag & uspi->s_fpbmask), err,
+				locked_page);
 	return tmp != 0;
 }
 
@@ -284,7 +285,7 @@
 			goal += uspi->s_fpb;
 	}
 	tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment),
-				goal, uspi->s_fpb, err, locked_page);
+				goal, nfrags, err, locked_page);
 
 	if (!tmp) {
 		*err = -ENOSPC;
@@ -402,7 +403,9 @@
 
 	if (!create) {
 		phys64 = ufs_frag_map(inode, offsets, depth);
-		goto out;
+		if (phys64)
+			map_bh(bh_result, sb, phys64 + frag);
+		return 0;
 	}
 
         /* This code entered only while writing ....? */
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index f3469ad..351162f 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -746,6 +746,23 @@
 	return;
 }
 
+static u64 ufs_max_bytes(struct super_block *sb)
+{
+	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+	int bits = uspi->s_apbshift;
+	u64 res;
+
+	if (bits > 21)
+		res = ~0ULL;
+	else
+		res = UFS_NDADDR + (1LL << bits) + (1LL << (2*bits)) +
+			(1LL << (3*bits));
+
+	if (res >= (MAX_LFS_FILESIZE >> uspi->s_bshift))
+		return MAX_LFS_FILESIZE;
+	return res << uspi->s_bshift;
+}
+
 static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct ufs_sb_info * sbi;
@@ -1211,6 +1228,7 @@
 			    "fast symlink size (%u)\n", uspi->s_maxsymlinklen);
 		uspi->s_maxsymlinklen = maxsymlen;
 	}
+	sb->s_maxbytes = ufs_max_bytes(sb);
 	sb->s_max_links = UFS_LINK_MAX;
 
 	inode = ufs_iget(sb, UFS_ROOTINO);
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index b7fbf53..398019f 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -473,15 +473,19 @@
 static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi,
 	struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
 {
+	u8 mask;
 	switch (uspi->s_fpb) {
 	case 8:
 	    	return (*ubh_get_addr (ubh, begin + block) == 0xff);
 	case 4:
-		return (*ubh_get_addr (ubh, begin + (block >> 1)) == (0x0f << ((block & 0x01) << 2)));
+		mask = 0x0f << ((block & 0x01) << 2);
+		return (*ubh_get_addr (ubh, begin + (block >> 1)) & mask) == mask;
 	case 2:
-		return (*ubh_get_addr (ubh, begin + (block >> 2)) == (0x03 << ((block & 0x03) << 1)));
+		mask = 0x03 << ((block & 0x03) << 1);
+		return (*ubh_get_addr (ubh, begin + (block >> 2)) & mask) == mask;
 	case 1:
-		return (*ubh_get_addr (ubh, begin + (block >> 3)) == (0x01 << (block & 0x07)));
+		mask = 0x01 << (block & 0x07);
+		return (*ubh_get_addr (ubh, begin + (block >> 3)) & mask) == mask;
 	}
 	return 0;	
 }
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 6df0a7c..5789814 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -108,9 +108,9 @@
 	unsigned int		bsize;
 
 	ASSERT(bvec->bv_offset < PAGE_SIZE);
-	ASSERT((bvec->bv_offset & ((1 << inode->i_blkbits) - 1)) == 0);
+	ASSERT((bvec->bv_offset & (i_blocksize(inode) - 1)) == 0);
 	ASSERT(end < PAGE_SIZE);
-	ASSERT((bvec->bv_len & ((1 << inode->i_blkbits) - 1)) == 0);
+	ASSERT((bvec->bv_len & (i_blocksize(inode) - 1)) == 0);
 
 	bh = head = page_buffers(bvec->bv_page);
 
@@ -349,7 +349,7 @@
 {
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct xfs_mount	*mp = ip->i_mount;
-	ssize_t			count = 1 << inode->i_blkbits;
+	ssize_t			count = i_blocksize(inode);
 	xfs_fileoff_t		offset_fsb, end_fsb;
 	int			error = 0;
 	int			bmapi_flags = XFS_BMAPI_ENTIRE;
@@ -759,7 +759,7 @@
 			break;
 		}
 next_buffer:
-		offset += 1 << inode->i_blkbits;
+		offset += i_blocksize(inode);
 
 	} while ((bh = bh->b_this_page) != head);
 
@@ -847,7 +847,7 @@
 	LIST_HEAD(submit_list);
 	struct xfs_ioend	*ioend, *next;
 	struct buffer_head	*bh, *head;
-	ssize_t			len = 1 << inode->i_blkbits;
+	ssize_t			len = i_blocksize(inode);
 	int			error = 0;
 	int			count = 0;
 	int			uptodate = 1;
@@ -1250,7 +1250,7 @@
 	    offset + mapping_size >= i_size_read(inode)) {
 		/* limit mapping to block that spans EOF */
 		mapping_size = roundup_64(i_size_read(inode) - offset,
-					  1 << inode->i_blkbits);
+					  i_blocksize(inode));
 	}
 	if (mapping_size > LONG_MAX)
 		mapping_size = LONG_MAX;
@@ -1286,7 +1286,7 @@
 		return -EIO;
 
 	offset = (xfs_off_t)iblock << inode->i_blkbits;
-	ASSERT(bh_result->b_size >= (1 << inode->i_blkbits));
+	ASSERT(bh_result->b_size >= i_blocksize(inode));
 	size = bh_result->b_size;
 
 	if (!create && offset >= i_size_read(inode))
@@ -1634,7 +1634,7 @@
 			if (offset < end_offset)
 				set_buffer_dirty(bh);
 			bh = bh->b_this_page;
-			offset += 1 << inode->i_blkbits;
+			offset += i_blocksize(inode);
 		} while (bh != head);
 	}
 	/*
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index a90ec3f..df206cf 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -823,7 +823,7 @@
 		if (error)
 			goto out_unlock;
 	} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
-		unsigned blksize_mask = (1 << inode->i_blkbits) - 1;
+		unsigned int blksize_mask = i_blocksize(inode) - 1;
 
 		if (offset & blksize_mask || len & blksize_mask) {
 			error = -EINVAL;
@@ -845,7 +845,7 @@
 		if (error)
 			goto out_unlock;
 	} else if (mode & FALLOC_FL_INSERT_RANGE) {
-		unsigned blksize_mask = (1 << inode->i_blkbits) - 1;
+		unsigned int blksize_mask = i_blocksize(inode) - 1;
 
 		new_size = i_size_read(inode) + len;
 		if (offset & blksize_mask || len & blksize_mask) {
diff --git a/include/dt-bindings/clock/qcom,camcc-sdm845.h b/include/dt-bindings/clock/qcom,camcc-sdm845.h
index 0d9d9f6..7218261 100644
--- a/include/dt-bindings/clock/qcom,camcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,camcc-sdm845.h
@@ -31,94 +31,86 @@
 #define CAM_CC_CSI1PHYTIMER_CLK_SRC				14
 #define CAM_CC_CSI2PHYTIMER_CLK					15
 #define CAM_CC_CSI2PHYTIMER_CLK_SRC				16
-#define CAM_CC_CSIPHY0_CLK					17
-#define CAM_CC_CSIPHY1_CLK					18
-#define CAM_CC_CSIPHY2_CLK					19
-#define CAM_CC_FAST_AHB_CLK_SRC					20
-#define CAM_CC_FD_CORE_CLK					21
-#define CAM_CC_FD_CORE_CLK_SRC					22
-#define CAM_CC_FD_CORE_UAR_CLK					23
-#define CAM_CC_ICP_APB_CLK					24
-#define CAM_CC_ICP_ATB_CLK					25
-#define CAM_CC_ICP_CLK						26
-#define CAM_CC_ICP_CLK_SRC					27
-#define CAM_CC_ICP_CTI_CLK					28
-#define CAM_CC_ICP_TS_CLK					29
-#define CAM_CC_IFE_0_AXI_CLK					30
-#define CAM_CC_IFE_0_CLK					31
-#define CAM_CC_IFE_0_CLK_SRC					32
-#define CAM_CC_IFE_0_CPHY_RX_CLK				33
-#define CAM_CC_IFE_0_CSID_CLK					34
-#define CAM_CC_IFE_0_CSID_CLK_SRC				35
-#define CAM_CC_IFE_0_DSP_CLK					36
-#define CAM_CC_IFE_1_AXI_CLK					37
-#define CAM_CC_IFE_1_CLK					38
-#define CAM_CC_IFE_1_CLK_SRC					39
-#define CAM_CC_IFE_1_CPHY_RX_CLK				40
-#define CAM_CC_IFE_1_CSID_CLK					41
-#define CAM_CC_IFE_1_CSID_CLK_SRC				42
-#define CAM_CC_IFE_1_DSP_CLK					43
-#define CAM_CC_IFE_LITE_CLK					44
-#define CAM_CC_IFE_LITE_CLK_SRC					45
-#define CAM_CC_IFE_LITE_CPHY_RX_CLK				46
-#define CAM_CC_IFE_LITE_CSID_CLK				47
-#define CAM_CC_IFE_LITE_CSID_CLK_SRC				48
-#define CAM_CC_IPE_0_AHB_CLK					49
-#define CAM_CC_IPE_0_AREG_CLK					50
-#define CAM_CC_IPE_0_AXI_CLK					51
-#define CAM_CC_IPE_0_CLK					52
-#define CAM_CC_IPE_0_CLK_SRC					53
-#define CAM_CC_IPE_1_AHB_CLK					54
-#define CAM_CC_IPE_1_AREG_CLK					55
-#define CAM_CC_IPE_1_AXI_CLK					56
-#define CAM_CC_IPE_1_CLK					57
-#define CAM_CC_IPE_1_CLK_SRC					58
-#define CAM_CC_JPEG_CLK						59
-#define CAM_CC_JPEG_CLK_SRC					60
-#define CAM_CC_LRME_CLK						61
-#define CAM_CC_LRME_CLK_SRC					62
-#define CAM_CC_MCLK0_CLK					63
-#define CAM_CC_MCLK0_CLK_SRC					64
-#define CAM_CC_MCLK1_CLK					65
-#define CAM_CC_MCLK1_CLK_SRC					66
-#define CAM_CC_MCLK2_CLK					67
-#define CAM_CC_MCLK2_CLK_SRC					68
-#define CAM_CC_MCLK3_CLK					69
-#define CAM_CC_MCLK3_CLK_SRC					70
-#define CAM_CC_PLL0						71
-#define CAM_CC_PLL0_OUT_EVEN					72
-#define CAM_CC_PLL1						73
-#define CAM_CC_PLL1_OUT_EVEN					74
-#define CAM_CC_PLL2						75
-#define CAM_CC_PLL2_OUT_EVEN					76
-#define CAM_CC_PLL2_OUT_ODD					77
-#define CAM_CC_PLL3						78
-#define CAM_CC_PLL3_OUT_EVEN					79
-#define CAM_CC_PLL_TEST_CLK					80
-#define CAM_CC_SLOW_AHB_CLK_SRC					81
-#define CAM_CC_SOC_AHB_CLK					82
-#define CAM_CC_SYS_TMR_CLK					83
+#define CAM_CC_CSI3PHYTIMER_CLK					17
+#define CAM_CC_CSI3PHYTIMER_CLK_SRC				18
+#define CAM_CC_CSIPHY0_CLK					19
+#define CAM_CC_CSIPHY1_CLK					20
+#define CAM_CC_CSIPHY2_CLK					21
+#define CAM_CC_CSIPHY3_CLK					22
+#define CAM_CC_FAST_AHB_CLK_SRC					23
+#define CAM_CC_FD_CORE_CLK					24
+#define CAM_CC_FD_CORE_CLK_SRC					25
+#define CAM_CC_FD_CORE_UAR_CLK					26
+#define CAM_CC_ICP_APB_CLK					27
+#define CAM_CC_ICP_ATB_CLK					28
+#define CAM_CC_ICP_CLK						29
+#define CAM_CC_ICP_CLK_SRC					30
+#define CAM_CC_ICP_CTI_CLK					31
+#define CAM_CC_ICP_TS_CLK					32
+#define CAM_CC_IFE_0_AXI_CLK					33
+#define CAM_CC_IFE_0_CLK					34
+#define CAM_CC_IFE_0_CLK_SRC					35
+#define CAM_CC_IFE_0_CPHY_RX_CLK				36
+#define CAM_CC_IFE_0_CSID_CLK					37
+#define CAM_CC_IFE_0_CSID_CLK_SRC				38
+#define CAM_CC_IFE_0_DSP_CLK					39
+#define CAM_CC_IFE_1_AXI_CLK					40
+#define CAM_CC_IFE_1_CLK					41
+#define CAM_CC_IFE_1_CLK_SRC					42
+#define CAM_CC_IFE_1_CPHY_RX_CLK				43
+#define CAM_CC_IFE_1_CSID_CLK					44
+#define CAM_CC_IFE_1_CSID_CLK_SRC				45
+#define CAM_CC_IFE_1_DSP_CLK					46
+#define CAM_CC_IFE_LITE_CLK					47
+#define CAM_CC_IFE_LITE_CLK_SRC					48
+#define CAM_CC_IFE_LITE_CPHY_RX_CLK				49
+#define CAM_CC_IFE_LITE_CSID_CLK				50
+#define CAM_CC_IFE_LITE_CSID_CLK_SRC				51
+#define CAM_CC_IPE_0_AHB_CLK					52
+#define CAM_CC_IPE_0_AREG_CLK					53
+#define CAM_CC_IPE_0_AXI_CLK					54
+#define CAM_CC_IPE_0_CLK					55
+#define CAM_CC_IPE_0_CLK_SRC					56
+#define CAM_CC_IPE_1_AHB_CLK					57
+#define CAM_CC_IPE_1_AREG_CLK					58
+#define CAM_CC_IPE_1_AXI_CLK					59
+#define CAM_CC_IPE_1_CLK					60
+#define CAM_CC_IPE_1_CLK_SRC					61
+#define CAM_CC_JPEG_CLK						62
+#define CAM_CC_JPEG_CLK_SRC					63
+#define CAM_CC_LRME_CLK						64
+#define CAM_CC_LRME_CLK_SRC					65
+#define CAM_CC_MCLK0_CLK					66
+#define CAM_CC_MCLK0_CLK_SRC					67
+#define CAM_CC_MCLK1_CLK					68
+#define CAM_CC_MCLK1_CLK_SRC					69
+#define CAM_CC_MCLK2_CLK					70
+#define CAM_CC_MCLK2_CLK_SRC					71
+#define CAM_CC_MCLK3_CLK					72
+#define CAM_CC_MCLK3_CLK_SRC					73
+#define CAM_CC_PLL0						74
+#define CAM_CC_PLL0_OUT_EVEN					75
+#define CAM_CC_PLL1						76
+#define CAM_CC_PLL1_OUT_EVEN					77
+#define CAM_CC_PLL2						78
+#define CAM_CC_PLL2_OUT_EVEN					79
+#define CAM_CC_PLL2_OUT_ODD					80
+#define CAM_CC_PLL3						81
+#define CAM_CC_PLL3_OUT_EVEN					82
+#define CAM_CC_PLL_TEST_CLK					83
+#define CAM_CC_SLOW_AHB_CLK_SRC					84
+#define CAM_CC_SOC_AHB_CLK					85
+#define CAM_CC_SYS_TMR_CLK					86
 
-#define TITAN_CAM_CC_BPS_BCR					0
-#define TITAN_CAM_CC_CAMNOC_BCR					1
-#define TITAN_CAM_CC_CCI_BCR					2
-#define TITAN_CAM_CC_CPAS_BCR					3
-#define TITAN_CAM_CC_CSI0PHY_BCR				4
-#define TITAN_CAM_CC_CSI1PHY_BCR				5
-#define TITAN_CAM_CC_CSI2PHY_BCR				6
-#define TITAN_CAM_CC_FD_BCR					7
-#define TITAN_CAM_CC_ICP_BCR					8
-#define TITAN_CAM_CC_IFE_0_BCR					9
-#define TITAN_CAM_CC_IFE_1_BCR					10
-#define TITAN_CAM_CC_IFE_LITE_BCR				11
-#define TITAN_CAM_CC_IPE_0_BCR					12
-#define TITAN_CAM_CC_IPE_1_BCR					13
-#define TITAN_CAM_CC_JPEG_BCR					14
-#define TITAN_CAM_CC_LRME_BCR					15
-#define TITAN_CAM_CC_MCLK0_BCR					16
-#define TITAN_CAM_CC_MCLK1_BCR					17
-#define TITAN_CAM_CC_MCLK2_BCR					18
-#define TITAN_CAM_CC_MCLK3_BCR					19
-#define TITAN_CAM_CC_TITAN_TOP_BCR				20
+#define TITAN_CAM_CC_CCI_BCR					0
+#define TITAN_CAM_CC_CPAS_BCR					1
+#define TITAN_CAM_CC_CSI0PHY_BCR				2
+#define TITAN_CAM_CC_CSI1PHY_BCR				3
+#define TITAN_CAM_CC_CSI2PHY_BCR				4
+#define TITAN_CAM_CC_MCLK0_BCR					5
+#define TITAN_CAM_CC_MCLK1_BCR					6
+#define TITAN_CAM_CC_MCLK2_BCR					7
+#define TITAN_CAM_CC_MCLK3_BCR					8
+#define TITAN_CAM_CC_TITAN_TOP_BCR				9
 
 #endif
diff --git a/include/dt-bindings/clock/qcom,dispcc-sdm845.h b/include/dt-bindings/clock/qcom,dispcc-sdm845.h
index 91ea077..42bb59f 100644
--- a/include/dt-bindings/clock/qcom,dispcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,dispcc-sdm845.h
@@ -56,9 +56,6 @@
 #define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC				39
 #define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC				40
 
-#define DISP_CC_MDSS_CORE_BCR					0
-#define DISP_CC_MDSS_GCC_CLOCKS_BCR				1
-#define DISP_CC_MDSS_RSCC_BCR					2
-#define DISP_CC_MDSS_SPDM_BCR					3
+#define DISP_CC_MDSS_RSCC_BCR					0
 
 #endif
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h
index 115b62f..678a885 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h
@@ -196,35 +196,41 @@
 #define GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK				178
 #define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK				179
 #define GCC_GPU_IREF_CLK					180
+#define GCC_SDCC1_AHB_CLK					181
+#define GCC_SDCC1_APPS_CLK					182
+#define GCC_SDCC1_ICE_CORE_CLK					183
+#define GCC_SDCC1_APPS_CLK_SRC					184
+#define GCC_SDCC1_ICE_CORE_CLK_SRC				185
+
 
 /* GCC reset clocks */
-#define GCC_GPU_BCR						0
-#define GCC_MMSS_BCR						1
-#define GCC_PCIE_0_BCR						2
-#define GCC_PCIE_1_BCR						3
-#define GCC_PCIE_PHY_BCR					4
-#define GCC_PDM_BCR						5
-#define GCC_PRNG_BCR						6
-#define GCC_QUPV3_WRAPPER_0_BCR					7
-#define GCC_QUPV3_WRAPPER_1_BCR					8
-#define GCC_QUSB2PHY_PRIM_BCR					9
-#define GCC_QUSB2PHY_SEC_BCR					10
-#define GCC_SDCC2_BCR						11
-#define GCC_SDCC4_BCR						12
-#define GCC_TSIF_BCR						13
-#define GCC_UFS_CARD_BCR					14
-#define GCC_UFS_PHY_BCR						15
-#define GCC_USB30_PRIM_BCR					16
-#define GCC_USB30_SEC_BCR					17
-#define GCC_USB3_PHY_PRIM_BCR					18
-#define GCC_USB3PHY_PHY_PRIM_BCR				19
-#define GCC_USB3_DP_PHY_PRIM_BCR				20
-#define GCC_USB3_PHY_SEC_BCR					21
-#define GCC_USB3PHY_PHY_SEC_BCR					22
-#define GCC_USB3_DP_PHY_SEC_BCR					23
-#define GCC_USB_PHY_CFG_AHB2PHY_BCR				24
-#define GCC_PCIE_0_PHY_BCR					25
-#define GCC_PCIE_1_PHY_BCR					26
+#define GCC_MMSS_BCR						0
+#define GCC_PCIE_0_BCR						1
+#define GCC_PCIE_1_BCR						2
+#define GCC_PCIE_PHY_BCR					3
+#define GCC_PDM_BCR						4
+#define GCC_PRNG_BCR						5
+#define GCC_QUPV3_WRAPPER_0_BCR					6
+#define GCC_QUPV3_WRAPPER_1_BCR					7
+#define GCC_QUSB2PHY_PRIM_BCR					8
+#define GCC_QUSB2PHY_SEC_BCR					9
+#define GCC_SDCC2_BCR						10
+#define GCC_SDCC4_BCR						11
+#define GCC_TSIF_BCR						12
+#define GCC_UFS_CARD_BCR					13
+#define GCC_UFS_PHY_BCR						14
+#define GCC_USB30_PRIM_BCR					15
+#define GCC_USB30_SEC_BCR					16
+#define GCC_USB3_PHY_PRIM_BCR					17
+#define GCC_USB3PHY_PHY_PRIM_BCR				18
+#define GCC_USB3_DP_PHY_PRIM_BCR				19
+#define GCC_USB3_PHY_SEC_BCR					20
+#define GCC_USB3PHY_PHY_SEC_BCR					21
+#define GCC_USB3_DP_PHY_SEC_BCR					22
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR				23
+#define GCC_PCIE_0_PHY_BCR					24
+#define GCC_PCIE_1_PHY_BCR					25
+#define GCC_SDCC1_BCR						26
 
 /* Dummy clocks for rate measurement */
 #define MEASURE_ONLY_SNOC_CLK					0
diff --git a/include/dt-bindings/clock/qcom,videocc-sdm845.h b/include/dt-bindings/clock/qcom,videocc-sdm845.h
index b362852d..21b5092 100644
--- a/include/dt-bindings/clock/qcom,videocc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,videocc-sdm845.h
@@ -28,9 +28,4 @@
 #define VIDEO_CC_VENUS_CTL_CORE_CLK				11
 #define VIDEO_PLL0						12
 
-#define VIDEO_CC_INTERFACE_BCR					0
-#define VIDEO_CC_VCODEC0_BCR					1
-#define VIDEO_CC_VCODEC1_BCR					2
-#define VIDEO_CC_VENUS_BCR					3
-
 #endif
diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h
index 9d52d2e..8bd30d4 100644
--- a/include/dt-bindings/msm/msm-bus-ids.h
+++ b/include/dt-bindings/msm/msm-bus-ids.h
@@ -588,7 +588,7 @@
 #define	MSM_BUS_SLAVE_SNOC_MEM_NOC_GC 774
 #define	MSM_BUS_SLAVE_SNOC_MEM_NOC_SF 775
 #define	MSM_BUS_SLAVE_MEM_NOC_SNOC 776
-#define	MSM_BUS_SLAVE_IPA 777
+#define	MSM_BUS_SLAVE_IPA_CORE 777
 #define	MSM_BUS_SLAVE_CAMNOC_UNCOMP 778
 #define	MSM_BUS_SLAVE_LAST 779
 
diff --git a/include/dt-bindings/thermal/thermal.h b/include/dt-bindings/thermal/thermal.h
index b5e6b00..edd2a15 100644
--- a/include/dt-bindings/thermal/thermal.h
+++ b/include/dt-bindings/thermal/thermal.h
@@ -12,6 +12,7 @@
 
 /* On cooling devices upper and lower limits */
 #define THERMAL_NO_LIMIT		(~0)
+#define THERMAL_MAX_LIMIT		(THERMAL_NO_LIMIT - 1)
 
 #endif
 
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 744ea4f..2b8b6e0 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -125,7 +125,15 @@
  * BVEC_POOL_IDX()
  */
 #define BIO_RESET_BITS	10
-#define BIO_INLINECRYPT 15
+
+
+/*
+ * Added for Req based dm which need to perform post processing. This flag
+ * ensures blk_update_request does not free the bios or request, this is done
+ * at the dm level
+ */
+#define BIO_DONTFREE	10
+#define BIO_INLINECRYPT	11
 
 /*
  * We support 6 different bvec pools, the last one is magic in that it
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index e47a7f7..fb910c6 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -816,6 +816,7 @@
 extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
 			 struct scsi_ioctl_command __user *);
 
+extern void blk_recalc_rq_segments(struct request *rq);
 extern int blk_queue_enter(struct request_queue *q, bool nowait);
 extern void blk_queue_exit(struct request_queue *q);
 extern void blk_start_queue(struct request_queue *q);
@@ -1031,6 +1032,8 @@
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
+extern int blk_rq_map_sg_no_cluster(struct request_queue *q, struct request *rq,
+				struct scatterlist *sglist);
 extern void blk_dump_rq_flags(struct request *, char *);
 extern long nr_blockdev_pages(void);
 
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index b008a33..c5a8afd 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -47,6 +47,7 @@
 	CSS_ONLINE	= (1 << 1), /* between ->css_online() and ->css_offline() */
 	CSS_RELEASED	= (1 << 2), /* refcnt reached zero, released */
 	CSS_VISIBLE	= (1 << 3), /* css is visible to userland */
+	CSS_DYING	= (1 << 4), /* css is dying */
 };
 
 /* bits in struct cgroup flags field */
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 0353461..3b242a3 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -344,6 +344,26 @@
 }
 
 /**
+ * css_is_dying - test whether the specified css is dying
+ * @css: target css
+ *
+ * Test whether @css is in the process of offlining or already offline.  In
+ * most cases, ->css_online() and ->css_offline() callbacks should be
+ * enough; however, the actual offline operations are RCU delayed and this
+ * test returns %true also when @css is scheduled to be offlined.
+ *
+ * This is useful, for example, when the use case requires synchronous
+ * behavior with respect to cgroup removal.  cgroup removal schedules css
+ * offlining but the css can seem alive while the operation is being
+ * delayed.  If the delay affects user visible semantics, this test can be
+ * used to resolve the situation.
+ */
+static inline bool css_is_dying(struct cgroup_subsys_state *css)
+{
+	return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt);
+}
+
+/**
  * css_put - put a css reference
  * @css: target css
  *
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 8ee110a..a52b65a 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -494,6 +494,7 @@
 #define CLK_DIVIDER_ROUND_CLOSEST	BIT(4)
 #define CLK_DIVIDER_READ_ONLY		BIT(5)
 #define CLK_DIVIDER_MAX_AT_ZERO		BIT(6)
+#define CLK_DIVIDER_ROUND_KHZ	BIT(7)
 
 extern const struct clk_ops clk_divider_ops;
 extern const struct clk_ops clk_divider_ro_ops;
diff --git a/include/linux/coresight-stm.h b/include/linux/coresight-stm.h
index 4619158..cd53673 100644
--- a/include/linux/coresight-stm.h
+++ b/include/linux/coresight-stm.h
@@ -70,6 +70,7 @@
  * @stmheer:		settings for register STMHEER.
  * @stmheter:		settings for register STMHETER.
  * @stmhebsr:		settings for register STMHEBSR.
+ * @ch_alloc_fail_count:	Number of ch allocation failures over time.
  */
 struct stm_drvdata {
 	void __iomem		*base;
@@ -90,6 +91,7 @@
 	u32			stmheer;
 	u32			stmheter;
 	u32			stmhebsr;
+	u32			ch_alloc_fail_count;
 };
 
 #ifdef CONFIG_CORESIGHT_STM
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 7f395e3..9f93d18 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -50,6 +50,7 @@
 	CPUHP_ARM_SHMOBILE_SCU_PREPARE,
 	CPUHP_SH_SH3X_PREPARE,
 	CPUHP_BLK_MQ_PREPARE,
+	CPUHP_TOPOLOGY_PREPARE,
 	CPUHP_TIMERS_DEAD,
 	CPUHP_NOTF_ERR_INJ_PREPARE,
 	CPUHP_MIPS_SOC_PREPARE,
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index cf86f52..20e26d9 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -650,4 +650,12 @@
 	return (n << SECTOR_SHIFT);
 }
 
+/*-----------------------------------------------------------------
+ * Helper for block layer and dm core operations
+ *-----------------------------------------------------------------
+ */
+void dm_dispatch_request(struct request *rq);
+void dm_kill_unmapped_request(struct request *rq, int error);
+void dm_end_request(struct request *clone, int error);
+
 #endif	/* _LINUX_DEVICE_MAPPER_H */
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 3b5c7bf..1731c3a 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2017, 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
@@ -144,11 +144,11 @@
 /* This needs to be modified manually now, when we add
  * a new RANGE of SSIDs to the msg_mask_tbl.
  */
-#define MSG_MASK_TBL_CNT		25
-#define APPS_EVENT_LAST_ID		0x0B14
+#define MSG_MASK_TBL_CNT		26
+#define APPS_EVENT_LAST_ID		0x0B3F
 
 #define MSG_SSID_0			0
-#define MSG_SSID_0_LAST			118
+#define MSG_SSID_0_LAST			121
 #define MSG_SSID_1			500
 #define MSG_SSID_1_LAST			506
 #define MSG_SSID_2			1000
@@ -160,11 +160,11 @@
 #define MSG_SSID_5			4000
 #define MSG_SSID_5_LAST			4010
 #define MSG_SSID_6			4500
-#define MSG_SSID_6_LAST			4573
+#define MSG_SSID_6_LAST			4583
 #define MSG_SSID_7			4600
 #define MSG_SSID_7_LAST			4615
 #define MSG_SSID_8			5000
-#define MSG_SSID_8_LAST			5032
+#define MSG_SSID_8_LAST			5033
 #define MSG_SSID_9			5500
 #define MSG_SSID_9_LAST			5516
 #define MSG_SSID_10			6000
@@ -184,7 +184,7 @@
 #define MSG_SSID_17			9000
 #define MSG_SSID_17_LAST		9008
 #define MSG_SSID_18			9500
-#define MSG_SSID_18_LAST		9510
+#define MSG_SSID_18_LAST		9521
 #define MSG_SSID_19			10200
 #define MSG_SSID_19_LAST		10210
 #define MSG_SSID_20			10251
@@ -194,9 +194,11 @@
 #define MSG_SSID_22			10350
 #define MSG_SSID_22_LAST		10377
 #define MSG_SSID_23			10400
-#define MSG_SSID_23_LAST		10415
-#define MSG_SSID_24			0xC000
-#define MSG_SSID_24_LAST		0xC063
+#define MSG_SSID_23_LAST		10416
+#define MSG_SSID_24			10500
+#define MSG_SSID_24_LAST		10505
+#define MSG_SSID_25			0xC000
+#define MSG_SSID_25_LAST		0xC063
 
 static const uint32_t msg_bld_masks_0[] = {
 	MSG_LVL_LOW,
@@ -347,6 +349,9 @@
 		MSG_LVL_FATAL,
 	MSG_LVL_MED,
 	MSG_LVL_MED,
+	MSG_LVL_HIGH,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
 	MSG_LVL_HIGH
 };
 
@@ -546,7 +551,8 @@
 	MSG_LVL_MED,
 	MSG_LVL_MED,
 	MSG_LVL_MED,
-	MSG_LVL_MED
+	MSG_LVL_MED,
+	MSG_LVL_HIGH
 };
 
 static const uint32_t msg_bld_masks_9[] = {
@@ -863,13 +869,27 @@
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW
+};
+
+static const uint32_t msg_bld_masks_24[] = {
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH
+};
+
+static const uint32_t msg_bld_masks_25[] = {
 	MSG_LVL_LOW
 };
 
 /* LOG CODES */
 static const uint32_t log_code_last_tbl[] = {
 	0x0,	/* EQUIP ID 0 */
-	0x1966,	/* EQUIP ID 1 */
+	0x1A11,	/* EQUIP ID 1 */
 	0x0,	/* EQUIP ID 2 */
 	0x0,	/* EQUIP ID 3 */
 	0x4910,	/* EQUIP ID 4 */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index bed7a84..026aa0a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -705,6 +705,11 @@
 	void			*i_private; /* fs or device private pointer */
 };
 
+static inline unsigned int i_blocksize(const struct inode *node)
+{
+	return (1 << node->i_blkbits);
+}
+
 static inline int inode_unhashed(struct inode *inode)
 {
 	return hlist_unhashed(&inode->i_hash);
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 72f0721..bbc65ef 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -450,6 +450,12 @@
 };
 
 #define SOFTIRQ_STOP_IDLE_MASK (~(1 << RCU_SOFTIRQ))
+/* Softirq's where the handling might be long: */
+#define LONG_SOFTIRQ_MASK ((1 << NET_TX_SOFTIRQ)       | \
+			   (1 << NET_RX_SOFTIRQ)       | \
+			   (1 << BLOCK_SOFTIRQ)        | \
+			   (1 << IRQ_POLL_SOFTIRQ)     | \
+			   (1 << TASKLET_SOFTIRQ))
 
 /* map softirq index to softirq name. update 'softirq_to_name' in
  * kernel/softirq.c when adding a new softirq.
@@ -485,6 +491,7 @@
 extern void raise_softirq(unsigned int nr);
 
 DECLARE_PER_CPU(struct task_struct *, ksoftirqd);
+DECLARE_PER_CPU(__u32, active_softirqs);
 
 static inline struct task_struct *this_cpu_ksoftirqd(void)
 {
diff --git a/include/linux/mfd/msm-cdc-pinctrl.h b/include/linux/mfd/msm-cdc-pinctrl.h
index 14b18fe..7eabefb 100644
--- a/include/linux/mfd/msm-cdc-pinctrl.h
+++ b/include/linux/mfd/msm-cdc-pinctrl.h
@@ -16,11 +16,13 @@
 #include <linux/types.h>
 #include <linux/of.h>
 
-#ifdef CONFIG_MSM_CDC_PINCTRL
+#if IS_ENABLED(CONFIG_MSM_CDC_PINCTRL)
 extern int msm_cdc_pinctrl_select_sleep_state(struct device_node *np);
 extern int msm_cdc_pinctrl_select_active_state(struct device_node *np);
 extern bool msm_cdc_pinctrl_get_state(struct device_node *np);
 extern int msm_cdc_get_gpio_state(struct device_node *np);
+int msm_cdc_pinctrl_drv_init(void);
+void msm_cdc_pinctrl_drv_exit(void);
 
 #else
 int msm_cdc_pinctrl_select_sleep_state(struct device_node *np)
@@ -35,7 +37,13 @@
 {
 	return 0;
 }
-#
+int msm_cdc_pinctrl_drv_init(void)
+{
+	return 0;
+}
+void msm_cdc_pinctrl_drv_exit(void)
+{
+}
 #endif
 
 #endif
diff --git a/include/linux/mfd/wcd9335/irq.h b/include/linux/mfd/wcd9335/irq.h
new file mode 100644
index 0000000..c666d31
--- /dev/null
+++ b/include/linux/mfd/wcd9335/irq.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD9335_IRQ_H_
+#define __WCD9335_IRQ_H_
+
+enum {
+	/* INTR_REG 0 */
+	WCD9335_IRQ_FLL_LOCK_LOSS = 1,
+	WCD9335_IRQ_HPH_PA_OCPL_FAULT,
+	WCD9335_IRQ_HPH_PA_OCPR_FAULT,
+	WCD9335_IRQ_EAR_PA_OCP_FAULT,
+	WCD9335_IRQ_HPH_PA_CNPL_COMPLETE,
+	WCD9335_IRQ_HPH_PA_CNPR_COMPLETE,
+	WCD9335_IRQ_EAR_PA_CNP_COMPLETE,
+	/* INTR_REG 1 */
+	WCD9335_IRQ_MBHC_SW_DET,
+	WCD9335_IRQ_MBHC_ELECT_INS_REM_DET,
+	WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
+	WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
+	WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+	WCD9335_IRQ_RESERVED_0,
+	WCD9335_IRQ_RESERVED_1,
+	WCD9335_IRQ_RESERVED_2,
+	/* INTR_REG 2 */
+	WCD9335_IRQ_LINE_PA1_CNP_COMPLETE,
+	WCD9335_IRQ_LINE_PA2_CNP_COMPLETE,
+	WCD9335_IRQ_LINE_PA3_CNP_COMPLETE,
+	WCD9335_IRQ_LINE_PA4_CNP_COMPLETE,
+	WCD9335_IRQ_SOUNDWIRE,
+	WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE,
+	WCD9335_IRQ_RCO_ERROR,
+	WCD9335_IRQ_SVA_ERROR,
+	/* INTR_REG 3 */
+	WCD9335_IRQ_MAD_AUDIO,
+	WCD9335_IRQ_MAD_BEACON,
+	WCD9335_IRQ_MAD_ULTRASOUND,
+	WCD9335_IRQ_VBAT_ATTACK,
+	WCD9335_IRQ_VBAT_RESTORE,
+	WCD9335_IRQ_SVA_OUTBOX1,
+	WCD9335_IRQ_SVA_OUTBOX2,
+	WCD9335_NUM_IRQS,
+};
+
+#endif
diff --git a/include/linux/mfd/wcd934x/irq.h b/include/linux/mfd/wcd934x/irq.h
new file mode 100644
index 0000000..1a18be3
--- /dev/null
+++ b/include/linux/mfd/wcd934x/irq.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD934X_IRQ_H_
+#define __WCD934X_IRQ_H_
+
+enum {
+	/* INTR_REG 0 */
+	WCD934X_IRQ_MISC = 1,
+	WCD934X_IRQ_HPH_PA_OCPL_FAULT,
+	WCD934X_IRQ_HPH_PA_OCPR_FAULT,
+	WCD934X_IRQ_EAR_PA_OCP_FAULT,
+	WCD934X_IRQ_HPH_PA_CNPL_COMPLETE,
+	WCD934X_IRQ_HPH_PA_CNPR_COMPLETE,
+	WCD934X_IRQ_EAR_PA_CNP_COMPLETE,
+	/* INTR_REG 1 */
+	WCD934X_IRQ_MBHC_SW_DET,
+	WCD934X_IRQ_MBHC_ELECT_INS_REM_DET,
+	WCD934X_IRQ_MBHC_BUTTON_PRESS_DET,
+	WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET,
+	WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+	WCD934X_IRQ_RESERVED_0,
+	WCD934X_IRQ_RESERVED_1,
+	WCD934X_IRQ_RESERVED_2,
+	/* INTR_REG 2 */
+	WCD934X_IRQ_LINE_PA1_CNP_COMPLETE,
+	WCD934X_IRQ_LINE_PA2_CNP_COMPLETE,
+	WCD934X_IRQ_SLNQ_ANALOG_ERROR,
+	WCD934X_IRQ_RESERVED_3,
+	WCD934X_IRQ_SOUNDWIRE,
+	WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE,
+	WCD934X_IRQ_RCO_ERROR,
+	WCD934X_IRQ_CPE_ERROR,
+	/* INTR_REG 3 */
+	WCD934X_IRQ_MAD_AUDIO,
+	WCD934X_IRQ_MAD_BEACON,
+	WCD934X_IRQ_MAD_ULTRASOUND,
+	WCD934X_IRQ_VBAT_ATTACK,
+	WCD934X_IRQ_VBAT_RESTORE,
+	WCD934X_IRQ_CPE1_INTR,
+	WCD934X_IRQ_RESERVED_4,
+	WCD934X_IRQ_SLNQ_DIGITAL,
+	WCD934X_NUM_IRQS,
+};
+
+#endif
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index c6c8d24..b4c1be4 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -434,4 +434,7 @@
 {
 	return 0;
 }
+
+int wcd9xxx_init(void);
+void wcd9xxx_exit(void);
 #endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9330_registers.h b/include/linux/mfd/wcd9xxx/wcd9330_registers.h
deleted file mode 100644
index c37d25f..0000000
--- a/include/linux/mfd/wcd9xxx/wcd9330_registers.h
+++ /dev/null
@@ -1,1626 +0,0 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef WCD9330_REGISTERS_H
-#define WCD9330_REGISTERS_H
-
-#include <linux/types.h>
-
-#define TOMTOM_A_CHIP_CTL			(0x000)
-#define TOMTOM_A_CHIP_CTL__POR				(0x38)
-#define TOMTOM_A_CHIP_STATUS			(0x001)
-#define TOMTOM_A_CHIP_STATUS__POR				(0x00)
-#define TOMTOM_A_CHIP_ID_BYTE_0			(0x004)
-#define TOMTOM_A_CHIP_ID_BYTE_0__POR				(0x00)
-#define TOMTOM_A_CHIP_ID_BYTE_1			(0x005)
-#define TOMTOM_A_CHIP_ID_BYTE_1__POR				(0x00)
-#define TOMTOM_A_CHIP_ID_BYTE_2			(0x006)
-#define TOMTOM_A_CHIP_ID_BYTE_2__POR				(0x05)
-#define TOMTOM_A_CHIP_ID_BYTE_3			(0x007)
-#define TOMTOM_A_CHIP_ID_BYTE_3__POR				(0x01)
-#define TOMTOM_A_CHIP_I2C_SLAVE_ID			(0x008)
-#define TOMTOM_A_CHIP_I2C_SLAVE_ID__POR				(0x01)
-#define TOMTOM_A_SLAVE_ID_1			(0x00C)
-#define TOMTOM_A_SLAVE_ID_1__POR				(0x77)
-#define TOMTOM_A_SLAVE_ID_2			(0x00D)
-#define TOMTOM_A_SLAVE_ID_2__POR				(0x66)
-#define TOMTOM_A_SLAVE_ID_3			(0x00E)
-#define TOMTOM_A_SLAVE_ID_3__POR				(0x55)
-#define TOMTOM_A_PIN_CTL_OE0			(0x010)
-#define TOMTOM_A_PIN_CTL_OE0__POR				(0x00)
-#define TOMTOM_A_PIN_CTL_OE1			(0x011)
-#define TOMTOM_A_PIN_CTL_OE1__POR				(0x00)
-#define TOMTOM_A_PIN_CTL_OE2			(0x012)
-#define TOMTOM_A_PIN_CTL_OE2__POR				(0x00)
-#define TOMTOM_A_PIN_CTL_DATA0			(0x013)
-#define TOMTOM_A_PIN_CTL_DATA0__POR				(0x00)
-#define TOMTOM_A_PIN_CTL_DATA1			(0x014)
-#define TOMTOM_A_PIN_CTL_DATA1__POR				(0x00)
-#define TOMTOM_A_PIN_CTL_DATA2			(0x015)
-#define TOMTOM_A_PIN_CTL_DATA2__POR				(0x00)
-#define TOMTOM_A_HDRIVE_GENERIC			(0x018)
-#define TOMTOM_A_HDRIVE_GENERIC__POR				(0x00)
-#define TOMTOM_A_HDRIVE_OVERRIDE			(0x019)
-#define TOMTOM_A_HDRIVE_OVERRIDE__POR				(0x08)
-#define TOMTOM_A_ANA_CSR_WAIT_STATE			(0x01C)
-#define TOMTOM_A_ANA_CSR_WAIT_STATE__POR				(0x44)
-#define TOMTOM_A_PROCESS_MONITOR_CTL0			(0x020)
-#define TOMTOM_A_PROCESS_MONITOR_CTL0__POR				(0x80)
-#define TOMTOM_A_PROCESS_MONITOR_CTL1			(0x021)
-#define TOMTOM_A_PROCESS_MONITOR_CTL1__POR				(0x00)
-#define TOMTOM_A_PROCESS_MONITOR_CTL2			(0x022)
-#define TOMTOM_A_PROCESS_MONITOR_CTL2__POR				(0x00)
-#define TOMTOM_A_PROCESS_MONITOR_CTL3			(0x023)
-#define TOMTOM_A_PROCESS_MONITOR_CTL3__POR				(0x01)
-#define TOMTOM_A_QFUSE_CTL			(0x028)
-#define TOMTOM_A_QFUSE_CTL__POR				(0x00)
-#define TOMTOM_A_QFUSE_STATUS			(0x029)
-#define TOMTOM_A_QFUSE_STATUS__POR				(0x00)
-#define TOMTOM_A_QFUSE_DATA_OUT0			(0x02A)
-#define TOMTOM_A_QFUSE_DATA_OUT0__POR				(0x00)
-#define TOMTOM_A_QFUSE_DATA_OUT1			(0x02B)
-#define TOMTOM_A_QFUSE_DATA_OUT1__POR				(0x00)
-#define TOMTOM_A_QFUSE_DATA_OUT2			(0x02C)
-#define TOMTOM_A_QFUSE_DATA_OUT2__POR				(0x00)
-#define TOMTOM_A_QFUSE_DATA_OUT3			(0x02D)
-#define TOMTOM_A_QFUSE_DATA_OUT3__POR				(0x00)
-#define TOMTOM_A_QFUSE_DATA_OUT4			(0x02E)
-#define TOMTOM_A_QFUSE_DATA_OUT4__POR				(0x00)
-#define TOMTOM_A_QFUSE_DATA_OUT5			(0x02F)
-#define TOMTOM_A_QFUSE_DATA_OUT5__POR				(0x00)
-#define TOMTOM_A_QFUSE_DATA_OUT6			(0x030)
-#define TOMTOM_A_QFUSE_DATA_OUT6__POR				(0x00)
-#define TOMTOM_A_QFUSE_DATA_OUT7			(0x031)
-#define TOMTOM_A_QFUSE_DATA_OUT7__POR				(0x00)
-#define TOMTOM_A_CDC_CTL			(0x034)
-#define TOMTOM_A_CDC_CTL__POR				(0x00)
-#define TOMTOM_A_LEAKAGE_CTL			(0x03C)
-#define TOMTOM_A_LEAKAGE_CTL__POR				(0x04)
-#define TOMTOM_A_SVASS_MEM_PTR0			(0x044)
-#define TOMTOM_A_SVASS_MEM_PTR0__POR				(0x00)
-#define TOMTOM_A_SVASS_MEM_PTR1			(0x045)
-#define TOMTOM_A_SVASS_MEM_PTR1__POR				(0x00)
-#define TOMTOM_A_SVASS_MEM_PTR2			(0x046)
-#define TOMTOM_A_SVASS_MEM_PTR2__POR				(0x00)
-#define TOMTOM_A_SVASS_MEM_CTL			(0x048)
-#define TOMTOM_A_SVASS_MEM_CTL__POR				(0x04)
-#define TOMTOM_A_SVASS_MEM_BANK			(0x049)
-#define TOMTOM_A_SVASS_MEM_BANK__POR				(0x00)
-#define TOMTOM_A_DMIC_B1_CTL			(0x04A)
-#define TOMTOM_A_DMIC_B1_CTL__POR				(0x00)
-#define TOMTOM_A_DMIC_B2_CTL			(0x04B)
-#define TOMTOM_A_DMIC_B2_CTL__POR				(0x00)
-#define TOMTOM_A_SVASS_CLKRST_CTL			(0x04C)
-#define TOMTOM_A_SVASS_CLKRST_CTL__POR				(0x00)
-#define TOMTOM_A_SVASS_CPAR_CFG			(0x04D)
-#define TOMTOM_A_SVASS_CPAR_CFG__POR				(0x00)
-#define TOMTOM_A_SVASS_BUF_RDY_INT_PERIOD			(0x04E)
-#define TOMTOM_A_SVASS_BUF_RDY_INT_PERIOD__POR				(0x14)
-#define TOMTOM_A_SVASS_CPAR_WDOG_CFG			(0x04F)
-#define TOMTOM_A_SVASS_CPAR_WDOG_CFG__POR				(0x00)
-#define TOMTOM_A_SVASS_CFG			(0x050)
-#define TOMTOM_A_SVASS_CFG__POR				(0x01)
-#define TOMTOM_A_SVASS_SPE_CFG			(0x051)
-#define TOMTOM_A_SVASS_SPE_CFG__POR				(0x04)
-#define TOMTOM_A_SVASS_STATUS			(0x052)
-#define TOMTOM_A_SVASS_STATUS__POR				(0x00)
-#define TOMTOM_A_SVASS_INT_MASK			(0x053)
-#define TOMTOM_A_SVASS_INT_MASK__POR				(0x3F)
-#define TOMTOM_A_SVASS_INT_STATUS			(0x054)
-#define TOMTOM_A_SVASS_INT_STATUS__POR				(0x00)
-#define TOMTOM_A_SVASS_INT_CLR			(0x055)
-#define TOMTOM_A_SVASS_INT_CLR__POR				(0x00)
-#define TOMTOM_A_SVASS_DEBUG			(0x056)
-#define TOMTOM_A_SVASS_DEBUG__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_BKUP_INT			(0x057)
-#define TOMTOM_A_SVASS_SPE_BKUP_INT__POR				(0x00)
-#define TOMTOM_A_SVASS_MEM_ACC			(0x058)
-#define TOMTOM_A_SVASS_MEM_ACC__POR				(0x00)
-#define TOMTOM_A_MEM_LEAKAGE_CTL			(0x059)
-#define TOMTOM_A_MEM_LEAKAGE_CTL__POR				(0x04)
-#define TOMTOM_A_SVASS_SPE_INBOX_TRG			(0x05A)
-#define TOMTOM_A_SVASS_SPE_INBOX_TRG__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_0			(0x060)
-#define TOMTOM_A_SVASS_SPE_INBOX_0__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_1			(0x061)
-#define TOMTOM_A_SVASS_SPE_INBOX_1__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_2			(0x062)
-#define TOMTOM_A_SVASS_SPE_INBOX_2__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_3			(0x063)
-#define TOMTOM_A_SVASS_SPE_INBOX_3__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_4			(0x064)
-#define TOMTOM_A_SVASS_SPE_INBOX_4__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_5			(0x065)
-#define TOMTOM_A_SVASS_SPE_INBOX_5__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_6			(0x066)
-#define TOMTOM_A_SVASS_SPE_INBOX_6__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_7			(0x067)
-#define TOMTOM_A_SVASS_SPE_INBOX_7__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_8			(0x068)
-#define TOMTOM_A_SVASS_SPE_INBOX_8__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_9			(0x069)
-#define TOMTOM_A_SVASS_SPE_INBOX_9__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_10			(0x06A)
-#define TOMTOM_A_SVASS_SPE_INBOX_10__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_INBOX_11			(0x06B)
-#define TOMTOM_A_SVASS_SPE_INBOX_11__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_0			(0x070)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_0__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_1			(0x071)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_1__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_2			(0x072)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_2__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_3			(0x073)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_3__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_4			(0x074)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_4__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_5			(0x075)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_5__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_6			(0x076)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_6__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_7			(0x077)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_7__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_8			(0x078)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_8__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_9			(0x079)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_9__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_10			(0x07A)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_10__POR				(0x00)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_11			(0x07B)
-#define TOMTOM_A_SVASS_SPE_OUTBOX_11__POR				(0x00)
-#define TOMTOM_A_INTR_MODE			(0x090)
-#define TOMTOM_A_INTR_MODE__POR				(0x00)
-#define TOMTOM_A_INTR1_MASK0			(0x094)
-#define TOMTOM_A_INTR1_MASK0__POR				(0xFF)
-#define TOMTOM_A_INTR1_MASK1			(0x095)
-#define TOMTOM_A_INTR1_MASK1__POR				(0xFF)
-#define TOMTOM_A_INTR1_MASK2			(0x096)
-#define TOMTOM_A_INTR1_MASK2__POR				(0xFF)
-#define TOMTOM_A_INTR1_MASK3			(0x097)
-#define TOMTOM_A_INTR1_MASK3__POR				(0xFF)
-#define TOMTOM_A_INTR1_STATUS0			(0x098)
-#define TOMTOM_A_INTR1_STATUS0__POR				(0x00)
-#define TOMTOM_A_INTR1_STATUS1			(0x099)
-#define TOMTOM_A_INTR1_STATUS1__POR				(0x00)
-#define TOMTOM_A_INTR1_STATUS2			(0x09A)
-#define TOMTOM_A_INTR1_STATUS2__POR				(0x00)
-#define TOMTOM_A_INTR1_STATUS3			(0x09B)
-#define TOMTOM_A_INTR1_STATUS3__POR				(0x00)
-#define TOMTOM_A_INTR1_CLEAR0			(0x09C)
-#define TOMTOM_A_INTR1_CLEAR0__POR				(0x00)
-#define TOMTOM_A_INTR1_CLEAR1			(0x09D)
-#define TOMTOM_A_INTR1_CLEAR1__POR				(0x00)
-#define TOMTOM_A_INTR1_CLEAR2			(0x09E)
-#define TOMTOM_A_INTR1_CLEAR2__POR				(0x00)
-#define TOMTOM_A_INTR1_CLEAR3			(0x09F)
-#define TOMTOM_A_INTR1_CLEAR3__POR				(0x00)
-#define TOMTOM_A_INTR1_LEVEL0			(0x0A0)
-#define TOMTOM_A_INTR1_LEVEL0__POR				(0x01)
-#define TOMTOM_A_INTR1_LEVEL1			(0x0A1)
-#define TOMTOM_A_INTR1_LEVEL1__POR				(0x00)
-#define TOMTOM_A_INTR1_LEVEL2			(0x0A2)
-#define TOMTOM_A_INTR1_LEVEL2__POR				(0x40)
-#define TOMTOM_A_INTR1_LEVEL3			(0x0A3)
-#define TOMTOM_A_INTR1_LEVEL3__POR				(0x00)
-#define TOMTOM_A_INTR1_TEST0			(0x0A4)
-#define TOMTOM_A_INTR1_TEST0__POR				(0x00)
-#define TOMTOM_A_INTR1_TEST1			(0x0A5)
-#define TOMTOM_A_INTR1_TEST1__POR				(0x00)
-#define TOMTOM_A_INTR1_TEST2			(0x0A6)
-#define TOMTOM_A_INTR1_TEST2__POR				(0x00)
-#define TOMTOM_A_INTR1_TEST3			(0x0A7)
-#define TOMTOM_A_INTR1_TEST3__POR				(0x00)
-#define TOMTOM_A_INTR1_SET0			(0x0A8)
-#define TOMTOM_A_INTR1_SET0__POR				(0x00)
-#define TOMTOM_A_INTR1_SET1			(0x0A9)
-#define TOMTOM_A_INTR1_SET1__POR				(0x00)
-#define TOMTOM_A_INTR1_SET2			(0x0AA)
-#define TOMTOM_A_INTR1_SET2__POR				(0x00)
-#define TOMTOM_A_INTR1_SET3			(0x0AB)
-#define TOMTOM_A_INTR1_SET3__POR				(0x00)
-#define TOMTOM_A_INTR2_MASK0			(0x0B0)
-#define TOMTOM_A_INTR2_MASK0__POR				(0xFF)
-#define TOMTOM_A_INTR2_STATUS0			(0x0B2)
-#define TOMTOM_A_INTR2_STATUS0__POR				(0x00)
-#define TOMTOM_A_INTR2_CLEAR0			(0x0B4)
-#define TOMTOM_A_INTR2_CLEAR0__POR				(0x00)
-#define TOMTOM_A_INTR2_LEVEL0			(0x0B6)
-#define TOMTOM_A_INTR2_LEVEL0__POR				(0x00)
-#define TOMTOM_A_INTR2_TEST0			(0x0B8)
-#define TOMTOM_A_INTR2_TEST0__POR				(0x00)
-#define TOMTOM_A_INTR2_SET0			(0x0BA)
-#define TOMTOM_A_INTR2_SET0__POR				(0x00)
-#define TOMTOM_A_CDC_TX_I2S_SCK_MODE			(0x0C0)
-#define TOMTOM_A_CDC_TX_I2S_SCK_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_TX_I2S_WS_MODE			(0x0C1)
-#define TOMTOM_A_CDC_TX_I2S_WS_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_DMIC_DATA0_MODE			(0x0C4)
-#define TOMTOM_A_CDC_DMIC_DATA0_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_DMIC_CLK0_MODE			(0x0C5)
-#define TOMTOM_A_CDC_DMIC_CLK0_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_DMIC_DATA1_MODE			(0x0C6)
-#define TOMTOM_A_CDC_DMIC_DATA1_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_DMIC_CLK1_MODE			(0x0C7)
-#define TOMTOM_A_CDC_DMIC_CLK1_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_RX_I2S_SCK_MODE			(0x0C8)
-#define TOMTOM_A_CDC_RX_I2S_SCK_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_RX_I2S_WS_MODE			(0x0C9)
-#define TOMTOM_A_CDC_RX_I2S_WS_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_DMIC_DATA2_MODE			(0x0CA)
-#define TOMTOM_A_CDC_DMIC_DATA2_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_DMIC_CLK2_MODE			(0x0CB)
-#define TOMTOM_A_CDC_DMIC_CLK2_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_INTR1_MODE			(0x0CC)
-#define TOMTOM_A_CDC_INTR1_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_SB_NRZ_SEL_MODE			(0x0CD)
-#define TOMTOM_A_CDC_SB_NRZ_SEL_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_INTR2_MODE			(0x0CE)
-#define TOMTOM_A_CDC_INTR2_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_RF_PA_ON_MODE			(0x0CF)
-#define TOMTOM_A_CDC_RF_PA_ON_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_BOOST_MODE			(0x0D0)
-#define TOMTOM_A_CDC_BOOST_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_JTCK_MODE			(0x0D1)
-#define TOMTOM_A_CDC_JTCK_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_JTDI_MODE			(0x0D2)
-#define TOMTOM_A_CDC_JTDI_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_JTMS_MODE			(0x0D3)
-#define TOMTOM_A_CDC_JTMS_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_JTDO_MODE			(0x0D4)
-#define TOMTOM_A_CDC_JTDO_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_JTRST_MODE			(0x0D5)
-#define TOMTOM_A_CDC_JTRST_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_BIST_MODE_MODE			(0x0D6)
-#define TOMTOM_A_CDC_BIST_MODE_MODE__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_MAIN_CTL_1			(0x0E0)
-#define TOMTOM_A_CDC_MAD_MAIN_CTL_1__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_MAIN_CTL_2			(0x0E1)
-#define TOMTOM_A_CDC_MAD_MAIN_CTL_2__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_1			(0x0E2)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_1__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_2			(0x0E3)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_2__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_3			(0x0E4)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_3__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_4			(0x0E5)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_4__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_5			(0x0E6)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_5__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_6			(0x0E7)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_6__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_7			(0x0E8)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_7__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_8			(0x0E9)
-#define TOMTOM_A_CDC_MAD_AUDIO_CTL_8__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_PTR			(0x0EA)
-#define TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_PTR__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_VAL			(0x0EB)
-#define TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_VAL__POR				(0x40)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_1			(0x0EC)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_1__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_2			(0x0ED)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_2__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_3			(0x0EE)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_3__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_4			(0x0EF)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_4__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_5			(0x0F0)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_5__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_6			(0x0F1)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_6__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_7			(0x0F2)
-#define TOMTOM_A_CDC_MAD_ULTR_CTL_7__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_1			(0x0F3)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_1__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_2			(0x0F4)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_2__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_3			(0x0F5)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_3__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_4			(0x0F6)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_4__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_5			(0x0F7)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_5__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_6			(0x0F8)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_6__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_7			(0x0F9)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_7__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_8			(0x0FA)
-#define TOMTOM_A_CDC_MAD_BEACON_CTL_8__POR				(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_PTR			(0x0FB)
-#define TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_PTR__POR			(0x00)
-#define TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_VAL			(0x0FC)
-#define TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_VAL__POR			(0x00)
-#define TOMTOM_A_CDC_MAD_INP_SEL			(0x0FD)
-#define TOMTOM_A_CDC_MAD_INP_SEL__POR				(0x00)
-#define TOMTOM_A_BIAS_REF_CTL			(0x100)
-#define TOMTOM_A_BIAS_REF_CTL__POR				(0x1C)
-#define TOMTOM_A_BIAS_CENTRAL_BG_CTL			(0x101)
-#define TOMTOM_A_BIAS_CENTRAL_BG_CTL__POR				(0x50)
-#define TOMTOM_A_BIAS_PRECHRG_CTL			(0x102)
-#define TOMTOM_A_BIAS_PRECHRG_CTL__POR				(0x07)
-#define TOMTOM_A_BIAS_CURR_CTL_1			(0x103)
-#define TOMTOM_A_BIAS_CURR_CTL_1__POR				(0x52)
-#define TOMTOM_A_BIAS_CURR_CTL_2			(0x104)
-#define TOMTOM_A_BIAS_CURR_CTL_2__POR				(0x00)
-#define TOMTOM_A_BIAS_OSC_BG_CTL			(0x105)
-#define TOMTOM_A_BIAS_OSC_BG_CTL__POR				(0x36)
-#define TOMTOM_A_CLK_BUFF_EN1			(0x108)
-#define TOMTOM_A_CLK_BUFF_EN1__POR				(0x04)
-#define TOMTOM_A_CLK_BUFF_EN2			(0x109)
-#define TOMTOM_A_CLK_BUFF_EN2__POR				(0x02)
-#define TOMTOM_A_LDO_L_MODE_1			(0x10A)
-#define TOMTOM_A_LDO_L_MODE_1__POR				(0x08)
-#define TOMTOM_A_LDO_L_MODE_2			(0x10B)
-#define TOMTOM_A_LDO_L_MODE_2__POR				(0x50)
-#define TOMTOM_A_LDO_L_CTRL_1			(0x10C)
-#define TOMTOM_A_LDO_L_CTRL_1__POR				(0x70)
-#define TOMTOM_A_LDO_L_CTRL_2			(0x10D)
-#define TOMTOM_A_LDO_L_CTRL_2__POR				(0x55)
-#define TOMTOM_A_LDO_L_CTRL_3			(0x10E)
-#define TOMTOM_A_LDO_L_CTRL_3__POR				(0x56)
-#define TOMTOM_A_LDO_L_CTRL_4			(0x10F)
-#define TOMTOM_A_LDO_L_CTRL_4__POR				(0x55)
-#define TOMTOM_A_LDO_H_MODE_1			(0x110)
-#define TOMTOM_A_LDO_H_MODE_1__POR				(0x65)
-#define TOMTOM_A_LDO_H_MODE_2			(0x111)
-#define TOMTOM_A_LDO_H_MODE_2__POR				(0xA8)
-#define TOMTOM_A_LDO_H_LOOP_CTL			(0x112)
-#define TOMTOM_A_LDO_H_LOOP_CTL__POR				(0x6B)
-#define TOMTOM_A_LDO_H_COMP_1			(0x113)
-#define TOMTOM_A_LDO_H_COMP_1__POR				(0x84)
-#define TOMTOM_A_LDO_H_COMP_2			(0x114)
-#define TOMTOM_A_LDO_H_COMP_2__POR				(0xE0)
-#define TOMTOM_A_LDO_H_BIAS_1			(0x115)
-#define TOMTOM_A_LDO_H_BIAS_1__POR				(0x6D)
-#define TOMTOM_A_LDO_H_BIAS_2			(0x116)
-#define TOMTOM_A_LDO_H_BIAS_2__POR				(0xA5)
-#define TOMTOM_A_LDO_H_BIAS_3			(0x117)
-#define TOMTOM_A_LDO_H_BIAS_3__POR				(0x60)
-#define TOMTOM_A_VBAT_CLK			(0x118)
-#define TOMTOM_A_VBAT_CLK__POR				(0x03)
-#define TOMTOM_A_VBAT_LOOP			(0x119)
-#define TOMTOM_A_VBAT_LOOP__POR				(0x02)
-#define TOMTOM_A_VBAT_REF			(0x11A)
-#define TOMTOM_A_VBAT_REF__POR				(0x20)
-#define TOMTOM_A_VBAT_ADC_TEST			(0x11B)
-#define TOMTOM_A_VBAT_ADC_TEST__POR				(0x00)
-#define TOMTOM_A_VBAT_FE			(0x11C)
-#define TOMTOM_A_VBAT_FE__POR				(0x48)
-#define TOMTOM_A_VBAT_BIAS_1			(0x11D)
-#define TOMTOM_A_VBAT_BIAS_1__POR				(0x03)
-#define TOMTOM_A_VBAT_BIAS_2			(0x11E)
-#define TOMTOM_A_VBAT_BIAS_2__POR				(0x00)
-#define TOMTOM_A_VBAT_ADC_DATA_MSB			(0x11F)
-#define TOMTOM_A_VBAT_ADC_DATA_MSB__POR				(0x00)
-#define TOMTOM_A_VBAT_ADC_DATA_LSB			(0x120)
-#define TOMTOM_A_VBAT_ADC_DATA_LSB__POR				(0x00)
-#define TOMTOM_A_FLL_NREF			(0x121)
-#define TOMTOM_A_FLL_NREF__POR				(0x12)
-#define TOMTOM_A_FLL_KDCO_TUNE			(0x122)
-#define TOMTOM_A_FLL_KDCO_TUNE__POR				(0x05)
-#define TOMTOM_A_FLL_LOCK_THRESH			(0x123)
-#define TOMTOM_A_FLL_LOCK_THRESH__POR				(0xC2)
-#define TOMTOM_A_FLL_LOCK_DET_COUNT			(0x124)
-#define TOMTOM_A_FLL_LOCK_DET_COUNT__POR				(0x40)
-#define TOMTOM_A_FLL_DAC_THRESHOLD			(0x125)
-#define TOMTOM_A_FLL_DAC_THRESHOLD__POR				(0xC8)
-#define TOMTOM_A_FLL_TEST_DCO_FREERUN			(0x126)
-#define TOMTOM_A_FLL_TEST_DCO_FREERUN__POR				(0x00)
-#define TOMTOM_A_FLL_TEST_ENABLE			(0x127)
-#define TOMTOM_A_FLL_TEST_ENABLE__POR				(0x00)
-#define TOMTOM_A_MICB_CFILT_1_CTL			(0x128)
-#define TOMTOM_A_MICB_CFILT_1_CTL__POR				(0x40)
-#define TOMTOM_A_MICB_CFILT_1_VAL			(0x129)
-#define TOMTOM_A_MICB_CFILT_1_VAL__POR				(0x80)
-#define TOMTOM_A_MICB_CFILT_1_PRECHRG			(0x12A)
-#define TOMTOM_A_MICB_CFILT_1_PRECHRG__POR				(0x38)
-#define TOMTOM_A_MICB_1_CTL			(0x12B)
-#define TOMTOM_A_MICB_1_CTL__POR				(0x16)
-#define TOMTOM_A_MICB_1_INT_RBIAS			(0x12C)
-#define TOMTOM_A_MICB_1_INT_RBIAS__POR				(0x24)
-#define TOMTOM_A_MICB_1_MBHC			(0x12D)
-#define TOMTOM_A_MICB_1_MBHC__POR				(0x01)
-#define TOMTOM_A_MICB_CFILT_2_CTL			(0x12E)
-#define TOMTOM_A_MICB_CFILT_2_CTL__POR				(0x41)
-#define TOMTOM_A_MICB_CFILT_2_VAL			(0x12F)
-#define TOMTOM_A_MICB_CFILT_2_VAL__POR				(0x80)
-#define TOMTOM_A_MICB_CFILT_2_PRECHRG			(0x130)
-#define TOMTOM_A_MICB_CFILT_2_PRECHRG__POR				(0x38)
-#define TOMTOM_A_MICB_2_CTL			(0x131)
-#define TOMTOM_A_MICB_2_CTL__POR				(0x16)
-#define TOMTOM_A_MICB_2_INT_RBIAS			(0x132)
-#define TOMTOM_A_MICB_2_INT_RBIAS__POR				(0x24)
-#define TOMTOM_A_MICB_2_MBHC			(0x133)
-#define TOMTOM_A_MICB_2_MBHC__POR				(0x02)
-#define TOMTOM_A_MICB_CFILT_3_CTL			(0x134)
-#define TOMTOM_A_MICB_CFILT_3_CTL__POR				(0x40)
-#define TOMTOM_A_MICB_CFILT_3_VAL			(0x135)
-#define TOMTOM_A_MICB_CFILT_3_VAL__POR				(0x80)
-#define TOMTOM_A_MICB_CFILT_3_PRECHRG			(0x136)
-#define TOMTOM_A_MICB_CFILT_3_PRECHRG__POR				(0x38)
-#define TOMTOM_A_MICB_3_CTL			(0x137)
-#define TOMTOM_A_MICB_3_CTL__POR				(0x16)
-#define TOMTOM_A_MICB_3_INT_RBIAS			(0x138)
-#define TOMTOM_A_MICB_3_INT_RBIAS__POR				(0x24)
-#define TOMTOM_A_MICB_3_MBHC			(0x139)
-#define TOMTOM_A_MICB_3_MBHC__POR				(0x00)
-#define TOMTOM_A_MICB_4_CTL			(0x13A)
-#define TOMTOM_A_MICB_4_CTL__POR				(0x16)
-#define TOMTOM_A_MICB_4_INT_RBIAS			(0x13B)
-#define TOMTOM_A_MICB_4_INT_RBIAS__POR				(0x24)
-#define TOMTOM_A_MICB_4_MBHC			(0x13C)
-#define TOMTOM_A_MICB_4_MBHC__POR				(0x01)
-#define TOMTOM_A_SPKR_DRV2_EN			(0x13D)
-#define TOMTOM_A_SPKR_DRV2_EN__POR				(0x6F)
-#define TOMTOM_A_SPKR_DRV2_GAIN			(0x13E)
-#define TOMTOM_A_SPKR_DRV2_GAIN__POR				(0x00)
-#define TOMTOM_A_SPKR_DRV2_DAC_CTL			(0x13F)
-#define TOMTOM_A_SPKR_DRV2_DAC_CTL__POR				(0x04)
-#define TOMTOM_A_SPKR_DRV2_OCP_CTL			(0x140)
-#define TOMTOM_A_SPKR_DRV2_OCP_CTL__POR				(0x97)
-#define TOMTOM_A_SPKR_DRV2_CLIP_DET			(0x141)
-#define TOMTOM_A_SPKR_DRV2_CLIP_DET__POR				(0x01)
-#define TOMTOM_A_SPKR_DRV2_DBG_DAC			(0x142)
-#define TOMTOM_A_SPKR_DRV2_DBG_DAC__POR				(0x05)
-#define TOMTOM_A_SPKR_DRV2_DBG_PA			(0x143)
-#define TOMTOM_A_SPKR_DRV2_DBG_PA__POR				(0x18)
-#define TOMTOM_A_SPKR_DRV2_DBG_PWRSTG			(0x144)
-#define TOMTOM_A_SPKR_DRV2_DBG_PWRSTG__POR				(0x00)
-#define TOMTOM_A_SPKR_DRV2_BIAS_LDO			(0x145)
-#define TOMTOM_A_SPKR_DRV2_BIAS_LDO__POR				(0x45)
-#define TOMTOM_A_SPKR_DRV2_BIAS_INT			(0x146)
-#define TOMTOM_A_SPKR_DRV2_BIAS_INT__POR				(0xA5)
-#define TOMTOM_A_SPKR_DRV2_BIAS_PA			(0x147)
-#define TOMTOM_A_SPKR_DRV2_BIAS_PA__POR				(0x55)
-#define TOMTOM_A_SPKR_DRV2_STATUS_OCP			(0x148)
-#define TOMTOM_A_SPKR_DRV2_STATUS_OCP__POR				(0x00)
-#define TOMTOM_A_SPKR_DRV2_STATUS_PA			(0x149)
-#define TOMTOM_A_SPKR_DRV2_STATUS_PA__POR				(0x00)
-#define TOMTOM_A_MBHC_INSERT_DETECT			(0x14A)
-#define TOMTOM_A_MBHC_INSERT_DETECT__POR				(0x00)
-#define TOMTOM_A_MBHC_INSERT_DET_STATUS			(0x14B)
-#define TOMTOM_A_MBHC_INSERT_DET_STATUS__POR				(0x00)
-#define TOMTOM_A_TX_COM_BIAS			(0x14C)
-#define TOMTOM_A_TX_COM_BIAS__POR				(0xF0)
-#define TOMTOM_A_MBHC_INSERT_DETECT2			(0x14D)
-#define TOMTOM_A_MBHC_INSERT_DETECT2__POR				(0xD0)
-#define TOMTOM_A_MBHC_SCALING_MUX_1			(0x14E)
-#define TOMTOM_A_MBHC_SCALING_MUX_1__POR				(0x00)
-#define TOMTOM_A_MBHC_SCALING_MUX_2			(0x14F)
-#define TOMTOM_A_MBHC_SCALING_MUX_2__POR				(0x80)
-#define TOMTOM_A_MAD_ANA_CTRL			(0x150)
-#define TOMTOM_A_MAD_ANA_CTRL__POR				(0xF1)
-#define TOMTOM_A_TX_SUP_SWITCH_CTRL_1			(0x151)
-#define TOMTOM_A_TX_SUP_SWITCH_CTRL_1__POR				(0x00)
-#define TOMTOM_A_TX_SUP_SWITCH_CTRL_2			(0x152)
-#define TOMTOM_A_TX_SUP_SWITCH_CTRL_2__POR				(0x80)
-#define TOMTOM_A_TX_1_GAIN			(0x153)
-#define TOMTOM_A_TX_1_GAIN__POR				(0x02)
-#define TOMTOM_A_TX_1_2_TEST_EN			(0x154)
-#define TOMTOM_A_TX_1_2_TEST_EN__POR				(0xCC)
-#define TOMTOM_A_TX_2_GAIN			(0x155)
-#define TOMTOM_A_TX_2_GAIN__POR				(0x02)
-#define TOMTOM_A_TX_1_2_ADC_IB			(0x156)
-#define TOMTOM_A_TX_1_2_ADC_IB__POR				(0x44)
-#define TOMTOM_A_TX_1_2_ATEST_REFCTRL			(0x157)
-#define TOMTOM_A_TX_1_2_ATEST_REFCTRL__POR				(0x00)
-#define TOMTOM_A_TX_1_2_TEST_CTL			(0x158)
-#define TOMTOM_A_TX_1_2_TEST_CTL__POR				(0x38)
-#define TOMTOM_A_TX_1_2_TEST_BLOCK_EN			(0x159)
-#define TOMTOM_A_TX_1_2_TEST_BLOCK_EN__POR				(0xFC)
-#define TOMTOM_A_TX_1_2_TXFE_CLKDIV			(0x15A)
-#define TOMTOM_A_TX_1_2_TXFE_CLKDIV__POR				(0x55)
-#define TOMTOM_A_TX_1_2_SAR_ERR_CH1			(0x15B)
-#define TOMTOM_A_TX_1_2_SAR_ERR_CH1__POR				(0x00)
-#define TOMTOM_A_TX_1_2_SAR_ERR_CH2			(0x15C)
-#define TOMTOM_A_TX_1_2_SAR_ERR_CH2__POR				(0x00)
-#define TOMTOM_A_TX_3_GAIN			(0x15D)
-#define TOMTOM_A_TX_3_GAIN__POR				(0x02)
-#define TOMTOM_A_TX_3_4_TEST_EN			(0x15E)
-#define TOMTOM_A_TX_3_4_TEST_EN__POR				(0xCC)
-#define TOMTOM_A_TX_4_GAIN			(0x15F)
-#define TOMTOM_A_TX_4_GAIN__POR				(0x02)
-#define TOMTOM_A_TX_3_4_ADC_IB			(0x160)
-#define TOMTOM_A_TX_3_4_ADC_IB__POR				(0x44)
-#define TOMTOM_A_TX_3_4_ATEST_REFCTRL			(0x161)
-#define TOMTOM_A_TX_3_4_ATEST_REFCTRL__POR				(0x00)
-#define TOMTOM_A_TX_3_4_TEST_CTL			(0x162)
-#define TOMTOM_A_TX_3_4_TEST_CTL__POR				(0x38)
-#define TOMTOM_A_TX_3_4_TEST_BLOCK_EN			(0x163)
-#define TOMTOM_A_TX_3_4_TEST_BLOCK_EN__POR				(0xFC)
-#define TOMTOM_A_TX_3_4_TXFE_CKDIV			(0x164)
-#define TOMTOM_A_TX_3_4_TXFE_CKDIV__POR				(0x55)
-#define TOMTOM_A_TX_3_4_SAR_ERR_CH3			(0x165)
-#define TOMTOM_A_TX_3_4_SAR_ERR_CH3__POR				(0x00)
-#define TOMTOM_A_TX_3_4_SAR_ERR_CH4			(0x166)
-#define TOMTOM_A_TX_3_4_SAR_ERR_CH4__POR				(0x00)
-#define TOMTOM_A_TX_5_GAIN			(0x167)
-#define TOMTOM_A_TX_5_GAIN__POR				(0x02)
-#define TOMTOM_A_TX_5_6_TEST_EN			(0x168)
-#define TOMTOM_A_TX_5_6_TEST_EN__POR				(0xCC)
-#define TOMTOM_A_TX_6_GAIN			(0x169)
-#define TOMTOM_A_TX_6_GAIN__POR				(0x02)
-#define TOMTOM_A_TX_5_6_ADC_IB			(0x16A)
-#define TOMTOM_A_TX_5_6_ADC_IB__POR				(0x44)
-#define TOMTOM_A_TX_5_6_ATEST_REFCTRL			(0x16B)
-#define TOMTOM_A_TX_5_6_ATEST_REFCTRL__POR				(0x00)
-#define TOMTOM_A_TX_5_6_TEST_CTL			(0x16C)
-#define TOMTOM_A_TX_5_6_TEST_CTL__POR				(0x38)
-#define TOMTOM_A_TX_5_6_TEST_BLOCK_EN			(0x16D)
-#define TOMTOM_A_TX_5_6_TEST_BLOCK_EN__POR				(0xFC)
-#define TOMTOM_A_TX_5_6_TXFE_CKDIV			(0x16E)
-#define TOMTOM_A_TX_5_6_TXFE_CKDIV__POR				(0x55)
-#define TOMTOM_A_TX_5_6_SAR_ERR_CH5			(0x16F)
-#define TOMTOM_A_TX_5_6_SAR_ERR_CH5__POR				(0x00)
-#define TOMTOM_A_TX_5_6_SAR_ERR_CH6			(0x170)
-#define TOMTOM_A_TX_5_6_SAR_ERR_CH6__POR				(0x00)
-#define TOMTOM_A_TX_7_MBHC_EN			(0x171)
-#define TOMTOM_A_TX_7_MBHC_EN__POR				(0x0C)
-#define TOMTOM_A_TX_7_MBHC_ATEST_REFCTRL			(0x172)
-#define TOMTOM_A_TX_7_MBHC_ATEST_REFCTRL__POR				(0x00)
-#define TOMTOM_A_TX_7_MBHC_ADC			(0x173)
-#define TOMTOM_A_TX_7_MBHC_ADC__POR				(0x44)
-#define TOMTOM_A_TX_7_MBHC_TEST_CTL			(0x174)
-#define TOMTOM_A_TX_7_MBHC_TEST_CTL__POR				(0x38)
-#define TOMTOM_A_TX_7_MBHC_SAR_ERR			(0x175)
-#define TOMTOM_A_TX_7_MBHC_SAR_ERR__POR				(0x00)
-#define TOMTOM_A_TX_7_TXFE_CLKDIV			(0x176)
-#define TOMTOM_A_TX_7_TXFE_CLKDIV__POR				(0x8B)
-#define TOMTOM_A_RCO_CTRL			(0x177)
-#define TOMTOM_A_RCO_CTRL__POR				(0x00)
-#define TOMTOM_A_RCO_CALIBRATION_CTRL1			(0x178)
-#define TOMTOM_A_RCO_CALIBRATION_CTRL1__POR				(0x00)
-#define TOMTOM_A_RCO_CALIBRATION_CTRL2			(0x179)
-#define TOMTOM_A_RCO_CALIBRATION_CTRL2__POR				(0x00)
-#define TOMTOM_A_RCO_CALIBRATION_CTRL3			(0x17A)
-#define TOMTOM_A_RCO_CALIBRATION_CTRL3__POR				(0x00)
-#define TOMTOM_A_RCO_TEST_CTRL			(0x17B)
-#define TOMTOM_A_RCO_TEST_CTRL__POR				(0x00)
-#define TOMTOM_A_RCO_CALIBRATION_RESULT1			(0x17C)
-#define TOMTOM_A_RCO_CALIBRATION_RESULT1__POR				(0x00)
-#define TOMTOM_A_RCO_CALIBRATION_RESULT2			(0x17D)
-#define TOMTOM_A_RCO_CALIBRATION_RESULT2__POR				(0x00)
-#define TOMTOM_A_BUCK_MODE_1			(0x181)
-#define TOMTOM_A_BUCK_MODE_1__POR				(0x21)
-#define TOMTOM_A_BUCK_MODE_2			(0x182)
-#define TOMTOM_A_BUCK_MODE_2__POR				(0xFF)
-#define TOMTOM_A_BUCK_MODE_3			(0x183)
-#define TOMTOM_A_BUCK_MODE_3__POR				(0xCE)
-#define TOMTOM_A_BUCK_MODE_4			(0x184)
-#define TOMTOM_A_BUCK_MODE_4__POR				(0x3A)
-#define TOMTOM_A_BUCK_MODE_5			(0x185)
-#define TOMTOM_A_BUCK_MODE_5__POR				(0x00)
-#define TOMTOM_A_BUCK_CTRL_VCL_1			(0x186)
-#define TOMTOM_A_BUCK_CTRL_VCL_1__POR				(0x08)
-#define TOMTOM_A_BUCK_CTRL_VCL_2			(0x187)
-#define TOMTOM_A_BUCK_CTRL_VCL_2__POR				(0xA3)
-#define TOMTOM_A_BUCK_CTRL_VCL_3			(0x188)
-#define TOMTOM_A_BUCK_CTRL_VCL_3__POR				(0x82)
-#define TOMTOM_A_BUCK_CTRL_CCL_1			(0x189)
-#define TOMTOM_A_BUCK_CTRL_CCL_1__POR				(0x5B)
-#define TOMTOM_A_BUCK_CTRL_CCL_2			(0x18A)
-#define TOMTOM_A_BUCK_CTRL_CCL_2__POR				(0xDC)
-#define TOMTOM_A_BUCK_CTRL_CCL_3			(0x18B)
-#define TOMTOM_A_BUCK_CTRL_CCL_3__POR				(0x6A)
-#define TOMTOM_A_BUCK_CTRL_CCL_4			(0x18C)
-#define TOMTOM_A_BUCK_CTRL_CCL_4__POR				(0x51)
-#define TOMTOM_A_BUCK_CTRL_PWM_DRVR_1			(0x18D)
-#define TOMTOM_A_BUCK_CTRL_PWM_DRVR_1__POR				(0x50)
-#define TOMTOM_A_BUCK_CTRL_PWM_DRVR_2			(0x18E)
-#define TOMTOM_A_BUCK_CTRL_PWM_DRVR_2__POR				(0x64)
-#define TOMTOM_A_BUCK_CTRL_PWM_DRVR_3			(0x18F)
-#define TOMTOM_A_BUCK_CTRL_PWM_DRVR_3__POR				(0x77)
-#define TOMTOM_A_BUCK_TMUX_A_D			(0x190)
-#define TOMTOM_A_BUCK_TMUX_A_D__POR				(0x00)
-#define TOMTOM_A_NCP_BUCKREF			(0x191)
-#define TOMTOM_A_NCP_BUCKREF__POR				(0x00)
-#define TOMTOM_A_NCP_EN			(0x192)
-#define TOMTOM_A_NCP_EN__POR				(0xFE)
-#define TOMTOM_A_NCP_CLK			(0x193)
-#define TOMTOM_A_NCP_CLK__POR				(0x94)
-#define TOMTOM_A_NCP_STATIC			(0x194)
-#define TOMTOM_A_NCP_STATIC__POR				(0x28)
-#define TOMTOM_A_NCP_VTH_LOW			(0x195)
-#define TOMTOM_A_NCP_VTH_LOW__POR				(0x88)
-#define TOMTOM_A_NCP_VTH_HIGH			(0x196)
-#define TOMTOM_A_NCP_VTH_HIGH__POR				(0xA0)
-#define TOMTOM_A_NCP_ATEST			(0x197)
-#define TOMTOM_A_NCP_ATEST__POR				(0x00)
-#define TOMTOM_A_NCP_DTEST			(0x198)
-#define TOMTOM_A_NCP_DTEST__POR				(0x10)
-#define TOMTOM_A_NCP_DLY1			(0x199)
-#define TOMTOM_A_NCP_DLY1__POR				(0x06)
-#define TOMTOM_A_NCP_DLY2			(0x19A)
-#define TOMTOM_A_NCP_DLY2__POR				(0x06)
-#define TOMTOM_A_RX_AUX_SW_CTL			(0x19B)
-#define TOMTOM_A_RX_AUX_SW_CTL__POR				(0x00)
-#define TOMTOM_A_RX_PA_AUX_IN_CONN			(0x19C)
-#define TOMTOM_A_RX_PA_AUX_IN_CONN__POR				(0x00)
-#define TOMTOM_A_RX_COM_TIMER_DIV			(0x19E)
-#define TOMTOM_A_RX_COM_TIMER_DIV__POR				(0xE8)
-#define TOMTOM_A_RX_COM_OCP_CTL			(0x19F)
-#define TOMTOM_A_RX_COM_OCP_CTL__POR				(0x1F)
-#define TOMTOM_A_RX_COM_OCP_COUNT			(0x1A0)
-#define TOMTOM_A_RX_COM_OCP_COUNT__POR				(0x77)
-#define TOMTOM_A_RX_COM_DAC_CTL			(0x1A1)
-#define TOMTOM_A_RX_COM_DAC_CTL__POR				(0x00)
-#define TOMTOM_A_RX_COM_BIAS			(0x1A2)
-#define TOMTOM_A_RX_COM_BIAS__POR				(0x20)
-#define TOMTOM_A_RX_HPH_AUTO_CHOP			(0x1A4)
-#define TOMTOM_A_RX_HPH_AUTO_CHOP__POR				(0x38)
-#define TOMTOM_A_RX_HPH_CHOP_CTL			(0x1A5)
-#define TOMTOM_A_RX_HPH_CHOP_CTL__POR				(0xA4)
-#define TOMTOM_A_RX_HPH_BIAS_PA			(0x1A6)
-#define TOMTOM_A_RX_HPH_BIAS_PA__POR				(0x7A)
-#define TOMTOM_A_RX_HPH_BIAS_LDO			(0x1A7)
-#define TOMTOM_A_RX_HPH_BIAS_LDO__POR				(0x87)
-#define TOMTOM_A_RX_HPH_BIAS_CNP			(0x1A8)
-#define TOMTOM_A_RX_HPH_BIAS_CNP__POR				(0x8A)
-#define TOMTOM_A_RX_HPH_BIAS_WG_OCP			(0x1A9)
-#define TOMTOM_A_RX_HPH_BIAS_WG_OCP__POR				(0x2A)
-#define TOMTOM_A_RX_HPH_OCP_CTL			(0x1AA)
-#define TOMTOM_A_RX_HPH_OCP_CTL__POR				(0x69)
-#define TOMTOM_A_RX_HPH_CNP_EN			(0x1AB)
-#define TOMTOM_A_RX_HPH_CNP_EN__POR				(0x80)
-#define TOMTOM_A_RX_HPH_CNP_WG_CTL			(0x1AC)
-#define TOMTOM_A_RX_HPH_CNP_WG_CTL__POR				(0xDA)
-#define TOMTOM_A_RX_HPH_CNP_WG_TIME			(0x1AD)
-#define TOMTOM_A_RX_HPH_CNP_WG_TIME__POR				(0x15)
-#define TOMTOM_A_RX_HPH_L_GAIN			(0x1AE)
-#define TOMTOM_A_RX_HPH_L_GAIN__POR				(0xC0)
-#define TOMTOM_A_RX_HPH_L_TEST			(0x1AF)
-#define TOMTOM_A_RX_HPH_L_TEST__POR				(0x02)
-#define TOMTOM_A_RX_HPH_L_PA_CTL			(0x1B0)
-#define TOMTOM_A_RX_HPH_L_PA_CTL__POR				(0x42)
-#define TOMTOM_A_RX_HPH_L_DAC_CTL			(0x1B1)
-#define TOMTOM_A_RX_HPH_L_DAC_CTL__POR				(0x00)
-#define TOMTOM_A_RX_HPH_L_ATEST			(0x1B2)
-#define TOMTOM_A_RX_HPH_L_ATEST__POR				(0x00)
-#define TOMTOM_A_RX_HPH_L_STATUS			(0x1B3)
-#define TOMTOM_A_RX_HPH_L_STATUS__POR				(0x00)
-#define TOMTOM_A_RX_HPH_R_GAIN			(0x1B4)
-#define TOMTOM_A_RX_HPH_R_GAIN__POR				(0x00)
-#define TOMTOM_A_RX_HPH_R_TEST			(0x1B5)
-#define TOMTOM_A_RX_HPH_R_TEST__POR				(0x02)
-#define TOMTOM_A_RX_HPH_R_PA_CTL			(0x1B6)
-#define TOMTOM_A_RX_HPH_R_PA_CTL__POR				(0x42)
-#define TOMTOM_A_RX_HPH_R_DAC_CTL			(0x1B7)
-#define TOMTOM_A_RX_HPH_R_DAC_CTL__POR				(0x00)
-#define TOMTOM_A_RX_HPH_R_ATEST			(0x1B8)
-#define TOMTOM_A_RX_HPH_R_ATEST__POR				(0x00)
-#define TOMTOM_A_RX_HPH_R_STATUS			(0x1B9)
-#define TOMTOM_A_RX_HPH_R_STATUS__POR				(0x00)
-#define TOMTOM_A_RX_EAR_BIAS_PA			(0x1BA)
-#define TOMTOM_A_RX_EAR_BIAS_PA__POR				(0x76)
-#define TOMTOM_A_RX_EAR_BIAS_CMBUFF			(0x1BB)
-#define TOMTOM_A_RX_EAR_BIAS_CMBUFF__POR				(0xA0)
-#define TOMTOM_A_RX_EAR_EN			(0x1BC)
-#define TOMTOM_A_RX_EAR_EN__POR				(0x00)
-#define TOMTOM_A_RX_EAR_GAIN			(0x1BD)
-#define TOMTOM_A_RX_EAR_GAIN__POR				(0x02)
-#define TOMTOM_A_RX_EAR_CMBUFF			(0x1BE)
-#define TOMTOM_A_RX_EAR_CMBUFF__POR				(0x05)
-#define TOMTOM_A_RX_EAR_ICTL			(0x1BF)
-#define TOMTOM_A_RX_EAR_ICTL__POR				(0x40)
-#define TOMTOM_A_RX_EAR_CCOMP			(0x1C0)
-#define TOMTOM_A_RX_EAR_CCOMP__POR				(0x08)
-#define TOMTOM_A_RX_EAR_VCM			(0x1C1)
-#define TOMTOM_A_RX_EAR_VCM__POR				(0x03)
-#define TOMTOM_A_RX_EAR_CNP			(0x1C2)
-#define TOMTOM_A_RX_EAR_CNP__POR				(0xC0)
-#define TOMTOM_A_RX_EAR_DAC_CTL_ATEST			(0x1C3)
-#define TOMTOM_A_RX_EAR_DAC_CTL_ATEST__POR				(0x00)
-#define TOMTOM_A_RX_EAR_STATUS			(0x1C5)
-#define TOMTOM_A_RX_EAR_STATUS__POR				(0x04)
-#define TOMTOM_A_RX_LINE_BIAS_PA			(0x1C6)
-#define TOMTOM_A_RX_LINE_BIAS_PA__POR				(0x78)
-#define TOMTOM_A_RX_BUCK_BIAS1			(0x1C7)
-#define TOMTOM_A_RX_BUCK_BIAS1__POR				(0x42)
-#define TOMTOM_A_RX_BUCK_BIAS2			(0x1C8)
-#define TOMTOM_A_RX_BUCK_BIAS2__POR				(0x84)
-#define TOMTOM_A_RX_LINE_COM			(0x1C9)
-#define TOMTOM_A_RX_LINE_COM__POR				(0x80)
-#define TOMTOM_A_RX_LINE_CNP_EN			(0x1CA)
-#define TOMTOM_A_RX_LINE_CNP_EN__POR				(0x00)
-#define TOMTOM_A_RX_LINE_CNP_WG_CTL			(0x1CB)
-#define TOMTOM_A_RX_LINE_CNP_WG_CTL__POR				(0x00)
-#define TOMTOM_A_RX_LINE_CNP_WG_TIME			(0x1CC)
-#define TOMTOM_A_RX_LINE_CNP_WG_TIME__POR				(0x04)
-#define TOMTOM_A_RX_LINE_1_GAIN			(0x1CD)
-#define TOMTOM_A_RX_LINE_1_GAIN__POR				(0x00)
-#define TOMTOM_A_RX_LINE_1_TEST			(0x1CE)
-#define TOMTOM_A_RX_LINE_1_TEST__POR				(0x02)
-#define TOMTOM_A_RX_LINE_1_DAC_CTL			(0x1CF)
-#define TOMTOM_A_RX_LINE_1_DAC_CTL__POR				(0x00)
-#define TOMTOM_A_RX_LINE_1_STATUS			(0x1D0)
-#define TOMTOM_A_RX_LINE_1_STATUS__POR				(0x00)
-#define TOMTOM_A_RX_LINE_2_GAIN			(0x1D1)
-#define TOMTOM_A_RX_LINE_2_GAIN__POR				(0x00)
-#define TOMTOM_A_RX_LINE_2_TEST			(0x1D2)
-#define TOMTOM_A_RX_LINE_2_TEST__POR				(0x02)
-#define TOMTOM_A_RX_LINE_2_DAC_CTL			(0x1D3)
-#define TOMTOM_A_RX_LINE_2_DAC_CTL__POR				(0x00)
-#define TOMTOM_A_RX_LINE_2_STATUS			(0x1D4)
-#define TOMTOM_A_RX_LINE_2_STATUS__POR				(0x00)
-#define TOMTOM_A_RX_LINE_3_GAIN			(0x1D5)
-#define TOMTOM_A_RX_LINE_3_GAIN__POR				(0x00)
-#define TOMTOM_A_RX_LINE_3_TEST			(0x1D6)
-#define TOMTOM_A_RX_LINE_3_TEST__POR				(0x02)
-#define TOMTOM_A_RX_LINE_3_DAC_CTL			(0x1D7)
-#define TOMTOM_A_RX_LINE_3_DAC_CTL__POR				(0x00)
-#define TOMTOM_A_RX_LINE_3_STATUS			(0x1D8)
-#define TOMTOM_A_RX_LINE_3_STATUS__POR				(0x00)
-#define TOMTOM_A_RX_LINE_4_GAIN			(0x1D9)
-#define TOMTOM_A_RX_LINE_4_GAIN__POR				(0x00)
-#define TOMTOM_A_RX_LINE_4_TEST			(0x1DA)
-#define TOMTOM_A_RX_LINE_4_TEST__POR				(0x02)
-#define TOMTOM_A_RX_LINE_4_DAC_CTL			(0x1DB)
-#define TOMTOM_A_RX_LINE_4_DAC_CTL__POR				(0x00)
-#define TOMTOM_A_RX_LINE_4_STATUS			(0x1DC)
-#define TOMTOM_A_RX_LINE_4_STATUS__POR				(0x00)
-#define TOMTOM_A_RX_LINE_CNP_DBG			(0x1DD)
-#define TOMTOM_A_RX_LINE_CNP_DBG__POR				(0x00)
-#define TOMTOM_A_SPKR_DRV1_EN			(0x1DF)
-#define TOMTOM_A_SPKR_DRV1_EN__POR				(0x6F)
-#define TOMTOM_A_SPKR_DRV1_GAIN			(0x1E0)
-#define TOMTOM_A_SPKR_DRV1_GAIN__POR				(0x00)
-#define TOMTOM_A_SPKR_DRV1_DAC_CTL			(0x1E1)
-#define TOMTOM_A_SPKR_DRV1_DAC_CTL__POR				(0x04)
-#define TOMTOM_A_SPKR_DRV1_OCP_CTL			(0x1E2)
-#define TOMTOM_A_SPKR_DRV1_OCP_CTL__POR				(0x97)
-#define TOMTOM_A_SPKR_DRV1_CLIP_DET			(0x1E3)
-#define TOMTOM_A_SPKR_DRV1_CLIP_DET__POR				(0x01)
-#define TOMTOM_A_SPKR_DRV1_IEC			(0x1E4)
-#define TOMTOM_A_SPKR_DRV1_IEC__POR				(0x00)
-#define TOMTOM_A_SPKR_DRV1_DBG_DAC			(0x1E5)
-#define TOMTOM_A_SPKR_DRV1_DBG_DAC__POR				(0x05)
-#define TOMTOM_A_SPKR_DRV1_DBG_PA			(0x1E6)
-#define TOMTOM_A_SPKR_DRV1_DBG_PA__POR				(0x18)
-#define TOMTOM_A_SPKR_DRV1_DBG_PWRSTG			(0x1E7)
-#define TOMTOM_A_SPKR_DRV1_DBG_PWRSTG__POR				(0x00)
-#define TOMTOM_A_SPKR_DRV1_BIAS_LDO			(0x1E8)
-#define TOMTOM_A_SPKR_DRV1_BIAS_LDO__POR				(0x45)
-#define TOMTOM_A_SPKR_DRV1_BIAS_INT			(0x1E9)
-#define TOMTOM_A_SPKR_DRV1_BIAS_INT__POR				(0xA5)
-#define TOMTOM_A_SPKR_DRV1_BIAS_PA			(0x1EA)
-#define TOMTOM_A_SPKR_DRV1_BIAS_PA__POR				(0x55)
-#define TOMTOM_A_SPKR_DRV1_STATUS_OCP			(0x1EB)
-#define TOMTOM_A_SPKR_DRV1_STATUS_OCP__POR				(0x00)
-#define TOMTOM_A_SPKR_DRV1_STATUS_PA			(0x1EC)
-#define TOMTOM_A_SPKR_DRV1_STATUS_PA__POR				(0x00)
-#define TOMTOM_A_SPKR1_PROT_EN			(0x1ED)
-#define TOMTOM_A_SPKR1_PROT_EN__POR				(0x00)
-#define TOMTOM_A_SPKR1_PROT_ADC_TEST_EN			(0x1EE)
-#define TOMTOM_A_SPKR1_PROT_ADC_TEST_EN__POR				(0x44)
-#define TOMTOM_A_SPKR1_PROT_ATEST			(0x1EF)
-#define TOMTOM_A_SPKR1_PROT_ATEST__POR				(0x00)
-#define TOMTOM_A_SPKR1_PROT_LDO_CTRL			(0x1F0)
-#define TOMTOM_A_SPKR1_PROT_LDO_CTRL__POR				(0x00)
-#define TOMTOM_A_SPKR1_PROT_ISENSE_CTRL			(0x1F1)
-#define TOMTOM_A_SPKR1_PROT_ISENSE_CTRL__POR				(0x00)
-#define TOMTOM_A_SPKR1_PROT_VSENSE_CTRL			(0x1F2)
-#define TOMTOM_A_SPKR1_PROT_VSENSE_CTRL__POR				(0x00)
-#define TOMTOM_A_SPKR2_PROT_EN			(0x1F3)
-#define TOMTOM_A_SPKR2_PROT_EN__POR				(0x00)
-#define TOMTOM_A_SPKR2_PROT_ADC_TEST_EN			(0x1F4)
-#define TOMTOM_A_SPKR2_PROT_ADC_TEST_EN__POR				(0x44)
-#define TOMTOM_A_SPKR2_PROT_ATEST			(0x1F5)
-#define TOMTOM_A_SPKR2_PROT_ATEST__POR				(0x00)
-#define TOMTOM_A_SPKR2_PROT_LDO_CTRL			(0x1F6)
-#define TOMTOM_A_SPKR2_PROT_LDO_CTRL__POR				(0x00)
-#define TOMTOM_A_SPKR2_PROT_ISENSE_CTRL			(0x1F7)
-#define TOMTOM_A_SPKR2_PROT_ISENSE_CTRL__POR				(0x00)
-#define TOMTOM_A_SPKR2_PROT_VSENSE_CTRL			(0x1F8)
-#define TOMTOM_A_SPKR2_PROT_VSENSE_CTRL__POR				(0x00)
-#define TOMTOM_A_MBHC_HPH			(0x1FE)
-#define TOMTOM_A_MBHC_HPH__POR				(0x44)
-#define TOMTOM_A_CDC_ANC1_B1_CTL			(0x200)
-#define TOMTOM_A_CDC_ANC1_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_B1_CTL			(0x280)
-#define TOMTOM_A_CDC_ANC2_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_SHIFT			(0x201)
-#define TOMTOM_A_CDC_ANC1_SHIFT__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_SHIFT			(0x281)
-#define TOMTOM_A_CDC_ANC2_SHIFT__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_IIR_B1_CTL			(0x202)
-#define TOMTOM_A_CDC_ANC1_IIR_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_IIR_B1_CTL			(0x282)
-#define TOMTOM_A_CDC_ANC2_IIR_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_IIR_B2_CTL			(0x203)
-#define TOMTOM_A_CDC_ANC1_IIR_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_IIR_B2_CTL			(0x283)
-#define TOMTOM_A_CDC_ANC2_IIR_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_IIR_B3_CTL			(0x204)
-#define TOMTOM_A_CDC_ANC1_IIR_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_IIR_B3_CTL			(0x284)
-#define TOMTOM_A_CDC_ANC2_IIR_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_LPF_B1_CTL			(0x206)
-#define TOMTOM_A_CDC_ANC1_LPF_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_LPF_B1_CTL			(0x286)
-#define TOMTOM_A_CDC_ANC2_LPF_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_LPF_B2_CTL			(0x207)
-#define TOMTOM_A_CDC_ANC1_LPF_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_LPF_B2_CTL			(0x287)
-#define TOMTOM_A_CDC_ANC2_LPF_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_SPARE			(0x209)
-#define TOMTOM_A_CDC_ANC1_SPARE__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_SPARE			(0x289)
-#define TOMTOM_A_CDC_ANC2_SPARE__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_SMLPF_CTL			(0x20A)
-#define TOMTOM_A_CDC_ANC1_SMLPF_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_SMLPF_CTL			(0x28A)
-#define TOMTOM_A_CDC_ANC2_SMLPF_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_DCFLT_CTL			(0x20B)
-#define TOMTOM_A_CDC_ANC1_DCFLT_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_DCFLT_CTL			(0x28B)
-#define TOMTOM_A_CDC_ANC2_DCFLT_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_GAIN_CTL			(0x20C)
-#define TOMTOM_A_CDC_ANC1_GAIN_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_GAIN_CTL			(0x28C)
-#define TOMTOM_A_CDC_ANC2_GAIN_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC1_B2_CTL			(0x20D)
-#define TOMTOM_A_CDC_ANC1_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_ANC2_B2_CTL			(0x28D)
-#define TOMTOM_A_CDC_ANC2_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX1_VOL_CTL_TIMER			(0x220)
-#define TOMTOM_A_CDC_TX1_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX2_VOL_CTL_TIMER			(0x228)
-#define TOMTOM_A_CDC_TX2_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX3_VOL_CTL_TIMER			(0x230)
-#define TOMTOM_A_CDC_TX3_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX4_VOL_CTL_TIMER			(0x238)
-#define TOMTOM_A_CDC_TX4_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX5_VOL_CTL_TIMER			(0x240)
-#define TOMTOM_A_CDC_TX5_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX6_VOL_CTL_TIMER			(0x248)
-#define TOMTOM_A_CDC_TX6_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX7_VOL_CTL_TIMER			(0x250)
-#define TOMTOM_A_CDC_TX7_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX8_VOL_CTL_TIMER			(0x258)
-#define TOMTOM_A_CDC_TX8_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX9_VOL_CTL_TIMER			(0x260)
-#define TOMTOM_A_CDC_TX9_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX10_VOL_CTL_TIMER			(0x268)
-#define TOMTOM_A_CDC_TX10_VOL_CTL_TIMER__POR				(0x00)
-#define TOMTOM_A_CDC_TX1_VOL_CTL_GAIN			(0x221)
-#define TOMTOM_A_CDC_TX1_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX2_VOL_CTL_GAIN			(0x229)
-#define TOMTOM_A_CDC_TX2_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX3_VOL_CTL_GAIN			(0x231)
-#define TOMTOM_A_CDC_TX3_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX4_VOL_CTL_GAIN			(0x239)
-#define TOMTOM_A_CDC_TX4_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX5_VOL_CTL_GAIN			(0x241)
-#define TOMTOM_A_CDC_TX5_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX6_VOL_CTL_GAIN			(0x249)
-#define TOMTOM_A_CDC_TX6_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX7_VOL_CTL_GAIN			(0x251)
-#define TOMTOM_A_CDC_TX7_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX8_VOL_CTL_GAIN			(0x259)
-#define TOMTOM_A_CDC_TX8_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX9_VOL_CTL_GAIN			(0x261)
-#define TOMTOM_A_CDC_TX9_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX10_VOL_CTL_GAIN			(0x269)
-#define TOMTOM_A_CDC_TX10_VOL_CTL_GAIN__POR				(0x00)
-#define TOMTOM_A_CDC_TX1_VOL_CTL_CFG			(0x222)
-#define TOMTOM_A_CDC_TX1_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX2_VOL_CTL_CFG			(0x22A)
-#define TOMTOM_A_CDC_TX2_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX3_VOL_CTL_CFG			(0x232)
-#define TOMTOM_A_CDC_TX3_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX4_VOL_CTL_CFG			(0x23A)
-#define TOMTOM_A_CDC_TX4_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX5_VOL_CTL_CFG			(0x242)
-#define TOMTOM_A_CDC_TX5_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX6_VOL_CTL_CFG			(0x24A)
-#define TOMTOM_A_CDC_TX6_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX7_VOL_CTL_CFG			(0x252)
-#define TOMTOM_A_CDC_TX7_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX8_VOL_CTL_CFG			(0x25A)
-#define TOMTOM_A_CDC_TX8_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX9_VOL_CTL_CFG			(0x262)
-#define TOMTOM_A_CDC_TX9_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX10_VOL_CTL_CFG			(0x26A)
-#define TOMTOM_A_CDC_TX10_VOL_CTL_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_TX1_MUX_CTL			(0x223)
-#define TOMTOM_A_CDC_TX1_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX2_MUX_CTL			(0x22B)
-#define TOMTOM_A_CDC_TX2_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX3_MUX_CTL			(0x233)
-#define TOMTOM_A_CDC_TX3_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX4_MUX_CTL			(0x23B)
-#define TOMTOM_A_CDC_TX4_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX5_MUX_CTL			(0x243)
-#define TOMTOM_A_CDC_TX5_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX6_MUX_CTL			(0x24B)
-#define TOMTOM_A_CDC_TX6_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX7_MUX_CTL			(0x253)
-#define TOMTOM_A_CDC_TX7_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX8_MUX_CTL			(0x25B)
-#define TOMTOM_A_CDC_TX8_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX9_MUX_CTL			(0x263)
-#define TOMTOM_A_CDC_TX9_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX10_MUX_CTL			(0x26B)
-#define TOMTOM_A_CDC_TX10_MUX_CTL__POR				(0x48)
-#define TOMTOM_A_CDC_TX1_CLK_FS_CTL			(0x224)
-#define TOMTOM_A_CDC_TX1_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX2_CLK_FS_CTL			(0x22C)
-#define TOMTOM_A_CDC_TX2_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX3_CLK_FS_CTL			(0x234)
-#define TOMTOM_A_CDC_TX3_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX4_CLK_FS_CTL			(0x23C)
-#define TOMTOM_A_CDC_TX4_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX5_CLK_FS_CTL			(0x244)
-#define TOMTOM_A_CDC_TX5_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX6_CLK_FS_CTL			(0x24C)
-#define TOMTOM_A_CDC_TX6_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX7_CLK_FS_CTL			(0x254)
-#define TOMTOM_A_CDC_TX7_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX8_CLK_FS_CTL			(0x25C)
-#define TOMTOM_A_CDC_TX8_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX9_CLK_FS_CTL			(0x264)
-#define TOMTOM_A_CDC_TX9_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX10_CLK_FS_CTL			(0x26C)
-#define TOMTOM_A_CDC_TX10_CLK_FS_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_TX1_DMIC_CTL			(0x225)
-#define TOMTOM_A_CDC_TX1_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX2_DMIC_CTL			(0x22D)
-#define TOMTOM_A_CDC_TX2_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX3_DMIC_CTL			(0x235)
-#define TOMTOM_A_CDC_TX3_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX4_DMIC_CTL			(0x23D)
-#define TOMTOM_A_CDC_TX4_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX5_DMIC_CTL			(0x245)
-#define TOMTOM_A_CDC_TX5_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX6_DMIC_CTL			(0x24D)
-#define TOMTOM_A_CDC_TX6_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX7_DMIC_CTL			(0x255)
-#define TOMTOM_A_CDC_TX7_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX8_DMIC_CTL			(0x25D)
-#define TOMTOM_A_CDC_TX8_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX9_DMIC_CTL			(0x265)
-#define TOMTOM_A_CDC_TX9_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TX10_DMIC_CTL			(0x26D)
-#define TOMTOM_A_CDC_TX10_DMIC_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL0			(0x270)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL0__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL1			(0x271)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL1__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL2			(0x272)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL2__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL3			(0x273)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL3__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL4			(0x274)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL4__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL5			(0x275)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL5__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL6			(0x276)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL6__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL7			(0x277)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_VAL7__POR				(0x00)
-#define TOMTOM_A_CDC_DEBUG_B1_CTL			(0x278)
-#define TOMTOM_A_CDC_DEBUG_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_DEBUG_B2_CTL			(0x279)
-#define TOMTOM_A_CDC_DEBUG_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_DEBUG_B3_CTL			(0x27A)
-#define TOMTOM_A_CDC_DEBUG_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_DEBUG_B4_CTL			(0x27B)
-#define TOMTOM_A_CDC_DEBUG_B4_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_DEBUG_B5_CTL			(0x27C)
-#define TOMTOM_A_CDC_DEBUG_B5_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_DEBUG_B6_CTL			(0x27D)
-#define TOMTOM_A_CDC_DEBUG_B6_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_DEBUG_B7_CTL			(0x27E)
-#define TOMTOM_A_CDC_DEBUG_B7_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_SRC1_PDA_CFG			(0x2A0)
-#define TOMTOM_A_CDC_SRC1_PDA_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_SRC2_PDA_CFG			(0x2A8)
-#define TOMTOM_A_CDC_SRC2_PDA_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_SRC1_FS_CTL			(0x2A1)
-#define TOMTOM_A_CDC_SRC1_FS_CTL__POR				(0x1B)
-#define TOMTOM_A_CDC_SRC2_FS_CTL			(0x2A9)
-#define TOMTOM_A_CDC_SRC2_FS_CTL__POR				(0x1B)
-#define TOMTOM_A_CDC_RX1_B1_CTL			(0x2B0)
-#define TOMTOM_A_CDC_RX1_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX2_B1_CTL			(0x2B8)
-#define TOMTOM_A_CDC_RX2_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX3_B1_CTL			(0x2C0)
-#define TOMTOM_A_CDC_RX3_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX4_B1_CTL			(0x2C8)
-#define TOMTOM_A_CDC_RX4_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX5_B1_CTL			(0x2D0)
-#define TOMTOM_A_CDC_RX5_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX6_B1_CTL			(0x2D8)
-#define TOMTOM_A_CDC_RX6_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX7_B1_CTL			(0x2E0)
-#define TOMTOM_A_CDC_RX7_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX1_B2_CTL			(0x2B1)
-#define TOMTOM_A_CDC_RX1_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX2_B2_CTL			(0x2B9)
-#define TOMTOM_A_CDC_RX2_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX3_B2_CTL			(0x2C1)
-#define TOMTOM_A_CDC_RX3_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX4_B2_CTL			(0x2C9)
-#define TOMTOM_A_CDC_RX4_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX5_B2_CTL			(0x2D1)
-#define TOMTOM_A_CDC_RX5_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX6_B2_CTL			(0x2D9)
-#define TOMTOM_A_CDC_RX6_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX7_B2_CTL			(0x2E1)
-#define TOMTOM_A_CDC_RX7_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX1_B3_CTL			(0x2B2)
-#define TOMTOM_A_CDC_RX1_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX2_B3_CTL			(0x2BA)
-#define TOMTOM_A_CDC_RX2_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX3_B3_CTL			(0x2C2)
-#define TOMTOM_A_CDC_RX3_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX4_B3_CTL			(0x2CA)
-#define TOMTOM_A_CDC_RX4_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX5_B3_CTL			(0x2D2)
-#define TOMTOM_A_CDC_RX5_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX6_B3_CTL			(0x2DA)
-#define TOMTOM_A_CDC_RX6_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX7_B3_CTL			(0x2E2)
-#define TOMTOM_A_CDC_RX7_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX1_B4_CTL			(0x2B3)
-#define TOMTOM_A_CDC_RX1_B4_CTL__POR				(0x0B)
-#define TOMTOM_A_CDC_RX2_B4_CTL			(0x2BB)
-#define TOMTOM_A_CDC_RX2_B4_CTL__POR				(0x0B)
-#define TOMTOM_A_CDC_RX3_B4_CTL			(0x2C3)
-#define TOMTOM_A_CDC_RX3_B4_CTL__POR				(0x0B)
-#define TOMTOM_A_CDC_RX4_B4_CTL			(0x2CB)
-#define TOMTOM_A_CDC_RX4_B4_CTL__POR				(0x0B)
-#define TOMTOM_A_CDC_RX5_B4_CTL			(0x2D3)
-#define TOMTOM_A_CDC_RX5_B4_CTL__POR				(0x0B)
-#define TOMTOM_A_CDC_RX6_B4_CTL			(0x2DB)
-#define TOMTOM_A_CDC_RX6_B4_CTL__POR				(0x0B)
-#define TOMTOM_A_CDC_RX7_B4_CTL			(0x2E3)
-#define TOMTOM_A_CDC_RX7_B4_CTL__POR				(0x0B)
-#define TOMTOM_A_CDC_RX1_B5_CTL			(0x2B4)
-#define TOMTOM_A_CDC_RX1_B5_CTL__POR				(0x78)
-#define TOMTOM_A_CDC_RX2_B5_CTL			(0x2BC)
-#define TOMTOM_A_CDC_RX2_B5_CTL__POR				(0x78)
-#define TOMTOM_A_CDC_RX3_B5_CTL			(0x2C4)
-#define TOMTOM_A_CDC_RX3_B5_CTL__POR				(0x78)
-#define TOMTOM_A_CDC_RX4_B5_CTL			(0x2CC)
-#define TOMTOM_A_CDC_RX4_B5_CTL__POR				(0x78)
-#define TOMTOM_A_CDC_RX5_B5_CTL			(0x2D4)
-#define TOMTOM_A_CDC_RX5_B5_CTL__POR				(0x78)
-#define TOMTOM_A_CDC_RX6_B5_CTL			(0x2DC)
-#define TOMTOM_A_CDC_RX6_B5_CTL__POR				(0x78)
-#define TOMTOM_A_CDC_RX7_B5_CTL			(0x2E4)
-#define TOMTOM_A_CDC_RX7_B5_CTL__POR				(0x78)
-#define TOMTOM_A_CDC_RX1_B6_CTL			(0x2B5)
-#define TOMTOM_A_CDC_RX1_B6_CTL__POR				(0x80)
-#define TOMTOM_A_CDC_RX2_B6_CTL			(0x2BD)
-#define TOMTOM_A_CDC_RX2_B6_CTL__POR				(0x80)
-#define TOMTOM_A_CDC_RX3_B6_CTL			(0x2C5)
-#define TOMTOM_A_CDC_RX3_B6_CTL__POR				(0x80)
-#define TOMTOM_A_CDC_RX4_B6_CTL			(0x2CD)
-#define TOMTOM_A_CDC_RX4_B6_CTL__POR				(0x80)
-#define TOMTOM_A_CDC_RX5_B6_CTL			(0x2D5)
-#define TOMTOM_A_CDC_RX5_B6_CTL__POR				(0x80)
-#define TOMTOM_A_CDC_RX6_B6_CTL			(0x2DD)
-#define TOMTOM_A_CDC_RX6_B6_CTL__POR				(0x80)
-#define TOMTOM_A_CDC_RX7_B6_CTL			(0x2E5)
-#define TOMTOM_A_CDC_RX7_B6_CTL__POR				(0x80)
-#define TOMTOM_A_CDC_RX1_VOL_CTL_B1_CTL			(0x2B6)
-#define TOMTOM_A_CDC_RX1_VOL_CTL_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX2_VOL_CTL_B1_CTL			(0x2BE)
-#define TOMTOM_A_CDC_RX2_VOL_CTL_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX3_VOL_CTL_B1_CTL			(0x2C6)
-#define TOMTOM_A_CDC_RX3_VOL_CTL_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX4_VOL_CTL_B1_CTL			(0x2CE)
-#define TOMTOM_A_CDC_RX4_VOL_CTL_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX5_VOL_CTL_B1_CTL			(0x2D6)
-#define TOMTOM_A_CDC_RX5_VOL_CTL_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX6_VOL_CTL_B1_CTL			(0x2DE)
-#define TOMTOM_A_CDC_RX6_VOL_CTL_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX7_VOL_CTL_B1_CTL			(0x2E6)
-#define TOMTOM_A_CDC_RX7_VOL_CTL_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL			(0x2B7)
-#define TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL			(0x2BF)
-#define TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL			(0x2C7)
-#define TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL			(0x2CF)
-#define TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL			(0x2D7)
-#define TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL			(0x2DF)
-#define TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL			(0x2E7)
-#define TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_VBAT_CFG			(0x2E8)
-#define TOMTOM_A_CDC_VBAT_CFG__POR				(0x1A)
-#define TOMTOM_A_CDC_VBAT_ADC_CAL1			(0x2E9)
-#define TOMTOM_A_CDC_VBAT_ADC_CAL1__POR				(0x00)
-#define TOMTOM_A_CDC_VBAT_ADC_CAL2			(0x2EA)
-#define TOMTOM_A_CDC_VBAT_ADC_CAL2__POR				(0x00)
-#define TOMTOM_A_CDC_VBAT_ADC_CAL3			(0x2EB)
-#define TOMTOM_A_CDC_VBAT_ADC_CAL3__POR				(0x04)
-#define TOMTOM_A_CDC_VBAT_PK_EST1			(0x2EC)
-#define TOMTOM_A_CDC_VBAT_PK_EST1__POR				(0xE0)
-#define TOMTOM_A_CDC_VBAT_PK_EST2			(0x2ED)
-#define TOMTOM_A_CDC_VBAT_PK_EST2__POR				(0x01)
-#define TOMTOM_A_CDC_VBAT_PK_EST3			(0x2EE)
-#define TOMTOM_A_CDC_VBAT_PK_EST3__POR				(0x40)
-#define TOMTOM_A_CDC_VBAT_RF_PROC1			(0x2EF)
-#define TOMTOM_A_CDC_VBAT_RF_PROC1__POR				(0x2A)
-#define TOMTOM_A_CDC_VBAT_RF_PROC2			(0x2F0)
-#define TOMTOM_A_CDC_VBAT_RF_PROC2__POR				(0x86)
-#define TOMTOM_A_CDC_VBAT_TAC1			(0x2F1)
-#define TOMTOM_A_CDC_VBAT_TAC1__POR				(0x70)
-#define TOMTOM_A_CDC_VBAT_TAC2			(0x2F2)
-#define TOMTOM_A_CDC_VBAT_TAC2__POR				(0x18)
-#define TOMTOM_A_CDC_VBAT_TAC3			(0x2F3)
-#define TOMTOM_A_CDC_VBAT_TAC3__POR				(0x18)
-#define TOMTOM_A_CDC_VBAT_TAC4			(0x2F4)
-#define TOMTOM_A_CDC_VBAT_TAC4__POR				(0x03)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD1			(0x2F5)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD1__POR				(0x01)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD2			(0x2F6)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD2__POR				(0x00)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD3			(0x2F7)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD3__POR				(0x64)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD4			(0x2F8)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD4__POR				(0x01)
-#define TOMTOM_A_CDC_VBAT_DEBUG1			(0x2F9)
-#define TOMTOM_A_CDC_VBAT_DEBUG1__POR				(0x00)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD_MON			(0x2FA)
-#define TOMTOM_A_CDC_VBAT_GAIN_UPD_MON__POR				(0x00)
-#define TOMTOM_A_CDC_VBAT_GAIN_MON_VAL			(0x2FB)
-#define TOMTOM_A_CDC_VBAT_GAIN_MON_VAL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_ANC_RESET_CTL			(0x300)
-#define TOMTOM_A_CDC_CLK_ANC_RESET_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_RX_RESET_CTL			(0x301)
-#define TOMTOM_A_CDC_CLK_RX_RESET_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_TX_RESET_B1_CTL			(0x302)
-#define TOMTOM_A_CDC_CLK_TX_RESET_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_TX_RESET_B2_CTL			(0x303)
-#define TOMTOM_A_CDC_CLK_TX_RESET_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_RX_I2S_CTL			(0x306)
-#define TOMTOM_A_CDC_CLK_RX_I2S_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_CLK_TX_I2S_CTL			(0x307)
-#define TOMTOM_A_CDC_CLK_TX_I2S_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_CLK_OTHR_RESET_B1_CTL			(0x308)
-#define TOMTOM_A_CDC_CLK_OTHR_RESET_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL			(0x309)
-#define TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL			(0x30A)
-#define TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL			(0x30B)
-#define TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_OTHR_CTL			(0x30C)
-#define TOMTOM_A_CDC_CLK_OTHR_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_ANC_CLK_EN_CTL			(0x30E)
-#define TOMTOM_A_CDC_CLK_ANC_CLK_EN_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_RX_B1_CTL			(0x30F)
-#define TOMTOM_A_CDC_CLK_RX_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_RX_B2_CTL			(0x310)
-#define TOMTOM_A_CDC_CLK_RX_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_MCLK_CTL			(0x311)
-#define TOMTOM_A_CDC_CLK_MCLK_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_PDM_CTL			(0x312)
-#define TOMTOM_A_CDC_CLK_PDM_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLK_SD_CTL			(0x313)
-#define TOMTOM_A_CDC_CLK_SD_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLSH_B1_CTL			(0x320)
-#define TOMTOM_A_CDC_CLSH_B1_CTL__POR				(0xE4)
-#define TOMTOM_A_CDC_CLSH_B2_CTL			(0x321)
-#define TOMTOM_A_CDC_CLSH_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLSH_B3_CTL			(0x322)
-#define TOMTOM_A_CDC_CLSH_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLSH_BUCK_NCP_VARS			(0x323)
-#define TOMTOM_A_CDC_CLSH_BUCK_NCP_VARS__POR				(0x00)
-#define TOMTOM_A_CDC_CLSH_IDLE_HPH_THSD			(0x324)
-#define TOMTOM_A_CDC_CLSH_IDLE_HPH_THSD__POR				(0x12)
-#define TOMTOM_A_CDC_CLSH_IDLE_EAR_THSD			(0x325)
-#define TOMTOM_A_CDC_CLSH_IDLE_EAR_THSD__POR				(0x0C)
-#define TOMTOM_A_CDC_CLSH_FCLKONLY_HPH_THSD			(0x326)
-#define TOMTOM_A_CDC_CLSH_FCLKONLY_HPH_THSD__POR			(0x18)
-#define TOMTOM_A_CDC_CLSH_FCLKONLY_EAR_THSD			(0x327)
-#define TOMTOM_A_CDC_CLSH_FCLKONLY_EAR_THSD__POR			(0x23)
-#define TOMTOM_A_CDC_CLSH_K_ADDR			(0x328)
-#define TOMTOM_A_CDC_CLSH_K_ADDR__POR				(0x00)
-#define TOMTOM_A_CDC_CLSH_K_DATA			(0x329)
-#define TOMTOM_A_CDC_CLSH_K_DATA__POR				(0xA4)
-#define TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_L			(0x32A)
-#define TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_L__POR				(0xD7)
-#define TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_U			(0x32B)
-#define TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_U__POR				(0x05)
-#define TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_L			(0x32C)
-#define TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_L__POR				(0x60)
-#define TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_U			(0x32D)
-#define TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_U__POR				(0x09)
-#define TOMTOM_A_CDC_CLSH_V_PA_HD_EAR			(0x32E)
-#define TOMTOM_A_CDC_CLSH_V_PA_HD_EAR__POR				(0x00)
-#define TOMTOM_A_CDC_CLSH_V_PA_HD_HPH			(0x32F)
-#define TOMTOM_A_CDC_CLSH_V_PA_HD_HPH__POR				(0x00)
-#define TOMTOM_A_CDC_CLSH_V_PA_MIN_EAR			(0x330)
-#define TOMTOM_A_CDC_CLSH_V_PA_MIN_EAR__POR				(0x00)
-#define TOMTOM_A_CDC_CLSH_V_PA_MIN_HPH			(0x331)
-#define TOMTOM_A_CDC_CLSH_V_PA_MIN_HPH__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_GAIN_B1_CTL			(0x340)
-#define TOMTOM_A_CDC_IIR1_GAIN_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_GAIN_B1_CTL			(0x350)
-#define TOMTOM_A_CDC_IIR2_GAIN_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_GAIN_B2_CTL			(0x341)
-#define TOMTOM_A_CDC_IIR1_GAIN_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_GAIN_B2_CTL			(0x351)
-#define TOMTOM_A_CDC_IIR2_GAIN_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_GAIN_B3_CTL			(0x342)
-#define TOMTOM_A_CDC_IIR1_GAIN_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_GAIN_B3_CTL			(0x352)
-#define TOMTOM_A_CDC_IIR2_GAIN_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_GAIN_B4_CTL			(0x343)
-#define TOMTOM_A_CDC_IIR1_GAIN_B4_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_GAIN_B4_CTL			(0x353)
-#define TOMTOM_A_CDC_IIR2_GAIN_B4_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_GAIN_B5_CTL			(0x344)
-#define TOMTOM_A_CDC_IIR1_GAIN_B5_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_GAIN_B5_CTL			(0x354)
-#define TOMTOM_A_CDC_IIR2_GAIN_B5_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_GAIN_B6_CTL			(0x345)
-#define TOMTOM_A_CDC_IIR1_GAIN_B6_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_GAIN_B6_CTL			(0x355)
-#define TOMTOM_A_CDC_IIR2_GAIN_B6_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_GAIN_B7_CTL			(0x346)
-#define TOMTOM_A_CDC_IIR1_GAIN_B7_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_GAIN_B7_CTL			(0x356)
-#define TOMTOM_A_CDC_IIR2_GAIN_B7_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_GAIN_B8_CTL			(0x347)
-#define TOMTOM_A_CDC_IIR1_GAIN_B8_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_GAIN_B8_CTL			(0x357)
-#define TOMTOM_A_CDC_IIR2_GAIN_B8_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_CTL			(0x348)
-#define TOMTOM_A_CDC_IIR1_CTL__POR				(0x40)
-#define TOMTOM_A_CDC_IIR2_CTL			(0x358)
-#define TOMTOM_A_CDC_IIR2_CTL__POR				(0x40)
-#define TOMTOM_A_CDC_IIR1_GAIN_TIMER_CTL			(0x349)
-#define TOMTOM_A_CDC_IIR1_GAIN_TIMER_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_GAIN_TIMER_CTL			(0x359)
-#define TOMTOM_A_CDC_IIR2_GAIN_TIMER_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_COEF_B1_CTL			(0x34A)
-#define TOMTOM_A_CDC_IIR1_COEF_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_COEF_B1_CTL			(0x35A)
-#define TOMTOM_A_CDC_IIR2_COEF_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR1_COEF_B2_CTL			(0x34B)
-#define TOMTOM_A_CDC_IIR1_COEF_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_IIR2_COEF_B2_CTL			(0x35B)
-#define TOMTOM_A_CDC_IIR2_COEF_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_TOP_GAIN_UPDATE			(0x360)
-#define TOMTOM_A_CDC_TOP_GAIN_UPDATE__POR				(0x00)
-#define TOMTOM_A_CDC_PA_RAMP_B1_CTL			(0x361)
-#define TOMTOM_A_CDC_PA_RAMP_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_PA_RAMP_B2_CTL			(0x362)
-#define TOMTOM_A_CDC_PA_RAMP_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_PA_RAMP_B3_CTL			(0x363)
-#define TOMTOM_A_CDC_PA_RAMP_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_PA_RAMP_B4_CTL			(0x364)
-#define TOMTOM_A_CDC_PA_RAMP_B4_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_B1_CTL			(0x365)
-#define TOMTOM_A_CDC_SPKR_CLIPDET_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_B1_CTL			(0x366)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_COMP0_B1_CTL			(0x368)
-#define TOMTOM_A_CDC_COMP0_B1_CTL__POR				(0x30)
-#define TOMTOM_A_CDC_COMP1_B1_CTL			(0x370)
-#define TOMTOM_A_CDC_COMP1_B1_CTL__POR				(0x30)
-#define TOMTOM_A_CDC_COMP2_B1_CTL			(0x378)
-#define TOMTOM_A_CDC_COMP2_B1_CTL__POR				(0x30)
-#define TOMTOM_A_CDC_COMP0_B2_CTL			(0x369)
-#define TOMTOM_A_CDC_COMP0_B2_CTL__POR				(0xB5)
-#define TOMTOM_A_CDC_COMP1_B2_CTL			(0x371)
-#define TOMTOM_A_CDC_COMP1_B2_CTL__POR				(0xB5)
-#define TOMTOM_A_CDC_COMP2_B2_CTL			(0x379)
-#define TOMTOM_A_CDC_COMP2_B2_CTL__POR				(0xB5)
-#define TOMTOM_A_CDC_COMP0_B3_CTL			(0x36A)
-#define TOMTOM_A_CDC_COMP0_B3_CTL__POR				(0x28)
-#define TOMTOM_A_CDC_COMP1_B3_CTL			(0x372)
-#define TOMTOM_A_CDC_COMP1_B3_CTL__POR				(0x28)
-#define TOMTOM_A_CDC_COMP2_B3_CTL			(0x37A)
-#define TOMTOM_A_CDC_COMP2_B3_CTL__POR				(0x28)
-#define TOMTOM_A_CDC_COMP0_B4_CTL			(0x36B)
-#define TOMTOM_A_CDC_COMP0_B4_CTL__POR				(0x37)
-#define TOMTOM_A_CDC_COMP1_B4_CTL			(0x373)
-#define TOMTOM_A_CDC_COMP1_B4_CTL__POR				(0x37)
-#define TOMTOM_A_CDC_COMP2_B4_CTL			(0x37B)
-#define TOMTOM_A_CDC_COMP2_B4_CTL__POR				(0x37)
-#define TOMTOM_A_CDC_COMP0_B5_CTL			(0x36C)
-#define TOMTOM_A_CDC_COMP0_B5_CTL__POR				(0x7F)
-#define TOMTOM_A_CDC_COMP1_B5_CTL			(0x374)
-#define TOMTOM_A_CDC_COMP1_B5_CTL__POR				(0x7F)
-#define TOMTOM_A_CDC_COMP2_B5_CTL			(0x37C)
-#define TOMTOM_A_CDC_COMP2_B5_CTL__POR				(0x7F)
-#define TOMTOM_A_CDC_COMP0_B6_CTL			(0x36D)
-#define TOMTOM_A_CDC_COMP0_B6_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_COMP1_B6_CTL			(0x375)
-#define TOMTOM_A_CDC_COMP1_B6_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_COMP2_B6_CTL			(0x37D)
-#define TOMTOM_A_CDC_COMP2_B6_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_COMP0_SHUT_DOWN_STATUS			(0x36E)
-#define TOMTOM_A_CDC_COMP0_SHUT_DOWN_STATUS__POR			(0x03)
-#define TOMTOM_A_CDC_COMP1_SHUT_DOWN_STATUS			(0x376)
-#define TOMTOM_A_CDC_COMP1_SHUT_DOWN_STATUS__POR			(0x03)
-#define TOMTOM_A_CDC_COMP2_SHUT_DOWN_STATUS			(0x37E)
-#define TOMTOM_A_CDC_COMP2_SHUT_DOWN_STATUS__POR			(0x03)
-#define TOMTOM_A_CDC_COMP0_FS_CFG			(0x36F)
-#define TOMTOM_A_CDC_COMP0_FS_CFG__POR				(0x03)
-#define TOMTOM_A_CDC_COMP1_FS_CFG			(0x377)
-#define TOMTOM_A_CDC_COMP1_FS_CFG__POR				(0x03)
-#define TOMTOM_A_CDC_COMP2_FS_CFG			(0x37F)
-#define TOMTOM_A_CDC_COMP2_FS_CFG__POR				(0x03)
-#define TOMTOM_A_CDC_CONN_RX1_B1_CTL			(0x380)
-#define TOMTOM_A_CDC_CONN_RX1_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX1_B2_CTL			(0x381)
-#define TOMTOM_A_CDC_CONN_RX1_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX1_B3_CTL			(0x382)
-#define TOMTOM_A_CDC_CONN_RX1_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX2_B1_CTL			(0x383)
-#define TOMTOM_A_CDC_CONN_RX2_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX2_B2_CTL			(0x384)
-#define TOMTOM_A_CDC_CONN_RX2_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX2_B3_CTL			(0x385)
-#define TOMTOM_A_CDC_CONN_RX2_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX3_B1_CTL			(0x386)
-#define TOMTOM_A_CDC_CONN_RX3_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX3_B2_CTL			(0x387)
-#define TOMTOM_A_CDC_CONN_RX3_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX4_B1_CTL			(0x388)
-#define TOMTOM_A_CDC_CONN_RX4_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX4_B2_CTL			(0x389)
-#define TOMTOM_A_CDC_CONN_RX4_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX5_B1_CTL			(0x38A)
-#define TOMTOM_A_CDC_CONN_RX5_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX5_B2_CTL			(0x38B)
-#define TOMTOM_A_CDC_CONN_RX5_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX6_B1_CTL			(0x38C)
-#define TOMTOM_A_CDC_CONN_RX6_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX6_B2_CTL			(0x38D)
-#define TOMTOM_A_CDC_CONN_RX6_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX7_B1_CTL			(0x38E)
-#define TOMTOM_A_CDC_CONN_RX7_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX7_B2_CTL			(0x38F)
-#define TOMTOM_A_CDC_CONN_RX7_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX7_B3_CTL			(0x390)
-#define TOMTOM_A_CDC_CONN_RX7_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_ANC_B1_CTL			(0x391)
-#define TOMTOM_A_CDC_CONN_ANC_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_ANC_B2_CTL			(0x392)
-#define TOMTOM_A_CDC_CONN_ANC_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_B1_CTL			(0x393)
-#define TOMTOM_A_CDC_CONN_TX_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_B2_CTL			(0x394)
-#define TOMTOM_A_CDC_CONN_TX_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_B3_CTL			(0x395)
-#define TOMTOM_A_CDC_CONN_TX_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_B4_CTL			(0x396)
-#define TOMTOM_A_CDC_CONN_TX_B4_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_EQ1_B1_CTL			(0x397)
-#define TOMTOM_A_CDC_CONN_EQ1_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_EQ1_B2_CTL			(0x398)
-#define TOMTOM_A_CDC_CONN_EQ1_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_EQ1_B3_CTL			(0x399)
-#define TOMTOM_A_CDC_CONN_EQ1_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_EQ1_B4_CTL			(0x39A)
-#define TOMTOM_A_CDC_CONN_EQ1_B4_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_EQ2_B1_CTL			(0x39B)
-#define TOMTOM_A_CDC_CONN_EQ2_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_EQ2_B2_CTL			(0x39C)
-#define TOMTOM_A_CDC_CONN_EQ2_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_EQ2_B3_CTL			(0x39D)
-#define TOMTOM_A_CDC_CONN_EQ2_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_EQ2_B4_CTL			(0x39E)
-#define TOMTOM_A_CDC_CONN_EQ2_B4_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_SRC1_B1_CTL			(0x39F)
-#define TOMTOM_A_CDC_CONN_SRC1_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_SRC1_B2_CTL			(0x3A0)
-#define TOMTOM_A_CDC_CONN_SRC1_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_SRC2_B1_CTL			(0x3A1)
-#define TOMTOM_A_CDC_CONN_SRC2_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_SRC2_B2_CTL			(0x3A2)
-#define TOMTOM_A_CDC_CONN_SRC2_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B1_CTL			(0x3A3)
-#define TOMTOM_A_CDC_CONN_TX_SB_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B2_CTL			(0x3A4)
-#define TOMTOM_A_CDC_CONN_TX_SB_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B3_CTL			(0x3A5)
-#define TOMTOM_A_CDC_CONN_TX_SB_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B4_CTL			(0x3A6)
-#define TOMTOM_A_CDC_CONN_TX_SB_B4_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B5_CTL			(0x3A7)
-#define TOMTOM_A_CDC_CONN_TX_SB_B5_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B6_CTL			(0x3A8)
-#define TOMTOM_A_CDC_CONN_TX_SB_B6_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B7_CTL			(0x3A9)
-#define TOMTOM_A_CDC_CONN_TX_SB_B7_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B8_CTL			(0x3AA)
-#define TOMTOM_A_CDC_CONN_TX_SB_B8_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B9_CTL			(0x3AB)
-#define TOMTOM_A_CDC_CONN_TX_SB_B9_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B10_CTL			(0x3AC)
-#define TOMTOM_A_CDC_CONN_TX_SB_B10_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_TX_SB_B11_CTL			(0x3AD)
-#define TOMTOM_A_CDC_CONN_TX_SB_B11_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX_SB_B1_CTL			(0x3AE)
-#define TOMTOM_A_CDC_CONN_RX_SB_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_RX_SB_B2_CTL			(0x3AF)
-#define TOMTOM_A_CDC_CONN_RX_SB_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_CLSH_CTL			(0x3B0)
-#define TOMTOM_A_CDC_CONN_CLSH_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CONN_MISC			(0x3B1)
-#define TOMTOM_A_CDC_CONN_MISC__POR				(0x01)
-#define TOMTOM_A_CDC_CONN_RX8_B1_CTL			(0x3B3)
-#define TOMTOM_A_CDC_CONN_RX8_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_B1_CTL		(0x3B4)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_B1_CTL__POR				(0x81)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_CLIP_LEVEL_ADJUST	(0x3B5)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_CLIP_LEVEL_ADJUST__POR		(0x00)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_MIN_CLIP_THRESHOLD	(0x3B6)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_MIN_CLIP_THRESHOLD__POR		(0xFF)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_THRESHOLD_STATUS	(0x3B7)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_THRESHOLD_STATUS__POR		(0x00)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_SAMPLE_MARK		(0x3B8)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_SAMPLE_MARK__POR			(0x04)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_BOOST_GATING		(0x3B9)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR_BOOST_GATING__POR			(0x04)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_B1_CTL		(0x3BA)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_B1_CTL__POR				(0x81)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_CLIP_LEVEL_ADJUST	(0x3BB)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_CLIP_LEVEL_ADJUST__POR		(0x00)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_MIN_CLIP_THRESHOLD	(0x3BC)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_MIN_CLIP_THRESHOLD__POR		(0xFF)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_THRESHOLD_STATUS	(0x3BD)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_THRESHOLD_STATUS__POR		(0x00)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_SAMPLE_MARK		(0x3BE)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_SAMPLE_MARK__POR			(0x04)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_BOOST_GATING	(0x3BF)
-#define TOMTOM_A_CDC_CLIP_ADJ_SPKR2_BOOST_GATING__POR			(0x04)
-#define TOMTOM_A_CDC_MBHC_EN_CTL			(0x3C0)
-#define TOMTOM_A_CDC_MBHC_EN_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_FIR_B1_CFG			(0x3C1)
-#define TOMTOM_A_CDC_MBHC_FIR_B1_CFG__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_FIR_B2_CFG			(0x3C2)
-#define TOMTOM_A_CDC_MBHC_FIR_B2_CFG__POR				(0x06)
-#define TOMTOM_A_CDC_MBHC_TIMER_B1_CTL			(0x3C3)
-#define TOMTOM_A_CDC_MBHC_TIMER_B1_CTL__POR				(0x03)
-#define TOMTOM_A_CDC_MBHC_TIMER_B2_CTL			(0x3C4)
-#define TOMTOM_A_CDC_MBHC_TIMER_B2_CTL__POR				(0x09)
-#define TOMTOM_A_CDC_MBHC_TIMER_B3_CTL			(0x3C5)
-#define TOMTOM_A_CDC_MBHC_TIMER_B3_CTL__POR				(0x1E)
-#define TOMTOM_A_CDC_MBHC_TIMER_B4_CTL			(0x3C6)
-#define TOMTOM_A_CDC_MBHC_TIMER_B4_CTL__POR				(0x45)
-#define TOMTOM_A_CDC_MBHC_TIMER_B5_CTL			(0x3C7)
-#define TOMTOM_A_CDC_MBHC_TIMER_B5_CTL__POR				(0x04)
-#define TOMTOM_A_CDC_MBHC_TIMER_B6_CTL			(0x3C8)
-#define TOMTOM_A_CDC_MBHC_TIMER_B6_CTL__POR				(0x78)
-#define TOMTOM_A_CDC_MBHC_B1_STATUS			(0x3C9)
-#define TOMTOM_A_CDC_MBHC_B1_STATUS__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_B2_STATUS			(0x3CA)
-#define TOMTOM_A_CDC_MBHC_B2_STATUS__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_B3_STATUS			(0x3CB)
-#define TOMTOM_A_CDC_MBHC_B3_STATUS__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_B4_STATUS			(0x3CC)
-#define TOMTOM_A_CDC_MBHC_B4_STATUS__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_B5_STATUS			(0x3CD)
-#define TOMTOM_A_CDC_MBHC_B5_STATUS__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_B1_CTL			(0x3CE)
-#define TOMTOM_A_CDC_MBHC_B1_CTL__POR				(0xC0)
-#define TOMTOM_A_CDC_MBHC_B2_CTL			(0x3CF)
-#define TOMTOM_A_CDC_MBHC_B2_CTL__POR				(0x5D)
-#define TOMTOM_A_CDC_MBHC_VOLT_B1_CTL			(0x3D0)
-#define TOMTOM_A_CDC_MBHC_VOLT_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_VOLT_B2_CTL			(0x3D1)
-#define TOMTOM_A_CDC_MBHC_VOLT_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_VOLT_B3_CTL			(0x3D2)
-#define TOMTOM_A_CDC_MBHC_VOLT_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_VOLT_B4_CTL			(0x3D3)
-#define TOMTOM_A_CDC_MBHC_VOLT_B4_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_VOLT_B5_CTL			(0x3D4)
-#define TOMTOM_A_CDC_MBHC_VOLT_B5_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_VOLT_B6_CTL			(0x3D5)
-#define TOMTOM_A_CDC_MBHC_VOLT_B6_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_VOLT_B7_CTL			(0x3D6)
-#define TOMTOM_A_CDC_MBHC_VOLT_B7_CTL__POR				(0xFF)
-#define TOMTOM_A_CDC_MBHC_VOLT_B8_CTL			(0x3D7)
-#define TOMTOM_A_CDC_MBHC_VOLT_B8_CTL__POR				(0x07)
-#define TOMTOM_A_CDC_MBHC_VOLT_B9_CTL			(0x3D8)
-#define TOMTOM_A_CDC_MBHC_VOLT_B9_CTL__POR				(0xFF)
-#define TOMTOM_A_CDC_MBHC_VOLT_B10_CTL			(0x3D9)
-#define TOMTOM_A_CDC_MBHC_VOLT_B10_CTL__POR				(0x7F)
-#define TOMTOM_A_CDC_MBHC_VOLT_B11_CTL			(0x3DA)
-#define TOMTOM_A_CDC_MBHC_VOLT_B11_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_VOLT_B12_CTL			(0x3DB)
-#define TOMTOM_A_CDC_MBHC_VOLT_B12_CTL__POR				(0x80)
-#define TOMTOM_A_CDC_MBHC_CLK_CTL			(0x3DC)
-#define TOMTOM_A_CDC_MBHC_CLK_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_INT_CTL			(0x3DD)
-#define TOMTOM_A_CDC_MBHC_INT_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_DEBUG_CTL			(0x3DE)
-#define TOMTOM_A_CDC_MBHC_DEBUG_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_MBHC_SPARE			(0x3DF)
-#define TOMTOM_A_CDC_MBHC_SPARE__POR				(0x00)
-#define TOMTOM_A_CDC_RX8_B1_CTL			(0x3E0)
-#define TOMTOM_A_CDC_RX8_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX8_B2_CTL			(0x3E1)
-#define TOMTOM_A_CDC_RX8_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX8_B3_CTL			(0x3E2)
-#define TOMTOM_A_CDC_RX8_B3_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX8_B4_CTL			(0x3E3)
-#define TOMTOM_A_CDC_RX8_B4_CTL__POR				(0x0B)
-#define TOMTOM_A_CDC_RX8_B5_CTL			(0x3E4)
-#define TOMTOM_A_CDC_RX8_B5_CTL__POR				(0x78)
-#define TOMTOM_A_CDC_RX8_B6_CTL			(0x3E5)
-#define TOMTOM_A_CDC_RX8_B6_CTL__POR				(0x80)
-#define TOMTOM_A_CDC_RX8_VOL_CTL_B1_CTL			(0x3E6)
-#define TOMTOM_A_CDC_RX8_VOL_CTL_B1_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL			(0x3E7)
-#define TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL0			(0x3E8)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL0__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL1			(0x3E9)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL1__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL2			(0x3EA)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL2__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL3			(0x3EB)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL3__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL4			(0x3EC)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL4__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL5			(0x3ED)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL5__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL6			(0x3EE)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL6__POR				(0x00)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL7			(0x3EF)
-#define TOMTOM_A_CDC_SPKR2_CLIPDET_VAL7__POR				(0x00)
-#define TOMTOM_A_CDC_BOOST_MODE_CTL			(0x3F0)
-#define TOMTOM_A_CDC_BOOST_MODE_CTL__POR				(0x00)
-#define TOMTOM_A_CDC_BOOST_THRESHOLD			(0x3F1)
-#define TOMTOM_A_CDC_BOOST_THRESHOLD__POR				(0x02)
-#define TOMTOM_A_CDC_BOOST_TAP_SEL			(0x3F2)
-#define TOMTOM_A_CDC_BOOST_TAP_SEL__POR				(0x00)
-#define TOMTOM_A_CDC_BOOST_HOLD_TIME			(0x3F3)
-#define TOMTOM_A_CDC_BOOST_HOLD_TIME__POR				(0x02)
-#define TOMTOM_A_CDC_BOOST_TRGR_EN			(0x3F4)
-#define TOMTOM_A_CDC_BOOST_TRGR_EN__POR				(0x00)
-
-/* SLIMBUS Slave Registers */
-#define TOMTOM_SLIM_PGD_PORT_INT_EN0                     (0x30)
-#define TOMTOM_SLIM_PGD_PORT_INT_STATUS_RX_0             (0x34)
-#define TOMTOM_SLIM_PGD_PORT_INT_STATUS_RX_1             (0x35)
-#define TOMTOM_SLIM_PGD_PORT_INT_STATUS_TX_0             (0x36)
-#define TOMTOM_SLIM_PGD_PORT_INT_STATUS_TX_1             (0x37)
-#define TOMTOM_SLIM_PGD_PORT_INT_CLR_RX_0                (0x38)
-#define TOMTOM_SLIM_PGD_PORT_INT_CLR_RX_1                (0x39)
-#define TOMTOM_SLIM_PGD_PORT_INT_CLR_TX_0                (0x3A)
-#define TOMTOM_SLIM_PGD_PORT_INT_CLR_TX_1                (0x3B)
-#define TOMTOM_SLIM_PGD_PORT_INT_RX_SOURCE0		(0x60)
-#define TOMTOM_SLIM_PGD_PORT_INT_TX_SOURCE0		(0x70)
-
-/* Macros for Packing Register Writes into a U32 */
-#define TOMTOM_PACKED_REG_SIZE sizeof(u32)
-
-#define TOMTOM_CODEC_PACK_ENTRY(reg, mask, val) ((val & 0xff)|\
-	((mask & 0xff) << 8)|((reg & 0xffff) << 16))
-#define TOMTOM_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \
-	do { \
-		((reg) = ((packed >> 16) & (0xffff))); \
-		((mask) = ((packed >> 8) & (0xff))); \
-		((val) = ((packed) & (0xff))); \
-	} while (0)
-
-#define TOMTOM_SB_PGD_PORT_TX_BASE    0x50
-#define TOMTOM_SB_PGD_PORT_RX_BASE    0x40
-#define WCD9330_MAX_REGISTER 0x3FF
-extern const u8 tomtom_reg_readable[WCD9330_MAX_REGISTER + 1];
-#endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-irq.h b/include/linux/mfd/wcd9xxx/wcd9xxx-irq.h
index 1e428a1..99ce603 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx-irq.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-irq.h
@@ -32,4 +32,6 @@
 
 int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res);
 void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res);
+int wcd9xxx_irq_drv_init(void);
+void wcd9xxx_irq_drv_exit(void);
 #endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h b/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h
index d0ac0ac..7a13dd1 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h
@@ -33,108 +33,8 @@
 typedef int (*codec_type_fn)(struct wcd9xxx *,
 			     struct wcd9xxx_codec_type *);
 
-#ifdef CONFIG_WCD934X_CODEC
-extern int wcd934x_bringup(struct wcd9xxx *wcd9xxx);
-extern int wcd934x_bringdown(struct wcd9xxx *wcd9xxx);
-extern int wcd934x_get_codec_info(struct wcd9xxx *wcd9xxx,
-				  struct wcd9xxx_codec_type *wcd_type);
-#endif
+codec_bringdown_fn wcd9xxx_bringdown_fn(int type);
+codec_bringup_fn wcd9xxx_bringup_fn(int type);
+codec_type_fn wcd9xxx_get_codec_info_fn(int type);
 
-#ifdef CONFIG_WCD9335_CODEC
-extern int wcd9335_bringup(struct wcd9xxx *wcd9xxx);
-extern int wcd9335_bringdown(struct wcd9xxx *wcd9xxx);
-extern int wcd9335_get_codec_info(struct wcd9xxx *wcd9xxx,
-				  struct wcd9xxx_codec_type *wcd_type);
-#endif
-
-#ifdef CONFIG_WCD9330_CODEC
-extern int wcd9330_bringup(struct wcd9xxx *wcd9xxx);
-extern int wcd9330_bringdown(struct wcd9xxx *wcd9xxx);
-extern int wcd9330_get_codec_info(struct wcd9xxx *wcd9xxx,
-				  struct wcd9xxx_codec_type *wcd_type);
-#endif
-
-static inline codec_bringdown_fn wcd9xxx_bringdown_fn(int type)
-{
-	codec_bringdown_fn cdc_bdown_fn;
-
-	switch (type) {
-#ifdef CONFIG_WCD934X_CODEC
-	case WCD934X:
-		cdc_bdown_fn = wcd934x_bringdown;
-		break;
-#endif
-#ifdef CONFIG_WCD9335_CODEC
-	case WCD9335:
-		cdc_bdown_fn = wcd9335_bringdown;
-		break;
-#endif
-#ifdef CONFIG_WCD9330_CODEC
-	case WCD9330:
-		cdc_bdown_fn = wcd9330_bringdown;
-		break;
-#endif
-	default:
-		cdc_bdown_fn = NULL;
-		break;
-	}
-
-	return cdc_bdown_fn;
-}
-
-static inline codec_bringup_fn wcd9xxx_bringup_fn(int type)
-{
-	codec_bringup_fn cdc_bup_fn;
-
-	switch (type) {
-#ifdef CONFIG_WCD934X_CODEC
-	case WCD934X:
-		cdc_bup_fn = wcd934x_bringup;
-		break;
-#endif
-#ifdef CONFIG_WCD9335_CODEC
-	case WCD9335:
-		cdc_bup_fn = wcd9335_bringup;
-		break;
-#endif
-#ifdef CONFIG_WCD9330_CODEC
-	case WCD9330:
-		cdc_bup_fn = wcd9330_bringup;
-		break;
-#endif
-	default:
-		cdc_bup_fn = NULL;
-		break;
-	}
-
-	return cdc_bup_fn;
-}
-
-static inline codec_type_fn wcd9xxx_get_codec_info_fn(int type)
-{
-	codec_type_fn cdc_type_fn;
-
-	switch (type) {
-#ifdef CONFIG_WCD934X_CODEC
-	case WCD934X:
-		cdc_type_fn = wcd934x_get_codec_info;
-		break;
-#endif
-#ifdef CONFIG_WCD9335_CODEC
-	case WCD9335:
-		cdc_type_fn = wcd9335_get_codec_info;
-		break;
-#endif
-#ifdef CONFIG_WCD9330_CODEC
-	case WCD9330:
-		cdc_type_fn = wcd9330_get_codec_info;
-		break;
-#endif
-	default:
-		cdc_type_fn = NULL;
-		break;
-	}
-
-	return cdc_type_fn;
-}
 #endif
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 227b1e2..0f2e651 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -214,6 +214,7 @@
 
 extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
 extern void mmc_release_host(struct mmc_host *host);
+extern int mmc_try_claim_host(struct mmc_host *host, unsigned int delay);
 
 extern void mmc_get_card(struct mmc_card *card);
 extern void mmc_put_card(struct mmc_card *card);
@@ -232,7 +233,6 @@
 	bool lock_needed);
 extern void mmc_cmdq_clk_scaling_stop_busy(struct mmc_host *host,
 	bool lock_needed, bool is_cmdq_dcmd);
-extern void mmc_recovery_fallback_lower_speed(struct mmc_host *host);
 
 /**
  *	mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2f943a0..9200069 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -559,6 +559,8 @@
 
 	struct dentry		*debugfs_root;
 
+	bool			err_occurred;
+
 	struct mmc_async_req	*areq;		/* active async req */
 	struct mmc_context_info	context_info;	/* async synchronization info */
 
@@ -855,6 +857,8 @@
 	return card->host->ios.enhanced_strobe;
 }
 
+void mmc_retune_enable(struct mmc_host *host);
+void mmc_retune_disable(struct mmc_host *host);
 void mmc_retune_timer_stop(struct mmc_host *host);
 
 static inline void mmc_retune_needed(struct mmc_host *host)
diff --git a/include/linux/msm-sps.h b/include/linux/msm-sps.h
index 4a9b8a8..662cd9f 100644
--- a/include/linux/msm-sps.h
+++ b/include/linux/msm-sps.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2017, 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
@@ -430,7 +430,7 @@
 
 	u32 options;
 	phys_addr_t phys_addr;
-	void *virt_addr;
+	void __iomem *virt_addr;
 	u32 virt_size;
 	u32 irq;
 	u32 num_pipes;
diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h
index 0c460a0..ebca446 100644
--- a/include/linux/msm_gsi.h
+++ b/include/linux/msm_gsi.h
@@ -752,6 +752,18 @@
 		uint32_t *db_addr_wp_lsb, uint32_t *db_addr_wp_msb);
 
 /**
+ * gsi_ring_evt_ring_db - Peripheral should call this function for
+ * ringing the event ring doorbell with given value
+ *
+ * @evt_ring_hdl:    Client handle previously obtained from
+ *	     gsi_alloc_evt_ring
+ * @value:           The value to be used for ringing the doorbell
+ *
+ * @Return gsi_status
+ */
+int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl, uint64_t value);
+
+/**
  * gsi_reset_evt_ring - Peripheral should call this function to
  * reset an event ring to recover from error state
  *
@@ -1142,6 +1154,12 @@
 	return -GSI_STATUS_UNSUPPORTED_OP;
 }
 
+static inline int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl,
+		uint64_t value)
+{
+	return -GSI_STATUS_UNSUPPORTED_OP;
+}
+
 static inline int gsi_reset_evt_ring(unsigned long evt_ring_hdl)
 {
 	return -GSI_STATUS_UNSUPPORTED_OP;
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index 70736e1..33a95d2 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -37,7 +37,7 @@
  */
 
 struct mtd_partition {
-	const char *name;		/* identifier string */
+	char *name;			/* identifier string */
 	uint64_t size;			/* partition size */
 	uint64_t offset;		/* offset within the master MTD space */
 	uint32_t mask_flags;		/* master MTD flags to mask out for this partition */
@@ -97,7 +97,7 @@
 		      deregister_mtd_parser)
 
 int mtd_is_partition(const struct mtd_info *mtd);
-int mtd_add_partition(struct mtd_info *master, const char *name,
+int mtd_add_partition(struct mtd_info *master, char *name,
 		      long long offset, long long length);
 int mtd_del_partition(struct mtd_info *master, int partno);
 uint64_t mtd_get_device_size(const struct mtd_info *mtd);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a47c29e..a9dcd27 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2831,6 +2831,8 @@
 	unsigned int		processed;
 	unsigned int		time_squeeze;
 	unsigned int		received_rps;
+	unsigned int            gro_coalesced;
+
 #ifdef CONFIG_RPS
 	struct softnet_data	*rps_ipi_list;
 #endif
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 72f9211..4381570 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -248,6 +248,7 @@
 	POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
 	POWER_SUPPLY_PROP_HW_CURRENT_MAX,
 	POWER_SUPPLY_PROP_REAL_TYPE,
+	POWER_SUPPLY_PROP_PR_SWAP,
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
 	/* Properties of type `const char *' */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index e0e5393..d53a231 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -53,7 +53,8 @@
 			  unsigned long addr, unsigned long data);
 extern void ptrace_notify(int exit_code);
 extern void __ptrace_link(struct task_struct *child,
-			  struct task_struct *new_parent);
+			  struct task_struct *new_parent,
+			  const struct cred *ptracer_cred);
 extern void __ptrace_unlink(struct task_struct *child);
 extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
 #define PTRACE_MODE_READ	0x01
@@ -205,7 +206,7 @@
 
 	if (unlikely(ptrace) && current->ptrace) {
 		child->ptrace = current->ptrace;
-		__ptrace_link(child, current->parent);
+		__ptrace_link(child, current->parent, current->ptracer_cred);
 
 		if (child->ptrace & PT_SEIZED)
 			task_set_jobctl_pending(child, JOBCTL_TRAP_STOP);
@@ -214,6 +215,8 @@
 
 		set_tsk_thread_flag(child, TIF_SIGPENDING);
 	}
+	else
+		child->ptracer_cred = NULL;
 }
 
 /**
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index 5947107..6c9ddcd 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -565,6 +565,41 @@
 			   unsigned long ab, unsigned long ib);
 
 /**
+ * geni_se_clk_tbl_get() - Get the clock table to program DFS
+ * @rsc:	Resource for which the clock table is requested.
+ * @tbl:	Table in which the output is returned.
+ *
+ * This function is called by the protocol drivers to determine the different
+ * clock frequencies supported by Serail Engine Core Clock. The protocol
+ * drivers use the output to determine the clock frequency index to be
+ * programmed into DFS.
+ *
+ * Return:	number of valid performance levels in the table on success,
+ *		standard Linux error codes on failure.
+ */
+int geni_se_clk_tbl_get(struct se_geni_rsc *rsc, unsigned long **tbl);
+
+/**
+ * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency
+ * @rsc:	Resource for which the clock frequency is requested.
+ * @req_freq:	Requested clock frequency.
+ * @index:	Index of the resultant frequency in the table.
+ * @res_freq:	Resultant frequency which matches or is closer to the
+ *		requested frequency.
+ * @exact:	Flag to indicate exact multiple requirement of the requested
+ *		frequency .
+ *
+ * This function is called by the protocol drivers to determine the matching
+ * or closest frequency of the Serial Engine clock to be selected in order
+ * to meet the performance requirements.
+ *
+ * Return:	0 on success, standard Linux error codes on failure.
+ */
+int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq,
+			   unsigned int *index, unsigned long *res_freq,
+			   bool exact);
+
+/**
  * geni_se_tx_dma_prep() - Prepare the Serial Engine for TX DMA transfer
  * @wrapper_dev:	QUPv3 Wrapper Device to which the TX buffer is mapped.
  * @base:		Base address of the SE register block.
@@ -796,6 +831,19 @@
 	return -ENXIO;
 }
 
+static inline int geni_se_clk_tbl_get(struct se_geni_rsc *rsc,
+					unsigned long **tbl)
+{
+	return -ENXIO;
+}
+
+static inline int geni_se_clk_freq_match(struct se_geni_rsc *rsc,
+			unsigned long req_freq, unsigned int *index,
+			unsigned long *res_freq, bool exact)
+{
+	return -ENXIO;
+}
+
 static inline int geni_se_tx_dma_prep(struct device *wrapper_dev,
 	void __iomem *base, void *tx_buf, int tx_len, dma_addr_t *tx_dma)
 {
diff --git a/include/linux/qcom_tspp.h b/include/linux/qcom_tspp.h
new file mode 100644
index 0000000..1b34c38
--- /dev/null
+++ b/include/linux/qcom_tspp.h
@@ -0,0 +1,108 @@
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_TSPP_H_
+#define _MSM_TSPP_H_
+
+struct tspp_data_descriptor {
+	void *virt_base;   /* logical address of the actual data */
+	phys_addr_t phys_base; /* physical address of the actual data */
+	u32 size;          /* size of buffer in bytes */
+	int id;            /* unique identifier */
+	void *user;        /* user-defined data */
+};
+
+enum tspp_key_parity {
+	TSPP_KEY_PARITY_EVEN,
+	TSPP_KEY_PARITY_ODD
+};
+
+struct tspp_key {
+	enum tspp_key_parity parity;
+	int lsb;
+	int msb;
+};
+
+enum tspp_source {
+	TSPP_SOURCE_TSIF0,
+	TSPP_SOURCE_TSIF1,
+	TSPP_SOURCE_MEM,
+	TSPP_SOURCE_NONE = -1
+};
+
+enum tspp_mode {
+	TSPP_MODE_DISABLED,
+	TSPP_MODE_PES,
+	TSPP_MODE_RAW,
+	TSPP_MODE_RAW_NO_SUFFIX
+};
+
+enum tspp_tsif_mode {
+	TSPP_TSIF_MODE_LOOPBACK, /* loopback mode */
+	TSPP_TSIF_MODE_1,        /* without sync */
+	TSPP_TSIF_MODE_2         /* with sync signal */
+};
+
+struct tspp_filter {
+	int pid;
+	int mask;
+	enum tspp_mode mode;
+	unsigned int priority;	/* 0 - 15 */
+	int decrypt;
+	enum tspp_source source;
+};
+
+struct tspp_select_source {
+	enum tspp_source source;
+	enum tspp_tsif_mode mode;
+	int clk_inverse;
+	int data_inverse;
+	int sync_inverse;
+	int enable_inverse;
+};
+
+enum tsif_tts_source {
+	TSIF_TTS_TCR = 0,	/* Time stamps from TCR counter */
+	TSIF_TTS_LPASS_TIMER	/* Time stamps from AV/Qtimer Timer  */
+};
+
+typedef void (tspp_notifier)(int channel_id, void *user);
+typedef void* (tspp_allocator)(int channel_id, u32 size,
+	phys_addr_t *phys_base, void *user);
+typedef void (tspp_memfree)(int channel_id, u32 size,
+	void *virt_base, phys_addr_t phys_base, void *user);
+
+/* Kernel API functions */
+int tspp_open_stream(u32 dev, u32 channel_id,
+			struct tspp_select_source *source);
+int tspp_close_stream(u32 dev, u32 channel_id);
+int tspp_open_channel(u32 dev, u32 channel_id);
+int tspp_close_channel(u32 dev, u32 channel_id);
+int tspp_get_ref_clk_counter(u32 dev,
+	enum tspp_source source, u32 *tcr_counter);
+int tspp_add_filter(u32 dev, u32 channel_id, struct tspp_filter *filter);
+int tspp_remove_filter(u32 dev, u32 channel_id,	struct tspp_filter *filter);
+int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key);
+int tspp_register_notification(u32 dev, u32 channel_id, tspp_notifier *notify,
+	void *data, u32 timer_ms);
+int tspp_unregister_notification(u32 dev, u32 channel_id);
+const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id);
+int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id);
+int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count,
+	u32 size, u32 int_freq, tspp_allocator *alloc,
+	tspp_memfree *memfree, void *user);
+
+int tspp_get_tts_source(u32 dev, int *tts_source);
+int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source,
+			u64 *lpass_time_counter);
+
+#endif /* _MSM_TSPP_H_ */
diff --git a/include/linux/qcrypto.h b/include/linux/qcrypto.h
index 252464a..ff0e64c 100644
--- a/include/linux/qcrypto.h
+++ b/include/linux/qcrypto.h
@@ -15,6 +15,7 @@
 
 #include <linux/crypto.h>
 #include <crypto/hash.h>
+#include <crypto/skcipher.h>
 
 #define QCRYPTO_CTX_KEY_MASK		0x000000ff
 #define QCRYPTO_CTX_USE_HW_KEY		0x00000001
@@ -29,7 +30,7 @@
 int qcrypto_ahash_set_device(struct ahash_request *req, unsigned int dev);
 /*int qcrypto_aead_set_device(struct aead_request *req, unsigned int dev);*/
 
-int qcrypto_cipher_set_flag(struct ablkcipher_request *req, unsigned int flags);
+int qcrypto_cipher_set_flag(struct skcipher_request *req, unsigned int flags);
 int qcrypto_ahash_set_flag(struct ahash_request *req, unsigned int flags);
 /*int qcrypto_aead_set_flag(struct aead_request *req, unsigned int flags);*/
 
@@ -47,16 +48,16 @@
 int qcrypto_get_num_engines(void);
 void qcrypto_get_engine_list(size_t num_engines,
 				struct crypto_engine_entry *arr);
-int qcrypto_cipher_set_device_hw(struct ablkcipher_request *req,
+int qcrypto_cipher_set_device_hw(struct skcipher_request *req,
 				unsigned int fde_pfe,
 				unsigned int hw_inst);
 
 
 struct qcrypto_func_set {
-	int (*cipher_set)(struct ablkcipher_request *req,
+	int (*cipher_set)(struct skcipher_request *req,
 			unsigned int fde_pfe,
 			unsigned int hw_inst);
-	int (*cipher_flag)(struct ablkcipher_request *req, unsigned int flags);
+	int (*cipher_flag)(struct skcipher_request *req, unsigned int flags);
 	int (*get_num_engines)(void);
 	void (*get_engine_list)(size_t num_engines,
 				struct crypto_engine_entry *arr);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 6c6ae4d..9e7ab05 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1155,8 +1155,9 @@
 extern int sched_domain_level_max;
 
 struct capacity_state {
-	unsigned long cap;	/* compute capacity */
-	unsigned long power;	/* power consumption at this compute capacity */
+	unsigned long cap;	/* capacity - calculated by energy driver */
+	unsigned long frequency;/* frequency */
+	unsigned long power;	/* power consumption at this frequency */
 };
 
 struct idle_state {
@@ -2637,7 +2638,6 @@
 #define MAX_NUM_CGROUP_COLOC_ID	20
 
 #ifdef CONFIG_SCHED_HMP
-extern void free_task_load_ptrs(struct task_struct *p);
 extern int sched_set_window(u64 window_start, unsigned int window_size);
 extern unsigned long sched_get_busy(int cpu);
 extern void sched_get_cpus_busy(struct sched_load *busy,
@@ -2661,8 +2661,6 @@
 extern unsigned int sched_get_group_id(struct task_struct *p);
 
 #else /* CONFIG_SCHED_HMP */
-static inline void free_task_load_ptrs(struct task_struct *p) { }
-
 static inline int sched_set_window(u64 window_start, unsigned int window_size)
 {
 	return -EINVAL;
@@ -2700,6 +2698,7 @@
 extern void sched_update_cpu_freq_min_max(const cpumask_t *cpus, u32 fmin,
 					  u32 fmax);
 extern int sched_set_boost(int enable);
+extern void free_task_load_ptrs(struct task_struct *p);
 #else
 static inline int
 register_cpu_cycle_counter_cb(struct cpu_cycle_counter_cb *cb)
@@ -2712,6 +2711,7 @@
 {
 	return -EINVAL;
 }
+static inline void free_task_load_ptrs(struct task_struct *p) { }
 #endif /* CONFIG_SCHED_WALT */
 
 #ifndef CONFIG_SCHED_WALT
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
index f921909..1450caa 100644
--- a/include/linux/sde_rsc.h
+++ b/include/linux/sde_rsc.h
@@ -179,13 +179,14 @@
  * sde_rsc_client_vote() - ab/ib vote from rsc client
  *
  * @client:	 Client pointer provided by sde_rsc_client_create().
+ * @bus_id:	 data bus identifier
  * @ab:		 aggregated bandwidth vote from client.
  * @ib:		 instant bandwidth vote from client.
  *
  * Return: error code.
  */
 int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
-	u64 ab_vote, u64 ib_vote);
+	u32 bus_id, u64 ab_vote, u64 ib_vote);
 
 /**
  * sde_rsc_register_event - register a callback function for an event
@@ -243,7 +244,7 @@
 }
 
 static inline int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
-	u64 ab_vote, u64 ib_vote)
+	u32 bus_id, u64 ab_vote, u64 ib_vote)
 {
 	return 0;
 }
diff --git a/include/linux/soundwire/soundwire.h b/include/linux/soundwire/soundwire.h
index 752a001..a60d78c 100644
--- a/include/linux/soundwire/soundwire.h
+++ b/include/linux/soundwire/soundwire.h
@@ -196,7 +196,6 @@
  * @shutdown: standard shutdown callback used during power down/halt
  * @suspend: standard suspend callback used during system suspend
  * @resume: standard resume callback used during system resume
- * @startup: additional init operation for slave devices
  * @driver: soundwire device drivers should initialize name and
  * owner field of this structure
  * @id_table: list of soundwire devices supported by this driver
@@ -210,7 +209,6 @@
 	int	(*device_up)(struct swr_device *swr);
 	int	(*device_down)(struct swr_device *swr);
 	int	(*reset_device)(struct swr_device *swr);
-	int	(*startup)(struct swr_device *swr);
 	struct device_driver		driver;
 	const struct swr_device_id	*id_table;
 };
@@ -309,4 +307,6 @@
 extern int swr_slvdev_datapath_control(struct swr_device *swr_dev, u8 dev_num,
 				       bool enable);
 extern int swr_remove_from_group(struct swr_device *dev, u8 dev_num);
+
+extern void swr_remove_device(struct swr_device *swr_dev);
 #endif /* _LINUX_SOUNDWIRE_H */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 9b0d5cb..6e49b86 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -40,6 +40,9 @@
 /* No upper/lower limit requirement */
 #define THERMAL_NO_LIMIT	((u32)~0)
 
+/* upper limit requirement */
+#define THERMAL_MAX_LIMIT	(THERMAL_NO_LIMIT - 1)
+
 /* Default weight of a bound cooling device */
 #define THERMAL_WEIGHT_DEFAULT 0
 
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index fd09a1b..ddd8f4d 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -58,7 +58,7 @@
 	GSI_EP_OP_STORE_DBL_INFO,
 	GSI_EP_OP_ENABLE_GSI,
 	GSI_EP_OP_UPDATEXFER,
-	GSI_EP_OP_RING_IN_DB,
+	GSI_EP_OP_RING_DB,
 	GSI_EP_OP_ENDXFER,
 	GSI_EP_OP_GET_CH_INFO,
 	GSI_EP_OP_GET_XFER_IDX,
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 8053c8a..623b6f0 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -20,7 +20,7 @@
 #include <linux/msm_ion.h>
 #include <uapi/media/msm_vidc.h>
 
-#define HAL_BUFFER_MAX 0xb
+#define HAL_BUFFER_MAX 0xd
 
 enum smem_type {
 	SMEM_ION,
@@ -49,6 +49,7 @@
 	HAL_BUFFER_INTERNAL_PERSIST = 0x200,
 	HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400,
 	HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800,
+	HAL_BUFFER_INTERNAL_RECON = 0x1000,
 };
 
 struct dma_mapping_info {
@@ -60,15 +61,17 @@
 };
 
 struct msm_smem {
-	int mem_type;
-	size_t size;
+	u32 refcount;
+	int fd;
+	void *dma_buf;
+	void *handle;
 	void *kvaddr;
-	ion_phys_addr_t device_addr;
+	u32 device_addr;
+	unsigned int offset;
+	unsigned int size;
 	unsigned long flags;
-	void *smem_priv;
 	enum hal_buffer buffer_type;
 	struct dma_mapping_info mapping_info;
-	unsigned int offset;
 };
 
 enum smem_cache_ops {
diff --git a/include/net/ip.h b/include/net/ip.h
index b043c7d..9816365 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -272,6 +272,8 @@
 
 __be32 inet_current_timestamp(void);
 
+extern int sysctl_reserved_port_bind;
+
 /* From inetpeer.c */
 extern int inet_peer_threshold;
 extern int inet_peer_minttl;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 7f15f95..91afb4a 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -1001,6 +1001,7 @@
  */
 extern const struct proto_ops inet6_stream_ops;
 extern const struct proto_ops inet6_dgram_ops;
+extern const struct proto_ops inet6_sockraw_ops;
 
 struct group_source_req;
 struct group_filter;
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index 7ef984a..549cb84 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -144,5 +144,6 @@
 extern int icnss_set_wlan_mac_address(const u8 *in, const uint32_t len);
 extern u8 *icnss_get_wlan_mac_address(struct device *dev, uint32_t *num);
 extern int icnss_trigger_recovery(struct device *dev);
-
+extern int icnss_get_driver_load_cnt(void);
+extern void icnss_increment_driver_load_cnt(void);
 #endif /* _ICNSS_WLAN_H_ */
diff --git a/include/soc/qcom/pm.h b/include/soc/qcom/pm.h
index a82ada6..58d011e 100644
--- a/include/soc/qcom/pm.h
+++ b/include/soc/qcom/pm.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
  * Author: San Mehat <san@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -70,16 +70,6 @@
 };
 
 /**
- * lpm_cpu_pre_pc_cb(): API to get the L2 flag to pass to TZ
- *
- * @cpu: cpuid of the CPU going down.
- *
- * Returns the l2 flush flag enum that is passed down to TZ during power
- * collaps
- */
-enum msm_pm_l2_scm_flag lpm_cpu_pre_pc_cb(unsigned int cpu);
-
-/**
  * msm_pm_sleep_mode_allow() - API to determine if sleep mode is allowed.
  * @cpu:	CPU on which to check for the sleep mode.
  * @mode:	Sleep Mode to check for.
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 7a09cb1..14f6445 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -15,6 +15,7 @@
 #define _APR_AUDIO_V2_H_
 
 #include <linux/qdsp6v2/apr.h>
+#include <linux/msm_audio.h>
 
 /* size of header needed for passing data out of band */
 #define APR_CMD_OB_HDR_SZ  12
@@ -43,6 +44,8 @@
 
 #define ADM_MATRIX_ID_COMPRESSED_AUDIO_RX   2
 
+#define ADM_MATRIX_ID_COMPRESSED_AUDIO_TX   3
+
 #define ADM_MATRIX_ID_LISTEN_TX             4
 /* Enumeration for an audio Tx matrix ID.*/
 #define ADM_MATRIX_ID_AUDIOX              1
@@ -444,6 +447,26 @@
 	 */
 } __packed;
 
+#define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213
+#define ASM_STREAM_PP_EVENT 0x00013214
+#define ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE 0x13333
+#define ASM_IEC_61937_MEDIA_FMT_EVENT 0x13334
+
+#define DSP_STREAM_CMD "ADSP Stream Cmd"
+#define DSP_STREAM_CALLBACK "ADSP Stream Callback Event"
+#define DSP_STREAM_CALLBACK_QUEUE_SIZE 1024
+
+struct dsp_stream_callback_list {
+	struct list_head list;
+	struct msm_adsp_event_data event;
+};
+
+struct dsp_stream_callback_prtd {
+	uint16_t event_count;
+	struct list_head event_queue;
+	spinlock_t prtd_spin_lock;
+};
+
 /* set customized mixing on matrix mixer */
 #define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5                        0x00010344
 struct adm_cmd_set_pspd_mtmx_strtr_params_v5 {
@@ -3993,6 +4016,32 @@
 
 } __packed;
 
+
+/* Command to send sample rate & channels for IEC61937 (compressed) or IEC60958
+ * (pcm) streams. Both audio standards use the same format and are used for
+ * HDMI or SPDIF.
+ */
+#define ASM_DATA_CMD_IEC_60958_MEDIA_FMT        0x0001321E
+
+struct asm_iec_compressed_fmt_blk_t {
+	struct apr_hdr hdr;
+
+	/*
+	 * Nominal sampling rate of the incoming bitstream.
+	 * Supported values: 8000, 11025, 16000, 22050, 24000, 32000,
+	 *                   44100, 48000, 88200, 96000, 176400, 192000,
+	 *                   352800, 384000
+	 */
+	uint32_t sampling_rate;
+
+	/*
+	 * Number of channels of the incoming bitstream.
+	 * Supported values: 1,2,3,4,5,6,7,8
+	 */
+	uint32_t num_channels;
+
+} __packed;
+
 struct asm_multi_channel_pcm_fmt_blk_v2 {
 	struct apr_hdr hdr;
 	struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
@@ -5054,6 +5103,12 @@
 #define ASM_MEDIA_FMT_VORBIS                 0x00010C15
 #define ASM_MEDIA_FMT_APE                    0x00012F32
 #define ASM_MEDIA_FMT_DSD                    0x00012F3E
+#define ASM_MEDIA_FMT_TRUEHD                 0x00013215
+/* 0x0 is used for fomat ID since ADSP dynamically determines the
+ * format encapsulated in the IEC61937 (compressed) or IEC60958
+ * (pcm) packets.
+ */
+#define ASM_MEDIA_FMT_IEC                    0x00000000
 
 /* Media format ID for adaptive transform acoustic coding. This
  * ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED command
@@ -6315,6 +6370,62 @@
 
 #define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10
 
+#define ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2     0x00013218
+
+struct asm_stream_cmd_set_encdec_param_v2 {
+	u16                  service_id;
+	/* 0 - ASM_ENCODER_SVC; 1 - ASM_DECODER_SVC */
+
+	u16                  reserved;
+
+	u32                  param_id;
+	/* ID of the parameter. */
+
+	u32                  param_size;
+	/*
+	 * Data size of this parameter, in bytes. The size is a multiple
+	 * of 4 bytes.
+	 */
+} __packed;
+
+#define ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS  0x00013219
+
+#define ASM_STREAM_CMD_ENCDEC_EVENTS           0x0001321A
+
+#define AVS_PARAM_ID_RTIC_SHARED_MEMORY_ADDR   0x00013237
+
+struct avs_rtic_shared_mem_addr {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param_v2  encdec;
+	u32                 shm_buf_addr_lsw;
+	/* Lower 32 bit of the RTIC shared memory */
+
+	u32                 shm_buf_addr_msw;
+	/* Upper 32 bit of the RTIC shared memory */
+
+	u32                 buf_size;
+	/* Size of buffer */
+
+	u16                 shm_buf_mem_pool_id;
+	/* ADSP_MEMORY_MAP_SHMEM8_4K_POOL */
+
+	u16                 shm_buf_num_regions;
+	/* number of regions to map */
+
+	u32                 shm_buf_flag;
+	/* buffer property flag */
+
+	struct avs_shared_map_region_payload map_region;
+	/* memory map region*/
+} __packed;
+
+#define AVS_PARAM_ID_RTIC_EVENT_ACK           0x00013238
+
+struct avs_param_rtic_event_ack {
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_encdec_param_v2  encdec;
+} __packed;
+
 #define ASM_PARAM_ID_ENCDEC_BITRATE     0x00010C13
 
 struct asm_bitrate_param {
@@ -10325,10 +10436,33 @@
 	u32                  flags;
 } __packed;
 
+
+/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC to
+ * realize smoother adjustment of audio session clock for a specified session.
+ * The desired audio session clock adjustment(in micro seconds) is specified
+ * using the command #ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2.
+ * Delaying/Advancing the session clock would be implemented by inserting
+ * interpolated/dropping audio samples in the playback path respectively.
+ * Also, this parameter has to be configured before the Audio Session is put
+ * to RUN state to avoid cold start latency/glitches in the playback.
+ */
+
+#define ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL         0x00013217
+
+struct asm_session_mtmx_param_adjust_session_time_ctl_t {
+	/* Specifies whether the module is enabled or not
+	 * @values
+	 * 0 -- disabled
+	 * 1 -- enabled
+	 */
+	u32                 enable;
+};
+
 union asm_session_mtmx_strtr_param_config {
 	struct asm_session_mtmx_strtr_param_window_v2_t window_param;
 	struct asm_session_mtmx_strtr_param_render_mode_t render_param;
 	struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
+	struct asm_session_mtmx_param_adjust_session_time_ctl_t adj_time_param;
 } __packed;
 
 struct asm_mtmx_strtr_params {
@@ -10457,6 +10591,7 @@
 	COMPRESSED_PASSTHROUGH_DSD,
 	LISTEN,
 	COMPRESSED_PASSTHROUGH_GEN,
+	COMPRESSED_PASSTHROUGH_IEC61937
 };
 
 #define AUDPROC_MODULE_ID_COMPRESSED_MUTE                0x00010770
diff --git a/include/sound/msm-dts-eagle.h b/include/sound/msm-dts-eagle.h
deleted file mode 100644
index 2ef0113..0000000
--- a/include/sound/msm-dts-eagle.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MSM_DTS_EAGLE_H__
-#define __MSM_DTS_EAGLE_H__
-
-#include <linux/compat.h>
-#include <sound/soc.h>
-#include <sound/devdep_params.h>
-#include <sound/q6asm-v2.h>
-
-#ifdef CONFIG_COMPAT
-enum {
-	DTS_EAGLE_IOCTL_GET_CACHE_SIZE32 = _IOR(0xF2, 0, __s32),
-	DTS_EAGLE_IOCTL_SET_CACHE_SIZE32 = _IOW(0xF2, 1, __s32),
-	DTS_EAGLE_IOCTL_GET_PARAM32 = _IOR(0xF2, 2, compat_uptr_t),
-	DTS_EAGLE_IOCTL_SET_PARAM32 = _IOW(0xF2, 3, compat_uptr_t),
-	DTS_EAGLE_IOCTL_SET_CACHE_BLOCK32 =
-				_IOW(0xF2, 4, compat_uptr_t),
-	DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE32 =
-				_IOW(0xF2, 5, compat_uptr_t),
-	DTS_EAGLE_IOCTL_GET_LICENSE32 =
-				_IOR(0xF2, 6, compat_uptr_t),
-	DTS_EAGLE_IOCTL_SET_LICENSE32 =
-				 _IOW(0xF2, 7, compat_uptr_t),
-	DTS_EAGLE_IOCTL_SEND_LICENSE32 = _IOW(0xF2, 8, __s32),
-	DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS32 = _IOW(0xF2, 9,
-						     compat_uptr_t),
-};
-#endif
-
-#ifdef CONFIG_DTS_EAGLE
-void msm_dts_ion_memmap(struct param_outband *po_);
-int msm_dts_eagle_enable_asm(struct audio_client *ac, u32 enable, int module);
-int msm_dts_eagle_enable_adm(int port_id, int copp_idx, u32 enable);
-void msm_dts_eagle_add_controls(struct snd_soc_platform *platform);
-int msm_dts_eagle_set_stream_gain(struct audio_client *ac,
-				  int lgain, int rgain);
-int msm_dts_eagle_handle_asm(struct dts_eagle_param_desc *depd, char *buf,
-			     bool for_pre, bool get, struct audio_client *ac,
-			     struct param_outband *po);
-int msm_dts_eagle_handle_adm(struct dts_eagle_param_desc *depd, char *buf,
-			     bool for_pre, bool get);
-int msm_dts_eagle_ioctl(unsigned int cmd, unsigned long arg);
-int msm_dts_eagle_is_hpx_on(void);
-int msm_dts_eagle_init_pre(struct audio_client *ac);
-int msm_dts_eagle_deinit_pre(struct audio_client *ac);
-int msm_dts_eagle_init_post(int port_id, int copp_id);
-int msm_dts_eagle_deinit_post(int port_id, int topology);
-int msm_dts_eagle_init_master_module(struct audio_client *ac);
-int msm_dts_eagle_deinit_master_module(struct audio_client *ac);
-int msm_dts_eagle_pcm_new(struct snd_soc_pcm_runtime *runtime);
-void msm_dts_eagle_pcm_free(struct snd_pcm *pcm);
-int msm_dts_eagle_compat_ioctl(unsigned int cmd, unsigned long arg);
-#else
-static inline void msm_dts_ion_memmap(struct param_outband *po_)
-{
-	pr_debug("%s\n", __func__);
-}
-static inline int msm_dts_eagle_enable_asm(struct audio_client *ac,
-					   u32 enable, int module)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_enable_adm(int port_id, int copp_idx,
-					   u32 enable)
-{
-	return 0;
-}
-static inline void msm_dts_eagle_add_controls(struct snd_soc_platform *platform)
-{
-}
-static inline int msm_dts_eagle_set_stream_gain(struct audio_client *ac,
-						int lgain, int rgain)
-{
-	pr_debug("%s\n", __func__);
-	return 0;
-}
-static inline int msm_dts_eagle_handle_asm(struct dts_eagle_param_desc *depd,
-					   char *buf, bool for_pre, bool get,
-					   struct audio_client *ac,
-					   struct param_outband *po)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_handle_adm(struct dts_eagle_param_desc *depd,
-					   char *buf, bool for_pre, bool get)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_ioctl(unsigned int cmd, unsigned long arg)
-{
-	return -EPERM;
-}
-static inline int msm_dts_eagle_is_hpx_on(void)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_init_pre(struct audio_client *ac)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_deinit_pre(struct audio_client *ac)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_init_post(int port_id, int coppid)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_deinit_post(int port_id, int topology)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_init_master_module(struct audio_client *ac)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_deinit_master_module(struct audio_client *ac)
-{
-	return 0;
-}
-static inline int msm_dts_eagle_pcm_new(struct snd_soc_pcm_runtime *runtime)
-{
-	pr_debug("%s\n", __func__);
-	return 0;
-}
-static inline void msm_dts_eagle_pcm_free(struct snd_pcm *pcm)
-{
-	pr_debug("%s\n", __func__);
-}
-static inline int msm_dts_eagle_compat_ioctl(unsigned int cmd,
-					unsigned long arg)
-{
-	return 0;
-}
-#endif
-
-#endif
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 42d048f..e689e93 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -17,6 +17,7 @@
 #define ADM_PATH_LIVE_REC 0x2
 #define ADM_PATH_NONLIVE_REC 0x3
 #define ADM_PATH_COMPRESSED_RX 0x5
+#define ADM_PATH_COMPRESSED_TX 0x6
 #include <linux/qdsp6v2/rtac.h>
 #include <sound/q6afe-v2.h>
 #include <sound/q6audio-v2.h>
@@ -34,7 +35,6 @@
 	ADM_AUDVOL_CAL,
 	ADM_RTAC_INFO_CAL,
 	ADM_RTAC_APR_CAL,
-	ADM_DTS_EAGLE,
 	ADM_SRS_TRUMEDIA,
 	ADM_RTAC_AUDVOL_CAL,
 	ADM_MAX_CAL_TYPES
@@ -65,6 +65,20 @@
 	unsigned int session_id;
 };
 
+struct default_chmixer_param_id_coeff {
+	uint32_t index;
+	uint16_t num_output_channels;
+	uint16_t num_input_channels;
+};
+
+struct msm_pcm_channel_mixer {
+	int output_channel;
+	int input_channels[ADM_MAX_CHANNELS];
+	bool enable;
+	int rule;
+	int channel_weight[ADM_MAX_CHANNELS][ADM_MAX_CHANNELS];
+};
+
 int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id,
 		      void *srs_params);
 
@@ -164,4 +178,10 @@
 			struct sound_focus_param *soundFocusData);
 int adm_get_source_tracking(int port_id, int copp_idx,
 			    struct source_tracking_param *sourceTrackingData);
+int adm_swap_speaker_channels(int port_id, int copp_idx, int sample_rate,
+				bool spk_swap);
+int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id,
+			int session_type,
+			struct msm_pcm_channel_mixer *ch_mixer,
+			int channel_index);
 #endif /* __Q6_ADM_V2_H__ */
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 6bc93f5..00b46a5 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -55,6 +55,8 @@
 #define FORMAT_DSD          0x001d
 #define FORMAT_APTX         0x001e
 #define FORMAT_GEN_COMPR    0x001f
+#define FORMAT_TRUEHD       0x0020
+#define FORMAT_IEC61937     0x0021
 
 #define ENCDEC_SBCBITRATE   0x0001
 #define ENCDEC_IMMEDIATE_DECODE 0x0002
@@ -211,6 +213,7 @@
 	int                    session;
 	app_cb		       cb;
 	atomic_t	       cmd_state;
+	atomic_t	       cmd_state_pp;
 	/* Relative or absolute TS */
 	atomic_t	       time_flag;
 	atomic_t	       nowait_cmd_cnt;
@@ -316,6 +319,10 @@
 int q6asm_open_loopback_v2(struct audio_client *ac,
 			   uint16_t bits_per_sample);
 
+int q6asm_open_transcode_loopback(struct audio_client *ac,
+			   uint16_t bits_per_sample, uint32_t source_format,
+			   uint32_t sink_format);
+
 int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
 				uint32_t lsw_ts, uint32_t flags);
 int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
@@ -507,6 +514,10 @@
 			bool use_default_chmap, char *channel_map,
 			uint16_t bits_per_sample);
 
+int q6asm_media_format_block_iec(
+			struct audio_client *ac,
+			uint32_t rate, uint32_t channels);
+
 int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
 					     uint32_t rate, uint32_t channels,
 					     bool use_default_chmap,
@@ -617,6 +628,14 @@
 int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
 				    uint32_t params_length);
 
+int q6asm_send_stream_cmd(struct audio_client *ac,
+			  struct msm_adsp_event_data *data);
+
+int q6asm_send_ion_fd(struct audio_client *ac, int fd);
+
+int q6asm_send_rtic_event_ack(struct audio_client *ac,
+			      void *param, uint32_t params_length);
+
 /* Client can set the IO mode to either AIO/SIO mode */
 int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);
 
@@ -649,6 +668,10 @@
 int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
 		uint32_t clk_rec_mode);
 
+/* Enable adjust session clock in DSP */
+int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
+		bool enable);
+
 /* Retrieve the current DSP path delay */
 int q6asm_get_path_delay(struct audio_client *ac);
 
@@ -656,4 +679,8 @@
 uint8_t q6asm_get_buf_index_from_token(uint32_t token);
 uint8_t q6asm_get_stream_id_from_token(uint32_t token);
 
+/* Adjust session clock in DSP */
+int q6asm_adjust_session_clock(struct audio_client *ac,
+		uint32_t adjust_time_lsw,
+		uint32_t adjust_time_msw);
 #endif /* __Q6_ASM_H__ */
diff --git a/include/sound/wcd-dsp-mgr.h b/include/sound/wcd-dsp-mgr.h
index 2beb9b3..8a4c6d9 100644
--- a/include/sound/wcd-dsp-mgr.h
+++ b/include/sound/wcd-dsp-mgr.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
 #define __WCD_DSP_MGR_H__
 
 #include <linux/types.h>
+#include <linux/device.h>
 
 /*
  * These enums correspond to the component types
@@ -63,6 +64,9 @@
 	/* Suspend/Resume related */
 	WDSP_EVENT_SUSPEND,
 	WDSP_EVENT_RESUME,
+
+	/* Misc */
+	WDSP_EVENT_GET_DEVOPS
 };
 
 enum wdsp_signal {
@@ -109,6 +113,8 @@
  *			their own ops to manager driver
  * @get_dev_for_cmpnt: components can use this to get handle
  *		       to struct device * of any other component
+ * @get_devops_for_cmpnt: components can use this to get ops
+ *			  from other related components.
  * @signal_handler: callback to notify manager driver that signal
  *		    has occurred. Cannot be called from interrupt
  *		    context as this can sleep
@@ -126,6 +132,8 @@
 				  struct wdsp_cmpnt_ops *ops);
 	struct device *(*get_dev_for_cmpnt)(struct device *wdsp_dev,
 					    enum wdsp_cmpnt_type type);
+	int (*get_devops_for_cmpnt)(struct device *wdsp_dev,
+				    enum wdsp_cmpnt_type type, void *data);
 	int (*signal_handler)(struct device *wdsp_dev,
 			      enum wdsp_signal signal, void *arg);
 	int (*vote_for_dsp)(struct device *wdsp_dev, bool vote);
@@ -133,4 +141,6 @@
 	int (*resume)(struct device *wdsp_dev);
 };
 
+int wcd_dsp_mgr_init(void);
+void wcd_dsp_mgr_exit(void);
 #endif /* end of __WCD_DSP_MGR_H__ */
diff --git a/include/sound/wcd-spi.h b/include/sound/wcd-spi.h
index 1fff58d..b85c68e 100644
--- a/include/sound/wcd-spi.h
+++ b/include/sound/wcd-spi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,23 +35,10 @@
 	u32 flags;
 };
 
-#ifdef CONFIG_SND_SOC_WCD_SPI
-
-int wcd_spi_data_write(struct spi_device *spi, struct wcd_spi_msg *msg);
-int wcd_spi_data_read(struct spi_device *spi, struct wcd_spi_msg *msg);
-
-#else
-
-int wcd_spi_data_write(struct spi_device *spi, struct wcd_spi_msg *msg)
-{
-	return -ENODEV;
-}
-
-int wcd_spi_data_read(struct spi_device *spi, struct wcd_spi_msg *msg)
-{
-	return -ENODEV;
-}
-
-#endif /* End of CONFIG_SND_SOC_WCD_SPI */
+struct wcd_spi_ops {
+	struct spi_device *spi_dev;
+	int (*read_dev)(struct spi_device *spi, struct wcd_spi_msg *msg);
+	int (*write_dev)(struct spi_device *spi, struct wcd_spi_msg *msg);
+};
 
 #endif /* End of __WCD_SPI_H__ */
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 8c1746a..bf8f149 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -862,7 +862,9 @@
 		__entry->target_cpu		= target_cpu;
 		__entry->ediff			= ediff;
 		__entry->need_idle		= need_idle;
-		__entry->latency		= sched_ktime_clock() - p->ravg.mark_start;
+		__entry->latency		= p->ravg.mark_start ?
+						  sched_ktime_clock() -
+						  p->ravg.mark_start : 0;
 	),
 
 	TP_printk("comm=%s pid=%d task_cpu=%d task_util=%lu nominated_cpu=%d target_cpu=%d energy_diff=%d need_idle=%d latency=%llu",
@@ -879,6 +881,11 @@
 	TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
 );
 
+DEFINE_EVENT(sched_task_util, sched_task_util_boosted,
+	TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
+	TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
+);
+
 DEFINE_EVENT(sched_task_util, sched_task_util_overutilzed,
 	TP_PROTO(struct task_struct *p, int task_cpu, unsigned long task_util, int nominated_cpu, int target_cpu, int ediff, bool need_idle),
 	TP_ARGS(p, task_cpu, task_util, nominated_cpu, target_cpu, ediff, need_idle)
diff --git a/include/trace/events/trace_msm_pil_event.h b/include/trace/events/trace_msm_pil_event.h
new file mode 100644
index 0000000..4795dc5
--- /dev/null
+++ b/include/trace/events/trace_msm_pil_event.h
@@ -0,0 +1,88 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM msm_pil_event
+
+#if !defined(_TRACE_MSM_PIL_EVENT_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MSM_PIL_EVENT_H_
+
+#include <linux/tracepoint.h>
+#include <../drivers/soc/qcom/peripheral-loader.h>
+
+TRACE_EVENT(pil_event,
+
+	TP_PROTO(const char *event_name, struct pil_desc *desc),
+
+	TP_ARGS(event_name, desc),
+
+	TP_STRUCT__entry(
+		__string(event_name, event_name)
+		__string(fw_name, desc->fw_name)
+	),
+
+	TP_fast_assign(
+		__assign_str(event_name, event_name);
+		__assign_str(fw_name, desc->fw_name);
+	),
+
+	TP_printk("event_name=%s fw_name=%s",
+		__get_str(event_name),
+		__get_str(fw_name))
+);
+
+TRACE_EVENT(pil_notif,
+
+	TP_PROTO(const char *event_name, unsigned long code,
+	const char *fw_name),
+
+	TP_ARGS(event_name, code, fw_name),
+
+	TP_STRUCT__entry(
+		__string(event_name, event_name)
+		__field(unsigned long, code)
+		__string(fw_name, fw_name)
+	),
+
+	TP_fast_assign(
+		__assign_str(event_name, event_name);
+		__entry->code = code;
+		__assign_str(fw_name, fw_name);
+	),
+
+	TP_printk("event_name=%s code=%lu fw=%s",
+		__get_str(event_name),
+		__entry->code,
+		__get_str(fw_name))
+);
+
+TRACE_EVENT(pil_func,
+
+	TP_PROTO(const char *func_name),
+
+	TP_ARGS(func_name),
+
+	TP_STRUCT__entry(
+		__string(func_name, func_name)
+	),
+
+	TP_fast_assign(
+		__assign_str(func_name, func_name);
+	),
+
+	TP_printk("func_name=%s",
+		__get_str(func_name))
+);
+
+#endif
+#define TRACE_INCLUDE_FILE trace_msm_pil_event
+#include <trace/define_trace.h>
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index ab38f9e..eb7e0c6 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -19,7 +19,6 @@
 #define __MSM_DRM_H__
 
 #include "drm.h"
-#include <stddef.h>
 #include "sde_drm.h"
 
 #if defined(__cplusplus)
diff --git a/include/uapi/linux/dvb/dmx.h b/include/uapi/linux/dvb/dmx.h
index 427e489..175534a 100644
--- a/include/uapi/linux/dvb/dmx.h
+++ b/include/uapi/linux/dvb/dmx.h
@@ -32,6 +32,11 @@
 
 #define DMX_FILTER_SIZE 16
 
+/* Min recording chunk upon which event is generated */
+#define DMX_REC_BUFF_CHUNK_MIN_SIZE		(100*188)
+
+#define DMX_MAX_DECODER_BUFFER_NUM		(32)
+
 enum dmx_output
 {
 	DMX_OUT_DECODER, /* Streaming directly to decoder. */
@@ -108,6 +113,44 @@
 #define DMX_KERNEL_CLIENT   0x8000
 };
 
+enum dmx_video_codec {
+	DMX_VIDEO_CODEC_MPEG2,
+	DMX_VIDEO_CODEC_H264,
+	DMX_VIDEO_CODEC_VC1
+};
+
+/* Index entries types */
+#define DMX_IDX_RAI                         0x00000001
+#define DMX_IDX_PUSI                        0x00000002
+#define DMX_IDX_MPEG_SEQ_HEADER             0x00000004
+#define DMX_IDX_MPEG_GOP                    0x00000008
+#define DMX_IDX_MPEG_FIRST_SEQ_FRAME_START  0x00000010
+#define DMX_IDX_MPEG_FIRST_SEQ_FRAME_END    0x00000020
+#define DMX_IDX_MPEG_I_FRAME_START          0x00000040
+#define DMX_IDX_MPEG_I_FRAME_END            0x00000080
+#define DMX_IDX_MPEG_P_FRAME_START          0x00000100
+#define DMX_IDX_MPEG_P_FRAME_END            0x00000200
+#define DMX_IDX_MPEG_B_FRAME_START          0x00000400
+#define DMX_IDX_MPEG_B_FRAME_END            0x00000800
+#define DMX_IDX_H264_SPS                    0x00001000
+#define DMX_IDX_H264_PPS                    0x00002000
+#define DMX_IDX_H264_FIRST_SPS_FRAME_START  0x00004000
+#define DMX_IDX_H264_FIRST_SPS_FRAME_END    0x00008000
+#define DMX_IDX_H264_IDR_START              0x00010000
+#define DMX_IDX_H264_IDR_END                0x00020000
+#define DMX_IDX_H264_NON_IDR_START          0x00040000
+#define DMX_IDX_H264_NON_IDR_END            0x00080000
+#define DMX_IDX_VC1_SEQ_HEADER              0x00100000
+#define DMX_IDX_VC1_ENTRY_POINT             0x00200000
+#define DMX_IDX_VC1_FIRST_SEQ_FRAME_START   0x00400000
+#define DMX_IDX_VC1_FIRST_SEQ_FRAME_END     0x00800000
+#define DMX_IDX_VC1_FRAME_START             0x01000000
+#define DMX_IDX_VC1_FRAME_END               0x02000000
+#define DMX_IDX_H264_ACCESS_UNIT_DEL        0x04000000
+#define DMX_IDX_H264_SEI                    0x08000000
+#define DMX_IDX_H264_IDR_ISLICE_START       0x10000000
+#define DMX_IDX_H264_NON_IDR_PSLICE_START   0x20000000
+#define DMX_IDX_H264_NON_IDR_BSLICE_START   0x40000000
 
 struct dmx_pes_filter_params
 {
@@ -116,11 +159,457 @@
 	dmx_output_t   output;
 	dmx_pes_type_t pes_type;
 	__u32          flags;
+
+	/*
+	 * The following configures when the event
+	 * DMX_EVENT_NEW_REC_CHUNK will be triggered.
+	 * When new recorded data is received with size
+	 * equal or larger than this value a new event
+	 * will be triggered. This is relevant when
+	 * output is DMX_OUT_TS_TAP or DMX_OUT_TSDEMUX_TAP,
+	 * size must be at least DMX_REC_BUFF_CHUNK_MIN_SIZE
+	 * and smaller than buffer size.
+	 */
+	__u32          rec_chunk_size;
+
+	enum dmx_video_codec video_codec;
+};
+
+struct dmx_buffer_status {
+	/* size of buffer in bytes */
+	unsigned int size;
+
+	/* fullness of buffer in bytes */
+	unsigned int fullness;
+
+	/*
+	 * How many bytes are free
+	 * It's the same as: size-fullness-1
+	 */
+	unsigned int free_bytes;
+
+	/* read pointer offset in bytes */
+	unsigned int read_offset;
+
+	/* write pointer offset in bytes */
+	unsigned int write_offset;
+
+	/* non-zero if data error occurred */
+	int error;
+};
+
+/* Events associated with each demux filter */
+enum dmx_event {
+	/* New PES packet is ready to be consumed */
+	DMX_EVENT_NEW_PES = 0x00000001,
+
+	/* New section is ready to be consumed */
+	DMX_EVENT_NEW_SECTION = 0x00000002,
+
+	/* New recording chunk is ready to be consumed */
+	DMX_EVENT_NEW_REC_CHUNK = 0x00000004,
+
+	/* New PCR value is ready */
+	DMX_EVENT_NEW_PCR = 0x00000008,
+
+	/* Overflow */
+	DMX_EVENT_BUFFER_OVERFLOW = 0x00000010,
+
+	/* Section was dropped due to CRC error */
+	DMX_EVENT_SECTION_CRC_ERROR = 0x00000020,
+
+	/* End-of-stream, no more data from this filter */
+	DMX_EVENT_EOS = 0x00000040,
+
+	/* New Elementary Stream data is ready */
+	DMX_EVENT_NEW_ES_DATA = 0x00000080,
+
+	/* Data markers */
+	DMX_EVENT_MARKER = 0x00000100,
+
+	/* New indexing entry is ready */
+	DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200,
+
+	/*
+	 * Section filter timer expired. This is notified
+	 * when timeout is configured to section filter
+	 * (dmx_sct_filter_params) and no sections were
+	 * received for the given time.
+	 */
+	DMX_EVENT_SECTION_TIMEOUT = 0x00000400,
+
+	/* Scrambling bits change between clear and scrambled */
+	DMX_EVENT_SCRAMBLING_STATUS_CHANGE = 0x00000800
+};
+
+enum dmx_oob_cmd {
+	/* End-of-stream, no more data from this filter */
+	DMX_OOB_CMD_EOS,
+
+	/* Data markers */
+	DMX_OOB_CMD_MARKER,
+};
+
+/* Flags passed in filter events */
+
+/* Continuity counter error was detected */
+#define DMX_FILTER_CC_ERROR			0x01
+
+/* Discontinuity indicator was set */
+#define DMX_FILTER_DISCONTINUITY_INDICATOR	0x02
+
+/* PES length in PES header is not correct */
+#define DMX_FILTER_PES_LENGTH_ERROR		0x04
+
+
+/* PES info associated with DMX_EVENT_NEW_PES event */
+struct dmx_pes_event_info {
+	/* Offset at which PES information starts */
+	__u32 base_offset;
+
+	/*
+	 * Start offset at which PES data
+	 * from the stream starts.
+	 * Equal to base_offset if PES data
+	 * starts from the beginning.
+	 */
+	__u32 start_offset;
+
+	/* Total length holding the PES information */
+	__u32 total_length;
+
+	/* Actual length holding the PES data */
+	__u32 actual_length;
+
+	/* Local receiver timestamp in 27MHz */
+	__u64 stc;
+
+	/* Flags passed in filter events */
+	__u32 flags;
+
+	/*
+	 * Number of TS packets with Transport Error Indicator (TEI)
+	 * found while constructing the PES.
+	 */
+	__u32 transport_error_indicator_counter;
+
+	/* Number of continuity errors found while constructing the PES */
+	__u32 continuity_error_counter;
+
+	/* Total number of TS packets holding the PES */
+	__u32 ts_packets_num;
+};
+
+/* Section info associated with DMX_EVENT_NEW_SECTION event */
+struct dmx_section_event_info {
+	/* Offset at which section information starts */
+	__u32 base_offset;
+
+	/*
+	 * Start offset at which section data
+	 * from the stream starts.
+	 * Equal to base_offset if section data
+	 * starts from the beginning.
+	 */
+	__u32 start_offset;
+
+	/* Total length holding the section information */
+	__u32 total_length;
+
+	/* Actual length holding the section data */
+	__u32 actual_length;
+
+	/* Flags passed in filter events */
+	__u32 flags;
+};
+
+/* Recording info associated with DMX_EVENT_NEW_REC_CHUNK event */
+struct dmx_rec_chunk_event_info {
+	/* Offset at which recording chunk starts */
+	__u32 offset;
+
+	/* Size of recording chunk in bytes */
+	__u32 size;
+};
+
+/* PCR info associated with DMX_EVENT_NEW_PCR event */
+struct dmx_pcr_event_info {
+	/* Local timestamp in 27MHz
+	 * when PCR packet was received
+	 */
+	__u64 stc;
+
+	/* PCR value in 27MHz */
+	__u64 pcr;
+
+	/* Flags passed in filter events */
+	__u32 flags;
+};
+
+/*
+ * Elementary stream data information associated
+ * with DMX_EVENT_NEW_ES_DATA event
+ */
+struct dmx_es_data_event_info {
+	/* Buffer user-space handle */
+	int buf_handle;
+
+	/*
+	 * Cookie to provide when releasing the buffer
+	 * using the DMX_RELEASE_DECODER_BUFFER ioctl command
+	 */
+	int cookie;
+
+	/* Offset of data from the beginning of the buffer */
+	__u32 offset;
+
+	/* Length of data in buffer (in bytes) */
+	__u32 data_len;
+
+	/* Indication whether PTS value is valid */
+	int pts_valid;
+
+	/* PTS value associated with the buffer */
+	__u64 pts;
+
+	/* Indication whether DTS value is valid */
+	int dts_valid;
+
+	/* DTS value associated with the buffer */
+	__u64 dts;
+
+	/* STC value associated with the buffer in 27MHz */
+	__u64 stc;
+
+	/*
+	 * Number of TS packets with Transport Error Indicator (TEI) set
+	 * in the TS packet header since last reported event
+	 */
+	__u32 transport_error_indicator_counter;
+
+	/* Number of continuity errors since last reported event */
+	__u32 continuity_error_counter;
+
+	/* Total number of TS packets processed since last reported event */
+	__u32 ts_packets_num;
+
+	/*
+	 * Number of dropped bytes due to insufficient buffer space,
+	 * since last reported event
+	 */
+	__u32 ts_dropped_bytes;
+};
+
+/* Marker details associated with DMX_EVENT_MARKER event */
+struct dmx_marker_event_info {
+	/* Marker id */
+	__u64 id;
+};
+
+/* Indexing information associated with DMX_EVENT_NEW_INDEX_ENTRY event */
+struct dmx_index_event_info {
+	/* Index entry type, one of DMX_IDX_* */
+	__u64 type;
+
+	/*
+	 * The PID the index entry belongs to.
+	 * In case of recording filter, multiple PIDs may exist in the same
+	 * filter through DMX_ADD_PID ioctl and each can be indexed separately.
+	 */
+	__u16 pid;
+
+	/*
+	 * The TS packet number in the recorded data at which
+	 * the indexing event is found.
+	 */
+	__u64 match_tsp_num;
+
+	/*
+	 * The TS packet number in the recorded data preceding
+	 * match_tsp_num and has PUSI set.
+	 */
+	__u64 last_pusi_tsp_num;
+
+	/* STC associated with match_tsp_num, in 27MHz */
+	__u64 stc;
+};
+
+/* Scrambling information associated with DMX_EVENT_SCRAMBLING_STATUS_CHANGE */
+struct dmx_scrambling_status_event_info {
+	/*
+	 * The PID which its scrambling bit status changed.
+	 * In case of recording filter, multiple PIDs may exist in the same
+	 * filter through DMX_ADD_PID ioctl, each may have
+	 * different scrambling bits status.
+	 */
+	__u16 pid;
+
+	/* old value of scrambling bits */
+	__u8 old_value;
+
+	/* new value of scrambling bits */
+	__u8 new_value;
+};
+
+/*
+ * Filter's event returned through DMX_GET_EVENT.
+ * poll with POLLPRI would block until events are available.
+ */
+struct dmx_filter_event {
+	enum dmx_event type;
+
+	union {
+		struct dmx_pes_event_info pes;
+		struct dmx_section_event_info section;
+		struct dmx_rec_chunk_event_info recording_chunk;
+		struct dmx_pcr_event_info pcr;
+		struct dmx_es_data_event_info es_data;
+		struct dmx_marker_event_info marker;
+		struct dmx_index_event_info index;
+		struct dmx_scrambling_status_event_info scrambling_status;
+	} params;
+};
+
+/* Filter's buffer requirement returned in dmx_caps */
+struct dmx_buffer_requirement {
+	/* Buffer size alignment, 0 means no special requirement */
+	__u32 size_alignment;
+
+	/* Maximum buffer size allowed */
+	__u32 max_size;
+
+	/* Maximum number of linear buffers handled by demux */
+	__u32 max_buffer_num;
+
+	/* Feature support bitmap as detailed below */
+	__u32 flags;
+
+/* Buffer must be allocated as physically contiguous memory */
+#define DMX_BUFFER_CONTIGUOUS_MEM		0x1
+
+/* If the filter's data is decrypted, the buffer should be secured one */
+#define DMX_BUFFER_SECURED_IF_DECRYPTED		0x2
+
+/* Buffer can be allocated externally */
+#define DMX_BUFFER_EXTERNAL_SUPPORT		0x4
+
+/* Buffer can be allocated internally */
+#define DMX_BUFFER_INTERNAL_SUPPORT		0x8
+
+/* Filter output can be output to a linear buffer group */
+#define DMX_BUFFER_LINEAR_GROUP_SUPPORT		0x10
+
+/* Buffer may be allocated as cached buffer */
+#define DMX_BUFFER_CACHED		0x20
+};
+
+/* Out-of-band (OOB) command */
+struct dmx_oob_command {
+	enum dmx_oob_cmd type;
+
+	union {
+		struct dmx_marker_event_info marker;
+	} params;
 };
 
 typedef struct dmx_caps {
 	__u32 caps;
+
+/* Indicates whether demux support playback from memory in pull mode */
+#define DMX_CAP_PULL_MODE				0x01
+
+/* Indicates whether demux support indexing of recorded video stream */
+#define DMX_CAP_VIDEO_INDEXING			0x02
+
+/* Indicates whether demux support sending data directly to video decoder */
+#define DMX_CAP_VIDEO_DECODER_DATA		0x04
+
+/* Indicates whether demux support sending data directly to audio decoder */
+#define DMX_CAP_AUDIO_DECODER_DATA		0x08
+
+/* Indicates whether demux support sending data directly to subtitle decoder */
+#define DMX_CAP_SUBTITLE_DECODER_DATA	0x10
+
+/* Indicates whether TS insertion is supported */
+#define DMX_CAP_TS_INSERTION	0x20
+
+/* Indicates whether playback from secured input is supported */
+#define DMX_CAP_SECURED_INPUT_PLAYBACK	0x40
+
+/* Indicates whether automatic buffer flush upon overflow is allowed */
+#define DMX_CAP_AUTO_BUFFER_FLUSH	0x80
+
+	/* Number of decoders demux can output data to */
 	int num_decoders;
+
+	/* Number of demux devices */
+	int num_demux_devices;
+
+	/* Max number of PID filters */
+	int num_pid_filters;
+
+	/* Max number of section filters */
+	int num_section_filters;
+
+	/*
+	 * Max number of section filters using same PID,
+	 * 0 if not supported
+	 */
+	int num_section_filters_per_pid;
+
+	/*
+	 * Length of section filter, not including section
+	 * length field (2 bytes).
+	 */
+	int section_filter_length;
+
+	/* Max number of demod based input */
+	int num_demod_inputs;
+
+	/* Max number of memory based input */
+	int num_memory_inputs;
+
+	/* Overall bitrate from all inputs concurrently. Mbit/sec */
+	int max_bitrate;
+
+	/* Max bitrate from single demod input. Mbit/sec */
+	int demod_input_max_bitrate;
+
+	/* Max bitrate from single memory input. Mbit/sec */
+	int memory_input_max_bitrate;
+
+	/* Max number of supported cipher operations per PID */
+	int num_cipher_ops;
+
+	/* Max possible value of STC reported by demux, in 27MHz */
+	__u64 max_stc;
+
+	/*
+	 * For indexing support (DMX_CAP_VIDEO_INDEXING capability) this is
+	 * the max number of video pids that can be indexed for a single
+	 * recording filter. If 0, means there is not limitation.
+	 */
+	int recording_max_video_pids_indexed;
+
+	struct dmx_buffer_requirement section;
+
+	/* For PES not sent to decoder */
+	struct dmx_buffer_requirement pes;
+
+	/* For PES sent to decoder */
+	struct dmx_buffer_requirement decoder;
+
+	/* Recording buffer for recording of 188 bytes packets */
+	struct dmx_buffer_requirement recording_188_tsp;
+
+	/* Recording buffer for recording of 192 bytes packets */
+	struct dmx_buffer_requirement recording_192_tsp;
+
+	/* DVR input buffer for playback of 188 bytes packets */
+	struct dmx_buffer_requirement playback_188_tsp;
+
+	/* DVR input buffer for playback of 192 bytes packets */
+	struct dmx_buffer_requirement playback_192_tsp;
 } dmx_caps_t;
 
 typedef enum dmx_source {
@@ -134,12 +623,229 @@
 	DMX_SOURCE_DVR3
 } dmx_source_t;
 
+enum dmx_tsp_format_t {
+	DMX_TSP_FORMAT_188 = 0,
+	DMX_TSP_FORMAT_192_TAIL,
+	DMX_TSP_FORMAT_192_HEAD,
+	DMX_TSP_FORMAT_204,
+};
+
+enum dmx_playback_mode_t {
+	/*
+	 * In push mode, if one of output buffers
+	 * is full, the buffer would overflow
+	 * and demux continue processing incoming stream.
+	 * This is the default mode. When playing from frontend,
+	 * this is the only mode that is allowed.
+	 */
+	DMX_PB_MODE_PUSH = 0,
+
+	/*
+	 * In pull mode, if one of output buffers
+	 * is full, demux stalls waiting for free space,
+	 * this would cause DVR input buffer fullness
+	 * to accumulate.
+	 * This mode is possible only when playing
+	 * from DVR.
+	 */
+	DMX_PB_MODE_PULL,
+};
+
 struct dmx_stc {
 	unsigned int num;	/* input : which STC? 0..N */
 	unsigned int base;	/* output: divisor for stc to get 90 kHz clock */
 	__u64 stc;		/* output: stc in 'base'*90 kHz units */
 };
 
+enum dmx_buffer_mode {
+	/*
+	 * demux buffers are allocated internally
+	 * by the demux driver. This is the default mode.
+	 * DMX_SET_BUFFER_SIZE can be used to set the size of
+	 * this buffer.
+	 */
+	DMX_BUFFER_MODE_INTERNAL,
+
+	/*
+	 * demux buffers are allocated externally and provided
+	 * to demux through DMX_SET_BUFFER.
+	 * When this mode is used DMX_SET_BUFFER_SIZE and
+	 * mmap are prohibited.
+	 */
+	DMX_BUFFER_MODE_EXTERNAL,
+};
+
+struct dmx_buffer {
+	unsigned int size;
+	int handle;
+
+	/*
+	 * The following indication is relevant only when setting
+	 * DVR input buffer. It indicates whether the input buffer
+	 * being set is secured one or not. Secured (locked) buffers
+	 * are required for playback from secured input. In such case
+	 * write() syscall is not allowed.
+	 */
+	int is_protected;
+};
+
+struct dmx_decoder_buffers {
+	/*
+	 * Specify if linear buffer support is requested. If set, buffers_num
+	 * must be greater than 1
+	 */
+	int is_linear;
+
+	/*
+	 * Specify number of external buffers allocated by user.
+	 * If set to 0 means internal buffer allocation is requested
+	 */
+	__u32 buffers_num;
+
+	/* Specify buffer size, either external or internal */
+	__u32 buffers_size;
+
+	/* Array of externally allocated buffer handles */
+	int handles[DMX_MAX_DECODER_BUFFER_NUM];
+};
+
+struct dmx_secure_mode {
+	/*
+	 * Specifies whether the filter is secure or not.
+	 * Filter should be set as secured if the filter's data *may* include
+	 * encrypted data that would require decryption configured through
+	 * DMX_SET_CIPHER ioctl. The setting may be done while
+	 * filter is in idle state only.
+	 */
+	int is_secured;
+};
+
+struct dmx_cipher_operation {
+	/* Indication whether the operation is encryption or decryption */
+	int encrypt;
+
+	/* The ID of the key used for decryption or encryption */
+	__u32 key_ladder_id;
+};
+
+#define DMX_MAX_CIPHER_OPERATIONS_COUNT	5
+struct dmx_cipher_operations {
+	/*
+	 * The PID to perform the cipher operations on.
+	 * In case of recording filter, multiple PIDs may exist in the same
+	 * filter through DMX_ADD_PID ioctl, each may have different
+	 * cipher operations.
+	 */
+	__u16 pid;
+
+	/* Total number of operations */
+	__u8 operations_count;
+
+	/*
+	 * Cipher operation to perform on the given PID.
+	 * The operations are performed in the order they are given.
+	 */
+	struct dmx_cipher_operation operations[DMX_MAX_CIPHER_OPERATIONS_COUNT];
+};
+
+struct dmx_events_mask {
+	/*
+	 * Bitmask of events to be disabled (dmx_event).
+	 * Disabled events will not be notified to the user.
+	 * By default all events are enabled except for
+	 * DMX_EVENT_NEW_ES_DATA.
+	 * Overflow event can't be disabled.
+	 */
+	__u32 disable_mask;
+
+	/*
+	 * Bitmask of events that will not wake-up the user
+	 * when user calls poll with POLLPRI flag.
+	 * Events that are used as wake-up source should not be
+	 * disabled in disable_mask or they would not be used
+	 * as a wake-up source.
+	 * By default all enabled events are set as wake-up events.
+	 * Overflow event can't be disabled as a wake-up source.
+	 */
+	__u32 no_wakeup_mask;
+
+	/*
+	 * Number of ready wake-up events which will trigger
+	 * a wake-up when user calls poll with POLLPRI flag.
+	 * Default is set to 1.
+	 */
+	__u32 wakeup_threshold;
+};
+
+struct dmx_indexing_params {
+	/*
+	 * PID to index. In case of recording filter, multiple PIDs
+	 * may exist in the same filter through DMX_ADD_PID ioctl.
+	 * It is assumed that the PID was already added using DMX_ADD_PID
+	 * or an error will be reported.
+	 */
+	__u16 pid;
+
+	/* enable or disable indexing, default is disabled */
+	int enable;
+
+	/* combination of DMX_IDX_* bits */
+	__u64 types;
+};
+
+struct dmx_set_ts_insertion {
+	/*
+	 * Unique identifier managed by the caller.
+	 * This identifier can be used later to remove the
+	 * insertion using DMX_ABORT_TS_INSERTION ioctl.
+	 */
+	__u32 identifier;
+
+	/*
+	 * Repetition time in msec, minimum allowed value is 25msec.
+	 * 0 repetition time means one-shot insertion is done.
+	 * Insertion done based on wall-clock.
+	 */
+	__u32 repetition_time;
+
+	/*
+	 * TS packets buffer to be inserted.
+	 * The buffer is inserted as-is to the recording buffer
+	 * without any modification.
+	 * It is advised to set discontinuity flag in the very
+	 * first TS packet in the buffer.
+	 */
+	const __u8 *ts_packets;
+
+	/*
+	 * Size in bytes of the TS packets buffer to be inserted.
+	 * Should be in multiples of 188 or 192 bytes
+	 * depending on recording filter output format.
+	 */
+	size_t size;
+};
+
+struct dmx_abort_ts_insertion {
+	/*
+	 * Identifier of the insertion buffer previously set
+	 * using DMX_SET_TS_INSERTION.
+	 */
+	__u32 identifier;
+};
+
+struct dmx_scrambling_bits {
+	/*
+	 * The PID to return its scrambling bit value.
+	 * In case of recording filter, multiple PIDs may exist in the same
+	 * filter through DMX_ADD_PID ioctl, each may have different
+	 * scrambling bits status.
+	 */
+	__u16 pid;
+
+	/* Current value of scrambling bits: 0, 1, 2 or 3 */
+	__u8 value;
+};
+
 #define DMX_START                _IO('o', 41)
 #define DMX_STOP                 _IO('o', 42)
 #define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
@@ -151,5 +857,27 @@
 #define DMX_GET_STC              _IOWR('o', 50, struct dmx_stc)
 #define DMX_ADD_PID              _IOW('o', 51, __u16)
 #define DMX_REMOVE_PID           _IOW('o', 52, __u16)
+#define DMX_SET_TS_PACKET_FORMAT _IOW('o', 53, enum dmx_tsp_format_t)
+#define DMX_SET_TS_OUT_FORMAT	 _IOW('o', 54, enum dmx_tsp_format_t)
+#define DMX_SET_DECODER_BUFFER_SIZE	_IO('o', 55)
+#define DMX_GET_BUFFER_STATUS	 _IOR('o', 56, struct dmx_buffer_status)
+#define DMX_RELEASE_DATA		 _IO('o', 57)
+#define DMX_FEED_DATA			 _IO('o', 58)
+#define DMX_SET_PLAYBACK_MODE	 _IOW('o', 59, enum dmx_playback_mode_t)
+#define DMX_GET_EVENT		 _IOR('o', 60, struct dmx_filter_event)
+#define DMX_SET_BUFFER_MODE	 _IOW('o', 61, enum dmx_buffer_mode)
+#define DMX_SET_BUFFER		 _IOW('o', 62, struct dmx_buffer)
+#define DMX_SET_DECODER_BUFFER	 _IOW('o', 63, struct dmx_decoder_buffers)
+#define DMX_REUSE_DECODER_BUFFER _IO('o', 64)
+#define DMX_SET_SECURE_MODE	_IOW('o', 65, struct dmx_secure_mode)
+#define DMX_SET_EVENTS_MASK	_IOW('o', 66, struct dmx_events_mask)
+#define DMX_GET_EVENTS_MASK	_IOR('o', 67, struct dmx_events_mask)
+#define DMX_PUSH_OOB_COMMAND	_IOW('o', 68, struct dmx_oob_command)
+#define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params)
+#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion)
+#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion)
+#define DMX_GET_SCRAMBLING_BITS _IOWR('o', 72, struct dmx_scrambling_bits)
+#define DMX_SET_CIPHER _IOW('o', 73, struct dmx_cipher_operations)
+#define DMX_FLUSH_BUFFER _IO('o', 74)
 
 #endif /* _UAPI_DVBDMX_H_ */
diff --git a/include/uapi/linux/msm_audio.h b/include/uapi/linux/msm_audio.h
index bde27d1..3213d00 100644
--- a/include/uapi/linux/msm_audio.h
+++ b/include/uapi/linux/msm_audio.h
@@ -461,4 +461,15 @@
 	__s32 topology;
 };
 
+#define ADSP_STREAM_PP_EVENT				0
+#define ADSP_STREAM_ENCDEC_EVENT			1
+#define ADSP_STREAM_IEC_61937_FMT_UPDATE_EVENT		2
+#define ADSP_STREAM_EVENT_MAX				3
+
+struct msm_adsp_event_data {
+	__u32 event_type;
+	__u32 payload_len;
+	__u8 payload[0];
+};
+
 #endif
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index 57c2ca4..48cfe31 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -68,7 +68,9 @@
 #define IPA_IOCTL_ADD_RT_RULE_AFTER 43
 #define IPA_IOCTL_ADD_FLT_RULE_AFTER 44
 #define IPA_IOCTL_GET_HW_VERSION 45
-#define IPA_IOCTL_MAX 46
+#define IPA_IOCTL_ADD_RT_RULE_EXT 46
+#define IPA_IOCTL_NAT_MODIFY_PDN 47
+#define IPA_IOCTL_MAX 48
 
 /**
  * max size of the header to be inserted
@@ -127,6 +129,11 @@
 #define IPA_FLT_MAC_ETHER_TYPE		(1ul << 21)
 
 /**
+ * maximal number of NAT PDNs in the PDN config table
+ */
+#define IPA_MAX_PDN_NUM 5
+
+/**
  * enum ipa_client_type - names for the various IPA "clients"
  * these are from the perspective of the clients, for e.g.
  * HSIC1_PROD means HSIC client is the producer and IPA is the
@@ -431,10 +438,20 @@
 	IPA_TETHERING_STATS_UPDATE_STATS = IPA_ECM_EVENT_MAX,
 	IPA_TETHERING_STATS_UPDATE_NETWORK_STATS,
 	IPA_TETHERING_STATS_EVENT_MAX,
-	IPA_EVENT_MAX_NUM = IPA_TETHERING_STATS_EVENT_MAX
 };
 
-#define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM)
+enum ipa_quota_event {
+	IPA_QUOTA_REACH = IPA_TETHERING_STATS_EVENT_MAX,
+	IPA_QUOTA_EVENT_MAX,
+};
+
+enum ipa_ssr_event {
+	IPA_SSR_BEFORE_SHUTDOWN = IPA_QUOTA_EVENT_MAX,
+	IPA_SSR_AFTER_POWERUP,
+	IPA_SSR_EVENT_MAX
+};
+
+#define IPA_EVENT_MAX_NUM ((int)IPA_SSR_EVENT_MAX)
 
 /**
  * enum ipa_rm_resource_name - IPA RM clients identification names
@@ -718,6 +735,11 @@
  *  consecutive packets
  * @rule_id: rule_id to be assigned to the filter rule. In case client specifies
  *  rule_id as 0 the driver will assign a new rule_id
+ * @set_metadata: bool switch. should metadata replacement at the NAT block
+ *  take place?
+ * @pdn_idx: if action is "pass to source\destination NAT" then a comparison
+ * against the PDN index in the matching PDN entry will take place as an
+ * additional condition for NAT hit.
  */
 struct ipa_flt_rule {
 	uint8_t retain_hdr;
@@ -731,6 +753,8 @@
 	uint8_t max_prio;
 	uint8_t hashable;
 	uint16_t rule_id;
+	uint8_t set_metadata;
+	uint8_t pdn_idx;
 };
 
 /**
@@ -1407,6 +1431,20 @@
 };
 
 /**
+* struct ipa_ioc_nat_pdn_entry - PDN entry modification data
+* @pdn_index: index of the entry in the PDN config table to be changed
+* @public_ip: PDN's public ip
+* @src_metadata: PDN's source NAT metadata for metadata replacement
+* @dst_metadata: PDN's destination NAT metadata for metadata replacement
+*/
+struct ipa_ioc_nat_pdn_entry {
+	uint8_t pdn_index;
+	uint32_t public_ip;
+	uint32_t src_metadata;
+	uint32_t dst_metadata;
+};
+
+/**
  * struct ipa_msg_meta - Format of the message meta-data.
  * @msg_type: the type of the message
  * @rsvd: reserved bits for future use.
@@ -1628,6 +1666,9 @@
 #define IPA_IOC_GET_NAT_OFFSET _IOWR(IPA_IOC_MAGIC, \
 				IPA_IOCTL_GET_NAT_OFFSET, \
 				uint32_t *)
+#define IPA_IOC_NAT_MODIFY_PDN _IOWR(IPA_IOC_MAGIC, \
+				IPA_IOCTL_NAT_MODIFY_PDN, \
+				struct ipa_ioc_nat_pdn_entry *)
 #define IPA_IOC_SET_FLT _IOW(IPA_IOC_MAGIC, \
 			IPA_IOCTL_SET_FLT, \
 			uint32_t)
diff --git a/include/uapi/linux/rmnet_ipa_fd_ioctl.h b/include/uapi/linux/rmnet_ipa_fd_ioctl.h
index 228bfe8..f04ac49 100644
--- a/include/uapi/linux/rmnet_ipa_fd_ioctl.h
+++ b/include/uapi/linux/rmnet_ipa_fd_ioctl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,7 @@
 #define WAN_IOCTL_RESET_TETHER_STATS     7
 #define WAN_IOCTL_QUERY_DL_FILTER_STATS  8
 #define WAN_IOCTL_ADD_FLT_RULE_EX        9
+#define WAN_IOCTL_QUERY_TETHER_STATS_ALL  10
 
 /* User space may not have this defined. */
 #ifndef IFNAMSIZ
@@ -99,6 +100,16 @@
 	uint64_t ipv6_rx_bytes;
 };
 
+struct wan_ioctl_query_tether_stats_all {
+	/* Name of the upstream interface */
+	char upstreamIface[IFNAMSIZ];
+	/* enum of tether interface */
+	enum ipacm_client_enum ipa_client;
+	uint8_t reset_stats;
+	uint64_t tx_bytes;
+	uint64_t rx_bytes;
+};
+
 struct wan_ioctl_reset_tether_stats {
 	/* Name of the upstream interface, not support now */
 	char upstreamIface[IFNAMSIZ];
@@ -155,4 +166,8 @@
 		WAN_IOCTL_ADD_FLT_RULE_EX, \
 		struct ipa_install_fltr_rule_req_ex_msg_v01 *)
 
+#define WAN_IOC_QUERY_TETHER_STATS_ALL _IOWR(WAN_IOC_MAGIC, \
+		WAN_IOCTL_QUERY_TETHER_STATS_ALL, \
+		struct wan_ioctl_query_tether_stats_all *)
+
 #endif /* _RMNET_IPA_FD_IOCTL_H */
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index cf96ac1..e5c4ddf 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -779,6 +779,9 @@
 #define V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE \
 	V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE
 	V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE = 30,
+#define V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO \
+	V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO
+	V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO = 31,
 };
 
 #define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE	\
diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h
index a4557d1..5f0f070 100644
--- a/include/uapi/media/cam_defs.h
+++ b/include/uapi/media/cam_defs.h
@@ -7,14 +7,15 @@
 
 
 /* camera op codes */
-#define CAM_COMMON_OPCODE_BASE                  0
-#define CAM_QUERY_CAP                           1
-#define CAM_ACQUIRE_DEV                         2
-#define CAM_START_DEV                           3
-#define CAM_STOP_DEV                            4
-#define CAM_CONFIG_DEV                          5
-#define CAM_RELEASE_DEV                         6
-#define CAM_COMMON_OPCODE_MAX                   7
+#define CAM_COMMON_OPCODE_BASE                  0x100
+#define CAM_QUERY_CAP                           (CAM_COMMON_OPCODE_BASE + 0x1)
+#define CAM_ACQUIRE_DEV                         (CAM_COMMON_OPCODE_BASE + 0x2)
+#define CAM_START_DEV                           (CAM_COMMON_OPCODE_BASE + 0x3)
+#define CAM_STOP_DEV                            (CAM_COMMON_OPCODE_BASE + 0x4)
+#define CAM_CONFIG_DEV                          (CAM_COMMON_OPCODE_BASE + 0x5)
+#define CAM_RELEASE_DEV                         (CAM_COMMON_OPCODE_BASE + 0x6)
+#define CAM_SD_SHUTDOWN                         (CAM_COMMON_OPCODE_BASE + 0x7)
+#define CAM_COMMON_OPCODE_MAX                   (CAM_COMMON_OPCODE_BASE + 0x8)
 
 /* camera handle type */
 #define CAM_HANDLE_USER_POINTER                 1
diff --git a/include/uapi/media/msm_vidc.h b/include/uapi/media/msm_vidc.h
index 7161102..4fe325d 100644
--- a/include/uapi/media/msm_vidc.h
+++ b/include/uapi/media/msm_vidc.h
@@ -170,6 +170,16 @@
 	unsigned int data[1];
 };
 
+struct msm_vidc_ubwc_cr_stats_info {
+	unsigned int stats_tile_32;
+	unsigned int stats_tile_64;
+	unsigned int stats_tile_96;
+	unsigned int stats_tile_128;
+	unsigned int stats_tile_160;
+	unsigned int stats_tile_192;
+	unsigned int stats_tile_256;
+};
+
 struct msm_vidc_yuv_stats_payload {
 	unsigned int frame_qp;
 	unsigned int texture;
@@ -250,6 +260,12 @@
 #define MSM_VIDC_EXTRADATA_PQ_INFO \
 	MSM_VIDC_EXTRADATA_PQ_INFO
 	MSM_VIDC_EXTRADATA_PQ_INFO = 0x00000017,
+#define MSM_VIDC_EXTRADATA_COLOUR_REMAPPING_INFO_SEI \
+	MSM_VIDC_EXTRADATA_COLOUR_REMAPPING_INFO_SEI
+	MSM_VIDC_EXTRADATA_COLOUR_REMAPPING_INFO_SEI = 0x00000018,
+#define MSM_VIDC_EXTRADATA_UBWC_CR_STAT_INFO \
+	MSM_VIDC_EXTRADATA_UBWC_CR_STAT_INFO
+	MSM_VIDC_EXTRADATA_UBWC_CR_STAT_INFO = 0x00000019,
 	MSM_VIDC_EXTRADATA_INPUT_CROP = 0x0700000E,
 #define MSM_VIDC_EXTRADATA_OUTPUT_CROP \
 	MSM_VIDC_EXTRADATA_OUTPUT_CROP
@@ -354,6 +370,15 @@
 	MSM_VIDC_TRANSFER_SRGB = 13,
 	MSM_VIDC_TRANSFER_BT_2020_10 = 14,
 	MSM_VIDC_TRANSFER_BT_2020_12 = 15,
+#define MSM_VIDC_TRANSFER_SMPTE_ST2084 \
+	MSM_VIDC_TRANSFER_SMPTE_ST2084
+	MSM_VIDC_TRANSFER_SMPTE_ST2084 = 16,
+#define MSM_VIDC_TRANSFER_SMPTE_ST428_1 \
+	MSM_VIDC_TRANSFER_SMPTE_ST428_1
+	MSM_VIDC_TRANSFER_SMPTE_ST428_1 = 17,
+#define MSM_VIDC_TRANSFER_HLG \
+	MSM_VIDC_TRANSFER_HLG
+	MSM_VIDC_TRANSFER_HLG = 18,
 };
 
 enum msm_vidc_pixel_depth {
diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h
index 3048105..866ec3d 100644
--- a/include/uapi/sound/compress_offload.h
+++ b/include/uapi/sound/compress_offload.h
@@ -149,6 +149,8 @@
  * @SNDRV_COMPRESS_CLK_REC_MODE: clock recovery mode ( none or auto)
  * @SNDRV_COMPRESS_RENDER_WINDOW: render window
  * @SNDRV_COMPRESS_START_DELAY: start delay
+ * @SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK: enable dsp drift correction
+ * @SNDRV_COMPRESS_ADJUST_SESSION_CLOCK: set drift correction value
  */
 enum sndrv_compress_encoder {
 	SNDRV_COMPRESS_ENCODER_PADDING = 1,
@@ -160,6 +162,8 @@
 	SNDRV_COMPRESS_CLK_REC_MODE = 7,
 	SNDRV_COMPRESS_RENDER_WINDOW = 8,
 	SNDRV_COMPRESS_START_DELAY = 9,
+	SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK = 10,
+	SNDRV_COMPRESS_ADJUST_SESSION_CLOCK = 11,
 };
 
 #define SNDRV_COMPRESS_PATH_DELAY SNDRV_COMPRESS_PATH_DELAY
@@ -167,6 +171,9 @@
 #define SNDRV_COMPRESS_CLK_REC_MODE SNDRV_COMPRESS_CLK_REC_MODE
 #define SNDRV_COMPRESS_RENDER_WINDOW SNDRV_COMPRESS_RENDER_WINDOW
 #define SNDRV_COMPRESS_START_DELAY SNDRV_COMPRESS_START_DELAY
+#define SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK \
+			SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK
+#define SNDRV_COMPRESS_ADJUST_SESSION_CLOCK SNDRV_COMPRESS_ADJUST_SESSION_CLOCK
 
 /**
  * struct snd_compr_metadata - compressed stream metadata
diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h
index 09593e7..8c84053 100644
--- a/include/uapi/sound/compress_params.h
+++ b/include/uapi/sound/compress_params.h
@@ -105,7 +105,8 @@
 #define SND_AUDIOCODEC_APE                   ((__u32) 0x00000021)
 #define SND_AUDIOCODEC_DSD                   ((__u32) 0x00000022)
 #define SND_AUDIOCODEC_APTX                  ((__u32) 0x00000023)
-#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_APTX
+#define SND_AUDIOCODEC_TRUEHD                ((__u32) 0x00000024)
+#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_TRUEHD
 
 /*
  * Profile and modes are listed with bit masks. This allows for a
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 02e367a..c0644f4 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -5433,6 +5433,11 @@
 {
 	lockdep_assert_held(&cgroup_mutex);
 
+	if (css->flags & CSS_DYING)
+		return;
+
+	css->flags |= CSS_DYING;
+
 	/*
 	 * This must happen before css is disassociated with its cgroup.
 	 * See seq_css() for details.
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 21a8764..78b72d5 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -463,6 +463,7 @@
 
 	for (; st->state > target; st->state--) {
 		ret = cpuhp_invoke_callback(cpu, st->state, false, NULL);
+		BUG_ON(ret && st->state < CPUHP_AP_IDLE_DEAD);
 		if (ret) {
 			st->target = prev_state;
 			undo_cpu_down(cpu, st);
@@ -494,6 +495,7 @@
 		if (ret) {
 			st->target = prev_state;
 			undo_cpu_up(cpu, st);
+			cpu_notify(CPU_UP_CANCELED, cpu);
 			break;
 		}
 	}
@@ -1812,13 +1814,13 @@
 	ret = !sp->name || sp->cant_stop ? -EINVAL : 0;
 	mutex_unlock(&cpuhp_state_mutex);
 	if (ret)
-		return ret;
+		goto out;
 
 	if (st->state < target)
 		ret = do_cpu_up(dev->id, target);
 	else
 		ret = do_cpu_down(dev->id, target);
-
+out:
 	unlock_device_hotplug();
 	return ret ? ret : count;
 }
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 4b7b6cb..a99cd8d 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -175,9 +175,9 @@
 } cpuset_flagbits_t;
 
 /* convenient tests for these bits */
-static inline bool is_cpuset_online(const struct cpuset *cs)
+static inline bool is_cpuset_online(struct cpuset *cs)
 {
-	return test_bit(CS_ONLINE, &cs->flags);
+	return test_bit(CS_ONLINE, &cs->flags) && !css_is_dying(&cs->css);
 }
 
 static inline int is_cpu_exclusive(const struct cpuset *cs)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 41f376d..d877aba 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -373,6 +373,7 @@
 static DEFINE_PER_CPU(int, perf_sched_cb_usages);
 static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events);
 static DEFINE_PER_CPU(bool, is_idle);
+static DEFINE_PER_CPU(bool, is_hotplugging);
 
 static atomic_t nr_mmap_events __read_mostly;
 static atomic_t nr_comm_events __read_mostly;
@@ -3495,6 +3496,9 @@
 	struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
 	struct pmu *pmu = event->pmu;
 
+	if (__this_cpu_read(is_hotplugging))
+		return;
+
 	/*
 	 * If this is a task context, we need to check whether it is
 	 * the current task context of this cpu.  If not it has been
@@ -3619,7 +3623,8 @@
 			return 0;
 		if (cpu_isolated(event_cpu) ||
 			(event->attr.exclude_idle &&
-				per_cpu(is_idle, event_cpu)))
+				per_cpu(is_idle, event_cpu)) ||
+				per_cpu(is_hotplugging, event_cpu))
 			active_event_skip_read = true;
 	}
 
@@ -3649,7 +3654,8 @@
 		preempt_enable();
 		ret = data.ret;
 	} else if (event->state == PERF_EVENT_STATE_INACTIVE ||
-			active_event_skip_read) {
+			(active_event_skip_read &&
+			!per_cpu(is_hotplugging, event_cpu))) {
 		struct perf_event_context *ctx = event->ctx;
 		unsigned long flags;
 
@@ -7080,6 +7086,21 @@
 	perf_output_end(&handle);
 }
 
+static bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs)
+{
+	/*
+	 * Due to interrupt latency (AKA "skid"), we may enter the
+	 * kernel before taking an overflow, even if the PMU is only
+	 * counting user events.
+	 * To avoid leaking information to userspace, we must always
+	 * reject kernel samples when exclude_kernel is set.
+	 */
+	if (event->attr.exclude_kernel && !user_mode(regs))
+		return false;
+
+	return true;
+}
+
 /*
  * Generic event overflow handling, sampling.
  */
@@ -7127,6 +7148,12 @@
 	}
 
 	/*
+	 * For security, drop the skid kernel samples if necessary.
+	 */
+	if (!sample_is_allowed(event, regs))
+		return ret;
+
+	/*
 	 * XXX event_limit might not quite work as expected on inherited
 	 * events
 	 */
@@ -10711,6 +10738,8 @@
 		raw_spin_lock_init(&per_cpu(pmu_sb_events.lock, cpu));
 
 		INIT_LIST_HEAD(&per_cpu(sched_cb_list, cpu));
+		per_cpu(is_hotplugging, cpu) = false;
+		per_cpu(is_idle, cpu) = false;
 	}
 }
 
@@ -10734,19 +10763,10 @@
 static void
 check_hotplug_start_event(struct perf_event *event)
 {
-	if (event->attr.type == PERF_TYPE_SOFTWARE) {
-		switch (event->attr.config) {
-		case PERF_COUNT_SW_CPU_CLOCK:
-			cpu_clock_event_start(event, 0);
-			break;
-		case PERF_COUNT_SW_TASK_CLOCK:
-			break;
-		default:
-			if (event->pmu->start)
-				event->pmu->start(event, 0);
-			break;
-		}
-	}
+	if (event->pmu->events_across_hotplug &&
+	    event->attr.type == PERF_TYPE_SOFTWARE &&
+	    event->pmu->start)
+		event->pmu->start(event, 0);
 }
 
 static int perf_event_start_swevents(unsigned int cpu)
@@ -10767,6 +10787,7 @@
 		mutex_unlock(&ctx->mutex);
 	}
 	srcu_read_unlock(&pmus_srcu, idx);
+	per_cpu(is_hotplugging, cpu) = false;
 	return 0;
 }
 
@@ -10783,22 +10804,13 @@
 			   struct perf_cpu_context *cpuctx,
 			   struct perf_event_context *ctx)
 {
-	if (!event->pmu->events_across_hotplug) {
+	if (event->pmu->events_across_hotplug &&
+	    event->attr.type == PERF_TYPE_SOFTWARE &&
+	    event->pmu->stop)
+		event->pmu->stop(event, PERF_EF_UPDATE);
+	else if (!event->pmu->events_across_hotplug)
 		__perf_remove_from_context(event, cpuctx,
 			ctx, (void *)DETACH_GROUP);
-	} else if (event->attr.type == PERF_TYPE_SOFTWARE) {
-		switch (event->attr.config) {
-		case PERF_COUNT_SW_CPU_CLOCK:
-			cpu_clock_event_stop(event, 0);
-			break;
-		case PERF_COUNT_SW_TASK_CLOCK:
-			break;
-		default:
-			if (event->pmu->stop)
-				event->pmu->stop(event, 0);
-			break;
-		}
-	}
 }
 
 static void __perf_event_exit_context(void *__info)
@@ -10837,6 +10849,7 @@
 
 int perf_event_exit_cpu(unsigned int cpu)
 {
+	per_cpu(is_hotplugging, cpu) = true;
 	perf_event_exit_cpu_context(cpu);
 	return 0;
 }
@@ -10880,6 +10893,24 @@
 	.notifier_call = event_idle_notif,
 };
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int perf_cpu_hp_init(void)
+{
+	int ret;
+
+	ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE,
+				"PERF/CORE/CPUHP_AP_PERF_ONLINE",
+				perf_event_start_swevents,
+				perf_event_exit_cpu);
+	if (ret)
+		pr_err("CPU hotplug notifier for perf core could not be registered: %d\n",
+		       ret);
+
+	return ret;
+}
+#else
+static int perf_cpu_hp_init(void) { return 0; }
+#endif
 
 void __init perf_event_init(void)
 {
@@ -10896,6 +10927,8 @@
 	perf_event_init_cpu(smp_processor_id());
 	idle_notifier_register(&perf_event_idle_nb);
 	register_reboot_notifier(&perf_reboot_notifier);
+	ret = perf_cpu_hp_init();
+	WARN(ret, "core perf_cpu_hp_init() failed with: %d", ret);
 
 	ret = init_hw_breakpoint();
 	WARN(ret, "hw_breakpoint initialization failed with: %d", ret);
@@ -10949,22 +10982,6 @@
 }
 device_initcall(perf_event_sysfs_init);
 
-#ifdef CONFIG_HOTPLUG_CPU
-static int perf_cpu_hp_init(void)
-{
-	int ret;
-
-	ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE,
-				"PERF/CORE/AP_PERF_ONLINE",
-				perf_event_start_swevents,
-				perf_event_exit_cpu);
-	if (ret)
-		pr_err("CPU hotplug notifier for perf core could not be registered: %d\n",
-		       ret);
-	return ret;
-}
-subsys_initcall(perf_cpu_hp_init);
-#endif
 
 #ifdef CONFIG_CGROUP_PERF
 static struct cgroup_subsys_state *
diff --git a/kernel/kthread.c b/kernel/kthread.c
index b65854c..80bf7ba 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -160,9 +160,11 @@
 {
 	__set_current_state(TASK_PARKED);
 	while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
+		preempt_disable();
 		if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
 			complete(&self->parked);
-		schedule();
+		schedule_preempt_disabled();
+		preempt_enable();
 		__set_current_state(TASK_PARKED);
 	}
 	clear_bit(KTHREAD_IS_PARKED, &self->flags);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index a5caece..f39a7be9 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -57,19 +57,25 @@
 }
 
 
+void __ptrace_link(struct task_struct *child, struct task_struct *new_parent,
+		   const struct cred *ptracer_cred)
+{
+	BUG_ON(!list_empty(&child->ptrace_entry));
+	list_add(&child->ptrace_entry, &new_parent->ptraced);
+	child->parent = new_parent;
+	child->ptracer_cred = get_cred(ptracer_cred);
+}
+
 /*
  * ptrace a task: make the debugger its new parent and
  * move it to the ptrace list.
  *
  * Must be called with the tasklist lock write-held.
  */
-void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
+static void ptrace_link(struct task_struct *child, struct task_struct *new_parent)
 {
-	BUG_ON(!list_empty(&child->ptrace_entry));
-	list_add(&child->ptrace_entry, &new_parent->ptraced);
-	child->parent = new_parent;
 	rcu_read_lock();
-	child->ptracer_cred = get_cred(__task_cred(new_parent));
+	__ptrace_link(child, new_parent, __task_cred(new_parent));
 	rcu_read_unlock();
 }
 
@@ -383,7 +389,7 @@
 		flags |= PT_SEIZED;
 	task->ptrace = flags;
 
-	__ptrace_link(task, current);
+	ptrace_link(task, current);
 
 	/* SEIZE doesn't trap tracee on attach */
 	if (!seize)
@@ -456,7 +462,7 @@
 		 */
 		if (!ret && !(current->real_parent->flags & PF_EXITING)) {
 			current->ptrace = PT_PTRACED;
-			__ptrace_link(current, current->real_parent);
+			ptrace_link(current, current->real_parent);
 		}
 	}
 	write_unlock_irq(&tasklist_lock);
diff --git a/kernel/sched/boost.c b/kernel/sched/boost.c
index f5e87791..1a3309b 100644
--- a/kernel/sched/boost.c
+++ b/kernel/sched/boost.c
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/jiffies.h>
 #include "sched.h"
 #include <linux/of.h>
 #include <linux/sched/core_ctl.h>
@@ -140,7 +139,6 @@
 	case RESTRAINED_BOOST:
 		freq_aggr_threshold_backup =
 			update_freq_aggregate_threshold(1);
-		mod_timer(&sched_grp_timer, jiffies + 1);
 		break;
 
 	default:
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index c42380a..0a0e9aa 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -36,7 +36,6 @@
 	raw_spinlock_t update_lock;  /* For shared policies */
 	u64 last_freq_update_time;
 	s64 freq_update_delay_ns;
-	u64 hispeed_jmp_ts;
 	unsigned int next_freq;
 	unsigned int cached_raw_freq;
 	unsigned long hispeed_util;
@@ -216,11 +215,8 @@
 					   HISPEED_LOAD,
 					   100));
 
-	if (is_hiload && !is_migration &&
-	    sg_policy->next_freq < sg_policy->tunables->hispeed_freq) {
+	if (is_hiload && !is_migration)
 		*util = max(*util, sg_policy->hispeed_util);
-		sg_policy->hispeed_jmp_ts = sg_cpu->last_update;
-	}
 
 	if (is_hiload && nl >= mult_frac(cpu_util, NL_RATIO, 100))
 		*util = *max;
diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c
index 11e9705..ba5e3e2 100644
--- a/kernel/sched/cpupri.c
+++ b/kernel/sched/cpupri.c
@@ -27,6 +27,8 @@
  *  of the License.
  */
 
+#include "sched.h"
+
 #include <linux/gfp.h>
 #include <linux/sched.h>
 #include <linux/sched/rt.h>
@@ -51,6 +53,27 @@
 }
 
 /**
+ * drop_nopreempt_cpus - remove a cpu from the mask if it is likely
+ *			 non-preemptible
+ * @lowest_mask: mask with selected CPUs (non-NULL)
+ */
+static void
+drop_nopreempt_cpus(struct cpumask *lowest_mask)
+{
+	unsigned int cpu = cpumask_first(lowest_mask);
+
+	while (cpu < nr_cpu_ids) {
+		/* unlocked access */
+		struct task_struct *task = READ_ONCE(cpu_rq(cpu)->curr);
+
+		if (task_may_not_preempt(task, cpu))
+			cpumask_clear_cpu(cpu, lowest_mask);
+
+		cpu = cpumask_next(cpu, lowest_mask);
+	}
+}
+
+/**
  * cpupri_find - find the best (lowest-pri) CPU in the system
  * @cp: The cpupri context
  * @p: The task
@@ -70,9 +93,11 @@
 {
 	int idx = 0;
 	int task_pri = convert_prio(p->prio);
+	bool drop_nopreempts = task_pri <= MAX_RT_PRIO;
 
 	BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES);
 
+retry:
 	for (idx = 0; idx < task_pri; idx++) {
 		struct cpupri_vec *vec  = &cp->pri_to_cpu[idx];
 		int skip = 0;
@@ -108,7 +133,8 @@
 
 		if (lowest_mask) {
 			cpumask_and(lowest_mask, tsk_cpus_allowed(p), vec->mask);
-
+			if (drop_nopreempts)
+				drop_nopreempt_cpus(lowest_mask);
 			/*
 			 * We have to ensure that we have at least one bit
 			 * still set in the array, since the map could have
@@ -123,7 +149,14 @@
 
 		return 1;
 	}
-
+	/*
+	 * If we can't find any non-preemptible cpu's, retry so we can
+	 * find the lowest priority target and avoid priority inversion.
+	 */
+	if (drop_nopreempts) {
+		drop_nopreempts = false;
+		goto retry;
+	}
 	return 0;
 }
 
diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c
index 05dd2cb..c32defa 100644
--- a/kernel/sched/energy.c
+++ b/kernel/sched/energy.c
@@ -18,14 +18,15 @@
  */
 #define pr_fmt(fmt) "sched-energy: " fmt
 
-#define DEBUG
-
 #include <linux/gfp.h>
 #include <linux/of.h>
 #include <linux/printk.h>
 #include <linux/sched.h>
 #include <linux/sched_energy.h>
 #include <linux/stddef.h>
+#include <linux/cpu.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
 
 struct sched_group_energy *sge_array[NR_CPUS][NR_SD_LEVELS];
 
@@ -84,14 +85,21 @@
 
 			sge = kcalloc(1, sizeof(struct sched_group_energy),
 				      GFP_NOWAIT);
+			if (!sge)
+				goto out;
 
 			nstates = (prop->length / sizeof(u32)) / 2;
 			cap_states = kcalloc(nstates,
 					     sizeof(struct capacity_state),
 					     GFP_NOWAIT);
+			if (!cap_states) {
+				kfree(sge);
+				goto out;
+			}
 
 			for (i = 0, val = prop->value; i < nstates; i++) {
-				cap_states[i].cap = be32_to_cpup(val++);
+				cap_states[i].cap = SCHED_CAPACITY_SCALE;
+				cap_states[i].frequency = be32_to_cpup(val++);
 				cap_states[i].power = be32_to_cpup(val++);
 			}
 
@@ -101,6 +109,8 @@
 			prop = of_find_property(cp, "idle-cost-data", NULL);
 			if (!prop || !prop->value) {
 				pr_warn("No idle-cost data, skipping sched_energy init\n");
+				kfree(sge);
+				kfree(cap_states);
 				goto out;
 			}
 
@@ -108,6 +118,11 @@
 			idle_states = kcalloc(nstates,
 					      sizeof(struct idle_state),
 					      GFP_NOWAIT);
+			if (!idle_states) {
+				kfree(sge);
+				kfree(cap_states);
+				goto out;
+			}
 
 			for (i = 0, val = prop->value; i < nstates; i++)
 				idle_states[i].power = be32_to_cpup(val++);
@@ -125,3 +140,166 @@
 out:
 	free_resources();
 }
+
+static int sched_energy_probe(struct platform_device *pdev)
+{
+	unsigned long max_freq = 0;
+	int max_efficiency = INT_MIN;
+	int cpu;
+	unsigned long *max_frequencies = NULL;
+	int ret;
+
+	if (!sched_is_energy_aware())
+		return 0;
+
+	max_frequencies = kmalloc_array(nr_cpu_ids, sizeof(unsigned long),
+					GFP_KERNEL);
+	if (!max_frequencies) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	/*
+	 * Find system max possible frequency and max frequencies for each
+	 * CPUs.
+	 */
+	for_each_possible_cpu(cpu) {
+		struct device *cpu_dev;
+		struct dev_pm_opp *opp;
+		int efficiency = arch_get_cpu_efficiency(cpu);
+
+		max_efficiency = max(efficiency, max_efficiency);
+
+		cpu_dev = get_cpu_device(cpu);
+		if (IS_ERR_OR_NULL(cpu_dev)) {
+			if (!cpu_dev)
+				ret = -EINVAL;
+			else
+				ret = PTR_ERR(cpu_dev);
+			goto exit;
+		}
+
+		max_frequencies[cpu] = ULONG_MAX;
+
+		rcu_read_lock();
+		opp = dev_pm_opp_find_freq_floor(cpu_dev,
+						 &max_frequencies[cpu]);
+		if (IS_ERR_OR_NULL(opp)) {
+			if (!opp || PTR_ERR(opp) == -ENODEV)
+				ret = -EPROBE_DEFER;
+			else
+				ret = PTR_ERR(opp);
+			goto exit_rcu_unlock;
+		}
+		rcu_read_unlock();
+
+		/* Convert HZ to KHZ */
+		max_frequencies[cpu] /= 1000;
+		max_freq = max(max_freq, max_frequencies[cpu]);
+	}
+
+	/* update capacity in energy model */
+	for_each_possible_cpu(cpu) {
+		unsigned long cpu_max_cap;
+		struct sched_group_energy *sge_l0, *sge;
+		int efficiency = arch_get_cpu_efficiency(cpu);
+
+		cpu_max_cap = DIV_ROUND_UP(SCHED_CAPACITY_SCALE *
+					   max_frequencies[cpu], max_freq);
+		cpu_max_cap = DIV_ROUND_UP(cpu_max_cap * efficiency,
+					   max_efficiency);
+
+		/*
+		 * All the cap_states have same frequency table so use
+		 * SD_LEVEL0's.
+		 */
+		sge_l0 = sge_array[cpu][SD_LEVEL0];
+		if (sge_l0 && sge_l0->nr_cap_states > 0) {
+			int i;
+			int ncapstates = sge_l0->nr_cap_states;
+
+			for (i = 0; i < ncapstates; i++) {
+				int sd_level;
+				unsigned long freq, cap;
+
+				/*
+				 * Energy model can contain more frequency
+				 * steps than actual for multiple speedbin
+				 * support. Ceil the max capacity with actual
+				 * one.
+				 */
+				freq = min(sge_l0->cap_states[i].frequency,
+					   max_frequencies[cpu]);
+				cap = DIV_ROUND_UP(cpu_max_cap * freq,
+						   max_frequencies[cpu]);
+
+				for_each_possible_sd_level(sd_level) {
+					sge = sge_array[cpu][sd_level];
+					if (!sge)
+						break;
+					sge->cap_states[i].cap = cap;
+				}
+
+				dev_dbg(&pdev->dev,
+					"cpu=%d freq=%ld cap=%ld power_d0=%ld\n",
+					cpu, freq, sge_l0->cap_states[i].cap,
+					sge_l0->cap_states[i].power);
+			}
+
+			dev_info(&pdev->dev,
+				"cpu=%d eff=%d [freq=%ld cap=%ld power_d0=%ld] -> [freq=%ld cap=%ld power_d0=%ld]\n",
+				cpu, efficiency,
+				sge_l0->cap_states[0].frequency,
+				sge_l0->cap_states[0].cap,
+				sge_l0->cap_states[0].power,
+				sge_l0->cap_states[ncapstates - 1].frequency,
+				sge_l0->cap_states[ncapstates - 1].cap,
+				sge_l0->cap_states[ncapstates - 1].power
+				);
+		}
+
+
+		dev_dbg(&pdev->dev,
+			"cpu=%d efficiency=%d max_frequency=%ld max_efficiency=%d cpu_max_capacity=%ld\n",
+			cpu, efficiency, max_frequencies[cpu], max_efficiency,
+			cpu_max_cap);
+
+		arch_update_cpu_capacity(cpu);
+	}
+
+	kfree(max_frequencies);
+
+	dev_info(&pdev->dev, "Sched-energy-costs capacity updated\n");
+	return 0;
+
+exit_rcu_unlock:
+	rcu_read_unlock();
+
+exit:
+	if (ret != -EPROBE_DEFER)
+		dev_err(&pdev->dev, "error=%d\n", ret);
+
+	kfree(max_frequencies);
+	return ret;
+}
+
+static const struct of_device_id of_sched_energy_dt[] = {
+	{
+		.compatible = "sched-energy",
+	},
+	{ }
+};
+
+static struct platform_driver energy_driver = {
+	.driver = {
+		.name = "sched-energy",
+		.of_match_table = of_sched_energy_dt,
+	},
+	.probe = sched_energy_probe,
+};
+
+static int __init sched_energy_init(void)
+{
+	return platform_driver_register(&energy_driver);
+}
+subsys_initcall(sched_energy_init);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index cd406da..4d7c054 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -5406,28 +5406,12 @@
 	return p->se.avg.util_avg;
 }
 
-#define SCHED_ENABLE_WAKER_WAKEE	0
-
-static unsigned int sched_small_wakee_task_util = 102; /* ~10% of max cap */
-static unsigned int sched_big_waker_task_util = 256;  /* 25% of max cap */
-
-static inline bool
-wake_on_waker_sibling(struct task_struct *p)
-{
-	return SCHED_ENABLE_WAKER_WAKEE &&
-	       task_util(current) > sched_big_waker_task_util &&
-	       task_util(p) < sched_small_wakee_task_util;
-}
-
-#define sysctl_sched_prefer_sync_wakee_to_waker 0
-
 static inline bool
 bias_to_waker_cpu(struct task_struct *p, int cpu)
 {
-	return sysctl_sched_prefer_sync_wakee_to_waker &&
-	       cpu_rq(cpu)->nr_running == 1 &&
-	       cpumask_test_cpu(cpu, tsk_cpus_allowed(p)) &&
-	       cpu_active(cpu) && !cpu_isolated(cpu);
+	return cpumask_test_cpu(cpu, tsk_cpus_allowed(p)) &&
+	       cpu_active(cpu) && !cpu_isolated(cpu) &&
+	       task_fits_max(p, cpu);
 }
 
 static int calc_util_delta(struct energy_env *eenv, int cpu)
@@ -5644,6 +5628,9 @@
 				if (unlikely(idle_idx < 0))
 					return idle_idx;
 
+				if (idle_idx > sg->sge->nr_idle_states - 1)
+					idle_idx = sg->sge->nr_idle_states - 1;
+
 				group_util = group_norm_util(eenv, sg);
 				sg_busy_energy = (group_util * sg->sge->cap_states[cap_idx].power);
 
@@ -6735,10 +6722,8 @@
 	unsigned int target_cpu_util = UINT_MAX;
 	long target_cpu_new_util_cum = LONG_MAX;
 	struct cpumask *rtg_target = NULL;
-	bool wake_on_sibling = false;
 	int isolated_candidate = -1;
 	bool need_idle;
-	bool skip_ediff = false;
 	enum sched_boost_policy placement_boost = task_sched_boost(p) ?
 				sched_boost_policy() : SCHED_BOOST_NONE;
 
@@ -6751,10 +6736,17 @@
 	sg_target = sg;
 
 	sync = sync && sysctl_sched_sync_hint_enable;
+
 	curr_util = boosted_task_util(cpu_rq(cpu)->curr);
 
 	need_idle = wake_to_idle(p);
 
+	if (sync && bias_to_waker_cpu(p, cpu)) {
+		trace_sched_task_util_bias_to_waker(p, task_cpu(p),
+					task_util(p), cpu, cpu, 0, need_idle);
+		return cpu;
+	}
+
 	if (sysctl_sched_is_big_little) {
 		struct related_thread_group *grp;
 
@@ -6762,17 +6754,8 @@
 		grp = task_related_thread_group(p);
 		rcu_read_unlock();
 
-		if (grp && grp->preferred_cluster) {
+		if (grp && grp->preferred_cluster)
 			rtg_target = &grp->preferred_cluster->cpus;
-		} else if (sync && wake_on_waker_sibling(p)) {
-			if (bias_to_waker_cpu(p, cpu)) {
-				trace_sched_task_util_bias_to_waker(p,
-						task_cpu(p), task_util(p), cpu,
-						cpu, 0, need_idle);
-				return cpu;
-			}
-			wake_on_sibling = true;
-		}
 
 		task_util_boosted = boosted_task_util(p);
 
@@ -6823,21 +6806,6 @@
 							     rtg_target))
 						break;
 					continue;
-				} else if (wake_on_sibling) {
-					/* Skip non-sibling CPUs */
-					if (!cpumask_test_cpu(cpu,
-							sched_group_cpus(sg)))
-						continue;
-				} else if (sync && curr_util >=
-						   task_util_boosted) {
-					if (cpumask_test_cpu(cpu,
-							sched_group_cpus(sg))) {
-						if (!cpumask_test_cpu(task_cpu(p),
-								      sched_group_cpus(sg)))
-							skip_ediff = true;
-						break;
-					}
-					continue;
 				}
 
 				target_max_cap = capacity_of(max_cap_cpu);
@@ -6902,12 +6870,9 @@
 			if (new_util > capacity_orig_of(i))
 				continue;
 
-			cpu_idle_idx = cpu_rq(i)->nr_running ? -1 :
-				       idle_get_state_idx(cpu_rq(i));
+			cpu_idle_idx = idle_get_state_idx(cpu_rq(i));
 
 			if (!need_idle &&
-			    (!wake_on_sibling ||
-			     (wake_on_sibling && i != cpu)) &&
 			    add_capacity_margin(new_util_cum) <
 			    capacity_curr_of(i)) {
 				if (sysctl_sched_cstate_aware) {
@@ -6941,9 +6906,7 @@
 					target_cpu = i;
 					break;
 				}
-			} else if (!need_idle &&
-				   (!wake_on_sibling ||
-				    (wake_on_sibling && i != cpu))) {
+			} else if (!need_idle) {
 				/*
 				 * At least one CPU other than target_cpu is
 				 * going to raise CPU's OPP higher than current
@@ -7014,13 +6977,6 @@
 		}
 	}
 
-	if (wake_on_sibling && target_cpu != -1) {
-		trace_sched_task_util_bias_to_waker(p, task_cpu(p),
-						task_util(p), target_cpu,
-						target_cpu, 0, need_idle);
-		return target_cpu;
-	}
-
 	if (target_cpu != task_cpu(p) && !cpu_isolated(task_cpu(p))) {
 		struct energy_env eenv = {
 			.util_delta	= task_util(p),
@@ -7042,6 +6998,18 @@
 			return target_cpu;
 		}
 
+		/*
+		 * We always want to migrate the task to the best CPU when
+		 * placement boost is active.
+		 */
+		if (placement_boost) {
+			trace_sched_task_util_boosted(p, task_cpu(p),
+						task_util(p),
+						target_cpu,
+						target_cpu, 0, need_idle);
+			return target_cpu;
+		}
+
 #ifdef CONFIG_SCHED_WALT
 		if (walt_disabled || !sysctl_sched_use_walt_cpu_util)
 			task_util_boosted = 0;
@@ -7056,8 +7024,7 @@
 			return target_cpu;
 		}
 
-		if (!skip_ediff)
-			ediff = energy_diff(&eenv);
+		ediff = energy_diff(&eenv);
 
 		if (!sysctl_sched_cstate_aware) {
 			if (ediff >= 0) {
@@ -8463,7 +8430,8 @@
 		mcc->cpu = cpu;
 #ifdef CONFIG_SCHED_DEBUG
 		raw_spin_unlock_irqrestore(&mcc->lock, flags);
-		pr_info("CPU%d: update max cpu_capacity %lu\n", cpu, capacity);
+		printk_deferred(KERN_INFO "CPU%d: update max cpu_capacity %lu\n",
+				cpu, capacity);
 		goto skip_unlock;
 #endif
 	}
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index 6c28298..24b60d7 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -783,20 +783,6 @@
 		return 0;
 }
 
-void free_task_load_ptrs(struct task_struct *p)
-{
-	kfree(p->ravg.curr_window_cpu);
-	kfree(p->ravg.prev_window_cpu);
-
-	/*
-	 * update_task_ravg() can be called for exiting tasks. While the
-	 * function itself ensures correct behavior, the corresponding
-	 * trace event requires that these pointers be NULL.
-	 */
-	p->ravg.curr_window_cpu = NULL;
-	p->ravg.prev_window_cpu = NULL;
-}
-
 /* Return task demand in percentage scale */
 unsigned int pct_task_load(struct task_struct *p)
 {
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 2703e0d..65b34b4 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -6,6 +6,7 @@
 #include "sched.h"
 #include "walt.h"
 
+#include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/irq_work.h>
 #include <trace/events/sched.h>
@@ -1489,11 +1490,30 @@
 #ifdef CONFIG_SMP
 static int find_lowest_rq(struct task_struct *task);
 
+/*
+ * Return whether the task on the given cpu is currently non-preemptible
+ * while handling a potentially long softint, or if the task is likely
+ * to block preemptions soon because it is a ksoftirq thread that is
+ * handling slow softints.
+ */
+bool
+task_may_not_preempt(struct task_struct *task, int cpu)
+{
+	__u32 softirqs = per_cpu(active_softirqs, cpu) |
+			 __IRQ_STAT(cpu, __softirq_pending);
+	struct task_struct *cpu_ksoftirqd = per_cpu(ksoftirqd, cpu);
+
+	return ((softirqs & LONG_SOFTIRQ_MASK) &&
+		(task == cpu_ksoftirqd ||
+		 task_thread_info(task)->preempt_count & SOFTIRQ_MASK));
+}
+
 static int
 select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
 {
 	struct task_struct *curr;
 	struct rq *rq;
+	bool may_not_preempt;
 
 #ifdef CONFIG_SCHED_HMP
 	return select_task_rq_rt_hmp(p, cpu, sd_flag, flags);
@@ -1509,7 +1529,17 @@
 	curr = READ_ONCE(rq->curr); /* unlocked access */
 
 	/*
-	 * If the current task on @p's runqueue is an RT task, then
+	 * If the current task on @p's runqueue is a softirq task,
+	 * it may run without preemption for a time that is
+	 * ill-suited for a waiting RT task. Therefore, try to
+	 * wake this RT task on another runqueue.
+	 *
+	 * Also, if the current task on @p's runqueue is an RT task, then
+	 * it may run without preemption for a time that is
+	 * ill-suited for a waiting RT task. Therefore, try to
+	 * wake this RT task on another runqueue.
+	 *
+	 * Also, if the current task on @p's runqueue is an RT task, then
 	 * try to see if we can wake this RT task up on another
 	 * runqueue. Otherwise simply start this RT task
 	 * on its current runqueue.
@@ -1530,18 +1560,22 @@
 	 * This test is optimistic, if we get it wrong the load-balancer
 	 * will have to sort it out.
 	 */
-	if (energy_aware() ||
-	    (curr && unlikely(rt_task(curr)) &&
+	may_not_preempt = task_may_not_preempt(curr, cpu);
+	if (energy_aware() || may_not_preempt ||
+	     (unlikely(rt_task(curr)) &&
 	     (tsk_nr_cpus_allowed(curr) < 2 ||
 	      curr->prio <= p->prio))) {
 		int target = find_lowest_rq(p);
 
 		/*
-		 * Don't bother moving it if the destination CPU is
-		 * not running a lower priority task.
+		 * If cpu is non-preemptible, prefer remote cpu
+		 * even if it's running a higher-prio task.
+		 * Otherwise: Don't bother moving it if the
+		 * destination CPU is not running a lower priority task.
 		 */
 		if (target != -1 &&
-		    p->prio < cpu_rq(target)->rt.highest_prio.curr)
+		   (may_not_preempt ||
+		    p->prio < cpu_rq(target)->rt.highest_prio.curr))
 			cpu = target;
 	}
 	rcu_read_unlock();
@@ -1936,9 +1970,6 @@
 
 				if (sysctl_sched_cstate_aware)
 					cpu_idle_idx =
-					    (cpu == smp_processor_id() ||
-					     cpu_rq(cpu)->nr_running) ?
-					     -1 :
 					     idle_get_state_idx(cpu_rq(cpu));
 
 				if (add_capacity_margin(new_util_cum) <
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 3194ae6..566e103 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1491,6 +1491,10 @@
 static inline int idle_get_state_idx(struct rq *rq)
 {
 	WARN_ON(!rcu_read_lock_held());
+
+	if (rq->nr_running || cpu_of(rq) == raw_smp_processor_id())
+		return -1;
+
 	return rq->idle_state_idx;
 }
 #else
@@ -1700,6 +1704,13 @@
 }
 #endif
 
+#ifndef arch_update_cpu_capacity
+static __always_inline
+void arch_update_cpu_capacity(int cpu)
+{
+}
+#endif
+
 #ifdef CONFIG_SMP
 static inline unsigned long capacity_of(int cpu)
 {
@@ -2089,6 +2100,11 @@
 		__release(rq2->lock);
 }
 
+/*
+ * task_may_not_preempt - check whether a task may not be preemptible soon
+ */
+extern bool task_may_not_preempt(struct task_struct *task, int cpu);
+
 #else /* CONFIG_SMP */
 
 /*
@@ -2681,6 +2697,15 @@
 extern void clear_ed_task(struct task_struct *p, struct rq *rq);
 extern bool early_detection_notify(struct rq *rq, u64 wallclock);
 
+#ifdef CONFIG_SCHED_HMP
+extern unsigned int power_cost(int cpu, u64 demand);
+#else
+static inline unsigned int power_cost(int cpu, u64 demand)
+{
+	return cpu_max_possible_capacity(cpu);
+}
+#endif
+
 #else	/* CONFIG_SCHED_WALT */
 
 struct hmp_sched_stats;
@@ -2835,6 +2860,11 @@
 	return 0;
 }
 
+static inline unsigned int power_cost(int cpu, u64 demand)
+{
+	return SCHED_CAPACITY_SCALE;
+}
+
 #endif	/* CONFIG_SCHED_WALT */
 
 #ifdef CONFIG_SCHED_HMP
@@ -2849,7 +2879,6 @@
 check_for_freq_change(struct rq *rq, bool check_pred, bool check_groups);
 extern void fixup_nr_big_tasks(struct hmp_sched_stats *stats,
 					struct task_struct *p, s64 delta);
-extern unsigned int power_cost(int cpu, u64 demand);
 extern unsigned int cpu_temp(int cpu);
 extern void pre_big_task_count_change(const struct cpumask *cpus);
 extern void post_big_task_count_change(const struct cpumask *cpus);
@@ -2906,11 +2935,6 @@
 static inline void fixup_nr_big_tasks(struct hmp_sched_stats *stats,
 				      struct task_struct *p, s64 delta) { }
 
-static inline unsigned int power_cost(int cpu, u64 demand)
-{
-	return SCHED_CAPACITY_SCALE;
-}
-
 static inline unsigned int cpu_temp(int cpu)
 {
 	return 0;
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index b38ec53..50f889b 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -100,45 +100,6 @@
 	local_irq_restore(*flags);
 }
 
-struct timer_list sched_grp_timer;
-static void sched_agg_grp_load(unsigned long data)
-{
-	struct sched_cluster *cluster;
-	unsigned long flags;
-	int cpu;
-
-	acquire_rq_locks_irqsave(cpu_possible_mask, &flags);
-
-	for_each_sched_cluster(cluster) {
-		u64 aggr_grp_load = 0;
-
-		for_each_cpu(cpu, &cluster->cpus) {
-			struct rq *rq = cpu_rq(cpu);
-
-			if (rq->curr)
-				update_task_ravg(rq->curr, rq, TASK_UPDATE,
-						sched_ktime_clock(), 0);
-			aggr_grp_load +=
-				rq->grp_time.prev_runnable_sum;
-		}
-
-		cluster->aggr_grp_load = aggr_grp_load;
-	}
-
-	release_rq_locks_irqrestore(cpu_possible_mask, &flags);
-
-	if (sched_boost() == RESTRAINED_BOOST)
-		mod_timer(&sched_grp_timer, jiffies + 1);
-}
-
-static int __init setup_sched_grp_timer(void)
-{
-	init_timer_deferrable(&sched_grp_timer);
-	sched_grp_timer.function = sched_agg_grp_load;
-	return 0;
-}
-late_initcall(setup_sched_grp_timer);
-
 /* 1 -> use PELT based load stats, 0 -> use window-based load stats */
 unsigned int __read_mostly walt_disabled = 0;
 
@@ -935,7 +896,7 @@
 	if (!sync_cpu_available) {
 		rq->window_start = 1;
 		sync_cpu_available = 1;
-		atomic_set(&walt_irq_work_lastq_ws, rq->window_start);
+		atomic64_set(&walt_irq_work_lastq_ws, rq->window_start);
 	} else {
 		struct rq *sync_rq = cpu_rq(cpumask_any(cpu_online_mask));
 
@@ -1934,7 +1895,7 @@
 	if (old_window_start == rq->window_start)
 		return;
 
-	result = atomic_cmpxchg(&walt_irq_work_lastq_ws, old_window_start,
+	result = atomic64_cmpxchg(&walt_irq_work_lastq_ws, old_window_start,
 				   rq->window_start);
 	if (result == old_window_start)
 		irq_work_queue(&rq->irq_work);
@@ -2025,6 +1986,20 @@
 	p->misfit = false;
 }
 
+void free_task_load_ptrs(struct task_struct *p)
+{
+	kfree(p->ravg.curr_window_cpu);
+	kfree(p->ravg.prev_window_cpu);
+
+	/*
+	 * update_task_ravg() can be called for exiting tasks. While the
+	 * function itself ensures correct behavior, the corresponding
+	 * trace event requires that these pointers be NULL.
+	 */
+	p->ravg.curr_window_cpu = NULL;
+	p->ravg.prev_window_cpu = NULL;
+}
+
 void reset_task_stats(struct task_struct *p)
 {
 	u32 sum = 0;
@@ -3044,6 +3019,8 @@
 	wc = sched_ktime_clock();
 
 	for_each_sched_cluster(cluster) {
+		u64 aggr_grp_load = 0;
+
 		raw_spin_lock(&cluster->load_lock);
 
 		for_each_cpu(cpu, &cluster->cpus) {
@@ -3052,14 +3029,19 @@
 				update_task_ravg(rq->curr, rq,
 						TASK_UPDATE, wc, 0);
 				account_load_subtractions(rq);
+				aggr_grp_load += rq->grp_time.prev_runnable_sum;
 			}
-
-			cpufreq_update_util(rq, 0);
 		}
 
+		cluster->aggr_grp_load = aggr_grp_load;
+
 		raw_spin_unlock(&cluster->load_lock);
 	}
 
+	for_each_sched_cluster(cluster)
+		for_each_cpu(cpu, &cluster->cpus)
+			cpufreq_update_util(cpu_rq(cpu), 0);
+
 	for_each_cpu(cpu, cpu_possible_mask)
 		raw_spin_unlock(&cpu_rq(cpu)->lock);
 
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 744fa61..bde8e33 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -57,6 +57,13 @@
 
 DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
 
+/*
+ * active_softirqs -- per cpu, a mask of softirqs that are being handled,
+ * with the expectation that approximate answers are acceptable and therefore
+ * no synchronization.
+ */
+DEFINE_PER_CPU(__u32, active_softirqs);
+
 const char * const softirq_to_name[NR_SOFTIRQS] = {
 	"HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "IRQ_POLL",
 	"TASKLET", "SCHED", "HRTIMER", "RCU"
@@ -264,6 +271,7 @@
 restart:
 	/* Reset the pending bitmask before enabling irqs */
 	set_softirq_pending(0);
+	__this_cpu_write(active_softirqs, pending);
 
 	local_irq_enable();
 
@@ -293,6 +301,7 @@
 		pending >>= softirq_bit;
 	}
 
+	__this_cpu_write(active_softirqs, 0);
 	rcu_bh_qs();
 	local_irq_disable();
 
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 9792763..2aef653 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -49,7 +49,6 @@
 #include <linux/sched/deadline.h>
 #include <linux/timer.h>
 #include <linux/freezer.h>
-#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 
@@ -1579,41 +1578,22 @@
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
-				 struct hrtimer_cpu_base *new_base,
-				 unsigned int i, bool wait,
+static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
+				 struct hrtimer_clock_base *new_base,
 				 bool remove_pinned)
 {
 	struct hrtimer *timer;
 	struct timerqueue_node *node;
 	struct timerqueue_head pinned;
 	int is_pinned;
-	struct hrtimer_clock_base *old_c_base = &old_base->clock_base[i];
-	struct hrtimer_clock_base *new_c_base = &new_base->clock_base[i];
+	bool is_hotplug = !cpu_online(old_base->cpu_base->cpu);
 
 	timerqueue_init_head(&pinned);
 
-	while ((node = timerqueue_getnext(&old_c_base->active))) {
+	while ((node = timerqueue_getnext(&old_base->active))) {
 		timer = container_of(node, struct hrtimer, node);
-		if (wait) {
-			/* Ensure timers are done running before continuing */
-			while (hrtimer_callback_running(timer)) {
-				raw_spin_unlock(&old_base->lock);
-				raw_spin_unlock(&new_base->lock);
-				cpu_relax();
-				/*
-				 * cpu_relax may just be a barrier. Grant the
-				 * run_hrtimer_list code some time to obtain
-				 * the spinlock.
-				 */
-				udelay(1);
-				raw_spin_lock(&new_base->lock);
-				raw_spin_lock_nested(&old_base->lock,
-							SINGLE_DEPTH_NESTING);
-			}
-		} else {
+		if (is_hotplug)
 			BUG_ON(hrtimer_callback_running(timer));
-		}
 		debug_deactivate(timer);
 
 		/*
@@ -1621,7 +1601,7 @@
 		 * timer could be seen as !active and just vanish away
 		 * under us on another CPU
 		 */
-		__remove_hrtimer(timer, old_c_base, HRTIMER_STATE_ENQUEUED, 0);
+		__remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0);
 
 		is_pinned = timer->state & HRTIMER_STATE_PINNED;
 		if (!remove_pinned && is_pinned) {
@@ -1629,7 +1609,7 @@
 			continue;
 		}
 
-		timer->base = new_c_base;
+		timer->base = new_base;
 		/*
 		 * Enqueue the timers on the new cpu. This does not
 		 * reprogram the event device in case the timer
@@ -1638,7 +1618,7 @@
 		 * sort out already expired timers and reprogram the
 		 * event device.
 		 */
-		enqueue_hrtimer(timer, new_c_base);
+		enqueue_hrtimer(timer, new_base);
 	}
 
 	/* Re-queue pinned timers for non-hotplug usecase */
@@ -1646,12 +1626,11 @@
 		timer = container_of(node, struct hrtimer, node);
 
 		timerqueue_del(&pinned, &timer->node);
-		enqueue_hrtimer(timer, old_c_base);
+		enqueue_hrtimer(timer, old_base);
 	}
 }
 
-static void
-__migrate_hrtimers(unsigned int scpu, bool wait, bool remove_pinned)
+static void __migrate_hrtimers(unsigned int scpu, bool remove_pinned)
 {
 	struct hrtimer_cpu_base *old_base, *new_base;
 	unsigned long flags;
@@ -1668,8 +1647,8 @@
 	raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
 
 	for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
-		migrate_hrtimer_list(old_base, new_base, i, wait,
-								remove_pinned);
+		migrate_hrtimer_list(&old_base->clock_base[i],
+				     &new_base->clock_base[i], remove_pinned);
 	}
 
 	raw_spin_unlock(&old_base->lock);
@@ -1685,13 +1664,13 @@
 	BUG_ON(cpu_online(scpu));
 	tick_cancel_sched_timer(scpu);
 
-	__migrate_hrtimers(scpu, false, true);
+	__migrate_hrtimers(scpu, true);
 	return 0;
 }
 
 void hrtimer_quiesce_cpu(void *cpup)
 {
-	__migrate_hrtimers(*(int *)cpup, true, false);
+	__migrate_hrtimers(*(int *)cpup, false);
 }
 
 #endif /* CONFIG_HOTPLUG_CPU */
diff --git a/kernel/trace/ipc_logging.c b/kernel/trace/ipc_logging.c
index 6d310ab..31e6a8e 100644
--- a/kernel/trace/ipc_logging.c
+++ b/kernel/trace/ipc_logging.c
@@ -314,8 +314,11 @@
 		ilctxt->write_page->hdr.end_time = t_now;
 
 		ilctxt->write_page = get_next_page(ilctxt, ilctxt->write_page);
-		if (WARN_ON(ilctxt->write_page == NULL))
+		if (WARN_ON(ilctxt->write_page == NULL)) {
+			spin_unlock(&ilctxt->context_lock_lhb1);
+			read_unlock_irqrestore(&context_list_lock_lha1, flags);
 			return;
+		}
 		ilctxt->write_page->hdr.write_offset = 0;
 		ilctxt->write_page->hdr.start_time = t_now;
 		memcpy((ilctxt->write_page->data +
diff --git a/kernel/trace/msm_rtb.c b/kernel/trace/msm_rtb.c
index 34c48b1..9d9f0bf 100644
--- a/kernel/trace/msm_rtb.c
+++ b/kernel/trace/msm_rtb.c
@@ -27,6 +27,7 @@
 #include <linux/io.h>
 #include <asm-generic/sizes.h>
 #include <linux/msm_rtb.h>
+#include <asm/timex.h>
 
 #define SENTINEL_BYTE_1 0xFF
 #define SENTINEL_BYTE_2 0xAA
@@ -41,8 +42,9 @@
  * 4) 4 bytes index
  * 4) 8 bytes extra data from the caller
  * 5) 8 bytes of timestamp
+ * 6) 8 bytes of cyclecount
  *
- * Total = 32 bytes.
+ * Total = 40 bytes.
  */
 struct msm_rtb_layout {
 	unsigned char sentinel[3];
@@ -51,6 +53,7 @@
 	uint64_t caller;
 	uint64_t data;
 	uint64_t timestamp;
+	uint64_t cycle_count;
 } __attribute__ ((__packed__));
 
 
@@ -132,6 +135,11 @@
 	start->timestamp = sched_clock();
 }
 
+static void msm_rtb_write_cyclecount(struct msm_rtb_layout *start)
+{
+	start->cycle_count = get_cycles();
+}
+
 static void uncached_logk_pc_idx(enum logk_event_type log_type, uint64_t caller,
 				 uint64_t data, int idx)
 {
@@ -145,6 +153,7 @@
 	msm_rtb_write_idx(idx, start);
 	msm_rtb_write_data(data, start);
 	msm_rtb_write_timestamp(start);
+	msm_rtb_write_cyclecount(start);
 	mb();
 
 }
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 22eff06..6878aa8 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1724,6 +1724,20 @@
 	  and to test how the mmc host driver handles retries from
 	  the block device.
 
+config UFS_FAULT_INJECTION
+	bool "Fault-injection capability for UFS IO"
+	select DEBUG_FS
+	depends on FAULT_INJECTION && SCSI_UFSHCD
+	help
+	 Provide fault-injection capability for UFS IO.
+	 This will make the UFS host controller driver to randomly
+	 abort ongoing commands in the host controller, update OCS
+	 field according to the injected fatal error and can also
+	 forcefully hang the command indefinitely till upper layer
+	 timeout occurs. This is useful to test error handling in
+	 the UFS contoller driver and test how the driver handles
+	 the retries from block/SCSI mid layer.
+
 config FAIL_FUTEX
 	bool "Fault-injection capability for futexes"
 	select DEBUG_FS
diff --git a/lib/test_user_copy.c b/lib/test_user_copy.c
index 0ecef3e..5e6db6b 100644
--- a/lib/test_user_copy.c
+++ b/lib/test_user_copy.c
@@ -58,7 +58,9 @@
 	usermem = (char __user *)user_addr;
 	bad_usermem = (char *)user_addr;
 
-	/* Legitimate usage: none of these should fail. */
+	/*
+	 * Legitimate usage: none of these copies should fail.
+	 */
 	ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE),
 		    "legitimate copy_from_user failed");
 	ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE),
@@ -68,19 +70,33 @@
 	ret |= test(put_user(value, (unsigned long __user *)usermem),
 		    "legitimate put_user failed");
 
-	/* Invalid usage: none of these should succeed. */
+	/*
+	 * Invalid usage: none of these copies should succeed.
+	 */
+
+	/* Reject kernel-to-kernel copies through copy_from_user(). */
 	ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE),
 				    PAGE_SIZE),
 		    "illegal all-kernel copy_from_user passed");
+
+#if 0
+	/*
+	 * When running with SMAP/PAN/etc, this will Oops the kernel
+	 * due to the zeroing of userspace memory on failure. This needs
+	 * to be tested in LKDTM instead, since this test module does not
+	 * expect to explode.
+	 */
 	ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem,
 				    PAGE_SIZE),
 		    "illegal reversed copy_from_user passed");
+#endif
 	ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE,
 				  PAGE_SIZE),
 		    "illegal all-kernel copy_to_user passed");
 	ret |= test(!copy_to_user((char __user *)kmem, bad_usermem,
 				  PAGE_SIZE),
 		    "illegal reversed copy_to_user passed");
+
 	ret |= test(!get_user(value, (unsigned long __user *)kmem),
 		    "illegal get_user passed");
 	ret |= test(!put_user(value, (unsigned long __user *)kmem),
diff --git a/mm/truncate.c b/mm/truncate.c
index 8d8c62d..9c809e7 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -753,7 +753,7 @@
  */
 void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to)
 {
-	int bsize = 1 << inode->i_blkbits;
+	int bsize = i_blocksize(inode);
 	loff_t rounded_from;
 	struct page *page;
 	pgoff_t index;
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 5a782f5..16b5aa9 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -185,7 +185,8 @@
 		br_debug(br, "using kernel STP\n");
 
 		/* To start timers on any ports left in blocking */
-		mod_timer(&br->hello_timer, jiffies + br->hello_time);
+		if (br->dev->flags & IFF_UP)
+			mod_timer(&br->hello_timer, jiffies + br->hello_time);
 		br_port_state_selection(br);
 	}
 
diff --git a/net/core/dev.c b/net/core/dev.c
index dff8012..c0d0b49 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4400,6 +4400,7 @@
 	}
 
 out:
+	__this_cpu_add(softnet_data.gro_coalesced, NAPI_GRO_CB(skb)->count > 1);
 	return netif_receive_skb_internal(skb);
 }
 
@@ -4836,9 +4837,15 @@
 		while (remsd) {
 			struct softnet_data *next = remsd->rps_ipi_next;
 
-			if (cpu_online(remsd->cpu))
+			if (cpu_online(remsd->cpu)) {
 				smp_call_function_single_async(remsd->cpu,
 							   &remsd->csd);
+			} else {
+				pr_err("%s() cpu offline\n", __func__);
+				rps_lock(remsd);
+				remsd->backlog.state = 0;
+				rps_unlock(remsd);
+			}
 			remsd = next;
 		}
 	} else
diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c
index 14d0934..699c4e7 100644
--- a/net/core/net-procfs.c
+++ b/net/core/net-procfs.c
@@ -158,12 +158,12 @@
 	rcu_read_unlock();
 #endif
 
-	seq_printf(seq,
-		   "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
-		   sd->processed, sd->dropped, sd->time_squeeze, 0,
-		   0, 0, 0, 0, /* was fastroute */
-		   0,	/* was cpu_collision */
-		   sd->received_rps, flow_limit_count);
+	seq_printf
+	(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+	 sd->processed, sd->dropped, sd->time_squeeze, 0,
+	 0, 0, 0, 0, /* was fastroute */
+	 0, /* was cpu_collision */
+	 sd->received_rps, flow_limit_count, sd->gro_coalesced);
 	return 0;
 }
 
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 39e9acf..ceddf42 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -136,6 +136,8 @@
 }
 #endif
 
+int sysctl_reserved_port_bind __read_mostly = 1;
+
 /* The inetsw table contains everything that inet_create needs to
  * build a new socket.
  */
@@ -1034,7 +1036,7 @@
 		.type =       SOCK_DGRAM,
 		.protocol =   IPPROTO_ICMP,
 		.prot =       &ping_prot,
-		.ops =        &inet_dgram_ops,
+		.ops =        &inet_sockraw_ops,
 		.flags =      INET_PROTOSW_REUSE,
        },
 
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index ceae0ea..c094ac9 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -111,6 +111,13 @@
 		head = &hinfo->bhash[inet_bhashfn(net, port,
 						  hinfo->bhash_size)];
 		spin_lock_bh(&head->lock);
+
+		if (inet_is_local_reserved_port(net, snum) &&
+		    !sysctl_reserved_port_bind) {
+			ret = 1;
+			goto fail_unlock;
+		}
+
 		inet_bind_bucket_for_each(tb, &head->chain)
 			if (net_eq(ib_net(tb), net) && tb->port == port)
 				goto tb_found;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index cf7cfa4..08605a4 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -789,6 +789,13 @@
 		.proc_handler	= proc_do_large_bitmap,
 	},
 	{
+		.procname       = "reserved_port_bind",
+		.data           = &sysctl_reserved_port_bind,
+		.maxlen         = sizeof(int),
+		.mode           = 0644,
+		.proc_handler   = proc_dointvec
+	},
+	{
 		.procname	= "ip_no_pmtu_disc",
 		.data		= &init_net.ipv4.sysctl_ip_no_pmtu_disc,
 		.maxlen		= sizeof(int),
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index baea5df..0cdbea9 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -179,6 +179,7 @@
 {
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 
+	tcp_sk(sk)->prior_ssthresh = 0;
 	if (icsk->icsk_ca_ops->init)
 		icsk->icsk_ca_ops->init(sk);
 	if (tcp_ca_needs_ecn(sk))
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index eca1433..e8ab585 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2228,6 +2228,7 @@
 	__be32 src = inet->inet_rcv_saddr;
 	__u16 destp = ntohs(inet->inet_dport);
 	__u16 srcp = ntohs(inet->inet_sport);
+	__u8 seq_state = sk->sk_state;
 	int rx_queue;
 	int state;
 
@@ -2247,6 +2248,9 @@
 		timer_expires = jiffies;
 	}
 
+	if (inet->transparent)
+		seq_state |= 0x80;
+
 	state = sk_state_load(sk);
 	if (state == TCP_LISTEN)
 		rx_queue = sk->sk_ack_backlog;
@@ -2258,7 +2262,7 @@
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
 			"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d",
-		i, src, srcp, dest, destp, state,
+		i, src, srcp, dest, destp, seq_state,
 		tp->write_seq - tp->snd_una,
 		rx_queue,
 		timer_active,
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 5093bb8..fe24424 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -290,6 +290,11 @@
 	} else {
 		hslot = udp_hashslot(udptable, net, snum);
 		spin_lock_bh(&hslot->lock);
+
+		if (inet_is_local_reserved_port(net, snum) &&
+		    !sysctl_reserved_port_bind)
+			goto fail_unlock;
+
 		if (hslot->count > 10) {
 			int exist;
 			unsigned int slot2 = udp_sk(sk)->udp_portaddr_hash ^ snum;
@@ -2377,14 +2382,21 @@
 		int bucket)
 {
 	struct inet_sock *inet = inet_sk(sp);
+	struct udp_sock *up = udp_sk(sp);
 	__be32 dest = inet->inet_daddr;
 	__be32 src  = inet->inet_rcv_saddr;
 	__u16 destp	  = ntohs(inet->inet_dport);
 	__u16 srcp	  = ntohs(inet->inet_sport);
+	__u8 state = sp->sk_state;
+
+	if (up->encap_rcv)
+		state |= 0xF0;
+	else if (inet->transparent)
+		state |= 0x80;
 
 	seq_printf(f, "%5d: %08X:%04X %08X:%04X"
 		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
-		bucket, src, srcp, dest, destp, sp->sk_state,
+		bucket, src, srcp, dest, destp, state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
 		0, 0L, 0,
diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c
index 37ac9de..8d772fe 100644
--- a/net/ipv6/calipso.c
+++ b/net/ipv6/calipso.c
@@ -1319,7 +1319,7 @@
 	struct ipv6hdr *ip6_hdr;
 	struct ipv6_opt_hdr *hop;
 	unsigned char buf[CALIPSO_MAX_BUFFER];
-	int len_delta, new_end, pad;
+	int len_delta, new_end, pad, payload;
 	unsigned int start, end;
 
 	ip6_hdr = ipv6_hdr(skb);
@@ -1346,6 +1346,8 @@
 	if (ret_val < 0)
 		return ret_val;
 
+	ip6_hdr = ipv6_hdr(skb); /* Reset as skb_cow() may have moved it */
+
 	if (len_delta) {
 		if (len_delta > 0)
 			skb_push(skb, len_delta);
@@ -1355,6 +1357,8 @@
 			sizeof(*ip6_hdr) + start);
 		skb_reset_network_header(skb);
 		ip6_hdr = ipv6_hdr(skb);
+		payload = ntohs(ip6_hdr->payload_len);
+		ip6_hdr->payload_len = htons(payload + len_delta);
 	}
 
 	hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index a381772..9217390 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -1008,9 +1008,14 @@
 			     __u16 srcp, __u16 destp, int bucket)
 {
 	const struct in6_addr *dest, *src;
+	__u8 state = sp->sk_state;
 
 	dest  = &sp->sk_v6_daddr;
 	src   = &sp->sk_v6_rcv_saddr;
+
+	if (inet_sk(sp) && inet_sk(sp)->transparent)
+		state |= 0x80;
+
 	seq_printf(seq,
 		   "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
 		   "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n",
@@ -1019,7 +1024,7 @@
 		   src->s6_addr32[2], src->s6_addr32[3], srcp,
 		   dest->s6_addr32[0], dest->s6_addr32[1],
 		   dest->s6_addr32[2], dest->s6_addr32[3], destp,
-		   sp->sk_state,
+		   state,
 		   sk_wmem_alloc_get(sp),
 		   sk_rmem_alloc_get(sp),
 		   0, 0L, 0,
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index 013086b..424fbe1 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -116,8 +116,10 @@
 
 		if (udpfrag) {
 			int err = ip6_find_1stfragopt(skb, &prevhdr);
-			if (err < 0)
+			if (err < 0) {
+				kfree_skb_list(segs);
 				return ERR_PTR(err);
+			}
 			fptr = (struct frag_hdr *)((u8 *)ipv6h + err);
 			fptr->frag_off = htons(offset);
 			if (skb->next)
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index e1f8b34..2a965d4 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -199,7 +199,7 @@
 	.type =      SOCK_DGRAM,
 	.protocol =  IPPROTO_ICMPV6,
 	.prot =      &pingv6_prot,
-	.ops =       &inet6_dgram_ops,
+	.ops =       &inet6_sockraw_ops,
 	.flags =     INET_PROTOSW_REUSE,
 };
 
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 83c7d2b..ff701ce 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1331,7 +1331,7 @@
 #endif	/* CONFIG_PROC_FS */
 
 /* Same as inet6_dgram_ops, sans udp_poll.  */
-static const struct proto_ops inet6_sockraw_ops = {
+const struct proto_ops inet6_sockraw_ops = {
 	.family		   = PF_INET6,
 	.owner		   = THIS_MODULE,
 	.release	   = inet6_release,
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 368c23a..f8a6036 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1741,6 +1741,7 @@
 	const struct fastopen_queue *fastopenq = &icsk->icsk_accept_queue.fastopenq;
 	int rx_queue;
 	int state;
+	__u8 state_seq = sp->sk_state;
 
 	dest  = &sp->sk_v6_daddr;
 	src   = &sp->sk_v6_rcv_saddr;
@@ -1772,6 +1773,9 @@
 		 */
 		rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
 
+	if (inet->transparent)
+		state_seq |= 0x80;
+
 	seq_printf(seq,
 		   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
 		   "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %lu %lu %u %u %d\n",
@@ -1780,7 +1784,7 @@
 		   src->s6_addr32[2], src->s6_addr32[3], srcp,
 		   dest->s6_addr32[0], dest->s6_addr32[1],
 		   dest->s6_addr32[2], dest->s6_addr32[3], destp,
-		   state,
+		   state_seq,
 		   tp->write_seq - tp->snd_una,
 		   rx_queue,
 		   timer_active,
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c
index 0e01590..07d3657 100644
--- a/net/ipv6/xfrm6_mode_ro.c
+++ b/net/ipv6/xfrm6_mode_ro.c
@@ -47,6 +47,8 @@
 	iph = ipv6_hdr(skb);
 
 	hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
+	if (hdr_len < 0)
+		return hdr_len;
 	skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data);
 	skb_set_network_header(skb, -x->props.header_len);
 	skb->transport_header = skb->network_header + hdr_len;
diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c
index 4e34410..1d3bbe6 100644
--- a/net/ipv6/xfrm6_mode_transport.c
+++ b/net/ipv6/xfrm6_mode_transport.c
@@ -28,6 +28,8 @@
 	iph = ipv6_hdr(skb);
 
 	hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
+	if (hdr_len < 0)
+		return hdr_len;
 	skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data);
 	skb_set_network_header(skb, -x->props.header_len);
 	skb->transport_header = skb->network_header + hdr_len;
diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
index 36493a7..93820e0 100644
--- a/net/netfilter/nft_set_rbtree.c
+++ b/net/netfilter/nft_set_rbtree.c
@@ -118,17 +118,17 @@
 		else if (d > 0)
 			p = &parent->rb_right;
 		else {
-			if (nft_set_elem_active(&rbe->ext, genmask)) {
-				if (nft_rbtree_interval_end(rbe) &&
-				    !nft_rbtree_interval_end(new))
-					p = &parent->rb_left;
-				else if (!nft_rbtree_interval_end(rbe) &&
-					 nft_rbtree_interval_end(new))
-					p = &parent->rb_right;
-				else {
-					*ext = &rbe->ext;
-					return -EEXIST;
-				}
+			if (nft_rbtree_interval_end(rbe) &&
+			    !nft_rbtree_interval_end(new)) {
+				p = &parent->rb_left;
+			} else if (!nft_rbtree_interval_end(rbe) &&
+				   nft_rbtree_interval_end(new)) {
+				p = &parent->rb_right;
+			} else if (nft_set_elem_active(&rbe->ext, genmask)) {
+				*ext = &rbe->ext;
+				return -EEXIST;
+			} else {
+				p = &parent->rb_left;
 			}
 		}
 	}
diff --git a/net/netfilter/xt_HARDIDLETIMER.c b/net/netfilter/xt_HARDIDLETIMER.c
index eb5b452..fc0b83f 100644
--- a/net/netfilter/xt_HARDIDLETIMER.c
+++ b/net/netfilter/xt_HARDIDLETIMER.c
@@ -180,6 +180,8 @@
 		pr_debug("couldn't add file to sysfs");
 		goto out_free_attr;
 	}
+	/*  notify userspace  */
+	kobject_uevent(hardidletimer_tg_kobj, KOBJ_ADD);
 
 	list_add(&info->timer->entry, &hardidletimer_tg_list);
 
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
index f11aa28..04a1b97 100644
--- a/net/netfilter/xt_IDLETIMER.c
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -301,6 +301,8 @@
 		pr_debug("couldn't add file to sysfs");
 		goto out_free_attr;
 	}
+	/* notify userspace */
+	kobject_uevent(idletimer_tg_kobj, KOBJ_ADD);
 
 	list_add(&info->timer->entry, &idletimer_tg_list);
 
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 744cfe6c5..c2225cc 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1206,12 +1206,7 @@
 			qdisc_len = q->q.qlen;
 			if (q->ops->change(q, &req.attr))
 				pr_err("%s(): qdisc change failed", __func__);
-		} else {
-			WARN_ONCE(1, "%s(): called on queue which does %s",
-				  __func__, "not support change() operation");
 		}
-	} else {
-		WARN_ONCE(1, "%s(): called on bad queue", __func__);
 	}
 	return qdisc_len;
 }
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 17a0610..56c458d 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -480,12 +480,9 @@
 	struct skcipher_request *req;
 	unsigned int encrypted_datalen;
 	u8 iv[AES_BLOCK_SIZE];
-	unsigned int padlen;
-	char pad[16];
 	int ret;
 
 	encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
-	padlen = encrypted_datalen - epayload->decrypted_datalen;
 
 	req = init_skcipher_req(derived_key, derived_keylen);
 	ret = PTR_ERR(req);
@@ -493,11 +490,10 @@
 		goto out;
 	dump_decrypted_data(epayload);
 
-	memset(pad, 0, sizeof pad);
 	sg_init_table(sg_in, 2);
 	sg_set_buf(&sg_in[0], epayload->decrypted_data,
 		   epayload->decrypted_datalen);
-	sg_set_buf(&sg_in[1], pad, padlen);
+	sg_set_page(&sg_in[1], ZERO_PAGE(0), AES_BLOCK_SIZE, 0);
 
 	sg_init_table(sg_out, 1);
 	sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen);
@@ -584,9 +580,14 @@
 	struct skcipher_request *req;
 	unsigned int encrypted_datalen;
 	u8 iv[AES_BLOCK_SIZE];
-	char pad[16];
+	u8 *pad;
 	int ret;
 
+	/* Throwaway buffer to hold the unused zero padding at the end */
+	pad = kmalloc(AES_BLOCK_SIZE, GFP_KERNEL);
+	if (!pad)
+		return -ENOMEM;
+
 	encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
 	req = init_skcipher_req(derived_key, derived_keylen);
 	ret = PTR_ERR(req);
@@ -594,13 +595,12 @@
 		goto out;
 	dump_encrypted_data(epayload, encrypted_datalen);
 
-	memset(pad, 0, sizeof pad);
 	sg_init_table(sg_in, 1);
 	sg_init_table(sg_out, 2);
 	sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen);
 	sg_set_buf(&sg_out[0], epayload->decrypted_data,
 		   epayload->decrypted_datalen);
-	sg_set_buf(&sg_out[1], pad, sizeof pad);
+	sg_set_buf(&sg_out[1], pad, AES_BLOCK_SIZE);
 
 	memcpy(iv, epayload->iv, sizeof(iv));
 	skcipher_request_set_crypt(req, sg_in, sg_out, encrypted_datalen, iv);
@@ -612,6 +612,7 @@
 		goto out;
 	dump_decrypted_data(epayload);
 out:
+	kfree(pad);
 	return ret;
 }
 
diff --git a/security/keys/key.c b/security/keys/key.c
index 346fbf2..2f4ce35 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -962,12 +962,11 @@
 	/* the key must be writable */
 	ret = key_permission(key_ref, KEY_NEED_WRITE);
 	if (ret < 0)
-		goto error;
+		return ret;
 
 	/* attempt to update it if supported */
-	ret = -EOPNOTSUPP;
 	if (!key->type->update)
-		goto error;
+		return -EOPNOTSUPP;
 
 	memset(&prep, 0, sizeof(prep));
 	prep.data = payload;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index dbbfd77..ada12c3 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -97,7 +97,7 @@
 	/* pull the payload in if one was supplied */
 	payload = NULL;
 
-	if (_payload) {
+	if (plen) {
 		ret = -ENOMEM;
 		payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
 		if (!payload) {
@@ -327,7 +327,7 @@
 
 	/* pull the payload in if one was supplied */
 	payload = NULL;
-	if (_payload) {
+	if (plen) {
 		ret = -ENOMEM;
 		payload = kmalloc(plen, GFP_KERNEL);
 		if (!payload)
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 1a8186b..7622551 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1626,6 +1626,7 @@
 	if (err < 0)
 		goto __err;
 
+	tu->qhead = tu->qtail = tu->qused = 0;
 	kfree(tu->queue);
 	tu->queue = NULL;
 	kfree(tu->tqueue);
@@ -1967,6 +1968,7 @@
 
 	tu = file->private_data;
 	unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read);
+	mutex_lock(&tu->ioctl_lock);
 	spin_lock_irq(&tu->qlock);
 	while ((long)count - result >= unit) {
 		while (!tu->qused) {
@@ -1982,7 +1984,9 @@
 			add_wait_queue(&tu->qchange_sleep, &wait);
 
 			spin_unlock_irq(&tu->qlock);
+			mutex_unlock(&tu->ioctl_lock);
 			schedule();
+			mutex_lock(&tu->ioctl_lock);
 			spin_lock_irq(&tu->qlock);
 
 			remove_wait_queue(&tu->qchange_sleep, &wait);
@@ -2002,7 +2006,6 @@
 		tu->qused--;
 		spin_unlock_irq(&tu->qlock);
 
-		mutex_lock(&tu->ioctl_lock);
 		if (tu->tread) {
 			if (copy_to_user(buffer, &tu->tqueue[qhead],
 					 sizeof(struct snd_timer_tread)))
@@ -2012,7 +2015,6 @@
 					 sizeof(struct snd_timer_read)))
 				err = -EFAULT;
 		}
-		mutex_unlock(&tu->ioctl_lock);
 
 		spin_lock_irq(&tu->qlock);
 		if (err < 0)
@@ -2022,6 +2024,7 @@
 	}
  _error:
 	spin_unlock_irq(&tu->qlock);
+	mutex_unlock(&tu->ioctl_lock);
 	return result > 0 ? result : err;
 }
 
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 17224de..f800858 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -878,28 +878,24 @@
 config SND_SOC_WCD934X_DSD
         tristate
 
-config SND_SOC_WCD9320
-        tristate
-
-config SND_SOC_WCD9330
-        tristate
-	depends on WCD9330_CODEC
-
 config SND_SOC_WCD9335
         tristate
-	depends on WCD9335_CODEC
+	depends on WCD9XXX_CODEC_CORE
+	select SND_SOC_WCD9XXX
 	select SND_SOC_WCD_MBHC
 	select SND_SOC_WCD_MBHC_LEGACY
+	select SND_SOC_WCD_CPE
 
 config SND_SOC_WCD934X
         tristate
-	depends on WCD934X_CODEC
-	select SND_SOC_WCD9XXX_V2
+	depends on WCD9XXX_CODEC_CORE
+	select SND_SOC_WCD9XXX
 	select AUDIO_EXT_CLK
 	select SND_SOC_WCD_DSP_MGR
 	select SND_SOC_WCD_SPI
 	select SND_SOC_WCD934X_MBHC
         select SND_SOC_WCD934X_DSD
+	select WCD_DSP_GLINK
 
 config SND_SOC_WCD934X_MBHC
         tristate
@@ -907,10 +903,14 @@
 	select SND_SOC_WCD_MBHC
 	select SND_SOC_WCD_MBHC_ADC
 
+config REGMAP_SWR
+	tristate
+	default y
+
 config SND_SOC_WSA881X
         tristate
+	depends on REGMAP_SWR
 	select MSM_CDC_PINCTRL
-	select REGMAP_SWR
 
 config SND_SOC_WSA881X_ANALOG
         tristate
@@ -918,19 +918,15 @@
 
 config SND_SOC_WCD9XXX
 	tristate
-	default y if SND_SOC_WCD9320=y || SND_SOC_WCD9330=y || SND_SOC_WCD9335=y
-
-config SND_SOC_WCD9XXX_V2
-	tristate
-	default y if SND_SOC_WCD9335=y
+	default y if SND_SOC_WCD9335=y || SND_SOC_WCD934X=y
 
 config SND_SOC_WCD_CPE
 	tristate
-	default y if SND_SOC_WCD9330=y || SND_SOC_WCD9335=y
+	default y if SND_SOC_WCD9335=y
 
 config AUDIO_EXT_CLK
 	tristate
-	default y if SND_SOC_WCD9335=y || SND_SOC_WCD9330=y || SND_SOC_SDM660_CDC=y
+	default y if SND_SOC_WCD9335=y || SND_SOC_SDM660_CDC=y
 
 config SND_SOC_WCD_MBHC
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8c84460..d5e4ab2 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -158,30 +158,27 @@
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
-snd-soc-wcd9320-objs := wcd9320.o wcd9320-tables.o
-snd-soc-wcd9330-objs := wcd9330.o wcd9330-tables.o
 snd-soc-wcd9335-objs := wcd9335.o
 snd-soc-wcd934x-objs := wcd934x.o
-snd-soc-wcd9xxx-objs := wcd9xxx-resmgr.o wcd9xxx-mbhc.o wcd9xxx-common.o wcdcal-hwdep.o
-snd-soc-wcd9xxx-v2-objs := wcd9xxx-common-v2.o wcd9xxx-resmgr-v2.o wcdcal-hwdep.o
+snd-soc-wcd9xxx-objs := wcd9xxx-common-v2.o wcd9xxx-resmgr-v2.o \
+			wcdcal-hwdep.o wcd-dsp-mgr.o wcd-dsp-utils.o \
+			wcd9xxx-soc-init.o
 ifeq ($(CONFIG_COMMON_CLK_MSM), y)
-	audio-ext-clock-objs := audio-ext-clk.o
+	snd-soc-wcd9xxx-objs += audio-ext-clk.o
 endif
 
 ifeq ($(CONFIG_COMMON_CLK_QCOM), y)
-	audio-ext-clock-up-objs := audio-ext-clk-up.o
+	snd-soc-wcd9xxx-objs += audio-ext-clk-up.o
 endif
 snd-soc-wcd-cpe-objs := wcd_cpe_services.o wcd_cpe_core.o
 snd-soc-wsa881x-objs := wsa881x.o wsa881x-tables.o wsa881x-regmap.o wsa881x-temp-sensor.o
-ifeq ($(CONFIG_SND_SOC_WCD_MBHC_LEGACY), y)
+ifneq (,$(filter $(CONFIG_SND_SOC_WCD_MBHC_LEGACY),y m))
 	snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o wcd-mbhc-legacy.o
-else ifeq ($(CONFIG_SND_SOC_WCD_MBHC_ADC), y)
+else ifneq (,$(filter $(CONFIG_SND_SOC_WCD_MBHC_ADC),y m))
 	snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o wcd-mbhc-adc.o
 endif
 snd-soc-wsa881x-analog-objs := wsa881x-analog.o wsa881x-tables-analog.o
 snd-soc-wsa881x-analog-objs += wsa881x-regmap-analog.o wsa881x-irq.o
-snd-soc-wcd-dsp-utils-objs := wcd-dsp-utils.o
-snd-soc-wcd-dsp-mgr-objs := wcd-dsp-mgr.o
 snd-soc-wcd-spi-objs := wcd-spi.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm-adsp-objs := wm_adsp.o
@@ -407,23 +404,14 @@
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WCD9320)	+= snd-soc-wcd9320.o
-obj-$(CONFIG_SND_SOC_WCD9330)	+= snd-soc-wcd9330.o
 obj-$(CONFIG_SND_SOC_WCD9335)	+= snd-soc-wcd9335.o
 obj-$(CONFIG_SND_SOC_WCD934X)	+= wcd934x/
-ifeq ($(CONFIG_COMMON_CLK_MSM), y)
-	obj-$(CONFIG_AUDIO_EXT_CLK)	+= audio-ext-clock.o
-endif
-ifeq ($(CONFIG_COMMON_CLK_QCOM), y)
-	obj-$(CONFIG_AUDIO_EXT_CLK)     += audio-ext-clock-up.o
-endif
-obj-$(CONFIG_SND_SOC_WCD9XXX)   += snd-soc-wcd9xxx.o
-obj-$(CONFIG_SND_SOC_WCD9XXX_V2) += snd-soc-wcd9xxx-v2.o
+obj-$(CONFIG_SND_SOC_WCD9XXX) += snd-soc-wcd9xxx.o
 obj-$(CONFIG_SND_SOC_WCD_CPE)   += snd-soc-wcd-cpe.o
 obj-$(CONFIG_SND_SOC_WCD_MBHC)  += snd-soc-wcd-mbhc.o
 obj-$(CONFIG_SND_SOC_WSA881X)	+= snd-soc-wsa881x.o
 obj-$(CONFIG_SND_SOC_WSA881X_ANALOG)	+= snd-soc-wsa881x-analog.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
-obj-$(CONFIG_SND_SOC_WCD_DSP_MGR)	+= snd-soc-wcd-dsp-mgr.o snd-soc-wcd-dsp-utils.o
 obj-$(CONFIG_SND_SOC_WCD_SPI)  += snd-soc-wcd-spi.o
 obj-$(CONFIG_SND_SOC_WM0010)	+= snd-soc-wm0010.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
diff --git a/sound/soc/codecs/audio-ext-clk-up.c b/sound/soc/codecs/audio-ext-clk-up.c
index 39986d6..3b54096 100644
--- a/sound/soc/codecs/audio-ext-clk-up.c
+++ b/sound/soc/codecs/audio-ext-clk-up.c
@@ -23,6 +23,7 @@
 #include <linux/of_gpio.h>
 #include <dt-bindings/clock/qcom,audio-ext-clk.h>
 #include <sound/q6afe-v2.h>
+#include "audio-ext-clk-up.h"
 
 enum audio_clk_mux {
 	AP_CLK2,
@@ -34,6 +35,7 @@
 	struct pinctrl *pinctrl;
 	struct pinctrl_state *sleep;
 	struct pinctrl_state *active;
+	char __iomem *base;
 };
 
 struct audio_ext_ap_clk {
@@ -192,8 +194,10 @@
 		pr_err("%s afe_set_digital_codec_core_clock failed\n",
 			__func__);
 		return ret;
-		}
+	}
 
+	if (pnctrl_info->base)
+		iowrite32(1, pnctrl_info->base);
 	return 0;
 }
 
@@ -219,6 +223,8 @@
 	if (ret < 0)
 		pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n",
 			__func__, ret);
+	if (pnctrl_info->base)
+		iowrite32(0, pnctrl_info->base);
 }
 
 static int audio_ext_lpass_mclk2_prepare(struct clk_hw *hw)
@@ -381,9 +387,11 @@
 static int audio_get_pinctrl(struct platform_device *pdev,
 			     enum audio_clk_mux mux)
 {
+	struct device *dev =  &pdev->dev;
 	struct pinctrl_info *pnctrl_info;
 	struct pinctrl *pinctrl;
 	int ret;
+	u32 reg;
 
 	switch (mux) {
 	case AP_CLK2:
@@ -396,21 +404,20 @@
 		pnctrl_info = &audio_lpass_mclk2.pnctrl_info;
 		break;
 	default:
-		dev_err(&pdev->dev, "%s Not a valid MUX ID: %d\n",
+		dev_err(dev, "%s Not a valid MUX ID: %d\n",
 			__func__, mux);
 		return -EINVAL;
 	}
-	pnctrl_info = &audio_ap_clk2.pnctrl_info;
 
 	if (pnctrl_info->pinctrl) {
-		dev_dbg(&pdev->dev, "%s: already requested before\n",
+		dev_dbg(dev, "%s: already requested before\n",
 			__func__);
 		return -EINVAL;
 	}
 
-	pinctrl = devm_pinctrl_get(&pdev->dev);
+	pinctrl = devm_pinctrl_get(dev);
 	if (IS_ERR_OR_NULL(pinctrl)) {
-		dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n",
+		dev_dbg(dev, "%s: Unable to get pinctrl handle\n",
 			__func__);
 		return -EINVAL;
 	}
@@ -418,13 +425,13 @@
 	/* get all state handles from Device Tree */
 	pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep");
 	if (IS_ERR(pnctrl_info->sleep)) {
-		dev_err(&pdev->dev, "%s: could not get sleep pinstate\n",
+		dev_err(dev, "%s: could not get sleep pinstate\n",
 			__func__);
 		goto err;
 	}
 	pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active");
 	if (IS_ERR(pnctrl_info->active)) {
-		dev_err(&pdev->dev, "%s: could not get active pinstate\n",
+		dev_err(dev, "%s: could not get active pinstate\n",
 			__func__);
 		goto err;
 	}
@@ -432,10 +439,22 @@
 	ret = pinctrl_select_state(pnctrl_info->pinctrl,
 				   pnctrl_info->sleep);
 	if (ret) {
-		dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n",
+		dev_err(dev, "%s: Disable TLMM pins failed with %d\n",
 			__func__, ret);
 		goto err;
 	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,mclk-clk-reg", &reg);
+	if (ret < 0) {
+		dev_dbg(dev, "%s: miss mclk reg\n", __func__);
+	} else {
+		pnctrl_info->base = ioremap(reg, sizeof(u32));
+		if (pnctrl_info->base ==  NULL) {
+			dev_err(dev, "%s ioremap failed\n", __func__);
+			goto err;
+		}
+	}
+
 	return 0;
 
 err:
@@ -593,17 +612,15 @@
 	.remove = audio_ref_clk_remove,
 };
 
-static int __init audio_ref_clk_platform_init(void)
+int audio_ref_clk_platform_init(void)
 {
 	return platform_driver_register(&audio_ref_clk_driver);
 }
-module_init(audio_ref_clk_platform_init);
 
-static void __exit audio_ref_clk_platform_exit(void)
+void audio_ref_clk_platform_exit(void)
 {
 	platform_driver_unregister(&audio_ref_clk_driver);
 }
-module_exit(audio_ref_clk_platform_exit);
 
 MODULE_DESCRIPTION("Audio Ref Up Clock module platform driver");
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/audio-ext-clk-up.h b/sound/soc/codecs/audio-ext-clk-up.h
new file mode 100644
index 0000000..8a0232e
--- /dev/null
+++ b/sound/soc/codecs/audio-ext-clk-up.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __AUDIO_EXT_CLK_UP_H_
+#define __AUDIO_EXT_CLK_UP_H_
+
+int audio_ref_clk_platform_init(void);
+void audio_ref_clk_platform_exit(void);
+
+#endif
diff --git a/sound/soc/codecs/audio-ext-clk.c b/sound/soc/codecs/audio-ext-clk.c
index ef795df..72f16f5 100644
--- a/sound/soc/codecs/audio-ext-clk.c
+++ b/sound/soc/codecs/audio-ext-clk.c
@@ -23,6 +23,7 @@
 #include <linux/of_gpio.h>
 #include <dt-bindings/clock/audio-ext-clk.h>
 #include <sound/q6afe-v2.h>
+#include "audio-ext-clk-up.h"
 
 struct pinctrl_info {
 	struct pinctrl *pinctrl;
@@ -333,17 +334,15 @@
 	.remove = audio_ref_clk_remove,
 };
 
-static int __init audio_ref_clk_platform_init(void)
+int audio_ref_clk_platform_init(void)
 {
 	return platform_driver_register(&audio_ref_clk_driver);
 }
-module_init(audio_ref_clk_platform_init);
 
-static void __exit audio_ref_clk_platform_exit(void)
+void audio_ref_clk_platform_exit(void)
 {
 	platform_driver_unregister(&audio_ref_clk_driver);
 }
-module_exit(audio_ref_clk_platform_exit);
 
 MODULE_DESCRIPTION("Audio Ref Clock module platform driver");
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm_sdw/msm-sdw-tables.c b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
index 4cbdb72..1b51805 100644
--- a/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
+++ b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
@@ -220,3 +220,100 @@
 	[MSM_SDW_TOP_I2S_RESET] = 1,
 	[MSM_SDW_TOP_BLOCKS_RESET] = 1,
 };
+
+const u8 msm_sdw_reg_writeable[MSM_SDW_MAX_REGISTER] = {
+	[MSM_SDW_PAGE_REGISTER] = 1,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 1,
+	[MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 1,
+	[MSM_SDW_COMPANDER7_CTL0] = 1,
+	[MSM_SDW_COMPANDER7_CTL1] = 1,
+	[MSM_SDW_COMPANDER7_CTL2] = 1,
+	[MSM_SDW_COMPANDER7_CTL3] = 1,
+	[MSM_SDW_COMPANDER7_CTL4] = 1,
+	[MSM_SDW_COMPANDER7_CTL5] = 1,
+	[MSM_SDW_COMPANDER7_CTL7] = 1,
+	[MSM_SDW_COMPANDER8_CTL0] = 1,
+	[MSM_SDW_COMPANDER8_CTL1] = 1,
+	[MSM_SDW_COMPANDER8_CTL2] = 1,
+	[MSM_SDW_COMPANDER8_CTL3] = 1,
+	[MSM_SDW_COMPANDER8_CTL4] = 1,
+	[MSM_SDW_COMPANDER8_CTL5] = 1,
+	[MSM_SDW_COMPANDER8_CTL7] = 1,
+	[MSM_SDW_RX7_RX_PATH_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG0] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG1] = 1,
+	[MSM_SDW_RX7_RX_PATH_CFG2] = 1,
+	[MSM_SDW_RX7_RX_VOL_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_CFG] = 1,
+	[MSM_SDW_RX7_RX_VOL_MIX_CTL] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC0] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC1] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC2] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC3] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC5] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC6] = 1,
+	[MSM_SDW_RX7_RX_PATH_SEC7] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 1,
+	[MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 1,
+	[MSM_SDW_RX8_RX_PATH_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG0] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG1] = 1,
+	[MSM_SDW_RX8_RX_PATH_CFG2] = 1,
+	[MSM_SDW_RX8_RX_VOL_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_CFG] = 1,
+	[MSM_SDW_RX8_RX_VOL_MIX_CTL] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC0] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC1] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC2] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC3] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC5] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC6] = 1,
+	[MSM_SDW_RX8_RX_PATH_SEC7] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 1,
+	[MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 1,
+	[MSM_SDW_BOOST0_BOOST_PATH_CTL] = 1,
+	[MSM_SDW_BOOST0_BOOST_CTL] = 1,
+	[MSM_SDW_BOOST0_BOOST_CFG1] = 1,
+	[MSM_SDW_BOOST0_BOOST_CFG2] = 1,
+	[MSM_SDW_BOOST1_BOOST_PATH_CTL] = 1,
+	[MSM_SDW_BOOST1_BOOST_CTL] = 1,
+	[MSM_SDW_BOOST1_BOOST_CFG1] = 1,
+	[MSM_SDW_BOOST1_BOOST_CFG2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 1,
+	[MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 1,
+	[MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 1,
+	[MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 1,
+	[MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 1,
+	[MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 1,
+	[MSM_SDW_TOP_TOP_CFG0] = 1,
+	[MSM_SDW_TOP_TOP_CFG1] = 1,
+	[MSM_SDW_TOP_RX_I2S_CTL] = 1,
+	[MSM_SDW_TOP_TX_I2S_CTL] = 1,
+	[MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 1,
+	[MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 1,
+	[MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 1,
+	[MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 1,
+	[MSM_SDW_TOP_FREQ_MCLK] = 1,
+	[MSM_SDW_TOP_DEBUG_BUS_SEL] = 1,
+	[MSM_SDW_TOP_DEBUG_EN] = 1,
+	[MSM_SDW_TOP_I2S_RESET] = 1,
+	[MSM_SDW_TOP_BLOCKS_RESET] = 1,
+};
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw.h b/sound/soc/codecs/msm_sdw/msm_sdw.h
index 3691e84..376ebc6 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw.h
+++ b/sound/soc/codecs/msm_sdw/msm_sdw.h
@@ -21,6 +21,7 @@
 extern const struct regmap_config msm_sdw_regmap_config;
 extern const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER];
 extern const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER];
+extern const u8 msm_sdw_reg_writeable[MSM_SDW_MAX_REGISTER];
 
 enum {
 	MSM_SDW_RX4 = 0,
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
index 0942d4a..62fdb94 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -854,8 +854,8 @@
 	if (!msm_sdw->comp_enabled[comp])
 		return 0;
 
-	comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 8);
-	rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 20);
+	comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 0x20);
+	rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 0x1E0);
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		/* Enable Compander Clock */
@@ -1044,7 +1044,7 @@
 	 * Add sleep as SWR slave access read takes time.
 	 * Allow for RD_DONE to complete for previous register if any.
 	 */
-	usleep_range(50, 55);
+	usleep_range(100, 105);
 
 	/* read_lock */
 	mutex_lock(&msm_sdw->sdw_read_lock);
@@ -1079,6 +1079,11 @@
 	sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
 	sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
 
+	/*
+	 * Add sleep as SWR slave write takes time.
+	 * Allow for any previous pending write to complete.
+	 */
+	usleep_range(50, 55);
 	for (i = 0; i < len; i += 2) {
 		/* First Write the Data to register */
 		ret = regmap_bulk_write(msm_sdw->regmap,
@@ -1656,12 +1661,17 @@
 						    service_nb);
 	bool adsp_ready = false;
 	unsigned long timeout;
+	static bool initial_boot = true;
 
 	pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
 
 	mutex_lock(&msm_sdw->codec_mutex);
 	switch (opcode) {
 	case AUDIO_NOTIFIER_SERVICE_DOWN:
+		if (initial_boot) {
+			initial_boot = false;
+			break;
+		}
 		msm_sdw->int_mclk1_enabled = false;
 		msm_sdw->dev_up = false;
 		for (i = 0; i < msm_sdw->nr; i++)
@@ -1669,6 +1679,8 @@
 					SWR_DEVICE_DOWN, NULL);
 		break;
 	case AUDIO_NOTIFIER_SERVICE_UP:
+		if (initial_boot)
+			initial_boot = false;
 		if (!q6core_is_adsp_ready()) {
 			dev_dbg(msm_sdw->dev, "ADSP isn't ready\n");
 			timeout = jiffies +
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c
index 78858f0..2266338 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c
@@ -115,6 +115,11 @@
 	return msm_sdw_reg_readable[reg];
 }
 
+static bool msm_sdw_is_writeable_register(struct device *dev, unsigned int reg)
+{
+	return msm_sdw_reg_writeable[reg];
+}
+
 static bool msm_sdw_is_volatile_register(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -150,6 +155,7 @@
 	.reg_defaults = msm_sdw_defaults,
 	.num_reg_defaults = ARRAY_SIZE(msm_sdw_defaults),
 	.max_register = MSM_SDW_MAX_REGISTER,
+	.writeable_reg = msm_sdw_is_writeable_register,
 	.volatile_reg = msm_sdw_is_volatile_register,
 	.readable_reg = msm_sdw_is_readable_register,
 };
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
index 5f8e3fd..a8fcd34 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -37,9 +37,10 @@
 #define DRV_NAME "pmic_analog_codec"
 #define SDM660_CDC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
 			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
-			SNDRV_PCM_RATE_48000)
+			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
+			SNDRV_PCM_RATE_192000)
 #define SDM660_CDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
-		SNDRV_PCM_FMTBIT_S24_LE)
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE)
 #define MSM_DIG_CDC_STRING_LEN 80
 #define MSM_ANLG_CDC_VERSION_ENTRY_SIZE 32
 
@@ -1399,8 +1400,26 @@
 	}
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		if (atomic_inc_return(&supply->ref) == 1)
+		if (atomic_inc_return(&supply->ref) == 1) {
+			ret = regulator_set_voltage(supply->supply,
+						    supply->min_uv,
+						    supply->max_uv);
+			if (ret) {
+				dev_err(codec->dev,
+					"Setting regulator voltage(en) for micbias with err = %d\n",
+					ret);
+				goto out;
+			}
+			ret = regulator_set_load(supply->supply,
+						 supply->optimum_ua);
+			if (ret < 0) {
+				dev_err(codec->dev,
+					"Setting regulator optimum mode(en) failed for micbias with err = %d\n",
+					ret);
+				goto out;
+			}
 			ret = regulator_enable(supply->supply);
+		}
 		if (ret)
 			dev_err(codec->dev, "%s: Failed to enable %s\n",
 				__func__,
@@ -1412,12 +1431,27 @@
 				 __func__, on_demand_supply_name[w->shift]);
 			goto out;
 		}
-		if (atomic_dec_return(&supply->ref) == 0)
+		if (atomic_dec_return(&supply->ref) == 0) {
 			ret = regulator_disable(supply->supply);
 			if (ret)
 				dev_err(codec->dev, "%s: Failed to disable %s\n",
 					__func__,
 					on_demand_supply_name[w->shift]);
+			ret = regulator_set_voltage(supply->supply,
+						    0,
+						    supply->max_uv);
+			if (ret) {
+				dev_err(codec->dev,
+					"Setting regulator voltage(dis) failed for micbias with err = %d\n",
+					ret);
+				goto out;
+			}
+			ret = regulator_set_load(supply->supply, 0);
+			if (ret < 0)
+				dev_err(codec->dev,
+					"Setting regulator optimum mode(dis) failed for micbias with err = %d\n",
+					ret);
+		}
 		break;
 	default:
 		break;
@@ -1435,11 +1469,11 @@
 	if (enable) {
 		snd_soc_update_bits(codec,
 			MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30);
+		msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON);
 		snd_soc_update_bits(codec,
 			MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
 		snd_soc_update_bits(codec,
 			MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C);
-		msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON);
 	} else {
 		snd_soc_update_bits(codec,
 			MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00);
@@ -3180,7 +3214,7 @@
 		.name = "msm_anlg_cdc_i2s_rx1",
 		.id = AIF1_PB,
 		.playback = {
-			.stream_name = "Playback",
+			.stream_name = "PDM Playback",
 			.rates = SDM660_CDC_RATES,
 			.formats = SDM660_CDC_FORMATS,
 			.rate_max = 192000,
@@ -3194,7 +3228,7 @@
 		.name = "msm_anlg_cdc_i2s_tx1",
 		.id = AIF1_CAP,
 		.capture = {
-			.stream_name = "Record",
+			.stream_name = "PDM Capture",
 			.rates = SDM660_CDC_RATES,
 			.formats = SDM660_CDC_FORMATS,
 			.rate_max = 48000,
@@ -3684,6 +3718,30 @@
 	return NULL;
 }
 
+static void msm_anlg_cdc_update_micbias_regulator(
+				const struct sdm660_cdc_priv *sdm660_cdc,
+				const char *name,
+				struct on_demand_supply *micbias_supply)
+{
+	int i;
+	struct sdm660_cdc_pdata *pdata = sdm660_cdc->dev->platform_data;
+
+	for (i = 0; i < sdm660_cdc->num_of_supplies; i++) {
+		if (sdm660_cdc->supplies[i].supply &&
+		    !strcmp(sdm660_cdc->supplies[i].supply, name)) {
+			micbias_supply->supply =
+				sdm660_cdc->supplies[i].consumer;
+			micbias_supply->min_uv = pdata->regulator[i].min_uv;
+			micbias_supply->max_uv = pdata->regulator[i].max_uv;
+			micbias_supply->optimum_ua =
+					pdata->regulator[i].optimum_ua;
+			return;
+		}
+	}
+
+	dev_err(sdm660_cdc->dev, "Error: regulator not found:%s\n", name);
+}
+
 static int msm_anlg_cdc_device_down(struct snd_soc_codec *codec)
 {
 	struct msm_asoc_mach_data *pdata = NULL;
@@ -3759,8 +3817,8 @@
 	snd_soc_write(codec,
 		MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93);
 
-	atomic_set(&pdata->int_mclk0_enabled, false);
 	msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_DOWN);
+	atomic_set(&pdata->int_mclk0_enabled, false);
 	set_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask);
 	snd_soc_card_change_online_state(codec->component.card, 0);
 
@@ -3771,7 +3829,6 @@
 {
 	struct sdm660_cdc_priv *sdm660_cdc_priv =
 		snd_soc_codec_get_drvdata(codec);
-	int ret = 0;
 
 	dev_dbg(codec->dev, "%s: device up!\n", __func__);
 
@@ -3793,18 +3850,6 @@
 	else if (sdm660_cdc_priv->boost_option == BYPASS_ALWAYS)
 		msm_anlg_cdc_bypass_on(codec);
 
-	msm_anlg_cdc_configure_cap(codec, false, false);
-	wcd_mbhc_stop(&sdm660_cdc_priv->mbhc);
-	wcd_mbhc_deinit(&sdm660_cdc_priv->mbhc);
-	ret = wcd_mbhc_init(&sdm660_cdc_priv->mbhc, codec, &mbhc_cb,
-			    &intr_ids, wcd_mbhc_registers, true);
-	if (ret)
-		dev_err(codec->dev, "%s: mbhc initialization failed\n",
-			__func__);
-	else
-		wcd_mbhc_start(&sdm660_cdc_priv->mbhc,
-			sdm660_cdc_priv->mbhc.mbhc_cfg);
-
 	return 0;
 }
 
@@ -3818,17 +3863,24 @@
 	bool adsp_ready = false;
 	bool timedout;
 	unsigned long timeout;
+	static bool initial_boot = true;
 
 	codec = sdm660_cdc_priv->codec;
 	dev_dbg(codec->dev, "%s: Service opcode 0x%lx\n", __func__, opcode);
 
 	switch (opcode) {
 	case AUDIO_NOTIFIER_SERVICE_DOWN:
+		if (initial_boot) {
+			initial_boot = false;
+			break;
+		}
 		dev_dbg(codec->dev,
 			"ADSP is about to power down. teardown/reset codec\n");
 		msm_anlg_cdc_device_down(codec);
 		break;
 	case AUDIO_NOTIFIER_SERVICE_UP:
+		if (initial_boot)
+			initial_boot = false;
 		dev_dbg(codec->dev,
 			"ADSP is about to power up. bring up codec\n");
 
@@ -4119,10 +4171,10 @@
 
 	wcd9xxx_spmi_set_codec(codec);
 
-	sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS].supply =
-				msm_anlg_cdc_find_regulator(
+	msm_anlg_cdc_update_micbias_regulator(
 				sdm660_cdc,
-				on_demand_supply_name[ON_DEMAND_MICBIAS]);
+				on_demand_supply_name[ON_DEMAND_MICBIAS],
+				&sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS]);
 	atomic_set(&sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS].ref,
 		   0);
 
@@ -4158,6 +4210,8 @@
 	snd_soc_dapm_ignore_suspend(dapm, "PDM Playback");
 	snd_soc_dapm_ignore_suspend(dapm, "PDM Capture");
 
+	snd_soc_dapm_sync(dapm);
+
 	return 0;
 }
 
@@ -4186,7 +4240,7 @@
 		if (pdata->regulator[i].ondemand)
 			continue;
 		if (regulator_count_voltages(
-				sdm660_cdc->supplies[i].consumer) <=	0)
+				sdm660_cdc->supplies[i].consumer) <= 0)
 			continue;
 
 		ret = regulator_set_voltage(
@@ -4219,7 +4273,7 @@
 		if (pdata->regulator[i].ondemand)
 			continue;
 		if (regulator_count_voltages(
-				sdm660_cdc->supplies[i].consumer) <=	0)
+				sdm660_cdc->supplies[i].consumer) <= 0)
 			continue;
 		regulator_set_voltage(sdm660_cdc->supplies[i].consumer, 0,
 				pdata->regulator[i].max_uv);
@@ -4320,6 +4374,28 @@
 		if (regulator_count_voltages(
 			sdm660_cdc->supplies[i].consumer) <= 0)
 			continue;
+		if (pdata->regulator[i].ondemand) {
+			ret = regulator_set_voltage(
+					sdm660_cdc->supplies[i].consumer,
+					0, pdata->regulator[i].max_uv);
+			if (ret) {
+				dev_err(sdm660_cdc->dev,
+					"Setting regulator voltage failed for regulator %s err = %d\n",
+					sdm660_cdc->supplies[i].supply, ret);
+				goto err_supplies;
+			}
+			ret = regulator_set_load(
+				sdm660_cdc->supplies[i].consumer, 0);
+			if (ret < 0) {
+				dev_err(sdm660_cdc->dev,
+					"Setting regulator optimum mode failed for regulator %s err = %d\n",
+					sdm660_cdc->supplies[i].supply, ret);
+				goto err_supplies;
+			} else {
+				ret = 0;
+				continue;
+			}
+		}
 		ret = regulator_set_voltage(sdm660_cdc->supplies[i].consumer,
 					    pdata->regulator[i].min_uv,
 					    pdata->regulator[i].max_uv);
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h
index 0c9e9a6..9563565 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h
@@ -144,6 +144,9 @@
 struct on_demand_supply {
 	struct regulator *supply;
 	atomic_t ref;
+	int min_uv;
+	int max_uv;
+	int optimum_ua;
 };
 
 struct wcd_imped_i_ref {
diff --git a/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
index 95dbc76..1a490a4 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
+++ b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
@@ -19,6 +19,7 @@
 		msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE];
 
 bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg);
+bool msm89xx_cdc_core_writeable_reg(struct device *dev, unsigned int reg);
 bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg);
 
 enum {
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
index 9d16521..3f9c0b4 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -30,6 +30,7 @@
 #include "msm-digital-cdc.h"
 #include "msm-cdc-common.h"
 #include "../../msm/sdm660-common.h"
+#include "../../../../drivers/base/regmap/internal.h"
 
 #define DRV_NAME "msm_digital_codec"
 #define MCLK_RATE_9P6MHZ        9600000
@@ -71,11 +72,13 @@
 {
 	int ret = -EINVAL;
 	struct msm_asoc_mach_data *pdata = NULL;
+	struct msm_dig_priv *msm_dig_cdc =
+				snd_soc_codec_get_drvdata(registered_digcodec);
 
 	pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card);
 
-	mutex_lock(&pdata->cdc_int_mclk0_mutex);
 	if (flag) {
+		mutex_lock(&pdata->cdc_int_mclk0_mutex);
 		if (atomic_read(&pdata->int_mclk0_enabled) == false) {
 			pdata->digital_cdc_core_clk.enable = 1;
 			ret = afe_set_lpass_clock_v2(
@@ -84,7 +87,12 @@
 			if (ret < 0) {
 				pr_err("%s:failed to enable the MCLK\n",
 				       __func__);
-				mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+				/*
+				 * Avoid access to lpass register
+				 * as clock enable failed during SSR.
+				 */
+				if (ret == -ENODEV)
+					msm_dig_cdc->regmap->cache_only = true;
 				return ret;
 			}
 			pr_debug("enabled digital codec core clk\n");
@@ -93,10 +101,10 @@
 					      50);
 		}
 	} else {
+		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
 		dev_dbg(registered_digcodec->dev,
 			"disable MCLK, workq to disable set already\n");
 	}
-	mutex_unlock(&pdata->cdc_int_mclk0_mutex);
 	return 0;
 }
 
@@ -107,6 +115,7 @@
 
 static void disable_digital_callback(void *flag)
 {
+	msm_digcdc_clock_control(false);
 	pr_debug("disable mclk happens in workq\n");
 }
 
@@ -973,6 +982,7 @@
 	struct snd_soc_codec *codec = registered_digcodec;
 	struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
 	struct msm_asoc_mach_data *pdata = NULL;
+	int ret = -EINVAL;
 
 	pdata = snd_soc_card_get_drvdata(codec->component.card);
 
@@ -1028,7 +1038,7 @@
 		break;
 	case DIG_CDC_EVENT_PRE_RX1_INT_ON:
 		snd_soc_update_bits(codec,
-				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x14);
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x28);
 		snd_soc_update_bits(codec,
 				MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10);
 		snd_soc_update_bits(codec,
@@ -1036,7 +1046,7 @@
 		break;
 	case DIG_CDC_EVENT_PRE_RX2_INT_ON:
 		snd_soc_update_bits(codec,
-				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x14);
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x28);
 		snd_soc_update_bits(codec,
 				MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10);
 		snd_soc_update_bits(codec,
@@ -1044,7 +1054,7 @@
 		break;
 	case DIG_CDC_EVENT_POST_RX1_INT_OFF:
 		snd_soc_update_bits(codec,
-				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x00);
+				MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x00);
 		snd_soc_update_bits(codec,
 				MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF);
 		snd_soc_update_bits(codec,
@@ -1052,7 +1062,7 @@
 		break;
 	case DIG_CDC_EVENT_POST_RX2_INT_OFF:
 		snd_soc_update_bits(codec,
-				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x00);
+				MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x00);
 		snd_soc_update_bits(codec,
 				MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF);
 		snd_soc_update_bits(codec,
@@ -1064,7 +1074,28 @@
 	case DIG_CDC_EVENT_SSR_UP:
 		regcache_cache_only(msm_dig_cdc->regmap, false);
 		regcache_mark_dirty(msm_dig_cdc->regmap);
+
+		mutex_lock(&pdata->cdc_int_mclk0_mutex);
+		pdata->digital_cdc_core_clk.enable = 1;
+		ret = afe_set_lpass_clock_v2(
+					AFE_PORT_ID_INT0_MI2S_RX,
+					&pdata->digital_cdc_core_clk);
+		if (ret < 0) {
+			pr_err("%s:failed to enable the MCLK\n",
+			       __func__);
+			mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+			break;
+		}
+		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+
 		regcache_sync(msm_dig_cdc->regmap);
+
+		mutex_lock(&pdata->cdc_int_mclk0_mutex);
+		pdata->digital_cdc_core_clk.enable = 0;
+		afe_set_lpass_clock_v2(
+				AFE_PORT_ID_INT0_MI2S_RX,
+				&pdata->digital_cdc_core_clk);
+		mutex_unlock(&pdata->cdc_int_mclk0_mutex);
 		break;
 	case DIG_CDC_EVENT_INVALID:
 	default:
@@ -1207,6 +1238,8 @@
 	snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX2");
 	snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX3");
 
+	snd_soc_dapm_sync(dapm);
+
 	return 0;
 }
 
@@ -1929,8 +1962,12 @@
 			.stream_name = "AIF1 Playback",
 			.channels_min = 1,
 			.channels_max = 2,
-			.rates = SNDRV_PCM_RATE_8000_48000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S24_LE |
+				SNDRV_PCM_FMTBIT_S24_3LE,
 		},
 		 .ops = &msm_dig_dai_ops,
 	},
@@ -2012,12 +2049,13 @@
 const struct regmap_config msm_digital_regmap_config = {
 	.reg_bits = 32,
 	.reg_stride = 4,
-	.val_bits = 32,
+	.val_bits = 8,
 	.lock = enable_digital_callback,
 	.unlock = disable_digital_callback,
 	.cache_type = REGCACHE_FLAT,
 	.reg_defaults = msm89xx_cdc_core_defaults,
 	.num_reg_defaults = MSM89XX_CDC_CORE_MAX_REGISTER,
+	.writeable_reg = msm89xx_cdc_core_writeable_reg,
 	.readable_reg = msm89xx_cdc_core_readable_reg,
 	.volatile_reg = msm89xx_cdc_core_volatile_reg,
 	.reg_format_endian = REGMAP_ENDIAN_NATIVE,
@@ -2123,8 +2161,8 @@
 }
 
 static const struct dev_pm_ops msm_dig_pm_ops = {
-	.suspend = msm_dig_suspend,
-	.resume = msm_dig_resume,
+	.suspend_late = msm_dig_suspend,
+	.resume_early = msm_dig_resume,
 };
 #endif
 
diff --git a/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
index fff1fdc..7d8ac6d 100644
--- a/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/regmap.h>
+#include "msm-cdc-common.h"
 #include "sdm660-cdc-registers.h"
 
 /*
@@ -444,16 +445,167 @@
 		[MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
 };
 
+static const u8 msm89xx_cdc_core_reg_writeable[MSM89XX_CDC_CORE_CACHE_SIZE] = {
+		[MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_SD_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_RX_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1,
+		[MSM89XX_CDC_CORE_TOP_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_COMP0_FS_CFG] = 1,
+		[MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1,
+		[MSM89XX_CDC_CORE_CONN_TX_B3_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN] = 1,
+		[MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG] = 1,
+		[MSM89XX_CDC_CORE_TX5_MUX_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_CLK_FS_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX5_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1,
+		[MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
+};
+
 bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg)
 {
 	return msm89xx_cdc_core_reg_readable[reg];
 }
 
+bool msm89xx_cdc_core_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return msm89xx_cdc_core_reg_writeable[reg];
+}
+
 bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
-	/* cache bypass for initial version */
-	default:
+	case MSM89XX_CDC_CORE_RX1_B1_CTL:
+	case MSM89XX_CDC_CORE_RX2_B1_CTL:
+	case MSM89XX_CDC_CORE_RX3_B1_CTL:
+	case MSM89XX_CDC_CORE_RX1_B6_CTL:
+	case MSM89XX_CDC_CORE_RX2_B6_CTL:
+	case MSM89XX_CDC_CORE_RX3_B6_CTL:
+	case MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG:
+	case MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL:
+	case MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL:
+	case MSM89XX_CDC_CORE_CLK_MCLK_CTL:
+	case MSM89XX_CDC_CORE_CLK_PDM_CTL:
 		return true;
+	default:
+		return false;
 	}
 }
diff --git a/sound/soc/codecs/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c
index ae53294..661db2b 100644
--- a/sound/soc/codecs/wcd-dsp-mgr.c
+++ b/sound/soc/codecs/wcd-dsp-mgr.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/stringify.h>
 #include <linux/of.h>
+#include <linux/debugfs.h>
 #include <linux/component.h>
 #include <linux/dma-mapping.h>
 #include <soc/qcom/ramdump.h>
@@ -182,6 +183,10 @@
 	struct work_struct ssr_work;
 	u16 ready_status;
 	struct completion ready_compl;
+
+	/* Debugfs related */
+	struct dentry *entry;
+	bool panic_on_error;
 };
 
 static char *wdsp_get_ssr_type_string(enum wdsp_ssr_type type)
@@ -605,6 +610,25 @@
 	return cmpnt->cdev;
 }
 
+static int wdsp_get_devops_for_cmpnt(struct device *wdsp_dev,
+				     enum wdsp_cmpnt_type type,
+				     void *data)
+{
+	struct wdsp_mgr_priv *wdsp;
+	int ret = 0;
+
+	if (!wdsp_dev || type >= WDSP_CMPNT_TYPE_MAX)
+		return -EINVAL;
+
+	wdsp = dev_get_drvdata(wdsp_dev);
+	ret = wdsp_unicast_event(wdsp, type,
+				 WDSP_EVENT_GET_DEVOPS, data);
+	if (ret)
+		WDSP_ERR(wdsp, "get_dev_ops failed for cmpnt type %d",
+			 type);
+	return ret;
+}
+
 static void wdsp_collect_ramdumps(struct wdsp_mgr_priv *wdsp)
 {
 	struct wdsp_img_section img_section;
@@ -656,6 +680,12 @@
 		goto err_read_dumps;
 	}
 
+	/*
+	 * If panic_on_error flag is explicitly set through the debugfs,
+	 * then cause a BUG here to aid debugging.
+	 */
+	BUG_ON(wdsp->panic_on_error);
+
 	rd_seg.address = (unsigned long) wdsp->dump_data.rd_v_addr;
 	rd_seg.size = img_section.size;
 	rd_seg.v_address = wdsp->dump_data.rd_v_addr;
@@ -930,6 +960,7 @@
 static struct wdsp_mgr_ops wdsp_ops = {
 	.register_cmpnt_ops = wdsp_register_cmpnt_ops,
 	.get_dev_for_cmpnt = wdsp_get_dev_for_cmpnt,
+	.get_devops_for_cmpnt = wdsp_get_devops_for_cmpnt,
 	.signal_handler = wdsp_signal_handler,
 	.vote_for_dsp = wdsp_vote_for_dsp,
 	.suspend = wdsp_suspend,
@@ -949,6 +980,22 @@
 		 !strcmp(dev_name(dev), cmpnt->cdev_name)));
 }
 
+static void wdsp_mgr_debugfs_init(struct wdsp_mgr_priv *wdsp)
+{
+	wdsp->entry = debugfs_create_dir("wdsp_mgr", NULL);
+	if (IS_ERR_OR_NULL(wdsp->entry))
+		return;
+
+	debugfs_create_bool("panic_on_error", 0644,
+			    wdsp->entry, &wdsp->panic_on_error);
+}
+
+static void wdsp_mgr_debugfs_remove(struct wdsp_mgr_priv *wdsp)
+{
+	debugfs_remove_recursive(wdsp->entry);
+	wdsp->entry = NULL;
+}
+
 static int wdsp_mgr_bind(struct device *dev)
 {
 	struct wdsp_mgr_priv *wdsp = dev_get_drvdata(dev);
@@ -978,6 +1025,8 @@
 		}
 	}
 
+	wdsp_mgr_debugfs_init(wdsp);
+
 	/* Schedule the work to download image if binding was successful. */
 	if (!ret)
 		schedule_work(&wdsp->load_fw_work);
@@ -993,6 +1042,8 @@
 
 	component_unbind_all(dev, wdsp->ops);
 
+	wdsp_mgr_debugfs_remove(wdsp);
+
 	if (wdsp->dump_data.rd_dev) {
 		destroy_ramdump_device(wdsp->dump_data.rd_dev);
 		wdsp->dump_data.rd_dev = NULL;
@@ -1186,7 +1237,16 @@
 	.probe = wdsp_mgr_probe,
 	.remove = wdsp_mgr_remove,
 };
-module_platform_driver(wdsp_mgr_driver);
+
+int wcd_dsp_mgr_init(void)
+{
+	return platform_driver_register(&wdsp_mgr_driver);
+}
+
+void wcd_dsp_mgr_exit(void)
+{
+	platform_driver_unregister(&wdsp_mgr_driver);
+}
 
 MODULE_DESCRIPTION("WCD DSP manager driver");
 MODULE_DEVICE_TABLE(of, wdsp_mgr_dt_match);
diff --git a/sound/soc/codecs/wcd-mbhc-adc.h b/sound/soc/codecs/wcd-mbhc-adc.h
index 112d508..3116108 100644
--- a/sound/soc/codecs/wcd-mbhc-adc.h
+++ b/sound/soc/codecs/wcd-mbhc-adc.h
@@ -24,7 +24,7 @@
 	MUX_CTL_NONE,
 };
 
-#ifdef CONFIG_SND_SOC_WCD_MBHC_ADC
+#if IS_ENABLED(CONFIG_SND_SOC_WCD_MBHC_ADC)
 void wcd_mbhc_adc_init(struct wcd_mbhc *mbhc);
 #else
 static inline void wcd_mbhc_adc_init(struct wcd_mbhc *mbhc)
diff --git a/sound/soc/codecs/wcd-mbhc-v2-api.h b/sound/soc/codecs/wcd-mbhc-v2-api.h
index fab2b49..7b6e945 100644
--- a/sound/soc/codecs/wcd-mbhc-v2-api.h
+++ b/sound/soc/codecs/wcd-mbhc-v2-api.h
@@ -14,7 +14,7 @@
 
 #include "wcd-mbhc-v2.h"
 
-#ifdef CONFIG_SND_SOC_WCD_MBHC
+#if IS_ENABLED(CONFIG_SND_SOC_WCD_MBHC)
 int wcd_mbhc_start(struct wcd_mbhc *mbhc,
 		       struct wcd_mbhc_config *mbhc_cfg);
 void wcd_mbhc_stop(struct wcd_mbhc *mbhc);
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index ebcb413..cb96f2b 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -1292,7 +1292,7 @@
 	wcd_program_btn_threshold(mbhc, false);
 
 
-	init_completion(&mbhc->btn_press_compl);
+	reinit_completion(&mbhc->btn_press_compl);
 
 	WCD_MBHC_RSC_UNLOCK(mbhc);
 	pr_debug("%s: leave\n", __func__);
@@ -1905,6 +1905,7 @@
 	}
 	mutex_init(&mbhc->hphl_pa_lock);
 	mutex_init(&mbhc->hphr_pa_lock);
+	init_completion(&mbhc->btn_press_compl);
 
 	/* Register event notifier */
 	mbhc->nblock.notifier_call = wcd_event_notify;
@@ -2057,6 +2058,9 @@
 	mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_right_ocp, mbhc);
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->register_notifier)
 		mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false);
+	if (mbhc->mbhc_fn->wcd_cancel_hs_detect_plug)
+		mbhc->mbhc_fn->wcd_cancel_hs_detect_plug(mbhc,
+					&mbhc->correct_plug_swch);
 	mutex_destroy(&mbhc->codec_resource_lock);
 	mutex_destroy(&mbhc->hphl_pa_lock);
 	mutex_destroy(&mbhc->hphr_pa_lock);
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index 7e217a6..957d642 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -82,8 +82,15 @@
 #define WCD_SPI_WORD_BYTE_CNT (4)
 #define WCD_SPI_RW_MULTI_MIN_LEN (16)
 
-/* Max size is closest multiple of 16 less than 64Kbytes */
-#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 16)
+/* Max size is 32 bytes less than 64Kbytes */
+#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 32)
+
+/*
+ * Max size for the pre-allocated buffers is the max
+ * possible read/write length + 32 bytes for the SPI
+ * read/write command header itself.
+ */
+#define WCD_SPI_RW_MAX_BUF_SIZE (WCD_SPI_RW_MULTI_MAX_LEN + 32)
 
 /* Alignment requirements */
 #define WCD_SPI_RW_MIN_ALIGN    WCD_SPI_WORD_BYTE_CNT
@@ -149,6 +156,10 @@
 
 	/* Completion object to indicate system resume completion */
 	struct completion resume_comp;
+
+	/* Buffers to hold memory used for transfers */
+	void *tx_buf;
+	void *rx_buf;
 };
 
 enum xfer_request {
@@ -230,17 +241,18 @@
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
 	struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0];
 	struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1];
-	u8 *tx_buf;
+	u8 *tx_buf = wcd_spi->tx_buf;
 	u32 frame = 0;
 	int ret;
 
 	dev_dbg(&spi->dev, "%s: remote_addr = 0x%x\n",
 		__func__, remote_addr);
 
-	tx_buf = kzalloc(WCD_SPI_READ_SINGLE_LEN,
-			 GFP_KERNEL | GFP_DMA);
-	if (!tx_buf)
+	if (!tx_buf) {
+		dev_err(&spi->dev, "%s: tx_buf not allocated\n",
+			__func__);
 		return -ENOMEM;
+	}
 
 	frame |= WCD_SPI_READ_FRAME_OPCODE;
 	frame |= remote_addr & WCD_CMD_ADDR_MASK;
@@ -256,7 +268,6 @@
 	rx_xfer->len = sizeof(*val);
 
 	ret = spi_sync(spi, &wcd_spi->msg2);
-	kfree(tx_buf);
 
 	return ret;
 }
@@ -267,8 +278,8 @@
 {
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
 	struct spi_transfer *xfer = &wcd_spi->xfer1;
-	u8 *tx_buf;
-	u8 *rx_buf;
+	u8 *tx_buf = wcd_spi->tx_buf;
+	u8 *rx_buf = wcd_spi->rx_buf;
 	u32 frame = 0;
 	int ret;
 
@@ -278,15 +289,9 @@
 	frame |= WCD_SPI_FREAD_FRAME_OPCODE;
 	frame |= remote_addr & WCD_CMD_ADDR_MASK;
 
-	tx_buf = kzalloc(WCD_SPI_CMD_FREAD_LEN + len,
-			 GFP_KERNEL | GFP_DMA);
-	if (!tx_buf)
-		return -ENOMEM;
-
-	rx_buf = kzalloc(WCD_SPI_CMD_FREAD_LEN + len,
-			 GFP_KERNEL | GFP_DMA);
-	if (!rx_buf) {
-		kfree(tx_buf);
+	if (!tx_buf || !rx_buf) {
+		dev_err(&spi->dev, "%s: %s not allocated\n", __func__,
+			(!tx_buf) ? "tx_buf" : "rx_buf");
 		return -ENOMEM;
 	}
 
@@ -306,8 +311,6 @@
 
 	memcpy(data, rx_buf + WCD_SPI_CMD_FREAD_LEN, len);
 done:
-	kfree(tx_buf);
-	kfree(rx_buf);
 	return ret;
 }
 
@@ -344,7 +347,7 @@
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
 	struct spi_transfer *xfer = &wcd_spi->xfer1;
 	u32 frame = 0;
-	u8 *tx_buf;
+	u8 *tx_buf = wcd_spi->tx_buf;
 	int xfer_len, ret;
 
 	dev_dbg(&spi->dev, "%s: addr = 0x%x len = %zd\n",
@@ -356,9 +359,11 @@
 	frame = cpu_to_be32(frame);
 	xfer_len = len + sizeof(frame);
 
-	tx_buf = kzalloc(xfer_len, GFP_KERNEL);
-	if (!tx_buf)
+	if (!tx_buf) {
+		dev_err(&spi->dev, "%s: tx_buf not allocated\n",
+			__func__);
 		return -ENOMEM;
+	}
 
 	memcpy(tx_buf, &frame, sizeof(frame));
 	memcpy(tx_buf + sizeof(frame), data, len);
@@ -372,8 +377,6 @@
 		dev_err(&spi->dev,
 			"%s: Failed, addr = 0x%x, len = %zd\n",
 			__func__, remote_addr, len);
-	kfree(tx_buf);
-
 	return ret;
 }
 
@@ -834,7 +837,7 @@
  * about the write are encapsulated in @msg. Write size should be multiple
  * of 4 bytes and write address should be 4-byte aligned.
  */
-int wcd_spi_data_write(struct spi_device *spi,
+static int wcd_spi_data_write(struct spi_device *spi,
 		       struct wcd_spi_msg *msg)
 {
 	if (!spi || !msg) {
@@ -847,7 +850,6 @@
 			    __func__, msg->remote_addr, msg->len);
 	return wcd_spi_data_xfer(spi, msg, WCD_SPI_XFER_WRITE);
 }
-EXPORT_SYMBOL(wcd_spi_data_write);
 
 /*
  * wcd_spi_data_read: Read data from WCD SPI
@@ -858,7 +860,7 @@
  * about the read are encapsulated in @msg. Read size should be multiple
  * of 4 bytes and read address should be 4-byte aligned.
  */
-int wcd_spi_data_read(struct spi_device *spi,
+static int wcd_spi_data_read(struct spi_device *spi,
 		      struct wcd_spi_msg *msg)
 {
 	if (!spi || !msg) {
@@ -871,7 +873,6 @@
 			    __func__, msg->remote_addr, msg->len);
 	return wcd_spi_data_xfer(spi, msg, WCD_SPI_XFER_READ);
 }
-EXPORT_SYMBOL(wcd_spi_data_read);
 
 static int wdsp_spi_dload_section(struct spi_device *spi,
 				  void *data)
@@ -922,6 +923,7 @@
 {
 	struct spi_device *spi = to_spi_device(dev);
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct wcd_spi_ops *spi_ops;
 	int ret = 0;
 
 	dev_dbg(&spi->dev, "%s: event type %d\n",
@@ -976,6 +978,20 @@
 		ret = wcd_spi_wait_for_resume(wcd_spi);
 		break;
 
+	case WDSP_EVENT_GET_DEVOPS:
+		if (!data) {
+			dev_err(&spi->dev, "%s: invalid data\n",
+				__func__);
+			ret = -EINVAL;
+			break;
+		}
+
+		spi_ops = (struct wcd_spi_ops *) data;
+		spi_ops->spi_dev = spi;
+		spi_ops->read_dev = wcd_spi_data_read;
+		spi_ops->write_dev = wcd_spi_data_write;
+		break;
+
 	default:
 		dev_dbg(&spi->dev, "%s: Unhandled event %d\n",
 			__func__, event);
@@ -1331,6 +1347,23 @@
 	spi_message_init(&wcd_spi->msg2);
 	spi_message_add_tail(&wcd_spi->xfer2[0], &wcd_spi->msg2);
 	spi_message_add_tail(&wcd_spi->xfer2[1], &wcd_spi->msg2);
+
+	/* Pre-allocate the buffers */
+	wcd_spi->tx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
+				  GFP_KERNEL | GFP_DMA);
+	if (!wcd_spi->tx_buf) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	wcd_spi->rx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
+				  GFP_KERNEL | GFP_DMA);
+	if (!wcd_spi->rx_buf) {
+		kfree(wcd_spi->tx_buf);
+		wcd_spi->tx_buf = NULL;
+		ret = -ENOMEM;
+		goto done;
+	}
 done:
 	return ret;
 }
@@ -1348,6 +1381,11 @@
 	spi_transfer_del(&wcd_spi->xfer1);
 	spi_transfer_del(&wcd_spi->xfer2[0]);
 	spi_transfer_del(&wcd_spi->xfer2[1]);
+
+	kfree(wcd_spi->tx_buf);
+	kfree(wcd_spi->rx_buf);
+	wcd_spi->tx_buf = NULL;
+	wcd_spi->rx_buf = NULL;
 }
 
 static const struct component_ops wcd_spi_component_ops = {
diff --git a/sound/soc/codecs/wcd9330-tables.c b/sound/soc/codecs/wcd9330-tables.c
deleted file mode 100644
index 1866fb3..0000000
--- a/sound/soc/codecs/wcd9330-tables.c
+++ /dev/null
@@ -1,1675 +0,0 @@
-/* Copyright (c) 2014, 2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mfd/wcd9xxx/wcd9330_registers.h>
-#include "wcd9330.h"
-
-const u8 tomtom_reg_readable[WCD9330_MAX_REGISTER + 1] = {
-	[TOMTOM_A_CHIP_CTL] = 1,
-	[TOMTOM_A_CHIP_STATUS] = 1,
-	[TOMTOM_A_CHIP_ID_BYTE_0] = 1,
-	[TOMTOM_A_CHIP_ID_BYTE_1] = 1,
-	[TOMTOM_A_CHIP_ID_BYTE_2] = 1,
-	[TOMTOM_A_CHIP_ID_BYTE_3] = 1,
-	[TOMTOM_A_CHIP_I2C_SLAVE_ID] = 1,
-	[TOMTOM_A_SLAVE_ID_1] = 1,
-	[TOMTOM_A_SLAVE_ID_2] = 1,
-	[TOMTOM_A_SLAVE_ID_3] = 1,
-	[TOMTOM_A_PIN_CTL_OE0] = 1,
-	[TOMTOM_A_PIN_CTL_OE1] = 1,
-	[TOMTOM_A_PIN_CTL_OE2] = 1,
-	[TOMTOM_A_PIN_CTL_DATA0] = 1,
-	[TOMTOM_A_PIN_CTL_DATA1] = 1,
-	[TOMTOM_A_PIN_CTL_DATA2] = 1,
-	[TOMTOM_A_HDRIVE_GENERIC] = 1,
-	[TOMTOM_A_HDRIVE_OVERRIDE] = 1,
-	[TOMTOM_A_ANA_CSR_WAIT_STATE] = 1,
-	[TOMTOM_A_PROCESS_MONITOR_CTL0] = 1,
-	[TOMTOM_A_PROCESS_MONITOR_CTL1] = 1,
-	[TOMTOM_A_PROCESS_MONITOR_CTL2] = 1,
-	[TOMTOM_A_PROCESS_MONITOR_CTL3] = 1,
-	[TOMTOM_A_QFUSE_CTL] = 1,
-	[TOMTOM_A_QFUSE_STATUS] = 1,
-	[TOMTOM_A_QFUSE_DATA_OUT0] = 1,
-	[TOMTOM_A_QFUSE_DATA_OUT1] = 1,
-	[TOMTOM_A_QFUSE_DATA_OUT2] = 1,
-	[TOMTOM_A_QFUSE_DATA_OUT3] = 1,
-	[TOMTOM_A_QFUSE_DATA_OUT4] = 1,
-	[TOMTOM_A_QFUSE_DATA_OUT5] = 1,
-	[TOMTOM_A_QFUSE_DATA_OUT6] = 1,
-	[TOMTOM_A_QFUSE_DATA_OUT7] = 1,
-	[TOMTOM_A_CDC_CTL] = 1,
-	[TOMTOM_A_LEAKAGE_CTL] = 1,
-	[TOMTOM_A_SVASS_MEM_PTR0] = 1,
-	[TOMTOM_A_SVASS_MEM_PTR1] = 1,
-	[TOMTOM_A_SVASS_MEM_PTR2] = 1,
-	[TOMTOM_A_SVASS_MEM_CTL] = 1,
-	[TOMTOM_A_SVASS_MEM_BANK] = 1,
-	[TOMTOM_A_DMIC_B1_CTL] = 1,
-	[TOMTOM_A_DMIC_B2_CTL] = 1,
-	[TOMTOM_A_SVASS_CLKRST_CTL] = 1,
-	[TOMTOM_A_SVASS_CPAR_CFG] = 1,
-	[TOMTOM_A_SVASS_BUF_RDY_INT_PERIOD] = 1,
-	[TOMTOM_A_SVASS_CPAR_WDOG_CFG] = 1,
-	[TOMTOM_A_SVASS_CFG] = 1,
-	[TOMTOM_A_SVASS_SPE_CFG] = 1,
-	[TOMTOM_A_SVASS_STATUS] = 1,
-	[TOMTOM_A_SVASS_INT_MASK] = 1,
-	[TOMTOM_A_SVASS_INT_STATUS] = 1,
-	[TOMTOM_A_SVASS_INT_CLR] = 0,
-	[TOMTOM_A_SVASS_DEBUG] = 1,
-	[TOMTOM_A_SVASS_SPE_BKUP_INT] = 0,
-	[TOMTOM_A_SVASS_MEM_ACC] = 1,
-	[TOMTOM_A_MEM_LEAKAGE_CTL] = 1,
-	[TOMTOM_A_SVASS_SPE_INBOX_TRG] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_0] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_1] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_2] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_3] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_4] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_5] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_6] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_7] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_8] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_9] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_10] = 0,
-	[TOMTOM_A_SVASS_SPE_INBOX_11] = 0,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_0] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_1] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_2] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_3] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_4] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_5] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_6] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_7] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_8] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_9] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_10] = 1,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_11] = 1,
-	[TOMTOM_A_INTR_MODE] = 1,
-	[TOMTOM_A_INTR1_MASK0] = 1,
-	[TOMTOM_A_INTR1_MASK1] = 1,
-	[TOMTOM_A_INTR1_MASK2] = 1,
-	[TOMTOM_A_INTR1_MASK3] = 1,
-	[TOMTOM_A_INTR1_STATUS0] = 1,
-	[TOMTOM_A_INTR1_STATUS1] = 1,
-	[TOMTOM_A_INTR1_STATUS2] = 1,
-	[TOMTOM_A_INTR1_STATUS3] = 1,
-	[TOMTOM_A_INTR1_CLEAR0] = 0,
-	[TOMTOM_A_INTR1_CLEAR1] = 0,
-	[TOMTOM_A_INTR1_CLEAR2] = 0,
-	[TOMTOM_A_INTR1_CLEAR3] = 0,
-	[TOMTOM_A_INTR1_LEVEL0] = 1,
-	[TOMTOM_A_INTR1_LEVEL1] = 1,
-	[TOMTOM_A_INTR1_LEVEL2] = 1,
-	[TOMTOM_A_INTR1_LEVEL3] = 1,
-	[TOMTOM_A_INTR1_TEST0] = 1,
-	[TOMTOM_A_INTR1_TEST1] = 1,
-	[TOMTOM_A_INTR1_TEST2] = 1,
-	[TOMTOM_A_INTR1_TEST3] = 1,
-	[TOMTOM_A_INTR1_SET0] = 1,
-	[TOMTOM_A_INTR1_SET1] = 1,
-	[TOMTOM_A_INTR1_SET2] = 1,
-	[TOMTOM_A_INTR1_SET3] = 1,
-	[TOMTOM_A_INTR2_MASK0] = 1,
-	[TOMTOM_A_INTR2_STATUS0] = 1,
-	[TOMTOM_A_INTR2_CLEAR0] = 0,
-	[TOMTOM_A_INTR2_LEVEL0] = 1,
-	[TOMTOM_A_INTR2_TEST0] = 1,
-	[TOMTOM_A_INTR2_SET0] = 1,
-	[TOMTOM_A_CDC_TX_I2S_SCK_MODE] = 1,
-	[TOMTOM_A_CDC_TX_I2S_WS_MODE] = 1,
-	[TOMTOM_A_CDC_DMIC_DATA0_MODE] = 1,
-	[TOMTOM_A_CDC_DMIC_CLK0_MODE] = 1,
-	[TOMTOM_A_CDC_DMIC_DATA1_MODE] = 1,
-	[TOMTOM_A_CDC_DMIC_CLK1_MODE] = 1,
-	[TOMTOM_A_CDC_RX_I2S_SCK_MODE] = 1,
-	[TOMTOM_A_CDC_RX_I2S_WS_MODE] = 1,
-	[TOMTOM_A_CDC_DMIC_DATA2_MODE] = 1,
-	[TOMTOM_A_CDC_DMIC_CLK2_MODE] = 1,
-	[TOMTOM_A_CDC_INTR1_MODE] = 1,
-	[TOMTOM_A_CDC_SB_NRZ_SEL_MODE] = 1,
-	[TOMTOM_A_CDC_INTR2_MODE] = 1,
-	[TOMTOM_A_CDC_RF_PA_ON_MODE] = 1,
-	[TOMTOM_A_CDC_BOOST_MODE] = 1,
-	[TOMTOM_A_CDC_JTCK_MODE] = 1,
-	[TOMTOM_A_CDC_JTDI_MODE] = 1,
-	[TOMTOM_A_CDC_JTMS_MODE] = 1,
-	[TOMTOM_A_CDC_JTDO_MODE] = 1,
-	[TOMTOM_A_CDC_JTRST_MODE] = 1,
-	[TOMTOM_A_CDC_BIST_MODE_MODE] = 1,
-	[TOMTOM_A_CDC_MAD_MAIN_CTL_1] = 1,
-	[TOMTOM_A_CDC_MAD_MAIN_CTL_2] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_1] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_2] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_3] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_4] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_5] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_6] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_7] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_8] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_PTR] = 1,
-	[TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_VAL] = 1,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_1] = 1,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_2] = 1,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_3] = 1,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_4] = 1,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_5] = 1,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_6] = 1,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_7] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_1] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_2] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_3] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_4] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_5] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_6] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_7] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_8] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_PTR] = 1,
-	[TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_VAL] = 1,
-	[TOMTOM_A_CDC_MAD_INP_SEL] = 1,
-	[TOMTOM_A_BIAS_REF_CTL] = 1,
-	[TOMTOM_A_BIAS_CENTRAL_BG_CTL] = 1,
-	[TOMTOM_A_BIAS_PRECHRG_CTL] = 1,
-	[TOMTOM_A_BIAS_CURR_CTL_1] = 1,
-	[TOMTOM_A_BIAS_CURR_CTL_2] = 1,
-	[TOMTOM_A_BIAS_OSC_BG_CTL] = 1,
-	[TOMTOM_A_CLK_BUFF_EN1] = 1,
-	[TOMTOM_A_CLK_BUFF_EN2] = 1,
-	[TOMTOM_A_LDO_L_MODE_1] = 1,
-	[TOMTOM_A_LDO_L_MODE_2] = 1,
-	[TOMTOM_A_LDO_L_CTRL_1] = 1,
-	[TOMTOM_A_LDO_L_CTRL_2] = 1,
-	[TOMTOM_A_LDO_L_CTRL_3] = 1,
-	[TOMTOM_A_LDO_L_CTRL_4] = 1,
-	[TOMTOM_A_LDO_H_MODE_1] = 1,
-	[TOMTOM_A_LDO_H_MODE_2] = 1,
-	[TOMTOM_A_LDO_H_LOOP_CTL] = 1,
-	[TOMTOM_A_LDO_H_COMP_1] = 1,
-	[TOMTOM_A_LDO_H_COMP_2] = 1,
-	[TOMTOM_A_LDO_H_BIAS_1] = 1,
-	[TOMTOM_A_LDO_H_BIAS_2] = 1,
-	[TOMTOM_A_LDO_H_BIAS_3] = 1,
-	[TOMTOM_A_VBAT_CLK] = 1,
-	[TOMTOM_A_VBAT_LOOP] = 1,
-	[TOMTOM_A_VBAT_REF] = 1,
-	[TOMTOM_A_VBAT_ADC_TEST] = 1,
-	[TOMTOM_A_VBAT_FE] = 1,
-	[TOMTOM_A_VBAT_BIAS_1] = 1,
-	[TOMTOM_A_VBAT_BIAS_2] = 1,
-	[TOMTOM_A_VBAT_ADC_DATA_MSB] = 1,
-	[TOMTOM_A_VBAT_ADC_DATA_LSB] = 1,
-	[TOMTOM_A_FLL_NREF] = 1,
-	[TOMTOM_A_FLL_KDCO_TUNE] = 1,
-	[TOMTOM_A_FLL_LOCK_THRESH] = 1,
-	[TOMTOM_A_FLL_LOCK_DET_COUNT] = 1,
-	[TOMTOM_A_FLL_DAC_THRESHOLD] = 1,
-	[TOMTOM_A_FLL_TEST_DCO_FREERUN] = 1,
-	[TOMTOM_A_FLL_TEST_ENABLE] = 1,
-	[TOMTOM_A_MICB_CFILT_1_CTL] = 1,
-	[TOMTOM_A_MICB_CFILT_1_VAL] = 1,
-	[TOMTOM_A_MICB_CFILT_1_PRECHRG] = 1,
-	[TOMTOM_A_MICB_1_CTL] = 1,
-	[TOMTOM_A_MICB_1_INT_RBIAS] = 1,
-	[TOMTOM_A_MICB_1_MBHC] = 1,
-	[TOMTOM_A_MICB_CFILT_2_CTL] = 1,
-	[TOMTOM_A_MICB_CFILT_2_VAL] = 1,
-	[TOMTOM_A_MICB_CFILT_2_PRECHRG] = 1,
-	[TOMTOM_A_MICB_2_CTL] = 1,
-	[TOMTOM_A_MICB_2_INT_RBIAS] = 1,
-	[TOMTOM_A_MICB_2_MBHC] = 1,
-	[TOMTOM_A_MICB_CFILT_3_CTL] = 1,
-	[TOMTOM_A_MICB_CFILT_3_VAL] = 1,
-	[TOMTOM_A_MICB_CFILT_3_PRECHRG] = 1,
-	[TOMTOM_A_MICB_3_CTL] = 1,
-	[TOMTOM_A_MICB_3_INT_RBIAS] = 1,
-	[TOMTOM_A_MICB_3_MBHC] = 1,
-	[TOMTOM_A_MICB_4_CTL] = 1,
-	[TOMTOM_A_MICB_4_INT_RBIAS] = 1,
-	[TOMTOM_A_MICB_4_MBHC] = 1,
-	[TOMTOM_A_SPKR_DRV2_EN] = 1,
-	[TOMTOM_A_SPKR_DRV2_GAIN] = 1,
-	[TOMTOM_A_SPKR_DRV2_DAC_CTL] = 1,
-	[TOMTOM_A_SPKR_DRV2_OCP_CTL] = 1,
-	[TOMTOM_A_SPKR_DRV2_CLIP_DET] = 1,
-	[TOMTOM_A_SPKR_DRV2_DBG_DAC] = 1,
-	[TOMTOM_A_SPKR_DRV2_DBG_PA] = 1,
-	[TOMTOM_A_SPKR_DRV2_DBG_PWRSTG] = 1,
-	[TOMTOM_A_SPKR_DRV2_BIAS_LDO] = 1,
-	[TOMTOM_A_SPKR_DRV2_BIAS_INT] = 1,
-	[TOMTOM_A_SPKR_DRV2_BIAS_PA] = 1,
-	[TOMTOM_A_SPKR_DRV2_STATUS_OCP] = 1,
-	[TOMTOM_A_SPKR_DRV2_STATUS_PA] = 1,
-	[TOMTOM_A_MBHC_INSERT_DETECT] = 1,
-	[TOMTOM_A_MBHC_INSERT_DET_STATUS] = 1,
-	[TOMTOM_A_TX_COM_BIAS] = 1,
-	[TOMTOM_A_MBHC_INSERT_DETECT2] = 1,
-	[TOMTOM_A_MBHC_SCALING_MUX_1] = 1,
-	[TOMTOM_A_MBHC_SCALING_MUX_2] = 1,
-	[TOMTOM_A_MAD_ANA_CTRL] = 1,
-	[TOMTOM_A_TX_SUP_SWITCH_CTRL_1] = 1,
-	[TOMTOM_A_TX_SUP_SWITCH_CTRL_2] = 1,
-	[TOMTOM_A_TX_1_GAIN] = 1,
-	[TOMTOM_A_TX_1_2_TEST_EN] = 1,
-	[TOMTOM_A_TX_2_GAIN] = 1,
-	[TOMTOM_A_TX_1_2_ADC_IB] = 1,
-	[TOMTOM_A_TX_1_2_ATEST_REFCTRL] = 1,
-	[TOMTOM_A_TX_1_2_TEST_CTL] = 1,
-	[TOMTOM_A_TX_1_2_TEST_BLOCK_EN] = 1,
-	[TOMTOM_A_TX_1_2_TXFE_CLKDIV] = 1,
-	[TOMTOM_A_TX_1_2_SAR_ERR_CH1] = 1,
-	[TOMTOM_A_TX_1_2_SAR_ERR_CH2] = 1,
-	[TOMTOM_A_TX_3_GAIN] = 1,
-	[TOMTOM_A_TX_3_4_TEST_EN] = 1,
-	[TOMTOM_A_TX_4_GAIN] = 1,
-	[TOMTOM_A_TX_3_4_ADC_IB] = 1,
-	[TOMTOM_A_TX_3_4_ATEST_REFCTRL] = 1,
-	[TOMTOM_A_TX_3_4_TEST_CTL] = 1,
-	[TOMTOM_A_TX_3_4_TEST_BLOCK_EN] = 1,
-	[TOMTOM_A_TX_3_4_TXFE_CKDIV] = 1,
-	[TOMTOM_A_TX_3_4_SAR_ERR_CH3] = 1,
-	[TOMTOM_A_TX_3_4_SAR_ERR_CH4] = 1,
-	[TOMTOM_A_TX_5_GAIN] = 1,
-	[TOMTOM_A_TX_5_6_TEST_EN] = 1,
-	[TOMTOM_A_TX_6_GAIN] = 1,
-	[TOMTOM_A_TX_5_6_ADC_IB] = 1,
-	[TOMTOM_A_TX_5_6_ATEST_REFCTRL] = 1,
-	[TOMTOM_A_TX_5_6_TEST_CTL] = 1,
-	[TOMTOM_A_TX_5_6_TEST_BLOCK_EN] = 1,
-	[TOMTOM_A_TX_5_6_TXFE_CKDIV] = 1,
-	[TOMTOM_A_TX_5_6_SAR_ERR_CH5] = 1,
-	[TOMTOM_A_TX_5_6_SAR_ERR_CH6] = 1,
-	[TOMTOM_A_TX_7_MBHC_EN] = 1,
-	[TOMTOM_A_TX_7_MBHC_ATEST_REFCTRL] = 1,
-	[TOMTOM_A_TX_7_MBHC_ADC] = 1,
-	[TOMTOM_A_TX_7_MBHC_TEST_CTL] = 1,
-	[TOMTOM_A_TX_7_MBHC_SAR_ERR] = 1,
-	[TOMTOM_A_TX_7_TXFE_CLKDIV] = 1,
-	[TOMTOM_A_RCO_CTRL] = 1,
-	[TOMTOM_A_RCO_CALIBRATION_CTRL1] = 1,
-	[TOMTOM_A_RCO_CALIBRATION_CTRL2] = 1,
-	[TOMTOM_A_RCO_CALIBRATION_CTRL3] = 1,
-	[TOMTOM_A_RCO_TEST_CTRL] = 1,
-	[TOMTOM_A_RCO_CALIBRATION_RESULT1] = 1,
-	[TOMTOM_A_RCO_CALIBRATION_RESULT2] = 1,
-	[TOMTOM_A_BUCK_MODE_1] = 1,
-	[TOMTOM_A_BUCK_MODE_2] = 1,
-	[TOMTOM_A_BUCK_MODE_3] = 1,
-	[TOMTOM_A_BUCK_MODE_4] = 1,
-	[TOMTOM_A_BUCK_MODE_5] = 1,
-	[TOMTOM_A_BUCK_CTRL_VCL_1] = 1,
-	[TOMTOM_A_BUCK_CTRL_VCL_2] = 1,
-	[TOMTOM_A_BUCK_CTRL_VCL_3] = 1,
-	[TOMTOM_A_BUCK_CTRL_CCL_1] = 1,
-	[TOMTOM_A_BUCK_CTRL_CCL_2] = 1,
-	[TOMTOM_A_BUCK_CTRL_CCL_3] = 1,
-	[TOMTOM_A_BUCK_CTRL_CCL_4] = 1,
-	[TOMTOM_A_BUCK_CTRL_PWM_DRVR_1] = 1,
-	[TOMTOM_A_BUCK_CTRL_PWM_DRVR_2] = 1,
-	[TOMTOM_A_BUCK_CTRL_PWM_DRVR_3] = 1,
-	[TOMTOM_A_BUCK_TMUX_A_D] = 1,
-	[TOMTOM_A_NCP_BUCKREF] = 1,
-	[TOMTOM_A_NCP_EN] = 1,
-	[TOMTOM_A_NCP_CLK] = 1,
-	[TOMTOM_A_NCP_STATIC] = 1,
-	[TOMTOM_A_NCP_VTH_LOW] = 1,
-	[TOMTOM_A_NCP_VTH_HIGH] = 1,
-	[TOMTOM_A_NCP_ATEST] = 1,
-	[TOMTOM_A_NCP_DTEST] = 1,
-	[TOMTOM_A_NCP_DLY1] = 1,
-	[TOMTOM_A_NCP_DLY2] = 1,
-	[TOMTOM_A_RX_AUX_SW_CTL] = 1,
-	[TOMTOM_A_RX_PA_AUX_IN_CONN] = 1,
-	[TOMTOM_A_RX_COM_TIMER_DIV] = 1,
-	[TOMTOM_A_RX_COM_OCP_CTL] = 1,
-	[TOMTOM_A_RX_COM_OCP_COUNT] = 1,
-	[TOMTOM_A_RX_COM_DAC_CTL] = 1,
-	[TOMTOM_A_RX_COM_BIAS] = 1,
-	[TOMTOM_A_RX_HPH_AUTO_CHOP] = 1,
-	[TOMTOM_A_RX_HPH_CHOP_CTL] = 1,
-	[TOMTOM_A_RX_HPH_BIAS_PA] = 1,
-	[TOMTOM_A_RX_HPH_BIAS_LDO] = 1,
-	[TOMTOM_A_RX_HPH_BIAS_CNP] = 1,
-	[TOMTOM_A_RX_HPH_BIAS_WG_OCP] = 1,
-	[TOMTOM_A_RX_HPH_OCP_CTL] = 1,
-	[TOMTOM_A_RX_HPH_CNP_EN] = 1,
-	[TOMTOM_A_RX_HPH_CNP_WG_CTL] = 1,
-	[TOMTOM_A_RX_HPH_CNP_WG_TIME] = 1,
-	[TOMTOM_A_RX_HPH_L_GAIN] = 1,
-	[TOMTOM_A_RX_HPH_L_TEST] = 1,
-	[TOMTOM_A_RX_HPH_L_PA_CTL] = 1,
-	[TOMTOM_A_RX_HPH_L_DAC_CTL] = 1,
-	[TOMTOM_A_RX_HPH_L_ATEST] = 1,
-	[TOMTOM_A_RX_HPH_L_STATUS] = 1,
-	[TOMTOM_A_RX_HPH_R_GAIN] = 1,
-	[TOMTOM_A_RX_HPH_R_TEST] = 1,
-	[TOMTOM_A_RX_HPH_R_PA_CTL] = 1,
-	[TOMTOM_A_RX_HPH_R_DAC_CTL] = 1,
-	[TOMTOM_A_RX_HPH_R_ATEST] = 1,
-	[TOMTOM_A_RX_HPH_R_STATUS] = 1,
-	[TOMTOM_A_RX_EAR_BIAS_PA] = 1,
-	[TOMTOM_A_RX_EAR_BIAS_CMBUFF] = 1,
-	[TOMTOM_A_RX_EAR_EN] = 1,
-	[TOMTOM_A_RX_EAR_GAIN] = 1,
-	[TOMTOM_A_RX_EAR_CMBUFF] = 1,
-	[TOMTOM_A_RX_EAR_ICTL] = 1,
-	[TOMTOM_A_RX_EAR_CCOMP] = 1,
-	[TOMTOM_A_RX_EAR_VCM] = 1,
-	[TOMTOM_A_RX_EAR_CNP] = 1,
-	[TOMTOM_A_RX_EAR_DAC_CTL_ATEST] = 1,
-	[TOMTOM_A_RX_EAR_STATUS] = 1,
-	[TOMTOM_A_RX_LINE_BIAS_PA] = 1,
-	[TOMTOM_A_RX_BUCK_BIAS1] = 1,
-	[TOMTOM_A_RX_BUCK_BIAS2] = 1,
-	[TOMTOM_A_RX_LINE_COM] = 1,
-	[TOMTOM_A_RX_LINE_CNP_EN] = 1,
-	[TOMTOM_A_RX_LINE_CNP_WG_CTL] = 1,
-	[TOMTOM_A_RX_LINE_CNP_WG_TIME] = 1,
-	[TOMTOM_A_RX_LINE_1_GAIN] = 1,
-	[TOMTOM_A_RX_LINE_1_TEST] = 1,
-	[TOMTOM_A_RX_LINE_1_DAC_CTL] = 1,
-	[TOMTOM_A_RX_LINE_1_STATUS] = 1,
-	[TOMTOM_A_RX_LINE_2_GAIN] = 1,
-	[TOMTOM_A_RX_LINE_2_TEST] = 1,
-	[TOMTOM_A_RX_LINE_2_DAC_CTL] = 1,
-	[TOMTOM_A_RX_LINE_2_STATUS] = 1,
-	[TOMTOM_A_RX_LINE_3_GAIN] = 1,
-	[TOMTOM_A_RX_LINE_3_TEST] = 1,
-	[TOMTOM_A_RX_LINE_3_DAC_CTL] = 1,
-	[TOMTOM_A_RX_LINE_3_STATUS] = 1,
-	[TOMTOM_A_RX_LINE_4_GAIN] = 1,
-	[TOMTOM_A_RX_LINE_4_TEST] = 1,
-	[TOMTOM_A_RX_LINE_4_DAC_CTL] = 1,
-	[TOMTOM_A_RX_LINE_4_STATUS] = 1,
-	[TOMTOM_A_RX_LINE_CNP_DBG] = 1,
-	[TOMTOM_A_SPKR_DRV1_EN] = 1,
-	[TOMTOM_A_SPKR_DRV1_GAIN] = 1,
-	[TOMTOM_A_SPKR_DRV1_DAC_CTL] = 1,
-	[TOMTOM_A_SPKR_DRV1_OCP_CTL] = 1,
-	[TOMTOM_A_SPKR_DRV1_CLIP_DET] = 1,
-	[TOMTOM_A_SPKR_DRV1_IEC] = 1,
-	[TOMTOM_A_SPKR_DRV1_DBG_DAC] = 1,
-	[TOMTOM_A_SPKR_DRV1_DBG_PA] = 1,
-	[TOMTOM_A_SPKR_DRV1_DBG_PWRSTG] = 1,
-	[TOMTOM_A_SPKR_DRV1_BIAS_LDO] = 1,
-	[TOMTOM_A_SPKR_DRV1_BIAS_INT] = 1,
-	[TOMTOM_A_SPKR_DRV1_BIAS_PA] = 1,
-	[TOMTOM_A_SPKR_DRV1_STATUS_OCP] = 1,
-	[TOMTOM_A_SPKR_DRV1_STATUS_PA] = 1,
-	[TOMTOM_A_SPKR1_PROT_EN] = 1,
-	[TOMTOM_A_SPKR1_PROT_ADC_TEST_EN] = 1,
-	[TOMTOM_A_SPKR1_PROT_ATEST] = 1,
-	[TOMTOM_A_SPKR1_PROT_LDO_CTRL] = 1,
-	[TOMTOM_A_SPKR1_PROT_ISENSE_CTRL] = 1,
-	[TOMTOM_A_SPKR1_PROT_VSENSE_CTRL] = 1,
-	[TOMTOM_A_SPKR2_PROT_EN] = 1,
-	[TOMTOM_A_SPKR2_PROT_ADC_TEST_EN] = 1,
-	[TOMTOM_A_SPKR2_PROT_ATEST] = 1,
-	[TOMTOM_A_SPKR2_PROT_LDO_CTRL] = 1,
-	[TOMTOM_A_SPKR2_PROT_ISENSE_CTRL] = 1,
-	[TOMTOM_A_SPKR2_PROT_VSENSE_CTRL] = 1,
-	[TOMTOM_A_MBHC_HPH] = 1,
-	[TOMTOM_A_CDC_ANC1_B1_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_B1_CTL] = 1,
-	[TOMTOM_A_CDC_ANC1_SHIFT] = 1,
-	[TOMTOM_A_CDC_ANC2_SHIFT] = 1,
-	[TOMTOM_A_CDC_ANC1_IIR_B1_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_IIR_B1_CTL] = 1,
-	[TOMTOM_A_CDC_ANC1_IIR_B2_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_IIR_B2_CTL] = 1,
-	[TOMTOM_A_CDC_ANC1_IIR_B3_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_IIR_B3_CTL] = 1,
-	[TOMTOM_A_CDC_ANC1_LPF_B1_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_LPF_B1_CTL] = 1,
-	[TOMTOM_A_CDC_ANC1_LPF_B2_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_LPF_B2_CTL] = 1,
-	[TOMTOM_A_CDC_ANC1_SPARE] = 1,
-	[TOMTOM_A_CDC_ANC2_SPARE] = 1,
-	[TOMTOM_A_CDC_ANC1_SMLPF_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_SMLPF_CTL] = 1,
-	[TOMTOM_A_CDC_ANC1_DCFLT_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_DCFLT_CTL] = 1,
-	[TOMTOM_A_CDC_ANC1_GAIN_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_GAIN_CTL] = 1,
-	[TOMTOM_A_CDC_ANC1_B2_CTL] = 1,
-	[TOMTOM_A_CDC_ANC2_B2_CTL] = 1,
-	[TOMTOM_A_CDC_TX1_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX2_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX3_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX4_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX5_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX6_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX7_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX8_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX9_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX10_VOL_CTL_TIMER] = 1,
-	[TOMTOM_A_CDC_TX1_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX2_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX3_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX4_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX5_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX6_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX7_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX8_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX9_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX10_VOL_CTL_GAIN] = 1,
-	[TOMTOM_A_CDC_TX1_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX2_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX3_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX4_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX5_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX6_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX7_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX8_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX9_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX10_VOL_CTL_CFG] = 1,
-	[TOMTOM_A_CDC_TX1_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX2_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX3_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX4_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX5_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX6_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX7_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX8_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX9_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX10_MUX_CTL] = 1,
-	[TOMTOM_A_CDC_TX1_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX2_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX3_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX4_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX5_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX6_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX7_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX8_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX9_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX10_CLK_FS_CTL] = 1,
-	[TOMTOM_A_CDC_TX1_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_TX2_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_TX3_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_TX4_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_TX5_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_TX6_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_TX7_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_TX8_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_TX9_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_TX10_DMIC_CTL] = 1,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL0] = 1,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL1] = 1,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL2] = 1,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL3] = 1,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL4] = 1,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL5] = 1,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL6] = 1,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL7] = 1,
-	[TOMTOM_A_CDC_DEBUG_B1_CTL] = 1,
-	[TOMTOM_A_CDC_DEBUG_B2_CTL] = 1,
-	[TOMTOM_A_CDC_DEBUG_B3_CTL] = 1,
-	[TOMTOM_A_CDC_DEBUG_B4_CTL] = 1,
-	[TOMTOM_A_CDC_DEBUG_B5_CTL] = 1,
-	[TOMTOM_A_CDC_DEBUG_B6_CTL] = 1,
-	[TOMTOM_A_CDC_DEBUG_B7_CTL] = 1,
-	[TOMTOM_A_CDC_SRC1_PDA_CFG] = 1,
-	[TOMTOM_A_CDC_SRC2_PDA_CFG] = 1,
-	[TOMTOM_A_CDC_SRC1_FS_CTL] = 1,
-	[TOMTOM_A_CDC_SRC2_FS_CTL] = 1,
-	[TOMTOM_A_CDC_RX1_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX2_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX3_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX4_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX5_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX6_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX7_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX1_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX2_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX3_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX4_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX5_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX6_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX7_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX1_B3_CTL] = 1,
-	[TOMTOM_A_CDC_RX2_B3_CTL] = 1,
-	[TOMTOM_A_CDC_RX3_B3_CTL] = 1,
-	[TOMTOM_A_CDC_RX4_B3_CTL] = 1,
-	[TOMTOM_A_CDC_RX5_B3_CTL] = 1,
-	[TOMTOM_A_CDC_RX6_B3_CTL] = 1,
-	[TOMTOM_A_CDC_RX7_B3_CTL] = 1,
-	[TOMTOM_A_CDC_RX1_B4_CTL] = 1,
-	[TOMTOM_A_CDC_RX2_B4_CTL] = 1,
-	[TOMTOM_A_CDC_RX3_B4_CTL] = 1,
-	[TOMTOM_A_CDC_RX4_B4_CTL] = 1,
-	[TOMTOM_A_CDC_RX5_B4_CTL] = 1,
-	[TOMTOM_A_CDC_RX6_B4_CTL] = 1,
-	[TOMTOM_A_CDC_RX7_B4_CTL] = 1,
-	[TOMTOM_A_CDC_RX1_B5_CTL] = 1,
-	[TOMTOM_A_CDC_RX2_B5_CTL] = 1,
-	[TOMTOM_A_CDC_RX3_B5_CTL] = 1,
-	[TOMTOM_A_CDC_RX4_B5_CTL] = 1,
-	[TOMTOM_A_CDC_RX5_B5_CTL] = 1,
-	[TOMTOM_A_CDC_RX6_B5_CTL] = 1,
-	[TOMTOM_A_CDC_RX7_B5_CTL] = 1,
-	[TOMTOM_A_CDC_RX1_B6_CTL] = 1,
-	[TOMTOM_A_CDC_RX2_B6_CTL] = 1,
-	[TOMTOM_A_CDC_RX3_B6_CTL] = 1,
-	[TOMTOM_A_CDC_RX4_B6_CTL] = 1,
-	[TOMTOM_A_CDC_RX5_B6_CTL] = 1,
-	[TOMTOM_A_CDC_RX6_B6_CTL] = 1,
-	[TOMTOM_A_CDC_RX7_B6_CTL] = 1,
-	[TOMTOM_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX2_VOL_CTL_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX3_VOL_CTL_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX4_VOL_CTL_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX5_VOL_CTL_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX6_VOL_CTL_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX7_VOL_CTL_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL] = 1,
-	[TOMTOM_A_CDC_VBAT_CFG] = 1,
-	[TOMTOM_A_CDC_VBAT_ADC_CAL1] = 1,
-	[TOMTOM_A_CDC_VBAT_ADC_CAL2] = 1,
-	[TOMTOM_A_CDC_VBAT_ADC_CAL3] = 1,
-	[TOMTOM_A_CDC_VBAT_PK_EST1] = 1,
-	[TOMTOM_A_CDC_VBAT_PK_EST2] = 1,
-	[TOMTOM_A_CDC_VBAT_PK_EST3] = 1,
-	[TOMTOM_A_CDC_VBAT_RF_PROC1] = 1,
-	[TOMTOM_A_CDC_VBAT_RF_PROC2] = 1,
-	[TOMTOM_A_CDC_VBAT_TAC1] = 1,
-	[TOMTOM_A_CDC_VBAT_TAC2] = 1,
-	[TOMTOM_A_CDC_VBAT_TAC3] = 1,
-	[TOMTOM_A_CDC_VBAT_TAC4] = 1,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD1] = 1,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD2] = 1,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD3] = 1,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD4] = 1,
-	[TOMTOM_A_CDC_VBAT_DEBUG1] = 1,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD_MON] = 0,
-	[TOMTOM_A_CDC_VBAT_GAIN_MON_VAL] = 1,
-	[TOMTOM_A_CDC_CLK_ANC_RESET_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_RX_RESET_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_TX_RESET_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_RX_I2S_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_TX_I2S_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_OTHR_RESET_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_OTHR_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_ANC_CLK_EN_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_RX_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_RX_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_MCLK_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_PDM_CTL] = 1,
-	[TOMTOM_A_CDC_CLK_SD_CTL] = 1,
-	[TOMTOM_A_CDC_CLSH_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CLSH_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CLSH_B3_CTL] = 1,
-	[TOMTOM_A_CDC_CLSH_BUCK_NCP_VARS] = 1,
-	[TOMTOM_A_CDC_CLSH_IDLE_HPH_THSD] = 1,
-	[TOMTOM_A_CDC_CLSH_IDLE_EAR_THSD] = 1,
-	[TOMTOM_A_CDC_CLSH_FCLKONLY_HPH_THSD] = 1,
-	[TOMTOM_A_CDC_CLSH_FCLKONLY_EAR_THSD] = 1,
-	[TOMTOM_A_CDC_CLSH_K_ADDR] = 1,
-	[TOMTOM_A_CDC_CLSH_K_DATA] = 1,
-	[TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_L] = 1,
-	[TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_U] = 1,
-	[TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_L] = 1,
-	[TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_U] = 1,
-	[TOMTOM_A_CDC_CLSH_V_PA_HD_EAR] = 1,
-	[TOMTOM_A_CDC_CLSH_V_PA_HD_HPH] = 1,
-	[TOMTOM_A_CDC_CLSH_V_PA_MIN_EAR] = 1,
-	[TOMTOM_A_CDC_CLSH_V_PA_MIN_HPH] = 1,
-	[TOMTOM_A_CDC_IIR1_GAIN_B1_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_GAIN_B1_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_GAIN_B2_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_GAIN_B2_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_GAIN_B3_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_GAIN_B3_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_GAIN_B4_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_GAIN_B4_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_GAIN_B5_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_GAIN_B5_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_GAIN_B6_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_GAIN_B6_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_GAIN_B7_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_GAIN_B7_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_GAIN_B8_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_GAIN_B8_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_GAIN_TIMER_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_GAIN_TIMER_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_COEF_B1_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_COEF_B1_CTL] = 1,
-	[TOMTOM_A_CDC_IIR1_COEF_B2_CTL] = 1,
-	[TOMTOM_A_CDC_IIR2_COEF_B2_CTL] = 1,
-	[TOMTOM_A_CDC_TOP_GAIN_UPDATE] = 1,
-	[TOMTOM_A_CDC_PA_RAMP_B1_CTL] = 1,
-	[TOMTOM_A_CDC_PA_RAMP_B2_CTL] = 1,
-	[TOMTOM_A_CDC_PA_RAMP_B3_CTL] = 1,
-	[TOMTOM_A_CDC_PA_RAMP_B4_CTL] = 1,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_B1_CTL] = 1,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_B1_CTL] = 1,
-	[TOMTOM_A_CDC_COMP0_B1_CTL] = 1,
-	[TOMTOM_A_CDC_COMP1_B1_CTL] = 1,
-	[TOMTOM_A_CDC_COMP2_B1_CTL] = 1,
-	[TOMTOM_A_CDC_COMP0_B2_CTL] = 1,
-	[TOMTOM_A_CDC_COMP1_B2_CTL] = 1,
-	[TOMTOM_A_CDC_COMP2_B2_CTL] = 1,
-	[TOMTOM_A_CDC_COMP0_B3_CTL] = 1,
-	[TOMTOM_A_CDC_COMP1_B3_CTL] = 1,
-	[TOMTOM_A_CDC_COMP2_B3_CTL] = 1,
-	[TOMTOM_A_CDC_COMP0_B4_CTL] = 1,
-	[TOMTOM_A_CDC_COMP1_B4_CTL] = 1,
-	[TOMTOM_A_CDC_COMP2_B4_CTL] = 1,
-	[TOMTOM_A_CDC_COMP0_B5_CTL] = 1,
-	[TOMTOM_A_CDC_COMP1_B5_CTL] = 1,
-	[TOMTOM_A_CDC_COMP2_B5_CTL] = 1,
-	[TOMTOM_A_CDC_COMP0_B6_CTL] = 1,
-	[TOMTOM_A_CDC_COMP1_B6_CTL] = 1,
-	[TOMTOM_A_CDC_COMP2_B6_CTL] = 1,
-	[TOMTOM_A_CDC_COMP0_SHUT_DOWN_STATUS] = 1,
-	[TOMTOM_A_CDC_COMP1_SHUT_DOWN_STATUS] = 1,
-	[TOMTOM_A_CDC_COMP2_SHUT_DOWN_STATUS] = 1,
-	[TOMTOM_A_CDC_COMP0_FS_CFG] = 1,
-	[TOMTOM_A_CDC_COMP1_FS_CFG] = 1,
-	[TOMTOM_A_CDC_COMP2_FS_CFG] = 1,
-	[TOMTOM_A_CDC_CONN_RX1_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX1_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX1_B3_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX2_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX2_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX2_B3_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX3_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX3_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX4_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX4_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX5_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX5_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX6_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX6_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX7_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX7_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX7_B3_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_ANC_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_ANC_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_B3_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_B4_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_EQ1_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_EQ1_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_EQ1_B3_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_EQ1_B4_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_EQ2_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_EQ2_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_EQ2_B3_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_EQ2_B4_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_SRC1_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_SRC1_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_SRC2_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_SRC2_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B3_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B4_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B5_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B6_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B7_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B8_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B9_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B10_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_TX_SB_B11_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX_SB_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_RX_SB_B2_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_CLSH_CTL] = 1,
-	[TOMTOM_A_CDC_CONN_MISC] = 1,
-	[TOMTOM_A_CDC_CONN_RX8_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_CLIP_LEVEL_ADJUST] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_MIN_CLIP_THRESHOLD] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_THRESHOLD_STATUS] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_SAMPLE_MARK] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_BOOST_GATING] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_B1_CTL] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_CLIP_LEVEL_ADJUST] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_MIN_CLIP_THRESHOLD] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_THRESHOLD_STATUS] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_SAMPLE_MARK] = 1,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_BOOST_GATING] = 1,
-	[TOMTOM_A_CDC_MBHC_EN_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_FIR_B1_CFG] = 1,
-	[TOMTOM_A_CDC_MBHC_FIR_B2_CFG] = 1,
-	[TOMTOM_A_CDC_MBHC_TIMER_B1_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_TIMER_B2_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_TIMER_B3_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_TIMER_B4_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_TIMER_B5_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_TIMER_B6_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_B1_STATUS] = 1,
-	[TOMTOM_A_CDC_MBHC_B2_STATUS] = 1,
-	[TOMTOM_A_CDC_MBHC_B3_STATUS] = 1,
-	[TOMTOM_A_CDC_MBHC_B4_STATUS] = 1,
-	[TOMTOM_A_CDC_MBHC_B5_STATUS] = 1,
-	[TOMTOM_A_CDC_MBHC_B1_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_B2_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B1_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B2_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B3_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B4_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B5_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B6_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B7_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B8_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B9_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B10_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B11_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_VOLT_B12_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_CLK_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_INT_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_DEBUG_CTL] = 1,
-	[TOMTOM_A_CDC_MBHC_SPARE] = 1,
-	[TOMTOM_A_CDC_RX8_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX8_B2_CTL] = 1,
-	[TOMTOM_A_CDC_RX8_B3_CTL] = 1,
-	[TOMTOM_A_CDC_RX8_B4_CTL] = 1,
-	[TOMTOM_A_CDC_RX8_B5_CTL] = 1,
-	[TOMTOM_A_CDC_RX8_B6_CTL] = 1,
-	[TOMTOM_A_CDC_RX8_VOL_CTL_B1_CTL] = 1,
-	[TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL] = 1,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL0] = 1,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL1] = 1,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL2] = 1,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL3] = 1,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL4] = 1,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL5] = 1,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL6] = 1,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL7] = 1,
-	[TOMTOM_A_CDC_BOOST_MODE_CTL] = 1,
-	[TOMTOM_A_CDC_BOOST_THRESHOLD] = 1,
-	[TOMTOM_A_CDC_BOOST_TAP_SEL] = 1,
-	[TOMTOM_A_CDC_BOOST_HOLD_TIME] = 1,
-	[TOMTOM_A_CDC_BOOST_TRGR_EN] = 1,
-};
-
-const u8 tomtom_reset_reg_defaults[TOMTOM_CACHE_SIZE] = {
-	[TOMTOM_A_CHIP_CTL] = TOMTOM_A_CHIP_CTL__POR,
-	[TOMTOM_A_CHIP_STATUS] = TOMTOM_A_CHIP_STATUS__POR,
-	[TOMTOM_A_CHIP_ID_BYTE_0] = TOMTOM_A_CHIP_ID_BYTE_0__POR,
-	[TOMTOM_A_CHIP_ID_BYTE_1] = TOMTOM_A_CHIP_ID_BYTE_1__POR,
-	[TOMTOM_A_CHIP_ID_BYTE_2] = TOMTOM_A_CHIP_ID_BYTE_2__POR,
-	[TOMTOM_A_CHIP_ID_BYTE_3] = TOMTOM_A_CHIP_ID_BYTE_3__POR,
-	[TOMTOM_A_CHIP_I2C_SLAVE_ID] = TOMTOM_A_CHIP_I2C_SLAVE_ID__POR,
-	[TOMTOM_A_SLAVE_ID_1] = TOMTOM_A_SLAVE_ID_1__POR,
-	[TOMTOM_A_SLAVE_ID_2] = TOMTOM_A_SLAVE_ID_2__POR,
-	[TOMTOM_A_SLAVE_ID_3] = TOMTOM_A_SLAVE_ID_3__POR,
-	[TOMTOM_A_PIN_CTL_OE0] = TOMTOM_A_PIN_CTL_OE0__POR,
-	[TOMTOM_A_PIN_CTL_OE1] = TOMTOM_A_PIN_CTL_OE1__POR,
-	[TOMTOM_A_PIN_CTL_OE2] = TOMTOM_A_PIN_CTL_OE2__POR,
-	[TOMTOM_A_PIN_CTL_DATA0] = TOMTOM_A_PIN_CTL_DATA0__POR,
-	[TOMTOM_A_PIN_CTL_DATA1] = TOMTOM_A_PIN_CTL_DATA1__POR,
-	[TOMTOM_A_PIN_CTL_DATA2] = TOMTOM_A_PIN_CTL_DATA2__POR,
-	[TOMTOM_A_HDRIVE_GENERIC] = TOMTOM_A_HDRIVE_GENERIC__POR,
-	[TOMTOM_A_HDRIVE_OVERRIDE] = TOMTOM_A_HDRIVE_OVERRIDE__POR,
-	[TOMTOM_A_ANA_CSR_WAIT_STATE] = TOMTOM_A_ANA_CSR_WAIT_STATE__POR,
-	[TOMTOM_A_PROCESS_MONITOR_CTL0] = TOMTOM_A_PROCESS_MONITOR_CTL0__POR,
-	[TOMTOM_A_PROCESS_MONITOR_CTL1] = TOMTOM_A_PROCESS_MONITOR_CTL1__POR,
-	[TOMTOM_A_PROCESS_MONITOR_CTL2] = TOMTOM_A_PROCESS_MONITOR_CTL2__POR,
-	[TOMTOM_A_PROCESS_MONITOR_CTL3] = TOMTOM_A_PROCESS_MONITOR_CTL3__POR,
-	[TOMTOM_A_QFUSE_CTL] = TOMTOM_A_QFUSE_CTL__POR,
-	[TOMTOM_A_QFUSE_STATUS] = TOMTOM_A_QFUSE_STATUS__POR,
-	[TOMTOM_A_QFUSE_DATA_OUT0] = TOMTOM_A_QFUSE_DATA_OUT0__POR,
-	[TOMTOM_A_QFUSE_DATA_OUT1] = TOMTOM_A_QFUSE_DATA_OUT1__POR,
-	[TOMTOM_A_QFUSE_DATA_OUT2] = TOMTOM_A_QFUSE_DATA_OUT2__POR,
-	[TOMTOM_A_QFUSE_DATA_OUT3] = TOMTOM_A_QFUSE_DATA_OUT3__POR,
-	[TOMTOM_A_QFUSE_DATA_OUT4] = TOMTOM_A_QFUSE_DATA_OUT4__POR,
-	[TOMTOM_A_QFUSE_DATA_OUT5] = TOMTOM_A_QFUSE_DATA_OUT5__POR,
-	[TOMTOM_A_QFUSE_DATA_OUT6] = TOMTOM_A_QFUSE_DATA_OUT6__POR,
-	[TOMTOM_A_QFUSE_DATA_OUT7] = TOMTOM_A_QFUSE_DATA_OUT7__POR,
-	[TOMTOM_A_CDC_CTL] = TOMTOM_A_CDC_CTL__POR,
-	[TOMTOM_A_LEAKAGE_CTL] = TOMTOM_A_LEAKAGE_CTL__POR,
-	[TOMTOM_A_SVASS_MEM_PTR0] = TOMTOM_A_SVASS_MEM_PTR0__POR,
-	[TOMTOM_A_SVASS_MEM_PTR1] = TOMTOM_A_SVASS_MEM_PTR1__POR,
-	[TOMTOM_A_SVASS_MEM_PTR2] = TOMTOM_A_SVASS_MEM_PTR2__POR,
-	[TOMTOM_A_SVASS_MEM_CTL] = TOMTOM_A_SVASS_MEM_CTL__POR,
-	[TOMTOM_A_SVASS_MEM_BANK] = TOMTOM_A_SVASS_MEM_BANK__POR,
-	[TOMTOM_A_DMIC_B1_CTL] = TOMTOM_A_DMIC_B1_CTL__POR,
-	[TOMTOM_A_DMIC_B2_CTL] = TOMTOM_A_DMIC_B2_CTL__POR,
-	[TOMTOM_A_SVASS_CLKRST_CTL] = TOMTOM_A_SVASS_CLKRST_CTL__POR,
-	[TOMTOM_A_SVASS_CPAR_CFG] = TOMTOM_A_SVASS_CPAR_CFG__POR,
-	[TOMTOM_A_SVASS_BUF_RDY_INT_PERIOD] =
-				TOMTOM_A_SVASS_BUF_RDY_INT_PERIOD__POR,
-	[TOMTOM_A_SVASS_CPAR_WDOG_CFG] = TOMTOM_A_SVASS_CPAR_WDOG_CFG__POR,
-	[TOMTOM_A_SVASS_CFG] = TOMTOM_A_SVASS_CFG__POR,
-	[TOMTOM_A_SVASS_SPE_CFG] = TOMTOM_A_SVASS_SPE_CFG__POR,
-	[TOMTOM_A_SVASS_STATUS] = TOMTOM_A_SVASS_STATUS__POR,
-	[TOMTOM_A_SVASS_INT_MASK] = TOMTOM_A_SVASS_INT_MASK__POR,
-	[TOMTOM_A_SVASS_INT_STATUS] = TOMTOM_A_SVASS_INT_STATUS__POR,
-	[TOMTOM_A_SVASS_INT_CLR] = TOMTOM_A_SVASS_INT_CLR__POR,
-	[TOMTOM_A_SVASS_DEBUG] = TOMTOM_A_SVASS_DEBUG__POR,
-	[TOMTOM_A_SVASS_SPE_BKUP_INT] = TOMTOM_A_SVASS_SPE_BKUP_INT__POR,
-	[TOMTOM_A_SVASS_MEM_ACC] = TOMTOM_A_SVASS_MEM_ACC__POR,
-	[TOMTOM_A_MEM_LEAKAGE_CTL] = TOMTOM_A_MEM_LEAKAGE_CTL__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_TRG] = TOMTOM_A_SVASS_SPE_INBOX_TRG__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_0] = TOMTOM_A_SVASS_SPE_INBOX_0__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_1] = TOMTOM_A_SVASS_SPE_INBOX_1__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_2] = TOMTOM_A_SVASS_SPE_INBOX_2__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_3] = TOMTOM_A_SVASS_SPE_INBOX_3__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_4] = TOMTOM_A_SVASS_SPE_INBOX_4__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_5] = TOMTOM_A_SVASS_SPE_INBOX_5__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_6] = TOMTOM_A_SVASS_SPE_INBOX_6__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_7] = TOMTOM_A_SVASS_SPE_INBOX_7__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_8] = TOMTOM_A_SVASS_SPE_INBOX_8__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_9] = TOMTOM_A_SVASS_SPE_INBOX_9__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_10] = TOMTOM_A_SVASS_SPE_INBOX_10__POR,
-	[TOMTOM_A_SVASS_SPE_INBOX_11] = TOMTOM_A_SVASS_SPE_INBOX_11__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_0] = TOMTOM_A_SVASS_SPE_OUTBOX_0__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_1] = TOMTOM_A_SVASS_SPE_OUTBOX_1__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_2] = TOMTOM_A_SVASS_SPE_OUTBOX_2__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_3] = TOMTOM_A_SVASS_SPE_OUTBOX_3__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_4] = TOMTOM_A_SVASS_SPE_OUTBOX_4__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_5] = TOMTOM_A_SVASS_SPE_OUTBOX_5__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_6] = TOMTOM_A_SVASS_SPE_OUTBOX_6__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_7] = TOMTOM_A_SVASS_SPE_OUTBOX_7__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_8] = TOMTOM_A_SVASS_SPE_OUTBOX_8__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_9] = TOMTOM_A_SVASS_SPE_OUTBOX_9__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_10] = TOMTOM_A_SVASS_SPE_OUTBOX_10__POR,
-	[TOMTOM_A_SVASS_SPE_OUTBOX_11] = TOMTOM_A_SVASS_SPE_OUTBOX_11__POR,
-	[TOMTOM_A_INTR_MODE] = TOMTOM_A_INTR_MODE__POR,
-	[TOMTOM_A_INTR1_MASK0] = TOMTOM_A_INTR1_MASK0__POR,
-	[TOMTOM_A_INTR1_MASK1] = TOMTOM_A_INTR1_MASK1__POR,
-	[TOMTOM_A_INTR1_MASK2] = TOMTOM_A_INTR1_MASK2__POR,
-	[TOMTOM_A_INTR1_MASK3] = TOMTOM_A_INTR1_MASK3__POR,
-	[TOMTOM_A_INTR1_STATUS0] = TOMTOM_A_INTR1_STATUS0__POR,
-	[TOMTOM_A_INTR1_STATUS1] = TOMTOM_A_INTR1_STATUS1__POR,
-	[TOMTOM_A_INTR1_STATUS2] = TOMTOM_A_INTR1_STATUS2__POR,
-	[TOMTOM_A_INTR1_STATUS3] = TOMTOM_A_INTR1_STATUS3__POR,
-	[TOMTOM_A_INTR1_CLEAR0] = TOMTOM_A_INTR1_CLEAR0__POR,
-	[TOMTOM_A_INTR1_CLEAR1] = TOMTOM_A_INTR1_CLEAR1__POR,
-	[TOMTOM_A_INTR1_CLEAR2] = TOMTOM_A_INTR1_CLEAR2__POR,
-	[TOMTOM_A_INTR1_CLEAR3] = TOMTOM_A_INTR1_CLEAR3__POR,
-	[TOMTOM_A_INTR1_LEVEL0] = TOMTOM_A_INTR1_LEVEL0__POR,
-	[TOMTOM_A_INTR1_LEVEL1] = TOMTOM_A_INTR1_LEVEL1__POR,
-	[TOMTOM_A_INTR1_LEVEL2] = TOMTOM_A_INTR1_LEVEL2__POR,
-	[TOMTOM_A_INTR1_LEVEL3] = TOMTOM_A_INTR1_LEVEL3__POR,
-	[TOMTOM_A_INTR1_TEST0] = TOMTOM_A_INTR1_TEST0__POR,
-	[TOMTOM_A_INTR1_TEST1] = TOMTOM_A_INTR1_TEST1__POR,
-	[TOMTOM_A_INTR1_TEST2] = TOMTOM_A_INTR1_TEST2__POR,
-	[TOMTOM_A_INTR1_TEST3] = TOMTOM_A_INTR1_TEST3__POR,
-	[TOMTOM_A_INTR1_SET0] = TOMTOM_A_INTR1_SET0__POR,
-	[TOMTOM_A_INTR1_SET1] = TOMTOM_A_INTR1_SET1__POR,
-	[TOMTOM_A_INTR1_SET2] = TOMTOM_A_INTR1_SET2__POR,
-	[TOMTOM_A_INTR1_SET3] = TOMTOM_A_INTR1_SET3__POR,
-	[TOMTOM_A_INTR2_MASK0] = TOMTOM_A_INTR2_MASK0__POR,
-	[TOMTOM_A_INTR2_STATUS0] = TOMTOM_A_INTR2_STATUS0__POR,
-	[TOMTOM_A_INTR2_CLEAR0] = TOMTOM_A_INTR2_CLEAR0__POR,
-	[TOMTOM_A_INTR2_LEVEL0] = TOMTOM_A_INTR2_LEVEL0__POR,
-	[TOMTOM_A_INTR2_TEST0] = TOMTOM_A_INTR2_TEST0__POR,
-	[TOMTOM_A_INTR2_SET0] = TOMTOM_A_INTR2_SET0__POR,
-	[TOMTOM_A_CDC_TX_I2S_SCK_MODE] = TOMTOM_A_CDC_TX_I2S_SCK_MODE__POR,
-	[TOMTOM_A_CDC_TX_I2S_WS_MODE] = TOMTOM_A_CDC_TX_I2S_WS_MODE__POR,
-	[TOMTOM_A_CDC_DMIC_DATA0_MODE] = TOMTOM_A_CDC_DMIC_DATA0_MODE__POR,
-	[TOMTOM_A_CDC_DMIC_CLK0_MODE] = TOMTOM_A_CDC_DMIC_CLK0_MODE__POR,
-	[TOMTOM_A_CDC_DMIC_DATA1_MODE] = TOMTOM_A_CDC_DMIC_DATA1_MODE__POR,
-	[TOMTOM_A_CDC_DMIC_CLK1_MODE] = TOMTOM_A_CDC_DMIC_CLK1_MODE__POR,
-	[TOMTOM_A_CDC_RX_I2S_SCK_MODE] = TOMTOM_A_CDC_RX_I2S_SCK_MODE__POR,
-	[TOMTOM_A_CDC_RX_I2S_WS_MODE] = TOMTOM_A_CDC_RX_I2S_WS_MODE__POR,
-	[TOMTOM_A_CDC_DMIC_DATA2_MODE] = TOMTOM_A_CDC_DMIC_DATA2_MODE__POR,
-	[TOMTOM_A_CDC_DMIC_CLK2_MODE] = TOMTOM_A_CDC_DMIC_CLK2_MODE__POR,
-	[TOMTOM_A_CDC_INTR1_MODE] = TOMTOM_A_CDC_INTR1_MODE__POR,
-	[TOMTOM_A_CDC_SB_NRZ_SEL_MODE] = TOMTOM_A_CDC_SB_NRZ_SEL_MODE__POR,
-	[TOMTOM_A_CDC_INTR2_MODE] = TOMTOM_A_CDC_INTR2_MODE__POR,
-	[TOMTOM_A_CDC_RF_PA_ON_MODE] = TOMTOM_A_CDC_RF_PA_ON_MODE__POR,
-	[TOMTOM_A_CDC_BOOST_MODE] = TOMTOM_A_CDC_BOOST_MODE__POR,
-	[TOMTOM_A_CDC_JTCK_MODE] = TOMTOM_A_CDC_JTCK_MODE__POR,
-	[TOMTOM_A_CDC_JTDI_MODE] = TOMTOM_A_CDC_JTDI_MODE__POR,
-	[TOMTOM_A_CDC_JTMS_MODE] = TOMTOM_A_CDC_JTMS_MODE__POR,
-	[TOMTOM_A_CDC_JTDO_MODE] = TOMTOM_A_CDC_JTDO_MODE__POR,
-	[TOMTOM_A_CDC_JTRST_MODE] = TOMTOM_A_CDC_JTRST_MODE__POR,
-	[TOMTOM_A_CDC_BIST_MODE_MODE] = TOMTOM_A_CDC_BIST_MODE_MODE__POR,
-	[TOMTOM_A_CDC_MAD_MAIN_CTL_1] = TOMTOM_A_CDC_MAD_MAIN_CTL_1__POR,
-	[TOMTOM_A_CDC_MAD_MAIN_CTL_2] = TOMTOM_A_CDC_MAD_MAIN_CTL_2__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_1] = TOMTOM_A_CDC_MAD_AUDIO_CTL_1__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_2] = TOMTOM_A_CDC_MAD_AUDIO_CTL_2__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_3] = TOMTOM_A_CDC_MAD_AUDIO_CTL_3__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_4] = TOMTOM_A_CDC_MAD_AUDIO_CTL_4__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_5] = TOMTOM_A_CDC_MAD_AUDIO_CTL_5__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_6] = TOMTOM_A_CDC_MAD_AUDIO_CTL_6__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_7] = TOMTOM_A_CDC_MAD_AUDIO_CTL_7__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_CTL_8] = TOMTOM_A_CDC_MAD_AUDIO_CTL_8__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_PTR] =
-				TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_PTR__POR,
-	[TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_VAL] =
-				TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_VAL__POR,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_1] = TOMTOM_A_CDC_MAD_ULTR_CTL_1__POR,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_2] = TOMTOM_A_CDC_MAD_ULTR_CTL_2__POR,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_3] = TOMTOM_A_CDC_MAD_ULTR_CTL_3__POR,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_4] = TOMTOM_A_CDC_MAD_ULTR_CTL_4__POR,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_5] = TOMTOM_A_CDC_MAD_ULTR_CTL_5__POR,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_6] = TOMTOM_A_CDC_MAD_ULTR_CTL_6__POR,
-	[TOMTOM_A_CDC_MAD_ULTR_CTL_7] = TOMTOM_A_CDC_MAD_ULTR_CTL_7__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_1] = TOMTOM_A_CDC_MAD_BEACON_CTL_1__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_2] = TOMTOM_A_CDC_MAD_BEACON_CTL_2__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_3] = TOMTOM_A_CDC_MAD_BEACON_CTL_3__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_4] = TOMTOM_A_CDC_MAD_BEACON_CTL_4__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_5] = TOMTOM_A_CDC_MAD_BEACON_CTL_5__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_6] = TOMTOM_A_CDC_MAD_BEACON_CTL_6__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_7] = TOMTOM_A_CDC_MAD_BEACON_CTL_7__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_CTL_8] = TOMTOM_A_CDC_MAD_BEACON_CTL_8__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_PTR] =
-				TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_PTR__POR,
-	[TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_VAL] =
-				TOMTOM_A_CDC_MAD_BEACON_IIR_CTL_VAL__POR,
-	[TOMTOM_A_CDC_MAD_INP_SEL] = TOMTOM_A_CDC_MAD_INP_SEL__POR,
-	[TOMTOM_A_BIAS_REF_CTL] = TOMTOM_A_BIAS_REF_CTL__POR,
-	[TOMTOM_A_BIAS_CENTRAL_BG_CTL] = TOMTOM_A_BIAS_CENTRAL_BG_CTL__POR,
-	[TOMTOM_A_BIAS_PRECHRG_CTL] = TOMTOM_A_BIAS_PRECHRG_CTL__POR,
-	[TOMTOM_A_BIAS_CURR_CTL_1] = TOMTOM_A_BIAS_CURR_CTL_1__POR,
-	[TOMTOM_A_BIAS_CURR_CTL_2] = TOMTOM_A_BIAS_CURR_CTL_2__POR,
-	[TOMTOM_A_BIAS_OSC_BG_CTL] = TOMTOM_A_BIAS_OSC_BG_CTL__POR,
-	[TOMTOM_A_CLK_BUFF_EN1] = TOMTOM_A_CLK_BUFF_EN1__POR,
-	[TOMTOM_A_CLK_BUFF_EN2] = TOMTOM_A_CLK_BUFF_EN2__POR,
-	[TOMTOM_A_LDO_L_MODE_1] = TOMTOM_A_LDO_L_MODE_1__POR,
-	[TOMTOM_A_LDO_L_MODE_2] = TOMTOM_A_LDO_L_MODE_2__POR,
-	[TOMTOM_A_LDO_L_CTRL_1] = TOMTOM_A_LDO_L_CTRL_1__POR,
-	[TOMTOM_A_LDO_L_CTRL_2] = TOMTOM_A_LDO_L_CTRL_2__POR,
-	[TOMTOM_A_LDO_L_CTRL_3] = TOMTOM_A_LDO_L_CTRL_3__POR,
-	[TOMTOM_A_LDO_L_CTRL_4] = TOMTOM_A_LDO_L_CTRL_4__POR,
-	[TOMTOM_A_LDO_H_MODE_1] = TOMTOM_A_LDO_H_MODE_1__POR,
-	[TOMTOM_A_LDO_H_MODE_2] = TOMTOM_A_LDO_H_MODE_2__POR,
-	[TOMTOM_A_LDO_H_LOOP_CTL] = TOMTOM_A_LDO_H_LOOP_CTL__POR,
-	[TOMTOM_A_LDO_H_COMP_1] = TOMTOM_A_LDO_H_COMP_1__POR,
-	[TOMTOM_A_LDO_H_COMP_2] = TOMTOM_A_LDO_H_COMP_2__POR,
-	[TOMTOM_A_LDO_H_BIAS_1] = TOMTOM_A_LDO_H_BIAS_1__POR,
-	[TOMTOM_A_LDO_H_BIAS_2] = TOMTOM_A_LDO_H_BIAS_2__POR,
-	[TOMTOM_A_LDO_H_BIAS_3] = TOMTOM_A_LDO_H_BIAS_3__POR,
-	[TOMTOM_A_VBAT_CLK] = TOMTOM_A_VBAT_CLK__POR,
-	[TOMTOM_A_VBAT_LOOP] = TOMTOM_A_VBAT_LOOP__POR,
-	[TOMTOM_A_VBAT_REF] = TOMTOM_A_VBAT_REF__POR,
-	[TOMTOM_A_VBAT_ADC_TEST] = TOMTOM_A_VBAT_ADC_TEST__POR,
-	[TOMTOM_A_VBAT_FE] = TOMTOM_A_VBAT_FE__POR,
-	[TOMTOM_A_VBAT_BIAS_1] = TOMTOM_A_VBAT_BIAS_1__POR,
-	[TOMTOM_A_VBAT_BIAS_2] = TOMTOM_A_VBAT_BIAS_2__POR,
-	[TOMTOM_A_VBAT_ADC_DATA_MSB] = TOMTOM_A_VBAT_ADC_DATA_MSB__POR,
-	[TOMTOM_A_VBAT_ADC_DATA_LSB] = TOMTOM_A_VBAT_ADC_DATA_LSB__POR,
-	[TOMTOM_A_FLL_NREF] = TOMTOM_A_FLL_NREF__POR,
-	[TOMTOM_A_FLL_KDCO_TUNE] = TOMTOM_A_FLL_KDCO_TUNE__POR,
-	[TOMTOM_A_FLL_LOCK_THRESH] = TOMTOM_A_FLL_LOCK_THRESH__POR,
-	[TOMTOM_A_FLL_LOCK_DET_COUNT] = TOMTOM_A_FLL_LOCK_DET_COUNT__POR,
-	[TOMTOM_A_FLL_DAC_THRESHOLD] = TOMTOM_A_FLL_DAC_THRESHOLD__POR,
-	[TOMTOM_A_FLL_TEST_DCO_FREERUN] = TOMTOM_A_FLL_TEST_DCO_FREERUN__POR,
-	[TOMTOM_A_FLL_TEST_ENABLE] = TOMTOM_A_FLL_TEST_ENABLE__POR,
-	[TOMTOM_A_MICB_CFILT_1_CTL] = TOMTOM_A_MICB_CFILT_1_CTL__POR,
-	[TOMTOM_A_MICB_CFILT_1_VAL] = TOMTOM_A_MICB_CFILT_1_VAL__POR,
-	[TOMTOM_A_MICB_CFILT_1_PRECHRG] = TOMTOM_A_MICB_CFILT_1_PRECHRG__POR,
-	[TOMTOM_A_MICB_1_CTL] = TOMTOM_A_MICB_1_CTL__POR,
-	[TOMTOM_A_MICB_1_INT_RBIAS] = TOMTOM_A_MICB_1_INT_RBIAS__POR,
-	[TOMTOM_A_MICB_1_MBHC] = TOMTOM_A_MICB_1_MBHC__POR,
-	[TOMTOM_A_MICB_CFILT_2_CTL] = TOMTOM_A_MICB_CFILT_2_CTL__POR,
-	[TOMTOM_A_MICB_CFILT_2_VAL] = TOMTOM_A_MICB_CFILT_2_VAL__POR,
-	[TOMTOM_A_MICB_CFILT_2_PRECHRG] = TOMTOM_A_MICB_CFILT_2_PRECHRG__POR,
-	[TOMTOM_A_MICB_2_CTL] = TOMTOM_A_MICB_2_CTL__POR,
-	[TOMTOM_A_MICB_2_INT_RBIAS] = TOMTOM_A_MICB_2_INT_RBIAS__POR,
-	[TOMTOM_A_MICB_2_MBHC] = TOMTOM_A_MICB_2_MBHC__POR,
-	[TOMTOM_A_MICB_CFILT_3_CTL] = TOMTOM_A_MICB_CFILT_3_CTL__POR,
-	[TOMTOM_A_MICB_CFILT_3_VAL] = TOMTOM_A_MICB_CFILT_3_VAL__POR,
-	[TOMTOM_A_MICB_CFILT_3_PRECHRG] = TOMTOM_A_MICB_CFILT_3_PRECHRG__POR,
-	[TOMTOM_A_MICB_3_CTL] = TOMTOM_A_MICB_3_CTL__POR,
-	[TOMTOM_A_MICB_3_INT_RBIAS] = TOMTOM_A_MICB_3_INT_RBIAS__POR,
-	[TOMTOM_A_MICB_3_MBHC] = TOMTOM_A_MICB_3_MBHC__POR,
-	[TOMTOM_A_MICB_4_CTL] = TOMTOM_A_MICB_4_CTL__POR,
-	[TOMTOM_A_MICB_4_INT_RBIAS] = TOMTOM_A_MICB_4_INT_RBIAS__POR,
-	[TOMTOM_A_MICB_4_MBHC] = TOMTOM_A_MICB_4_MBHC__POR,
-	[TOMTOM_A_SPKR_DRV2_EN] = TOMTOM_A_SPKR_DRV2_EN__POR,
-	[TOMTOM_A_SPKR_DRV2_GAIN] = TOMTOM_A_SPKR_DRV2_GAIN__POR,
-	[TOMTOM_A_SPKR_DRV2_DAC_CTL] = TOMTOM_A_SPKR_DRV2_DAC_CTL__POR,
-	[TOMTOM_A_SPKR_DRV2_OCP_CTL] = TOMTOM_A_SPKR_DRV2_OCP_CTL__POR,
-	[TOMTOM_A_SPKR_DRV2_CLIP_DET] = TOMTOM_A_SPKR_DRV2_CLIP_DET__POR,
-	[TOMTOM_A_SPKR_DRV2_DBG_DAC] = TOMTOM_A_SPKR_DRV2_DBG_DAC__POR,
-	[TOMTOM_A_SPKR_DRV2_DBG_PA] = TOMTOM_A_SPKR_DRV2_DBG_PA__POR,
-	[TOMTOM_A_SPKR_DRV2_DBG_PWRSTG] = TOMTOM_A_SPKR_DRV2_DBG_PWRSTG__POR,
-	[TOMTOM_A_SPKR_DRV2_BIAS_LDO] = TOMTOM_A_SPKR_DRV2_BIAS_LDO__POR,
-	[TOMTOM_A_SPKR_DRV2_BIAS_INT] = TOMTOM_A_SPKR_DRV2_BIAS_INT__POR,
-	[TOMTOM_A_SPKR_DRV2_BIAS_PA] = TOMTOM_A_SPKR_DRV2_BIAS_PA__POR,
-	[TOMTOM_A_SPKR_DRV2_STATUS_OCP] = TOMTOM_A_SPKR_DRV2_STATUS_OCP__POR,
-	[TOMTOM_A_SPKR_DRV2_STATUS_PA] = TOMTOM_A_SPKR_DRV2_STATUS_PA__POR,
-	[TOMTOM_A_MBHC_INSERT_DETECT] = TOMTOM_A_MBHC_INSERT_DETECT__POR,
-	[TOMTOM_A_MBHC_INSERT_DET_STATUS] =
-				TOMTOM_A_MBHC_INSERT_DET_STATUS__POR,
-	[TOMTOM_A_TX_COM_BIAS] = TOMTOM_A_TX_COM_BIAS__POR,
-	[TOMTOM_A_MBHC_INSERT_DETECT2] = TOMTOM_A_MBHC_INSERT_DETECT2__POR,
-	[TOMTOM_A_MBHC_SCALING_MUX_1] = TOMTOM_A_MBHC_SCALING_MUX_1__POR,
-	[TOMTOM_A_MBHC_SCALING_MUX_2] = TOMTOM_A_MBHC_SCALING_MUX_2__POR,
-	[TOMTOM_A_MAD_ANA_CTRL] = TOMTOM_A_MAD_ANA_CTRL__POR,
-	[TOMTOM_A_TX_SUP_SWITCH_CTRL_1] = TOMTOM_A_TX_SUP_SWITCH_CTRL_1__POR,
-	[TOMTOM_A_TX_SUP_SWITCH_CTRL_2] = TOMTOM_A_TX_SUP_SWITCH_CTRL_2__POR,
-	[TOMTOM_A_TX_1_GAIN] = TOMTOM_A_TX_1_GAIN__POR,
-	[TOMTOM_A_TX_1_2_TEST_EN] = TOMTOM_A_TX_1_2_TEST_EN__POR,
-	[TOMTOM_A_TX_2_GAIN] = TOMTOM_A_TX_2_GAIN__POR,
-	[TOMTOM_A_TX_1_2_ADC_IB] = TOMTOM_A_TX_1_2_ADC_IB__POR,
-	[TOMTOM_A_TX_1_2_ATEST_REFCTRL] = TOMTOM_A_TX_1_2_ATEST_REFCTRL__POR,
-	[TOMTOM_A_TX_1_2_TEST_CTL] = TOMTOM_A_TX_1_2_TEST_CTL__POR,
-	[TOMTOM_A_TX_1_2_TEST_BLOCK_EN] = TOMTOM_A_TX_1_2_TEST_BLOCK_EN__POR,
-	[TOMTOM_A_TX_1_2_TXFE_CLKDIV] = TOMTOM_A_TX_1_2_TXFE_CLKDIV__POR,
-	[TOMTOM_A_TX_1_2_SAR_ERR_CH1] = TOMTOM_A_TX_1_2_SAR_ERR_CH1__POR,
-	[TOMTOM_A_TX_1_2_SAR_ERR_CH2] = TOMTOM_A_TX_1_2_SAR_ERR_CH2__POR,
-	[TOMTOM_A_TX_3_GAIN] = TOMTOM_A_TX_3_GAIN__POR,
-	[TOMTOM_A_TX_3_4_TEST_EN] = TOMTOM_A_TX_3_4_TEST_EN__POR,
-	[TOMTOM_A_TX_4_GAIN] = TOMTOM_A_TX_4_GAIN__POR,
-	[TOMTOM_A_TX_3_4_ADC_IB] = TOMTOM_A_TX_3_4_ADC_IB__POR,
-	[TOMTOM_A_TX_3_4_ATEST_REFCTRL] = TOMTOM_A_TX_3_4_ATEST_REFCTRL__POR,
-	[TOMTOM_A_TX_3_4_TEST_CTL] = TOMTOM_A_TX_3_4_TEST_CTL__POR,
-	[TOMTOM_A_TX_3_4_TEST_BLOCK_EN] = TOMTOM_A_TX_3_4_TEST_BLOCK_EN__POR,
-	[TOMTOM_A_TX_3_4_TXFE_CKDIV] = TOMTOM_A_TX_3_4_TXFE_CKDIV__POR,
-	[TOMTOM_A_TX_3_4_SAR_ERR_CH3] = TOMTOM_A_TX_3_4_SAR_ERR_CH3__POR,
-	[TOMTOM_A_TX_3_4_SAR_ERR_CH4] = TOMTOM_A_TX_3_4_SAR_ERR_CH4__POR,
-	[TOMTOM_A_TX_5_GAIN] = TOMTOM_A_TX_5_GAIN__POR,
-	[TOMTOM_A_TX_5_6_TEST_EN] = TOMTOM_A_TX_5_6_TEST_EN__POR,
-	[TOMTOM_A_TX_6_GAIN] = TOMTOM_A_TX_6_GAIN__POR,
-	[TOMTOM_A_TX_5_6_ADC_IB] = TOMTOM_A_TX_5_6_ADC_IB__POR,
-	[TOMTOM_A_TX_5_6_ATEST_REFCTRL] = TOMTOM_A_TX_5_6_ATEST_REFCTRL__POR,
-	[TOMTOM_A_TX_5_6_TEST_CTL] = TOMTOM_A_TX_5_6_TEST_CTL__POR,
-	[TOMTOM_A_TX_5_6_TEST_BLOCK_EN] = TOMTOM_A_TX_5_6_TEST_BLOCK_EN__POR,
-	[TOMTOM_A_TX_5_6_TXFE_CKDIV] = TOMTOM_A_TX_5_6_TXFE_CKDIV__POR,
-	[TOMTOM_A_TX_5_6_SAR_ERR_CH5] = TOMTOM_A_TX_5_6_SAR_ERR_CH5__POR,
-	[TOMTOM_A_TX_5_6_SAR_ERR_CH6] = TOMTOM_A_TX_5_6_SAR_ERR_CH6__POR,
-	[TOMTOM_A_TX_7_MBHC_EN] = TOMTOM_A_TX_7_MBHC_EN__POR,
-	[TOMTOM_A_TX_7_MBHC_ATEST_REFCTRL] =
-				TOMTOM_A_TX_7_MBHC_ATEST_REFCTRL__POR,
-	[TOMTOM_A_TX_7_MBHC_ADC] = TOMTOM_A_TX_7_MBHC_ADC__POR,
-	[TOMTOM_A_TX_7_MBHC_TEST_CTL] = TOMTOM_A_TX_7_MBHC_TEST_CTL__POR,
-	[TOMTOM_A_TX_7_MBHC_SAR_ERR] = TOMTOM_A_TX_7_MBHC_SAR_ERR__POR,
-	[TOMTOM_A_TX_7_TXFE_CLKDIV] = TOMTOM_A_TX_7_TXFE_CLKDIV__POR,
-	[TOMTOM_A_RCO_CTRL] = TOMTOM_A_RCO_CTRL__POR,
-	[TOMTOM_A_RCO_CALIBRATION_CTRL1] = TOMTOM_A_RCO_CALIBRATION_CTRL1__POR,
-	[TOMTOM_A_RCO_CALIBRATION_CTRL2] = TOMTOM_A_RCO_CALIBRATION_CTRL2__POR,
-	[TOMTOM_A_RCO_CALIBRATION_CTRL3] = TOMTOM_A_RCO_CALIBRATION_CTRL3__POR,
-	[TOMTOM_A_RCO_TEST_CTRL] = TOMTOM_A_RCO_TEST_CTRL__POR,
-	[TOMTOM_A_RCO_CALIBRATION_RESULT1] =
-				TOMTOM_A_RCO_CALIBRATION_RESULT1__POR,
-	[TOMTOM_A_RCO_CALIBRATION_RESULT2] =
-				TOMTOM_A_RCO_CALIBRATION_RESULT2__POR,
-	[TOMTOM_A_BUCK_MODE_1] = TOMTOM_A_BUCK_MODE_1__POR,
-	[TOMTOM_A_BUCK_MODE_2] = TOMTOM_A_BUCK_MODE_2__POR,
-	[TOMTOM_A_BUCK_MODE_3] = TOMTOM_A_BUCK_MODE_3__POR,
-	[TOMTOM_A_BUCK_MODE_4] = TOMTOM_A_BUCK_MODE_4__POR,
-	[TOMTOM_A_BUCK_MODE_5] = TOMTOM_A_BUCK_MODE_5__POR,
-	[TOMTOM_A_BUCK_CTRL_VCL_1] = TOMTOM_A_BUCK_CTRL_VCL_1__POR,
-	[TOMTOM_A_BUCK_CTRL_VCL_2] = TOMTOM_A_BUCK_CTRL_VCL_2__POR,
-	[TOMTOM_A_BUCK_CTRL_VCL_3] = TOMTOM_A_BUCK_CTRL_VCL_3__POR,
-	[TOMTOM_A_BUCK_CTRL_CCL_1] = TOMTOM_A_BUCK_CTRL_CCL_1__POR,
-	[TOMTOM_A_BUCK_CTRL_CCL_2] = TOMTOM_A_BUCK_CTRL_CCL_2__POR,
-	[TOMTOM_A_BUCK_CTRL_CCL_3] = TOMTOM_A_BUCK_CTRL_CCL_3__POR,
-	[TOMTOM_A_BUCK_CTRL_CCL_4] = TOMTOM_A_BUCK_CTRL_CCL_4__POR,
-	[TOMTOM_A_BUCK_CTRL_PWM_DRVR_1] = TOMTOM_A_BUCK_CTRL_PWM_DRVR_1__POR,
-	[TOMTOM_A_BUCK_CTRL_PWM_DRVR_2] = TOMTOM_A_BUCK_CTRL_PWM_DRVR_2__POR,
-	[TOMTOM_A_BUCK_CTRL_PWM_DRVR_3] = TOMTOM_A_BUCK_CTRL_PWM_DRVR_3__POR,
-	[TOMTOM_A_BUCK_TMUX_A_D] = TOMTOM_A_BUCK_TMUX_A_D__POR,
-	[TOMTOM_A_NCP_BUCKREF] = TOMTOM_A_NCP_BUCKREF__POR,
-	[TOMTOM_A_NCP_EN] = TOMTOM_A_NCP_EN__POR,
-	[TOMTOM_A_NCP_CLK] = TOMTOM_A_NCP_CLK__POR,
-	[TOMTOM_A_NCP_STATIC] = TOMTOM_A_NCP_STATIC__POR,
-	[TOMTOM_A_NCP_VTH_LOW] = TOMTOM_A_NCP_VTH_LOW__POR,
-	[TOMTOM_A_NCP_VTH_HIGH] = TOMTOM_A_NCP_VTH_HIGH__POR,
-	[TOMTOM_A_NCP_ATEST] = TOMTOM_A_NCP_ATEST__POR,
-	[TOMTOM_A_NCP_DTEST] = TOMTOM_A_NCP_DTEST__POR,
-	[TOMTOM_A_NCP_DLY1] = TOMTOM_A_NCP_DLY1__POR,
-	[TOMTOM_A_NCP_DLY2] = TOMTOM_A_NCP_DLY2__POR,
-	[TOMTOM_A_RX_AUX_SW_CTL] = TOMTOM_A_RX_AUX_SW_CTL__POR,
-	[TOMTOM_A_RX_PA_AUX_IN_CONN] = TOMTOM_A_RX_PA_AUX_IN_CONN__POR,
-	[TOMTOM_A_RX_COM_TIMER_DIV] = TOMTOM_A_RX_COM_TIMER_DIV__POR,
-	[TOMTOM_A_RX_COM_OCP_CTL] = TOMTOM_A_RX_COM_OCP_CTL__POR,
-	[TOMTOM_A_RX_COM_OCP_COUNT] = TOMTOM_A_RX_COM_OCP_COUNT__POR,
-	[TOMTOM_A_RX_COM_DAC_CTL] = TOMTOM_A_RX_COM_DAC_CTL__POR,
-	[TOMTOM_A_RX_COM_BIAS] = TOMTOM_A_RX_COM_BIAS__POR,
-	[TOMTOM_A_RX_HPH_AUTO_CHOP] = TOMTOM_A_RX_HPH_AUTO_CHOP__POR,
-	[TOMTOM_A_RX_HPH_CHOP_CTL] = TOMTOM_A_RX_HPH_CHOP_CTL__POR,
-	[TOMTOM_A_RX_HPH_BIAS_PA] = TOMTOM_A_RX_HPH_BIAS_PA__POR,
-	[TOMTOM_A_RX_HPH_BIAS_LDO] = TOMTOM_A_RX_HPH_BIAS_LDO__POR,
-	[TOMTOM_A_RX_HPH_BIAS_CNP] = TOMTOM_A_RX_HPH_BIAS_CNP__POR,
-	[TOMTOM_A_RX_HPH_BIAS_WG_OCP] = TOMTOM_A_RX_HPH_BIAS_WG_OCP__POR,
-	[TOMTOM_A_RX_HPH_OCP_CTL] = TOMTOM_A_RX_HPH_OCP_CTL__POR,
-	[TOMTOM_A_RX_HPH_CNP_EN] = TOMTOM_A_RX_HPH_CNP_EN__POR,
-	[TOMTOM_A_RX_HPH_CNP_WG_CTL] = TOMTOM_A_RX_HPH_CNP_WG_CTL__POR,
-	[TOMTOM_A_RX_HPH_CNP_WG_TIME] = TOMTOM_A_RX_HPH_CNP_WG_TIME__POR,
-	[TOMTOM_A_RX_HPH_L_GAIN] = TOMTOM_A_RX_HPH_L_GAIN__POR,
-	[TOMTOM_A_RX_HPH_L_TEST] = TOMTOM_A_RX_HPH_L_TEST__POR,
-	[TOMTOM_A_RX_HPH_L_PA_CTL] = TOMTOM_A_RX_HPH_L_PA_CTL__POR,
-	[TOMTOM_A_RX_HPH_L_DAC_CTL] = TOMTOM_A_RX_HPH_L_DAC_CTL__POR,
-	[TOMTOM_A_RX_HPH_L_ATEST] = TOMTOM_A_RX_HPH_L_ATEST__POR,
-	[TOMTOM_A_RX_HPH_L_STATUS] = TOMTOM_A_RX_HPH_L_STATUS__POR,
-	[TOMTOM_A_RX_HPH_R_GAIN] = TOMTOM_A_RX_HPH_R_GAIN__POR,
-	[TOMTOM_A_RX_HPH_R_TEST] = TOMTOM_A_RX_HPH_R_TEST__POR,
-	[TOMTOM_A_RX_HPH_R_PA_CTL] = TOMTOM_A_RX_HPH_R_PA_CTL__POR,
-	[TOMTOM_A_RX_HPH_R_DAC_CTL] = TOMTOM_A_RX_HPH_R_DAC_CTL__POR,
-	[TOMTOM_A_RX_HPH_R_ATEST] = TOMTOM_A_RX_HPH_R_ATEST__POR,
-	[TOMTOM_A_RX_HPH_R_STATUS] = TOMTOM_A_RX_HPH_R_STATUS__POR,
-	[TOMTOM_A_RX_EAR_BIAS_PA] = TOMTOM_A_RX_EAR_BIAS_PA__POR,
-	[TOMTOM_A_RX_EAR_BIAS_CMBUFF] = TOMTOM_A_RX_EAR_BIAS_CMBUFF__POR,
-	[TOMTOM_A_RX_EAR_EN] = TOMTOM_A_RX_EAR_EN__POR,
-	[TOMTOM_A_RX_EAR_GAIN] = TOMTOM_A_RX_EAR_GAIN__POR,
-	[TOMTOM_A_RX_EAR_CMBUFF] = TOMTOM_A_RX_EAR_CMBUFF__POR,
-	[TOMTOM_A_RX_EAR_ICTL] = TOMTOM_A_RX_EAR_ICTL__POR,
-	[TOMTOM_A_RX_EAR_CCOMP] = TOMTOM_A_RX_EAR_CCOMP__POR,
-	[TOMTOM_A_RX_EAR_VCM] = TOMTOM_A_RX_EAR_VCM__POR,
-	[TOMTOM_A_RX_EAR_CNP] = TOMTOM_A_RX_EAR_CNP__POR,
-	[TOMTOM_A_RX_EAR_DAC_CTL_ATEST] = TOMTOM_A_RX_EAR_DAC_CTL_ATEST__POR,
-	[TOMTOM_A_RX_EAR_STATUS] = TOMTOM_A_RX_EAR_STATUS__POR,
-	[TOMTOM_A_RX_LINE_BIAS_PA] = TOMTOM_A_RX_LINE_BIAS_PA__POR,
-	[TOMTOM_A_RX_BUCK_BIAS1] = TOMTOM_A_RX_BUCK_BIAS1__POR,
-	[TOMTOM_A_RX_BUCK_BIAS2] = TOMTOM_A_RX_BUCK_BIAS2__POR,
-	[TOMTOM_A_RX_LINE_COM] = TOMTOM_A_RX_LINE_COM__POR,
-	[TOMTOM_A_RX_LINE_CNP_EN] = TOMTOM_A_RX_LINE_CNP_EN__POR,
-	[TOMTOM_A_RX_LINE_CNP_WG_CTL] = TOMTOM_A_RX_LINE_CNP_WG_CTL__POR,
-	[TOMTOM_A_RX_LINE_CNP_WG_TIME] = TOMTOM_A_RX_LINE_CNP_WG_TIME__POR,
-	[TOMTOM_A_RX_LINE_1_GAIN] = TOMTOM_A_RX_LINE_1_GAIN__POR,
-	[TOMTOM_A_RX_LINE_1_TEST] = TOMTOM_A_RX_LINE_1_TEST__POR,
-	[TOMTOM_A_RX_LINE_1_DAC_CTL] = TOMTOM_A_RX_LINE_1_DAC_CTL__POR,
-	[TOMTOM_A_RX_LINE_1_STATUS] = TOMTOM_A_RX_LINE_1_STATUS__POR,
-	[TOMTOM_A_RX_LINE_2_GAIN] = TOMTOM_A_RX_LINE_2_GAIN__POR,
-	[TOMTOM_A_RX_LINE_2_TEST] = TOMTOM_A_RX_LINE_2_TEST__POR,
-	[TOMTOM_A_RX_LINE_2_DAC_CTL] = TOMTOM_A_RX_LINE_2_DAC_CTL__POR,
-	[TOMTOM_A_RX_LINE_2_STATUS] = TOMTOM_A_RX_LINE_2_STATUS__POR,
-	[TOMTOM_A_RX_LINE_3_GAIN] = TOMTOM_A_RX_LINE_3_GAIN__POR,
-	[TOMTOM_A_RX_LINE_3_TEST] = TOMTOM_A_RX_LINE_3_TEST__POR,
-	[TOMTOM_A_RX_LINE_3_DAC_CTL] = TOMTOM_A_RX_LINE_3_DAC_CTL__POR,
-	[TOMTOM_A_RX_LINE_3_STATUS] = TOMTOM_A_RX_LINE_3_STATUS__POR,
-	[TOMTOM_A_RX_LINE_4_GAIN] = TOMTOM_A_RX_LINE_4_GAIN__POR,
-	[TOMTOM_A_RX_LINE_4_TEST] = TOMTOM_A_RX_LINE_4_TEST__POR,
-	[TOMTOM_A_RX_LINE_4_DAC_CTL] = TOMTOM_A_RX_LINE_4_DAC_CTL__POR,
-	[TOMTOM_A_RX_LINE_4_STATUS] = TOMTOM_A_RX_LINE_4_STATUS__POR,
-	[TOMTOM_A_RX_LINE_CNP_DBG] = TOMTOM_A_RX_LINE_CNP_DBG__POR,
-	[TOMTOM_A_SPKR_DRV1_EN] = TOMTOM_A_SPKR_DRV1_EN__POR,
-	[TOMTOM_A_SPKR_DRV1_GAIN] = TOMTOM_A_SPKR_DRV1_GAIN__POR,
-	[TOMTOM_A_SPKR_DRV1_DAC_CTL] = TOMTOM_A_SPKR_DRV1_DAC_CTL__POR,
-	[TOMTOM_A_SPKR_DRV1_OCP_CTL] = TOMTOM_A_SPKR_DRV1_OCP_CTL__POR,
-	[TOMTOM_A_SPKR_DRV1_CLIP_DET] = TOMTOM_A_SPKR_DRV1_CLIP_DET__POR,
-	[TOMTOM_A_SPKR_DRV1_IEC] = TOMTOM_A_SPKR_DRV1_IEC__POR,
-	[TOMTOM_A_SPKR_DRV1_DBG_DAC] = TOMTOM_A_SPKR_DRV1_DBG_DAC__POR,
-	[TOMTOM_A_SPKR_DRV1_DBG_PA] = TOMTOM_A_SPKR_DRV1_DBG_PA__POR,
-	[TOMTOM_A_SPKR_DRV1_DBG_PWRSTG] = TOMTOM_A_SPKR_DRV1_DBG_PWRSTG__POR,
-	[TOMTOM_A_SPKR_DRV1_BIAS_LDO] = TOMTOM_A_SPKR_DRV1_BIAS_LDO__POR,
-	[TOMTOM_A_SPKR_DRV1_BIAS_INT] = TOMTOM_A_SPKR_DRV1_BIAS_INT__POR,
-	[TOMTOM_A_SPKR_DRV1_BIAS_PA] = TOMTOM_A_SPKR_DRV1_BIAS_PA__POR,
-	[TOMTOM_A_SPKR_DRV1_STATUS_OCP] = TOMTOM_A_SPKR_DRV1_STATUS_OCP__POR,
-	[TOMTOM_A_SPKR_DRV1_STATUS_PA] = TOMTOM_A_SPKR_DRV1_STATUS_PA__POR,
-	[TOMTOM_A_SPKR1_PROT_EN] = TOMTOM_A_SPKR1_PROT_EN__POR,
-	[TOMTOM_A_SPKR1_PROT_ADC_TEST_EN] =
-				TOMTOM_A_SPKR1_PROT_ADC_TEST_EN__POR,
-	[TOMTOM_A_SPKR1_PROT_ATEST] = TOMTOM_A_SPKR1_PROT_ATEST__POR,
-	[TOMTOM_A_SPKR1_PROT_LDO_CTRL] = TOMTOM_A_SPKR1_PROT_LDO_CTRL__POR,
-	[TOMTOM_A_SPKR1_PROT_ISENSE_CTRL] =
-				TOMTOM_A_SPKR1_PROT_ISENSE_CTRL__POR,
-	[TOMTOM_A_SPKR1_PROT_VSENSE_CTRL] =
-				TOMTOM_A_SPKR1_PROT_VSENSE_CTRL__POR,
-	[TOMTOM_A_SPKR2_PROT_EN] = TOMTOM_A_SPKR2_PROT_EN__POR,
-	[TOMTOM_A_SPKR2_PROT_ADC_TEST_EN] =
-				TOMTOM_A_SPKR2_PROT_ADC_TEST_EN__POR,
-	[TOMTOM_A_SPKR2_PROT_ATEST] = TOMTOM_A_SPKR2_PROT_ATEST__POR,
-	[TOMTOM_A_SPKR2_PROT_LDO_CTRL] = TOMTOM_A_SPKR2_PROT_LDO_CTRL__POR,
-	[TOMTOM_A_SPKR2_PROT_ISENSE_CTRL] =
-				TOMTOM_A_SPKR2_PROT_ISENSE_CTRL__POR,
-	[TOMTOM_A_SPKR2_PROT_VSENSE_CTRL] =
-				TOMTOM_A_SPKR2_PROT_VSENSE_CTRL__POR,
-	[TOMTOM_A_MBHC_HPH] = TOMTOM_A_MBHC_HPH__POR,
-	[TOMTOM_A_CDC_ANC1_B1_CTL] = TOMTOM_A_CDC_ANC1_B1_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_B1_CTL] = TOMTOM_A_CDC_ANC2_B1_CTL__POR,
-	[TOMTOM_A_CDC_ANC1_SHIFT] = TOMTOM_A_CDC_ANC1_SHIFT__POR,
-	[TOMTOM_A_CDC_ANC2_SHIFT] = TOMTOM_A_CDC_ANC2_SHIFT__POR,
-	[TOMTOM_A_CDC_ANC1_IIR_B1_CTL] = TOMTOM_A_CDC_ANC1_IIR_B1_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_IIR_B1_CTL] = TOMTOM_A_CDC_ANC2_IIR_B1_CTL__POR,
-	[TOMTOM_A_CDC_ANC1_IIR_B2_CTL] = TOMTOM_A_CDC_ANC1_IIR_B2_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_IIR_B2_CTL] = TOMTOM_A_CDC_ANC2_IIR_B2_CTL__POR,
-	[TOMTOM_A_CDC_ANC1_IIR_B3_CTL] = TOMTOM_A_CDC_ANC1_IIR_B3_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_IIR_B3_CTL] = TOMTOM_A_CDC_ANC2_IIR_B3_CTL__POR,
-	[TOMTOM_A_CDC_ANC1_LPF_B1_CTL] = TOMTOM_A_CDC_ANC1_LPF_B1_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_LPF_B1_CTL] = TOMTOM_A_CDC_ANC2_LPF_B1_CTL__POR,
-	[TOMTOM_A_CDC_ANC1_LPF_B2_CTL] = TOMTOM_A_CDC_ANC1_LPF_B2_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_LPF_B2_CTL] = TOMTOM_A_CDC_ANC2_LPF_B2_CTL__POR,
-	[TOMTOM_A_CDC_ANC1_SPARE] = TOMTOM_A_CDC_ANC1_SPARE__POR,
-	[TOMTOM_A_CDC_ANC2_SPARE] = TOMTOM_A_CDC_ANC2_SPARE__POR,
-	[TOMTOM_A_CDC_ANC1_SMLPF_CTL] = TOMTOM_A_CDC_ANC1_SMLPF_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_SMLPF_CTL] = TOMTOM_A_CDC_ANC2_SMLPF_CTL__POR,
-	[TOMTOM_A_CDC_ANC1_DCFLT_CTL] = TOMTOM_A_CDC_ANC1_DCFLT_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_DCFLT_CTL] = TOMTOM_A_CDC_ANC2_DCFLT_CTL__POR,
-	[TOMTOM_A_CDC_ANC1_GAIN_CTL] = TOMTOM_A_CDC_ANC1_GAIN_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_GAIN_CTL] = TOMTOM_A_CDC_ANC2_GAIN_CTL__POR,
-	[TOMTOM_A_CDC_ANC1_B2_CTL] = TOMTOM_A_CDC_ANC1_B2_CTL__POR,
-	[TOMTOM_A_CDC_ANC2_B2_CTL] = TOMTOM_A_CDC_ANC2_B2_CTL__POR,
-	[TOMTOM_A_CDC_TX1_VOL_CTL_TIMER] = TOMTOM_A_CDC_TX1_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX2_VOL_CTL_TIMER] = TOMTOM_A_CDC_TX2_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX3_VOL_CTL_TIMER] = TOMTOM_A_CDC_TX3_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX4_VOL_CTL_TIMER] = TOMTOM_A_CDC_TX4_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX5_VOL_CTL_TIMER] = TOMTOM_A_CDC_TX5_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX6_VOL_CTL_TIMER] = TOMTOM_A_CDC_TX6_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX7_VOL_CTL_TIMER] = TOMTOM_A_CDC_TX7_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX8_VOL_CTL_TIMER] = TOMTOM_A_CDC_TX8_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX9_VOL_CTL_TIMER] = TOMTOM_A_CDC_TX9_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX10_VOL_CTL_TIMER] =
-				TOMTOM_A_CDC_TX10_VOL_CTL_TIMER__POR,
-	[TOMTOM_A_CDC_TX1_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX1_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX2_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX2_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX3_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX3_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX4_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX4_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX5_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX5_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX6_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX6_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX7_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX7_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX8_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX8_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX9_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX9_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX10_VOL_CTL_GAIN] = TOMTOM_A_CDC_TX10_VOL_CTL_GAIN__POR,
-	[TOMTOM_A_CDC_TX1_VOL_CTL_CFG] = TOMTOM_A_CDC_TX1_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX2_VOL_CTL_CFG] = TOMTOM_A_CDC_TX2_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX3_VOL_CTL_CFG] = TOMTOM_A_CDC_TX3_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX4_VOL_CTL_CFG] = TOMTOM_A_CDC_TX4_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX5_VOL_CTL_CFG] = TOMTOM_A_CDC_TX5_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX6_VOL_CTL_CFG] = TOMTOM_A_CDC_TX6_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX7_VOL_CTL_CFG] = TOMTOM_A_CDC_TX7_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX8_VOL_CTL_CFG] = TOMTOM_A_CDC_TX8_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX9_VOL_CTL_CFG] = TOMTOM_A_CDC_TX9_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX10_VOL_CTL_CFG] = TOMTOM_A_CDC_TX10_VOL_CTL_CFG__POR,
-	[TOMTOM_A_CDC_TX1_MUX_CTL] = TOMTOM_A_CDC_TX1_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX2_MUX_CTL] = TOMTOM_A_CDC_TX2_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX3_MUX_CTL] = TOMTOM_A_CDC_TX3_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX4_MUX_CTL] = TOMTOM_A_CDC_TX4_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX5_MUX_CTL] = TOMTOM_A_CDC_TX5_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX6_MUX_CTL] = TOMTOM_A_CDC_TX6_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX7_MUX_CTL] = TOMTOM_A_CDC_TX7_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX8_MUX_CTL] = TOMTOM_A_CDC_TX8_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX9_MUX_CTL] = TOMTOM_A_CDC_TX9_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX10_MUX_CTL] = TOMTOM_A_CDC_TX10_MUX_CTL__POR,
-	[TOMTOM_A_CDC_TX1_CLK_FS_CTL] = TOMTOM_A_CDC_TX1_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX2_CLK_FS_CTL] = TOMTOM_A_CDC_TX2_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX3_CLK_FS_CTL] = TOMTOM_A_CDC_TX3_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX4_CLK_FS_CTL] = TOMTOM_A_CDC_TX4_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX5_CLK_FS_CTL] = TOMTOM_A_CDC_TX5_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX6_CLK_FS_CTL] = TOMTOM_A_CDC_TX6_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX7_CLK_FS_CTL] = TOMTOM_A_CDC_TX7_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX8_CLK_FS_CTL] = TOMTOM_A_CDC_TX8_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX9_CLK_FS_CTL] = TOMTOM_A_CDC_TX9_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX10_CLK_FS_CTL] = TOMTOM_A_CDC_TX10_CLK_FS_CTL__POR,
-	[TOMTOM_A_CDC_TX1_DMIC_CTL] = TOMTOM_A_CDC_TX1_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_TX2_DMIC_CTL] = TOMTOM_A_CDC_TX2_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_TX3_DMIC_CTL] = TOMTOM_A_CDC_TX3_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_TX4_DMIC_CTL] = TOMTOM_A_CDC_TX4_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_TX5_DMIC_CTL] = TOMTOM_A_CDC_TX5_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_TX6_DMIC_CTL] = TOMTOM_A_CDC_TX6_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_TX7_DMIC_CTL] = TOMTOM_A_CDC_TX7_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_TX8_DMIC_CTL] = TOMTOM_A_CDC_TX8_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_TX9_DMIC_CTL] = TOMTOM_A_CDC_TX9_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_TX10_DMIC_CTL] = TOMTOM_A_CDC_TX10_DMIC_CTL__POR,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL0] = TOMTOM_A_CDC_SPKR_CLIPDET_VAL0__POR,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL1] = TOMTOM_A_CDC_SPKR_CLIPDET_VAL1__POR,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL2] = TOMTOM_A_CDC_SPKR_CLIPDET_VAL2__POR,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL3] = TOMTOM_A_CDC_SPKR_CLIPDET_VAL3__POR,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL4] = TOMTOM_A_CDC_SPKR_CLIPDET_VAL4__POR,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL5] = TOMTOM_A_CDC_SPKR_CLIPDET_VAL5__POR,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL6] = TOMTOM_A_CDC_SPKR_CLIPDET_VAL6__POR,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_VAL7] = TOMTOM_A_CDC_SPKR_CLIPDET_VAL7__POR,
-	[TOMTOM_A_CDC_DEBUG_B1_CTL] = TOMTOM_A_CDC_DEBUG_B1_CTL__POR,
-	[TOMTOM_A_CDC_DEBUG_B2_CTL] = TOMTOM_A_CDC_DEBUG_B2_CTL__POR,
-	[TOMTOM_A_CDC_DEBUG_B3_CTL] = TOMTOM_A_CDC_DEBUG_B3_CTL__POR,
-	[TOMTOM_A_CDC_DEBUG_B4_CTL] = TOMTOM_A_CDC_DEBUG_B4_CTL__POR,
-	[TOMTOM_A_CDC_DEBUG_B5_CTL] = TOMTOM_A_CDC_DEBUG_B5_CTL__POR,
-	[TOMTOM_A_CDC_DEBUG_B6_CTL] = TOMTOM_A_CDC_DEBUG_B6_CTL__POR,
-	[TOMTOM_A_CDC_DEBUG_B7_CTL] = TOMTOM_A_CDC_DEBUG_B7_CTL__POR,
-	[TOMTOM_A_CDC_SRC1_PDA_CFG] = TOMTOM_A_CDC_SRC1_PDA_CFG__POR,
-	[TOMTOM_A_CDC_SRC2_PDA_CFG] = TOMTOM_A_CDC_SRC2_PDA_CFG__POR,
-	[TOMTOM_A_CDC_SRC1_FS_CTL] = TOMTOM_A_CDC_SRC1_FS_CTL__POR,
-	[TOMTOM_A_CDC_SRC2_FS_CTL] = TOMTOM_A_CDC_SRC2_FS_CTL__POR,
-	[TOMTOM_A_CDC_RX1_B1_CTL] = TOMTOM_A_CDC_RX1_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX2_B1_CTL] = TOMTOM_A_CDC_RX2_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX3_B1_CTL] = TOMTOM_A_CDC_RX3_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX4_B1_CTL] = TOMTOM_A_CDC_RX4_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX5_B1_CTL] = TOMTOM_A_CDC_RX5_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX6_B1_CTL] = TOMTOM_A_CDC_RX6_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX7_B1_CTL] = TOMTOM_A_CDC_RX7_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX1_B2_CTL] = TOMTOM_A_CDC_RX1_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX2_B2_CTL] = TOMTOM_A_CDC_RX2_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX3_B2_CTL] = TOMTOM_A_CDC_RX3_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX4_B2_CTL] = TOMTOM_A_CDC_RX4_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX5_B2_CTL] = TOMTOM_A_CDC_RX5_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX6_B2_CTL] = TOMTOM_A_CDC_RX6_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX7_B2_CTL] = TOMTOM_A_CDC_RX7_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX1_B3_CTL] = TOMTOM_A_CDC_RX1_B3_CTL__POR,
-	[TOMTOM_A_CDC_RX2_B3_CTL] = TOMTOM_A_CDC_RX2_B3_CTL__POR,
-	[TOMTOM_A_CDC_RX3_B3_CTL] = TOMTOM_A_CDC_RX3_B3_CTL__POR,
-	[TOMTOM_A_CDC_RX4_B3_CTL] = TOMTOM_A_CDC_RX4_B3_CTL__POR,
-	[TOMTOM_A_CDC_RX5_B3_CTL] = TOMTOM_A_CDC_RX5_B3_CTL__POR,
-	[TOMTOM_A_CDC_RX6_B3_CTL] = TOMTOM_A_CDC_RX6_B3_CTL__POR,
-	[TOMTOM_A_CDC_RX7_B3_CTL] = TOMTOM_A_CDC_RX7_B3_CTL__POR,
-	[TOMTOM_A_CDC_RX1_B4_CTL] = TOMTOM_A_CDC_RX1_B4_CTL__POR,
-	[TOMTOM_A_CDC_RX2_B4_CTL] = TOMTOM_A_CDC_RX2_B4_CTL__POR,
-	[TOMTOM_A_CDC_RX3_B4_CTL] = TOMTOM_A_CDC_RX3_B4_CTL__POR,
-	[TOMTOM_A_CDC_RX4_B4_CTL] = TOMTOM_A_CDC_RX4_B4_CTL__POR,
-	[TOMTOM_A_CDC_RX5_B4_CTL] = TOMTOM_A_CDC_RX5_B4_CTL__POR,
-	[TOMTOM_A_CDC_RX6_B4_CTL] = TOMTOM_A_CDC_RX6_B4_CTL__POR,
-	[TOMTOM_A_CDC_RX7_B4_CTL] = TOMTOM_A_CDC_RX7_B4_CTL__POR,
-	[TOMTOM_A_CDC_RX1_B5_CTL] = TOMTOM_A_CDC_RX1_B5_CTL__POR,
-	[TOMTOM_A_CDC_RX2_B5_CTL] = TOMTOM_A_CDC_RX2_B5_CTL__POR,
-	[TOMTOM_A_CDC_RX3_B5_CTL] = TOMTOM_A_CDC_RX3_B5_CTL__POR,
-	[TOMTOM_A_CDC_RX4_B5_CTL] = TOMTOM_A_CDC_RX4_B5_CTL__POR,
-	[TOMTOM_A_CDC_RX5_B5_CTL] = TOMTOM_A_CDC_RX5_B5_CTL__POR,
-	[TOMTOM_A_CDC_RX6_B5_CTL] = TOMTOM_A_CDC_RX6_B5_CTL__POR,
-	[TOMTOM_A_CDC_RX7_B5_CTL] = TOMTOM_A_CDC_RX7_B5_CTL__POR,
-	[TOMTOM_A_CDC_RX1_B6_CTL] = TOMTOM_A_CDC_RX1_B6_CTL__POR,
-	[TOMTOM_A_CDC_RX2_B6_CTL] = TOMTOM_A_CDC_RX2_B6_CTL__POR,
-	[TOMTOM_A_CDC_RX3_B6_CTL] = TOMTOM_A_CDC_RX3_B6_CTL__POR,
-	[TOMTOM_A_CDC_RX4_B6_CTL] = TOMTOM_A_CDC_RX4_B6_CTL__POR,
-	[TOMTOM_A_CDC_RX5_B6_CTL] = TOMTOM_A_CDC_RX5_B6_CTL__POR,
-	[TOMTOM_A_CDC_RX6_B6_CTL] = TOMTOM_A_CDC_RX6_B6_CTL__POR,
-	[TOMTOM_A_CDC_RX7_B6_CTL] = TOMTOM_A_CDC_RX7_B6_CTL__POR,
-	[TOMTOM_A_CDC_RX1_VOL_CTL_B1_CTL] =
-				TOMTOM_A_CDC_RX1_VOL_CTL_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX2_VOL_CTL_B1_CTL] =
-				TOMTOM_A_CDC_RX2_VOL_CTL_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX3_VOL_CTL_B1_CTL] =
-				TOMTOM_A_CDC_RX3_VOL_CTL_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX4_VOL_CTL_B1_CTL] =
-				TOMTOM_A_CDC_RX4_VOL_CTL_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX5_VOL_CTL_B1_CTL] =
-				TOMTOM_A_CDC_RX5_VOL_CTL_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX6_VOL_CTL_B1_CTL] =
-				TOMTOM_A_CDC_RX6_VOL_CTL_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX7_VOL_CTL_B1_CTL] =
-				TOMTOM_A_CDC_RX7_VOL_CTL_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL] =
-				TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL] =
-				TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL] =
-				TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL] =
-				TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL] =
-				TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL] =
-				TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL] =
-				TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL__POR,
-	[TOMTOM_A_CDC_VBAT_CFG] = TOMTOM_A_CDC_VBAT_CFG__POR,
-	[TOMTOM_A_CDC_VBAT_ADC_CAL1] = TOMTOM_A_CDC_VBAT_ADC_CAL1__POR,
-	[TOMTOM_A_CDC_VBAT_ADC_CAL2] = TOMTOM_A_CDC_VBAT_ADC_CAL2__POR,
-	[TOMTOM_A_CDC_VBAT_ADC_CAL3] = TOMTOM_A_CDC_VBAT_ADC_CAL3__POR,
-	[TOMTOM_A_CDC_VBAT_PK_EST1] = TOMTOM_A_CDC_VBAT_PK_EST1__POR,
-	[TOMTOM_A_CDC_VBAT_PK_EST2] = TOMTOM_A_CDC_VBAT_PK_EST2__POR,
-	[TOMTOM_A_CDC_VBAT_PK_EST3] = TOMTOM_A_CDC_VBAT_PK_EST3__POR,
-	[TOMTOM_A_CDC_VBAT_RF_PROC1] = TOMTOM_A_CDC_VBAT_RF_PROC1__POR,
-	[TOMTOM_A_CDC_VBAT_RF_PROC2] = TOMTOM_A_CDC_VBAT_RF_PROC2__POR,
-	[TOMTOM_A_CDC_VBAT_TAC1] = TOMTOM_A_CDC_VBAT_TAC1__POR,
-	[TOMTOM_A_CDC_VBAT_TAC2] = TOMTOM_A_CDC_VBAT_TAC2__POR,
-	[TOMTOM_A_CDC_VBAT_TAC3] = TOMTOM_A_CDC_VBAT_TAC3__POR,
-	[TOMTOM_A_CDC_VBAT_TAC4] = TOMTOM_A_CDC_VBAT_TAC4__POR,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD1] = TOMTOM_A_CDC_VBAT_GAIN_UPD1__POR,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD2] = TOMTOM_A_CDC_VBAT_GAIN_UPD2__POR,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD3] = TOMTOM_A_CDC_VBAT_GAIN_UPD3__POR,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD4] = TOMTOM_A_CDC_VBAT_GAIN_UPD4__POR,
-	[TOMTOM_A_CDC_VBAT_DEBUG1] = TOMTOM_A_CDC_VBAT_DEBUG1__POR,
-	[TOMTOM_A_CDC_VBAT_GAIN_UPD_MON] = TOMTOM_A_CDC_VBAT_GAIN_UPD_MON__POR,
-	[TOMTOM_A_CDC_VBAT_GAIN_MON_VAL] = TOMTOM_A_CDC_VBAT_GAIN_MON_VAL__POR,
-	[TOMTOM_A_CDC_CLK_ANC_RESET_CTL] = TOMTOM_A_CDC_CLK_ANC_RESET_CTL__POR,
-	[TOMTOM_A_CDC_CLK_RX_RESET_CTL] = TOMTOM_A_CDC_CLK_RX_RESET_CTL__POR,
-	[TOMTOM_A_CDC_CLK_TX_RESET_B1_CTL] =
-				TOMTOM_A_CDC_CLK_TX_RESET_B1_CTL__POR,
-	[TOMTOM_A_CDC_CLK_TX_RESET_B2_CTL] =
-				TOMTOM_A_CDC_CLK_TX_RESET_B2_CTL__POR,
-	[TOMTOM_A_CDC_CLK_RX_I2S_CTL] = TOMTOM_A_CDC_CLK_RX_I2S_CTL__POR,
-	[TOMTOM_A_CDC_CLK_TX_I2S_CTL] = TOMTOM_A_CDC_CLK_TX_I2S_CTL__POR,
-	[TOMTOM_A_CDC_CLK_OTHR_RESET_B1_CTL] =
-				TOMTOM_A_CDC_CLK_OTHR_RESET_B1_CTL__POR,
-	[TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL] =
-				TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL__POR,
-	[TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL] =
-				TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR,
-	[TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL] =
-				TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL__POR,
-	[TOMTOM_A_CDC_CLK_OTHR_CTL] = TOMTOM_A_CDC_CLK_OTHR_CTL__POR,
-	[TOMTOM_A_CDC_CLK_ANC_CLK_EN_CTL] =
-				TOMTOM_A_CDC_CLK_ANC_CLK_EN_CTL__POR,
-	[TOMTOM_A_CDC_CLK_RX_B1_CTL] = TOMTOM_A_CDC_CLK_RX_B1_CTL__POR,
-	[TOMTOM_A_CDC_CLK_RX_B2_CTL] = TOMTOM_A_CDC_CLK_RX_B2_CTL__POR,
-	[TOMTOM_A_CDC_CLK_MCLK_CTL] = TOMTOM_A_CDC_CLK_MCLK_CTL__POR,
-	[TOMTOM_A_CDC_CLK_PDM_CTL] = TOMTOM_A_CDC_CLK_PDM_CTL__POR,
-	[TOMTOM_A_CDC_CLK_SD_CTL] = TOMTOM_A_CDC_CLK_SD_CTL__POR,
-	[TOMTOM_A_CDC_CLSH_B1_CTL] = TOMTOM_A_CDC_CLSH_B1_CTL__POR,
-	[TOMTOM_A_CDC_CLSH_B2_CTL] = TOMTOM_A_CDC_CLSH_B2_CTL__POR,
-	[TOMTOM_A_CDC_CLSH_B3_CTL] = TOMTOM_A_CDC_CLSH_B3_CTL__POR,
-	[TOMTOM_A_CDC_CLSH_BUCK_NCP_VARS] =
-				TOMTOM_A_CDC_CLSH_BUCK_NCP_VARS__POR,
-	[TOMTOM_A_CDC_CLSH_IDLE_HPH_THSD] =
-				TOMTOM_A_CDC_CLSH_IDLE_HPH_THSD__POR,
-	[TOMTOM_A_CDC_CLSH_IDLE_EAR_THSD] =
-				TOMTOM_A_CDC_CLSH_IDLE_EAR_THSD__POR,
-	[TOMTOM_A_CDC_CLSH_FCLKONLY_HPH_THSD] =
-				TOMTOM_A_CDC_CLSH_FCLKONLY_HPH_THSD__POR,
-	[TOMTOM_A_CDC_CLSH_FCLKONLY_EAR_THSD] =
-				TOMTOM_A_CDC_CLSH_FCLKONLY_EAR_THSD__POR,
-	[TOMTOM_A_CDC_CLSH_K_ADDR] = TOMTOM_A_CDC_CLSH_K_ADDR__POR,
-	[TOMTOM_A_CDC_CLSH_K_DATA] = TOMTOM_A_CDC_CLSH_K_DATA__POR,
-	[TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_L] =
-				TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_L__POR,
-	[TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_U] =
-				TOMTOM_A_CDC_CLSH_I_PA_FACT_HPH_U__POR,
-	[TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_L] =
-				TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_L__POR,
-	[TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_U] =
-				TOMTOM_A_CDC_CLSH_I_PA_FACT_EAR_U__POR,
-	[TOMTOM_A_CDC_CLSH_V_PA_HD_EAR] = TOMTOM_A_CDC_CLSH_V_PA_HD_EAR__POR,
-	[TOMTOM_A_CDC_CLSH_V_PA_HD_HPH] = TOMTOM_A_CDC_CLSH_V_PA_HD_HPH__POR,
-	[TOMTOM_A_CDC_CLSH_V_PA_MIN_EAR] = TOMTOM_A_CDC_CLSH_V_PA_MIN_EAR__POR,
-	[TOMTOM_A_CDC_CLSH_V_PA_MIN_HPH] = TOMTOM_A_CDC_CLSH_V_PA_MIN_HPH__POR,
-	[TOMTOM_A_CDC_IIR1_GAIN_B1_CTL] = TOMTOM_A_CDC_IIR1_GAIN_B1_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_GAIN_B1_CTL] = TOMTOM_A_CDC_IIR2_GAIN_B1_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_GAIN_B2_CTL] = TOMTOM_A_CDC_IIR1_GAIN_B2_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_GAIN_B2_CTL] = TOMTOM_A_CDC_IIR2_GAIN_B2_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_GAIN_B3_CTL] = TOMTOM_A_CDC_IIR1_GAIN_B3_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_GAIN_B3_CTL] = TOMTOM_A_CDC_IIR2_GAIN_B3_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_GAIN_B4_CTL] = TOMTOM_A_CDC_IIR1_GAIN_B4_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_GAIN_B4_CTL] = TOMTOM_A_CDC_IIR2_GAIN_B4_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_GAIN_B5_CTL] = TOMTOM_A_CDC_IIR1_GAIN_B5_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_GAIN_B5_CTL] = TOMTOM_A_CDC_IIR2_GAIN_B5_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_GAIN_B6_CTL] = TOMTOM_A_CDC_IIR1_GAIN_B6_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_GAIN_B6_CTL] = TOMTOM_A_CDC_IIR2_GAIN_B6_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_GAIN_B7_CTL] = TOMTOM_A_CDC_IIR1_GAIN_B7_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_GAIN_B7_CTL] = TOMTOM_A_CDC_IIR2_GAIN_B7_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_GAIN_B8_CTL] = TOMTOM_A_CDC_IIR1_GAIN_B8_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_GAIN_B8_CTL] = TOMTOM_A_CDC_IIR2_GAIN_B8_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_CTL] = TOMTOM_A_CDC_IIR1_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_CTL] = TOMTOM_A_CDC_IIR2_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_GAIN_TIMER_CTL] =
-				TOMTOM_A_CDC_IIR1_GAIN_TIMER_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_GAIN_TIMER_CTL] =
-				TOMTOM_A_CDC_IIR2_GAIN_TIMER_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_COEF_B1_CTL] = TOMTOM_A_CDC_IIR1_COEF_B1_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_COEF_B1_CTL] = TOMTOM_A_CDC_IIR2_COEF_B1_CTL__POR,
-	[TOMTOM_A_CDC_IIR1_COEF_B2_CTL] = TOMTOM_A_CDC_IIR1_COEF_B2_CTL__POR,
-	[TOMTOM_A_CDC_IIR2_COEF_B2_CTL] = TOMTOM_A_CDC_IIR2_COEF_B2_CTL__POR,
-	[TOMTOM_A_CDC_TOP_GAIN_UPDATE] = TOMTOM_A_CDC_TOP_GAIN_UPDATE__POR,
-	[TOMTOM_A_CDC_PA_RAMP_B1_CTL] = TOMTOM_A_CDC_PA_RAMP_B1_CTL__POR,
-	[TOMTOM_A_CDC_PA_RAMP_B2_CTL] = TOMTOM_A_CDC_PA_RAMP_B2_CTL__POR,
-	[TOMTOM_A_CDC_PA_RAMP_B3_CTL] = TOMTOM_A_CDC_PA_RAMP_B3_CTL__POR,
-	[TOMTOM_A_CDC_PA_RAMP_B4_CTL] = TOMTOM_A_CDC_PA_RAMP_B4_CTL__POR,
-	[TOMTOM_A_CDC_SPKR_CLIPDET_B1_CTL] =
-				TOMTOM_A_CDC_SPKR_CLIPDET_B1_CTL__POR,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_B1_CTL] =
-				TOMTOM_A_CDC_SPKR2_CLIPDET_B1_CTL__POR,
-	[TOMTOM_A_CDC_COMP0_B1_CTL] = TOMTOM_A_CDC_COMP0_B1_CTL__POR,
-	[TOMTOM_A_CDC_COMP1_B1_CTL] = TOMTOM_A_CDC_COMP1_B1_CTL__POR,
-	[TOMTOM_A_CDC_COMP2_B1_CTL] = TOMTOM_A_CDC_COMP2_B1_CTL__POR,
-	[TOMTOM_A_CDC_COMP0_B2_CTL] = TOMTOM_A_CDC_COMP0_B2_CTL__POR,
-	[TOMTOM_A_CDC_COMP1_B2_CTL] = TOMTOM_A_CDC_COMP1_B2_CTL__POR,
-	[TOMTOM_A_CDC_COMP2_B2_CTL] = TOMTOM_A_CDC_COMP2_B2_CTL__POR,
-	[TOMTOM_A_CDC_COMP0_B3_CTL] = TOMTOM_A_CDC_COMP0_B3_CTL__POR,
-	[TOMTOM_A_CDC_COMP1_B3_CTL] = TOMTOM_A_CDC_COMP1_B3_CTL__POR,
-	[TOMTOM_A_CDC_COMP2_B3_CTL] = TOMTOM_A_CDC_COMP2_B3_CTL__POR,
-	[TOMTOM_A_CDC_COMP0_B4_CTL] = TOMTOM_A_CDC_COMP0_B4_CTL__POR,
-	[TOMTOM_A_CDC_COMP1_B4_CTL] = TOMTOM_A_CDC_COMP1_B4_CTL__POR,
-	[TOMTOM_A_CDC_COMP2_B4_CTL] = TOMTOM_A_CDC_COMP2_B4_CTL__POR,
-	[TOMTOM_A_CDC_COMP0_B5_CTL] = TOMTOM_A_CDC_COMP0_B5_CTL__POR,
-	[TOMTOM_A_CDC_COMP1_B5_CTL] = TOMTOM_A_CDC_COMP1_B5_CTL__POR,
-	[TOMTOM_A_CDC_COMP2_B5_CTL] = TOMTOM_A_CDC_COMP2_B5_CTL__POR,
-	[TOMTOM_A_CDC_COMP0_B6_CTL] = TOMTOM_A_CDC_COMP0_B6_CTL__POR,
-	[TOMTOM_A_CDC_COMP1_B6_CTL] = TOMTOM_A_CDC_COMP1_B6_CTL__POR,
-	[TOMTOM_A_CDC_COMP2_B6_CTL] = TOMTOM_A_CDC_COMP2_B6_CTL__POR,
-	[TOMTOM_A_CDC_COMP0_SHUT_DOWN_STATUS] =
-				TOMTOM_A_CDC_COMP0_SHUT_DOWN_STATUS__POR,
-	[TOMTOM_A_CDC_COMP1_SHUT_DOWN_STATUS] =
-				TOMTOM_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
-	[TOMTOM_A_CDC_COMP2_SHUT_DOWN_STATUS] =
-				TOMTOM_A_CDC_COMP2_SHUT_DOWN_STATUS__POR,
-	[TOMTOM_A_CDC_COMP0_FS_CFG] = TOMTOM_A_CDC_COMP0_FS_CFG__POR,
-	[TOMTOM_A_CDC_COMP1_FS_CFG] = TOMTOM_A_CDC_COMP1_FS_CFG__POR,
-	[TOMTOM_A_CDC_COMP2_FS_CFG] = TOMTOM_A_CDC_COMP2_FS_CFG__POR,
-	[TOMTOM_A_CDC_CONN_RX1_B1_CTL] = TOMTOM_A_CDC_CONN_RX1_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX1_B2_CTL] = TOMTOM_A_CDC_CONN_RX1_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX1_B3_CTL] = TOMTOM_A_CDC_CONN_RX1_B3_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX2_B1_CTL] = TOMTOM_A_CDC_CONN_RX2_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX2_B2_CTL] = TOMTOM_A_CDC_CONN_RX2_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX2_B3_CTL] = TOMTOM_A_CDC_CONN_RX2_B3_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX3_B1_CTL] = TOMTOM_A_CDC_CONN_RX3_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX3_B2_CTL] = TOMTOM_A_CDC_CONN_RX3_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX4_B1_CTL] = TOMTOM_A_CDC_CONN_RX4_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX4_B2_CTL] = TOMTOM_A_CDC_CONN_RX4_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX5_B1_CTL] = TOMTOM_A_CDC_CONN_RX5_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX5_B2_CTL] = TOMTOM_A_CDC_CONN_RX5_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX6_B1_CTL] = TOMTOM_A_CDC_CONN_RX6_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX6_B2_CTL] = TOMTOM_A_CDC_CONN_RX6_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX7_B1_CTL] = TOMTOM_A_CDC_CONN_RX7_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX7_B2_CTL] = TOMTOM_A_CDC_CONN_RX7_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX7_B3_CTL] = TOMTOM_A_CDC_CONN_RX7_B3_CTL__POR,
-	[TOMTOM_A_CDC_CONN_ANC_B1_CTL] = TOMTOM_A_CDC_CONN_ANC_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_ANC_B2_CTL] = TOMTOM_A_CDC_CONN_ANC_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_B1_CTL] = TOMTOM_A_CDC_CONN_TX_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_B2_CTL] = TOMTOM_A_CDC_CONN_TX_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_B3_CTL] = TOMTOM_A_CDC_CONN_TX_B3_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_B4_CTL] = TOMTOM_A_CDC_CONN_TX_B4_CTL__POR,
-	[TOMTOM_A_CDC_CONN_EQ1_B1_CTL] = TOMTOM_A_CDC_CONN_EQ1_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_EQ1_B2_CTL] = TOMTOM_A_CDC_CONN_EQ1_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_EQ1_B3_CTL] = TOMTOM_A_CDC_CONN_EQ1_B3_CTL__POR,
-	[TOMTOM_A_CDC_CONN_EQ1_B4_CTL] = TOMTOM_A_CDC_CONN_EQ1_B4_CTL__POR,
-	[TOMTOM_A_CDC_CONN_EQ2_B1_CTL] = TOMTOM_A_CDC_CONN_EQ2_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_EQ2_B2_CTL] = TOMTOM_A_CDC_CONN_EQ2_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_EQ2_B3_CTL] = TOMTOM_A_CDC_CONN_EQ2_B3_CTL__POR,
-	[TOMTOM_A_CDC_CONN_EQ2_B4_CTL] = TOMTOM_A_CDC_CONN_EQ2_B4_CTL__POR,
-	[TOMTOM_A_CDC_CONN_SRC1_B1_CTL] = TOMTOM_A_CDC_CONN_SRC1_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_SRC1_B2_CTL] = TOMTOM_A_CDC_CONN_SRC1_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_SRC2_B1_CTL] = TOMTOM_A_CDC_CONN_SRC2_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_SRC2_B2_CTL] = TOMTOM_A_CDC_CONN_SRC2_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B1_CTL] = TOMTOM_A_CDC_CONN_TX_SB_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B2_CTL] = TOMTOM_A_CDC_CONN_TX_SB_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B3_CTL] = TOMTOM_A_CDC_CONN_TX_SB_B3_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B4_CTL] = TOMTOM_A_CDC_CONN_TX_SB_B4_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B5_CTL] = TOMTOM_A_CDC_CONN_TX_SB_B5_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B6_CTL] = TOMTOM_A_CDC_CONN_TX_SB_B6_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B7_CTL] = TOMTOM_A_CDC_CONN_TX_SB_B7_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B8_CTL] = TOMTOM_A_CDC_CONN_TX_SB_B8_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B9_CTL] = TOMTOM_A_CDC_CONN_TX_SB_B9_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B10_CTL] =
-				TOMTOM_A_CDC_CONN_TX_SB_B10_CTL__POR,
-	[TOMTOM_A_CDC_CONN_TX_SB_B11_CTL] =
-				TOMTOM_A_CDC_CONN_TX_SB_B11_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX_SB_B1_CTL] = TOMTOM_A_CDC_CONN_RX_SB_B1_CTL__POR,
-	[TOMTOM_A_CDC_CONN_RX_SB_B2_CTL] = TOMTOM_A_CDC_CONN_RX_SB_B2_CTL__POR,
-	[TOMTOM_A_CDC_CONN_CLSH_CTL] = TOMTOM_A_CDC_CONN_CLSH_CTL__POR,
-	[TOMTOM_A_CDC_CONN_MISC] = TOMTOM_A_CDC_CONN_MISC__POR,
-	[TOMTOM_A_CDC_CONN_RX8_B1_CTL] = TOMTOM_A_CDC_CONN_RX8_B1_CTL__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_B1_CTL] =
-				TOMTOM_A_CDC_CLIP_ADJ_SPKR_B1_CTL__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_CLIP_LEVEL_ADJUST] =
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_CLIP_LEVEL_ADJUST__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_MIN_CLIP_THRESHOLD] =
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_MIN_CLIP_THRESHOLD__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_THRESHOLD_STATUS] =
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_THRESHOLD_STATUS__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_SAMPLE_MARK] =
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_SAMPLE_MARK__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR_BOOST_GATING] =
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR_BOOST_GATING__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_B1_CTL] =
-				TOMTOM_A_CDC_CLIP_ADJ_SPKR2_B1_CTL__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_CLIP_LEVEL_ADJUST] =
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR2_CLIP_LEVEL_ADJUST__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_MIN_CLIP_THRESHOLD] =
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR2_MIN_CLIP_THRESHOLD__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_THRESHOLD_STATUS] =
-			TOMTOM_A_CDC_CLIP_ADJ_SPKR2_THRESHOLD_STATUS__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_SAMPLE_MARK] =
-				TOMTOM_A_CDC_CLIP_ADJ_SPKR2_SAMPLE_MARK__POR,
-	[TOMTOM_A_CDC_CLIP_ADJ_SPKR2_BOOST_GATING] =
-				TOMTOM_A_CDC_CLIP_ADJ_SPKR2_BOOST_GATING__POR,
-	[TOMTOM_A_CDC_MBHC_EN_CTL] = TOMTOM_A_CDC_MBHC_EN_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_FIR_B1_CFG] = TOMTOM_A_CDC_MBHC_FIR_B1_CFG__POR,
-	[TOMTOM_A_CDC_MBHC_FIR_B2_CFG] = TOMTOM_A_CDC_MBHC_FIR_B2_CFG__POR,
-	[TOMTOM_A_CDC_MBHC_TIMER_B1_CTL] = TOMTOM_A_CDC_MBHC_TIMER_B1_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_TIMER_B2_CTL] = TOMTOM_A_CDC_MBHC_TIMER_B2_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_TIMER_B3_CTL] = TOMTOM_A_CDC_MBHC_TIMER_B3_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_TIMER_B4_CTL] = TOMTOM_A_CDC_MBHC_TIMER_B4_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_TIMER_B5_CTL] = TOMTOM_A_CDC_MBHC_TIMER_B5_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_TIMER_B6_CTL] = TOMTOM_A_CDC_MBHC_TIMER_B6_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_B1_STATUS] = TOMTOM_A_CDC_MBHC_B1_STATUS__POR,
-	[TOMTOM_A_CDC_MBHC_B2_STATUS] = TOMTOM_A_CDC_MBHC_B2_STATUS__POR,
-	[TOMTOM_A_CDC_MBHC_B3_STATUS] = TOMTOM_A_CDC_MBHC_B3_STATUS__POR,
-	[TOMTOM_A_CDC_MBHC_B4_STATUS] = TOMTOM_A_CDC_MBHC_B4_STATUS__POR,
-	[TOMTOM_A_CDC_MBHC_B5_STATUS] = TOMTOM_A_CDC_MBHC_B5_STATUS__POR,
-	[TOMTOM_A_CDC_MBHC_B1_CTL] = TOMTOM_A_CDC_MBHC_B1_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_B2_CTL] = TOMTOM_A_CDC_MBHC_B2_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B1_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B1_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B2_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B2_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B3_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B3_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B4_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B4_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B5_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B5_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B6_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B6_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B7_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B7_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B8_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B8_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B9_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B9_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B10_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B10_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B11_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B11_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_VOLT_B12_CTL] = TOMTOM_A_CDC_MBHC_VOLT_B12_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_CLK_CTL] = TOMTOM_A_CDC_MBHC_CLK_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_INT_CTL] = TOMTOM_A_CDC_MBHC_INT_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_DEBUG_CTL] = TOMTOM_A_CDC_MBHC_DEBUG_CTL__POR,
-	[TOMTOM_A_CDC_MBHC_SPARE] = TOMTOM_A_CDC_MBHC_SPARE__POR,
-	[TOMTOM_A_CDC_RX8_B1_CTL] = TOMTOM_A_CDC_RX8_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX8_B2_CTL] = TOMTOM_A_CDC_RX8_B2_CTL__POR,
-	[TOMTOM_A_CDC_RX8_B3_CTL] = TOMTOM_A_CDC_RX8_B3_CTL__POR,
-	[TOMTOM_A_CDC_RX8_B4_CTL] = TOMTOM_A_CDC_RX8_B4_CTL__POR,
-	[TOMTOM_A_CDC_RX8_B5_CTL] = TOMTOM_A_CDC_RX8_B5_CTL__POR,
-	[TOMTOM_A_CDC_RX8_B6_CTL] = TOMTOM_A_CDC_RX8_B6_CTL__POR,
-	[TOMTOM_A_CDC_RX8_VOL_CTL_B1_CTL] =
-				TOMTOM_A_CDC_RX8_VOL_CTL_B1_CTL__POR,
-	[TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL] =
-				TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL__POR,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL0] =
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL0__POR,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL1] =
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL1__POR,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL2] =
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL2__POR,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL3] =
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL3__POR,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL4] =
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL4__POR,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL5] =
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL5__POR,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL6] =
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL6__POR,
-	[TOMTOM_A_CDC_SPKR2_CLIPDET_VAL7] =
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL7__POR,
-	[TOMTOM_A_CDC_BOOST_MODE_CTL] = TOMTOM_A_CDC_BOOST_MODE_CTL__POR,
-	[TOMTOM_A_CDC_BOOST_THRESHOLD] = TOMTOM_A_CDC_BOOST_THRESHOLD__POR,
-	[TOMTOM_A_CDC_BOOST_TAP_SEL] = TOMTOM_A_CDC_BOOST_TAP_SEL__POR,
-	[TOMTOM_A_CDC_BOOST_HOLD_TIME] = TOMTOM_A_CDC_BOOST_HOLD_TIME__POR,
-	[TOMTOM_A_CDC_BOOST_TRGR_EN] = TOMTOM_A_CDC_BOOST_TRGR_EN__POR,
-};
diff --git a/sound/soc/codecs/wcd9330.c b/sound/soc/codecs/wcd9330.c
deleted file mode 100644
index 4278e36..0000000
--- a/sound/soc/codecs/wcd9330.c
+++ /dev/null
@@ -1,9113 +0,0 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/printk.h>
-#include <linux/ratelimit.h>
-#include <linux/debugfs.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/regmap.h>
-#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
-#include <linux/mfd/wcd9xxx/wcd9330_registers.h>
-#include <linux/mfd/wcd9xxx/pdata.h>
-#include <linux/regulator/consumer.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include "wcd9330.h"
-#include "wcd9xxx-resmgr.h"
-#include "wcd9xxx-common.h"
-#include "wcdcal-hwdep.h"
-#include "wcd_cpe_core.h"
-
-enum {
-	BUS_DOWN,
-	ADC1_TXFE,
-	ADC2_TXFE,
-	ADC3_TXFE,
-	ADC4_TXFE,
-	ADC5_TXFE,
-	ADC6_TXFE,
-	HPH_DELAY,
-};
-
-#define TOMTOM_MAD_SLIMBUS_TX_PORT 12
-#define TOMTOM_MAD_AUDIO_FIRMWARE_PATH "wcd9320/wcd9320_mad_audio.bin"
-#define TOMTOM_VALIDATE_RX_SBPORT_RANGE(port) ((port >= 16) && (port <= 23))
-#define TOMTOM_VALIDATE_TX_SBPORT_RANGE(port) ((port >= 0) && (port <= 15))
-#define TOMTOM_CONVERT_RX_SBPORT_ID(port) (port - 16) /* RX1 port ID = 0 */
-#define TOMTOM_BIT_ADJ_SHIFT_PORT1_6 4
-#define TOMTOM_BIT_ADJ_SHIFT_PORT7_10 5
-
-#define TOMTOM_HPH_PA_SETTLE_COMP_ON 10000
-#define TOMTOM_HPH_PA_SETTLE_COMP_OFF 13000
-#define TOMTOM_HPH_PA_RAMP_DELAY 30000
-
-#define TOMTOM_SVASS_INT_STATUS_RCO_WDOG 0x20
-#define TOMTOM_SVASS_INT_STATUS_WDOG_BITE 0x02
-
-/* Add any SVA IRQs that are to be treated as FATAL */
-#define TOMTOM_CPE_FATAL_IRQS \
-	(TOMTOM_SVASS_INT_STATUS_RCO_WDOG | \
-	 TOMTOM_SVASS_INT_STATUS_WDOG_BITE)
-
-#define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
-
-/* RX_HPH_CNP_WG_TIME increases by 0.24ms */
-#define TOMTOM_WG_TIME_FACTOR_US	240
-
-#define RX8_PATH 8
-#define HPH_PA_ENABLE true
-#define HPH_PA_DISABLE false
-
-#define SLIM_BW_CLK_GEAR_9 6200000
-#define SLIM_BW_UNVOTE 0
-
-static int cpe_debug_mode;
-module_param(cpe_debug_mode, int, 0664);
-MODULE_PARM_DESC(cpe_debug_mode, "boot cpe in debug mode");
-
-static atomic_t kp_tomtom_priv;
-
-static int high_perf_mode;
-module_param(high_perf_mode, int, 0664);
-MODULE_PARM_DESC(high_perf_mode, "enable/disable class AB config for hph");
-
-static struct afe_param_slimbus_slave_port_cfg tomtom_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
-};
-
-static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_CDC_MAD_MAIN_CTL_1),
-		HW_MAD_AUDIO_ENABLE, 0x1, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_CDC_MAD_AUDIO_CTL_3),
-		HW_MAD_AUDIO_SLEEP_TIME, 0xF, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_CDC_MAD_AUDIO_CTL_4),
-		HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR_MODE),
-		MAD_AUDIO_INT_DEST_SELECT_REG, 0x4, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR2_MASK0),
-		MAD_AUDIO_INT_MASK_REG, 0x2, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR2_STATUS0),
-		MAD_AUDIO_INT_STATUS_REG, 0x2, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR2_CLEAR0),
-		MAD_AUDIO_INT_CLEAR_REG, 0x2, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_SB_PGD_PORT_TX_BASE),
-		SB_PGD_PORT_TX_WATERMARK_N, 0x1E, 8, 0x1
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_SB_PGD_PORT_TX_BASE),
-		SB_PGD_PORT_TX_ENABLE_N, 0x1, 8, 0x1
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_SB_PGD_PORT_RX_BASE),
-		SB_PGD_PORT_RX_WATERMARK_N, 0x1E, 8, 0x1
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_SB_PGD_PORT_RX_BASE),
-		SB_PGD_PORT_RX_ENABLE_N, 0x1, 8, 0x1
-	},
-	{	1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_CDC_ANC1_IIR_B1_CTL),
-		AANC_FF_GAIN_ADAPTIVE, 0x4, 8, 0
-	},
-	{	1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_CDC_ANC1_IIR_B1_CTL),
-		AANC_FFGAIN_ADAPTIVE_EN, 0x8, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_CDC_ANC1_GAIN_CTL),
-		AANC_GAIN_CONTROL, 0xFF, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR2_MASK0),
-		MAD_CLIP_INT_MASK_REG, 0x10, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR2_MASK0),
-		MAD2_CLIP_INT_MASK_REG, 0x20, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR2_STATUS0),
-		MAD_CLIP_INT_STATUS_REG, 0x10, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR2_STATUS0),
-		MAD2_CLIP_INT_STATUS_REG, 0x20, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR2_CLEAR0),
-		MAD_CLIP_INT_CLEAR_REG, 0x10, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET + TOMTOM_A_INTR2_CLEAR0),
-		MAD2_CLIP_INT_CLEAR_REG, 0x20, 8, 0
-	},
-};
-
-static struct afe_param_cdc_reg_cfg clip_reg_cfg[] = {
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				 TOMTOM_A_CDC_SPKR_CLIPDET_B1_CTL),
-		SPKR_CLIP_PIPE_BANK_SEL, 0x3, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR_CLIPDET_VAL0),
-		SPKR_CLIPDET_VAL0, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR_CLIPDET_VAL1),
-		SPKR_CLIPDET_VAL1, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR_CLIPDET_VAL2),
-		SPKR_CLIPDET_VAL2, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR_CLIPDET_VAL3),
-		SPKR_CLIPDET_VAL3, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR_CLIPDET_VAL4),
-		SPKR_CLIPDET_VAL4, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR_CLIPDET_VAL5),
-		SPKR_CLIPDET_VAL5, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR_CLIPDET_VAL6),
-		SPKR_CLIPDET_VAL6, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR_CLIPDET_VAL7),
-		SPKR_CLIPDET_VAL7, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				 TOMTOM_A_CDC_SPKR2_CLIPDET_B1_CTL),
-		SPKR2_CLIP_PIPE_BANK_SEL, 0x3, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL0),
-		SPKR2_CLIPDET_VAL0, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL1),
-		SPKR2_CLIPDET_VAL1, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL2),
-		SPKR2_CLIPDET_VAL2, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL3),
-		SPKR2_CLIPDET_VAL3, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL4),
-		SPKR2_CLIPDET_VAL4, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL5),
-		SPKR2_CLIPDET_VAL5, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL6),
-		SPKR2_CLIPDET_VAL6, 0xff, 8, 0
-	},
-	{
-		1,
-		(TOMTOM_REGISTER_START_OFFSET +
-				TOMTOM_A_CDC_SPKR2_CLIPDET_VAL7),
-		SPKR2_CLIPDET_VAL7, 0xff, 8, 0
-	},
-};
-
-static struct afe_param_cdc_reg_cfg_data tomtom_audio_reg_cfg = {
-	.num_registers = ARRAY_SIZE(audio_reg_cfg),
-	.reg_data = audio_reg_cfg,
-};
-
-static struct afe_param_cdc_reg_cfg_data tomtom_clip_reg_cfg = {
-	.num_registers = ARRAY_SIZE(clip_reg_cfg),
-	.reg_data = clip_reg_cfg,
-};
-
-static struct afe_param_id_cdc_aanc_version tomtom_cdc_aanc_version = {
-	.cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
-	.aanc_hw_version        = AANC_HW_BLOCK_VERSION_2,
-};
-
-static struct afe_param_id_clip_bank_sel clip_bank_sel = {
-	.minor_version = AFE_API_VERSION_CLIP_BANK_SEL_CFG,
-	.num_banks = AFE_CLIP_MAX_BANKS,
-	.bank_map = {0, 1, 2, 3},
-};
-
-#define WCD9330_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
-			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
-			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
-
-#define NUM_DECIMATORS 10
-#define NUM_INTERPOLATORS 8
-#define BITS_PER_REG 8
-#define TOMTOM_TX_PORT_NUMBER	16
-#define TOMTOM_RX_PORT_START_NUMBER	16
-
-#define TOMTOM_I2S_MASTER_MODE_MASK 0x08
-
-#define TOMTOM_SLIM_CLOSE_TIMEOUT 1000
-#define TOMTOM_SLIM_IRQ_OVERFLOW (1 << 0)
-#define TOMTOM_SLIM_IRQ_UNDERFLOW (1 << 1)
-#define TOMTOM_SLIM_IRQ_PORT_CLOSED (1 << 2)
-#define TOMTOM_MCLK_CLK_12P288MHZ 12288000
-#define TOMTOM_MCLK_CLK_9P6MHZ 9600000
-
-#define TOMTOM_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
-			SNDRV_PCM_FORMAT_S24_LE)
-
-#define TOMTOM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
-
-#define TOMTOM_SLIM_PGD_PORT_INT_TX_EN0 (TOMTOM_SLIM_PGD_PORT_INT_EN0 + 2)
-#define TOMTOM_ZDET_BOX_CAR_AVG_LOOP_COUNT 1
-#define TOMTOM_ZDET_MUL_FACTOR_1X 7218
-#define TOMTOM_ZDET_MUL_FACTOR_10X (TOMTOM_ZDET_MUL_FACTOR_1X * 10)
-#define TOMTOM_ZDET_MUL_FACTOR_100X (TOMTOM_ZDET_MUL_FACTOR_1X * 100)
-#define TOMTOM_ZDET_ERROR_APPROX_MUL_FACTOR 655
-#define TOMTOM_ZDET_ERROR_APPROX_SHIFT 16
-#define TOMTOM_ZDET_ZONE_3_DEFAULT_VAL 1000000
-
-enum {
-	AIF1_PB = 0,
-	AIF1_CAP,
-	AIF2_PB,
-	AIF2_CAP,
-	AIF3_PB,
-	AIF3_CAP,
-	AIF4_VIFEED,
-	AIF4_MAD_TX,
-	NUM_CODEC_DAIS,
-};
-
-enum {
-	RX_MIX1_INP_SEL_ZERO = 0,
-	RX_MIX1_INP_SEL_SRC1,
-	RX_MIX1_INP_SEL_SRC2,
-	RX_MIX1_INP_SEL_IIR1,
-	RX_MIX1_INP_SEL_IIR2,
-	RX_MIX1_INP_SEL_RX1,
-	RX_MIX1_INP_SEL_RX2,
-	RX_MIX1_INP_SEL_RX3,
-	RX_MIX1_INP_SEL_RX4,
-	RX_MIX1_INP_SEL_RX5,
-	RX_MIX1_INP_SEL_RX6,
-	RX_MIX1_INP_SEL_RX7,
-	RX_MIX1_INP_SEL_AUXRX,
-};
-enum {
-	RX8_MIX1_INP_SEL_ZERO = 0,
-	RX8_MIX1_INP_SEL_IIR1,
-	RX8_MIX1_INP_SEL_IIR2,
-	RX8_MIX1_INP_SEL_RX1,
-	RX8_MIX1_INP_SEL_RX2,
-	RX8_MIX1_INP_SEL_RX3,
-	RX8_MIX1_INP_SEL_RX4,
-	RX8_MIX1_INP_SEL_RX5,
-	RX8_MIX1_INP_SEL_RX6,
-	RX8_MIX1_INP_SEL_RX7,
-	RX8_MIX1_INP_SEL_RX8,
-};
-
-#define TOMTOM_COMP_DIGITAL_GAIN_OFFSET 3
-
-static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
-static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
-static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
-static struct snd_soc_dai_driver tomtom_dai[];
-static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
-
-/* Codec supports 2 IIR filters */
-enum {
-	IIR1 = 0,
-	IIR2,
-	IIR_MAX,
-};
-/* Codec supports 5 bands */
-enum {
-	BAND1 = 0,
-	BAND2,
-	BAND3,
-	BAND4,
-	BAND5,
-	BAND_MAX,
-};
-
-enum {
-	COMPANDER_0,
-	COMPANDER_1,
-	COMPANDER_2,
-	COMPANDER_MAX,
-};
-
-enum {
-	COMPANDER_FS_8KHZ = 0,
-	COMPANDER_FS_16KHZ,
-	COMPANDER_FS_32KHZ,
-	COMPANDER_FS_48KHZ,
-	COMPANDER_FS_96KHZ,
-	COMPANDER_FS_192KHZ,
-	COMPANDER_FS_MAX,
-};
-
-struct comp_sample_dependent_params {
-	u32 peak_det_timeout;
-	u32 rms_meter_div_fact;
-	u32 rms_meter_resamp_fact;
-};
-
-struct hpf_work {
-	struct tomtom_priv *tomtom;
-	u32 decimator;
-	u8 tx_hpf_cut_of_freq;
-	bool tx_hpf_bypass;
-	struct delayed_work dwork;
-};
-
-static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
-
-static const struct wcd9xxx_ch tomtom_rx_chs[TOMTOM_RX_MAX] = {
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER, 0),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 1, 1),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 2, 2),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 3, 3),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 4, 4),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 5, 5),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 6, 6),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 7, 7),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 8, 8),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 9, 9),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 10, 10),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 11, 11),
-	WCD9XXX_CH(TOMTOM_RX_PORT_START_NUMBER + 12, 12),
-};
-
-static const struct wcd9xxx_ch tomtom_tx_chs[TOMTOM_TX_MAX] = {
-	WCD9XXX_CH(0, 0),
-	WCD9XXX_CH(1, 1),
-	WCD9XXX_CH(2, 2),
-	WCD9XXX_CH(3, 3),
-	WCD9XXX_CH(4, 4),
-	WCD9XXX_CH(5, 5),
-	WCD9XXX_CH(6, 6),
-	WCD9XXX_CH(7, 7),
-	WCD9XXX_CH(8, 8),
-	WCD9XXX_CH(9, 9),
-	WCD9XXX_CH(10, 10),
-	WCD9XXX_CH(11, 11),
-	WCD9XXX_CH(12, 12),
-	WCD9XXX_CH(13, 13),
-	WCD9XXX_CH(14, 14),
-	WCD9XXX_CH(15, 15),
-};
-
-static const u32 vport_check_table[NUM_CODEC_DAIS] = {
-	0,					/* AIF1_PB */
-	(1 << AIF2_CAP) | (1 << AIF3_CAP),	/* AIF1_CAP */
-	0,					/* AIF2_PB */
-	(1 << AIF1_CAP) | (1 << AIF3_CAP),	/* AIF2_CAP */
-	0,					/* AIF3_PB */
-	(1 << AIF1_CAP) | (1 << AIF2_CAP),	/* AIF3_CAP */
-};
-
-static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
-	0,	/* AIF1_PB */
-	0,	/* AIF1_CAP */
-	0,	/* AIF2_PB */
-	0,	/* AIF2_CAP */
-};
-
-/*
- * Interrupt table for v3 corresponds to newer version
- * codecs (wcd9330)
- */
-static const struct intr_data wcd9330_intr_tbl[] = {
-	{WCD9XXX_IRQ_SLIMBUS, false},
-	{WCD9XXX_IRQ_MBHC_INSERTION, true},
-	{WCD9XXX_IRQ_MBHC_POTENTIAL, true},
-	{WCD9XXX_IRQ_MBHC_RELEASE, true},
-	{WCD9XXX_IRQ_MBHC_PRESS, true},
-	{WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
-	{WCD9XXX_IRQ_MBHC_REMOVAL, true},
-	{WCD9330_IRQ_MBHC_JACK_SWITCH, true},
-	{WCD9XXX_IRQ_BG_PRECHARGE, false},
-	{WCD9XXX_IRQ_PA1_STARTUP, false},
-	{WCD9XXX_IRQ_PA2_STARTUP, false},
-	{WCD9XXX_IRQ_PA3_STARTUP, false},
-	{WCD9XXX_IRQ_PA4_STARTUP, false},
-	{WCD9XXX_IRQ_PA5_STARTUP, false},
-	{WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
-	{WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
-	{WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
-	{WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
-	{WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
-	{WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
-	{WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
-	{WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
-	{WCD9320_IRQ_EAR_PA_STARTUP, false},
-	{WCD9330_IRQ_SVASS_ERR_EXCEPTION, false},
-	{WCD9330_IRQ_SVASS_ENGINE, true},
-	{WCD9330_IRQ_MAD_AUDIO, false},
-	{WCD9330_IRQ_MAD_BEACON, false},
-	{WCD9330_IRQ_MAD_ULTRASOUND, false},
-	{WCD9330_IRQ_SPEAKER1_CLIPPING, false},
-	{WCD9330_IRQ_SPEAKER2_CLIPPING, false},
-	{WCD9330_IRQ_VBAT_MONITOR_ATTACK, false},
-	{WCD9330_IRQ_VBAT_MONITOR_RELEASE, false},
-};
-
-struct tomtom_priv {
-	struct snd_soc_codec *codec;
-	u32 adc_count;
-	u32 rx_bias_count;
-	s32 dmic_1_2_clk_cnt;
-	s32 dmic_3_4_clk_cnt;
-	s32 dmic_5_6_clk_cnt;
-	s32 ldo_h_users;
-	s32 micb_2_users;
-
-	u32 anc_slot;
-	bool anc_func;
-
-	/* cal info for codec */
-	struct fw_info *fw_data;
-
-	/*track tomtom interface type*/
-	u8 intf_type;
-
-	/* num of slim ports required */
-	struct wcd9xxx_codec_dai_data  dai[NUM_CODEC_DAIS];
-
-	/*compander*/
-	int comp_enabled[COMPANDER_MAX];
-	u32 comp_fs[COMPANDER_MAX];
-
-	/* Maintain the status of AUX PGA */
-	int aux_pga_cnt;
-	u8 aux_l_gain;
-	u8 aux_r_gain;
-
-	bool spkr_pa_widget_on;
-	struct regulator *spkdrv_reg;
-	struct regulator *spkdrv2_reg;
-
-	bool mbhc_started;
-
-	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
-
-	/* resmgr module */
-	struct wcd9xxx_resmgr resmgr;
-	/* mbhc module */
-	struct wcd9xxx_mbhc mbhc;
-
-	/* class h specific data */
-	struct wcd9xxx_clsh_cdc_data clsh_d;
-
-	int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
-			enum wcd9xxx_codec_event);
-	int (*codec_ext_clk_en_cb)(struct snd_soc_codec *codec,
-			int enable, bool dapm);
-	int (*codec_get_ext_clk_cnt)(void);
-	/*
-	 * list used to save/restore registers at start and
-	 * end of impedance measurement
-	 */
-	struct list_head reg_save_restore;
-
-	/* handle to cpe core */
-	struct wcd_cpe_core *cpe_core;
-
-	/* UHQA (class AB) mode */
-	u8 uhqa_mode;
-
-	/* Multiplication factor used for impedance detection */
-	int zdet_gain_mul_fact;
-
-	/* to track the status */
-	unsigned long status_mask;
-
-	int ext_clk_users;
-	struct clk *wcd_ext_clk;
-
-	/* Port values for Rx and Tx codec_dai */
-	unsigned int rx_port_value;
-	unsigned int tx_port_value;
-
-	struct mutex codec_mutex;
-};
-
-static const u32 comp_shift[] = {
-	4, /* Compander 0's clock source is on interpolator 7 */
-	0,
-	2,
-};
-
-static const int comp_rx_path[] = {
-	COMPANDER_1,
-	COMPANDER_1,
-	COMPANDER_2,
-	COMPANDER_2,
-	COMPANDER_2,
-	COMPANDER_2,
-	COMPANDER_0,
-	COMPANDER_0,
-	COMPANDER_MAX,
-};
-
-static const struct comp_sample_dependent_params comp_samp_params[] = {
-	{
-		/* 8 Khz */
-		.peak_det_timeout = 0x06,
-		.rms_meter_div_fact = 0x09,
-		.rms_meter_resamp_fact = 0x06,
-	},
-	{
-		/* 16 Khz */
-		.peak_det_timeout = 0x07,
-		.rms_meter_div_fact = 0x0A,
-		.rms_meter_resamp_fact = 0x0C,
-	},
-	{
-		/* 32 Khz */
-		.peak_det_timeout = 0x08,
-		.rms_meter_div_fact = 0x0B,
-		.rms_meter_resamp_fact = 0x1E,
-	},
-	{
-		/* 48 Khz */
-		.peak_det_timeout = 0x09,
-		.rms_meter_div_fact = 0x0B,
-		.rms_meter_resamp_fact = 0x28,
-	},
-	{
-		/* 96 Khz */
-		.peak_det_timeout = 0x0A,
-		.rms_meter_div_fact = 0x0C,
-		.rms_meter_resamp_fact = 0x50,
-	},
-	{
-		/* 192 Khz */
-		.peak_det_timeout = 0x0B,
-		.rms_meter_div_fact = 0xC,
-		.rms_meter_resamp_fact = 0xA0,
-	},
-};
-
-static unsigned short rx_digital_gain_reg[] = {
-	TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL,
-	TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL,
-	TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL,
-	TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL,
-	TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL,
-	TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL,
-	TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL,
-	TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL,
-};
-
-
-static unsigned short tx_digital_gain_reg[] = {
-	TOMTOM_A_CDC_TX1_VOL_CTL_GAIN,
-	TOMTOM_A_CDC_TX2_VOL_CTL_GAIN,
-	TOMTOM_A_CDC_TX3_VOL_CTL_GAIN,
-	TOMTOM_A_CDC_TX4_VOL_CTL_GAIN,
-	TOMTOM_A_CDC_TX5_VOL_CTL_GAIN,
-	TOMTOM_A_CDC_TX6_VOL_CTL_GAIN,
-	TOMTOM_A_CDC_TX7_VOL_CTL_GAIN,
-	TOMTOM_A_CDC_TX8_VOL_CTL_GAIN,
-	TOMTOM_A_CDC_TX9_VOL_CTL_GAIN,
-	TOMTOM_A_CDC_TX10_VOL_CTL_GAIN,
-};
-
-/*
- * wcd9330_get_codec_info: Get codec specific information
- *
- * @wcd9xxx: pointer to wcd9xxx structure
- * @wcd_type: pointer to wcd9xxx_codec_type structure
- *
- * Returns 0 for success or negative error code for failure
- */
-int wcd9330_get_codec_info(struct wcd9xxx *wcd9xxx,
-			   struct wcd9xxx_codec_type *wcd_type)
-{
-	u16 id_minor, id_major;
-	struct regmap *wcd_regmap;
-	int rc, val, version = 0;
-
-	if (!wcd9xxx || !wcd_type)
-		return -EINVAL;
-
-	if (!wcd9xxx->regmap) {
-		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
-			__func__);
-		return -EINVAL;
-	}
-	wcd_regmap = wcd9xxx->regmap;
-	rc = regmap_bulk_read(wcd_regmap, TOMTOM_A_CHIP_ID_BYTE_0,
-			      (u8 *)&id_minor, sizeof(u16));
-	if (rc)
-		return -EINVAL;
-
-	rc = regmap_bulk_read(wcd_regmap, TOMTOM_A_CHIP_ID_BYTE_2,
-			      (u8 *)&id_major, sizeof(u16));
-	if (rc)
-		return -EINVAL;
-
-	dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
-		 __func__, id_major, id_minor);
-
-	if (id_minor == cpu_to_le16(0x1))
-		version = 2;
-	else if (id_minor == cpu_to_le16(0x0))
-		version = 1;
-	else
-		dev_err(wcd9xxx->dev, "%s: wcd9330 version unknown (major 0x%x, minor 0x%x)\n",
-			__func__, id_major, id_minor);
-
-	/* Fill codec type info */
-	wcd_type->id_major = id_major;
-	wcd_type->id_minor = id_minor;
-	wcd_type->num_irqs = WCD9330_NUM_IRQS;
-	wcd_type->version = version;
-	wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
-	wcd_type->i2c_chip_status = 0x01;
-	wcd_type->intr_tbl = wcd9330_intr_tbl;
-	wcd_type->intr_tbl_size = ARRAY_SIZE(wcd9330_intr_tbl);
-
-	wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
-						TOMTOM_A_INTR1_STATUS0;
-	wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
-						TOMTOM_A_INTR1_CLEAR0;
-	wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
-						TOMTOM_A_INTR1_MASK0;
-	wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
-						TOMTOM_A_INTR1_LEVEL0;
-	wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
-						TOMTOM_A_INTR_MODE;
-
-	return rc;
-}
-EXPORT_SYMBOL(wcd9330_get_codec_info);
-
-/*
- * wcd9330_bringdown: Bringdown WCD Codec
- *
- * @wcd9xxx: Pointer to wcd9xxx structure
- *
- * Returns 0 for success or negative error code for failure
- */
-int wcd9330_bringdown(struct wcd9xxx *wcd9xxx)
-{
-	if (!wcd9xxx || !wcd9xxx->regmap)
-		return -EINVAL;
-
-	regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x7);
-	regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x6);
-	regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0xe);
-	regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x8);
-
-	return 0;
-}
-EXPORT_SYMBOL(wcd9330_bringdown);
-
-/*
- * wcd9330_bringup: Bring up WCD Codec
- *
- * @wcd9xxx: Pointer to wcd9xxx structure
- *
- * Returns 0 for success or negative error code for failure
- */
-int wcd9330_bringup(struct wcd9xxx *wcd9xxx)
-{
-	if (!wcd9xxx || !wcd9xxx->regmap)
-		return -EINVAL;
-
-	regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x4);
-	regmap_write(wcd9xxx->regmap, TOMTOM_A_CDC_CTL, 0x0);
-	/* wait for 5ms after codec reset for it to complete */
-	usleep_range(5000, 5100);
-	regmap_write(wcd9xxx->regmap, TOMTOM_A_CDC_CTL, 0x1);
-	regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x3);
-	regmap_write(wcd9xxx->regmap, TOMTOM_A_CDC_CTL, 0x3);
-
-	return 0;
-}
-EXPORT_SYMBOL(wcd9330_bringup);
-
-int tomtom_enable_qfuse_sensing(struct snd_soc_codec *codec)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	if (tomtom->wcd_ext_clk)
-		tomtom_codec_mclk_enable(codec, true, false);
-
-	snd_soc_write(codec, TOMTOM_A_QFUSE_CTL, 0x03);
-	/*
-	 * 5ms sleep required after enabling qfuse control
-	 * before checking the status.
-	 */
-	usleep_range(5000, 5500);
-	if ((snd_soc_read(codec, TOMTOM_A_QFUSE_STATUS) & (0x03)) != 0x03)
-		WARN(1, "%s: Qfuse sense is not complete\n", __func__);
-
-	if (tomtom->wcd_ext_clk)
-		tomtom_codec_mclk_enable(codec, false, false);
-	return 0;
-}
-EXPORT_SYMBOL(tomtom_enable_qfuse_sensing);
-
-static int tomtom_get_sample_rate(struct snd_soc_codec *codec, int path)
-{
-	if (path == RX8_PATH)
-		return snd_soc_read(codec, TOMTOM_A_CDC_RX8_B5_CTL);
-	else
-		return snd_soc_read(codec,
-			(TOMTOM_A_CDC_RX1_B5_CTL + 8 * (path - 1)));
-}
-
-static int tomtom_compare_bit_format(struct snd_soc_codec *codec,
-				int bit_format)
-{
-	int i = 0;
-	int ret = 0;
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-
-	for (i = 0; i < NUM_CODEC_DAIS; i++) {
-		if (tomtom_p->dai[i].bit_width == bit_format) {
-			ret = 1;
-			break;
-		}
-	}
-	return ret;
-}
-
-static int tomtom_update_uhqa_mode(struct snd_soc_codec *codec, int path)
-{
-	int ret = 0;
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-
-	/* UHQA path has fs=192KHz & bit=24 bit */
-	if (((tomtom_get_sample_rate(codec, path) & 0xE0) == 0xA0) &&
-		(tomtom_compare_bit_format(codec, 24))) {
-		tomtom_p->uhqa_mode = 1;
-	} else {
-		tomtom_p->uhqa_mode = 0;
-	}
-	dev_dbg(codec->dev, "%s: uhqa_mode=%d", __func__, tomtom_p->uhqa_mode);
-	return ret;
-}
-
-static int tomtom_get_anc_slot(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.integer.value[0] = tomtom->anc_slot;
-	return 0;
-}
-
-static int tomtom_put_anc_slot(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	tomtom->anc_slot = ucontrol->value.integer.value[0];
-	return 0;
-}
-
-static int tomtom_get_anc_func(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.integer.value[0] = (tomtom->anc_func == true ? 1 : 0);
-	return 0;
-}
-
-static int tomtom_put_anc_func(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm =
-				snd_soc_codec_get_dapm(codec);
-
-	mutex_lock(&tomtom->codec_mutex);
-	tomtom->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
-
-	dev_dbg(codec->dev, "%s: anc_func %x", __func__, tomtom->anc_func);
-
-	if (tomtom->anc_func == true) {
-		snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
-		snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
-		snd_soc_dapm_enable_pin(dapm, "ANC HEADPHONE");
-		snd_soc_dapm_enable_pin(dapm, "ANC EAR PA");
-		snd_soc_dapm_enable_pin(dapm, "ANC EAR");
-		snd_soc_dapm_disable_pin(dapm, "HPHR");
-		snd_soc_dapm_disable_pin(dapm, "HPHL");
-		snd_soc_dapm_disable_pin(dapm, "HEADPHONE");
-		snd_soc_dapm_disable_pin(dapm, "EAR PA");
-		snd_soc_dapm_disable_pin(dapm, "EAR");
-	} else {
-		snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
-		snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
-		snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
-		snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
-		snd_soc_dapm_disable_pin(dapm, "ANC EAR");
-		snd_soc_dapm_enable_pin(dapm, "HPHR");
-		snd_soc_dapm_enable_pin(dapm, "HPHL");
-		snd_soc_dapm_enable_pin(dapm, "HEADPHONE");
-		snd_soc_dapm_enable_pin(dapm, "EAR PA");
-		snd_soc_dapm_enable_pin(dapm, "EAR");
-	}
-	mutex_unlock(&tomtom->codec_mutex);
-	snd_soc_dapm_sync(dapm);
-	return 0;
-}
-
-static int tomtom_get_iir_enable_audio_mixer(
-					struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	int iir_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int band_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-
-	ucontrol->value.integer.value[0] =
-		(snd_soc_read(codec, (TOMTOM_A_CDC_IIR1_CTL + 16 * iir_idx)) &
-		(1 << band_idx)) != 0;
-
-	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
-		iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[0]);
-	return 0;
-}
-
-static int tomtom_put_iir_enable_audio_mixer(
-					struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	int iir_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int band_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-	int value = ucontrol->value.integer.value[0];
-
-	/* Mask first 5 bits, 6-8 are reserved */
-	snd_soc_update_bits(codec, (TOMTOM_A_CDC_IIR1_CTL + 16 * iir_idx),
-		(1 << band_idx), (value << band_idx));
-
-	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
-		iir_idx, band_idx,
-		((snd_soc_read(codec, (TOMTOM_A_CDC_IIR1_CTL + 16 * iir_idx)) &
-		(1 << band_idx)) != 0));
-	return 0;
-}
-static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
-				int iir_idx, int band_idx,
-				int coeff_idx)
-{
-	uint32_t value = 0;
-
-	/* Address does not automatically update if reading */
-	snd_soc_write(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
-		((band_idx * BAND_MAX + coeff_idx)
-		* sizeof(uint32_t)) & 0x7F);
-
-	value |= snd_soc_read(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx));
-
-	snd_soc_write(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
-		((band_idx * BAND_MAX + coeff_idx)
-		* sizeof(uint32_t) + 1) & 0x7F);
-
-	value |= (snd_soc_read(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 8);
-
-	snd_soc_write(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
-		((band_idx * BAND_MAX + coeff_idx)
-		* sizeof(uint32_t) + 2) & 0x7F);
-
-	value |= (snd_soc_read(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 16);
-
-	snd_soc_write(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
-		((band_idx * BAND_MAX + coeff_idx)
-		* sizeof(uint32_t) + 3) & 0x7F);
-
-	/* Mask bits top 2 bits since they are reserved */
-	value |= ((snd_soc_read(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) & 0x3F) << 24);
-
-	return value;
-}
-
-static int tomtom_get_iir_band_audio_mixer(
-					struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	int iir_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int band_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-
-	ucontrol->value.integer.value[0] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 0);
-	ucontrol->value.integer.value[1] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 1);
-	ucontrol->value.integer.value[2] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 2);
-	ucontrol->value.integer.value[3] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 3);
-	ucontrol->value.integer.value[4] =
-		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
-
-	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
-		"%s: IIR #%d band #%d b1 = 0x%x\n"
-		"%s: IIR #%d band #%d b2 = 0x%x\n"
-		"%s: IIR #%d band #%d a1 = 0x%x\n"
-		"%s: IIR #%d band #%d a2 = 0x%x\n",
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[0],
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[1],
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[2],
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[3],
-		__func__, iir_idx, band_idx,
-		(uint32_t)ucontrol->value.integer.value[4]);
-	return 0;
-}
-
-static void set_iir_band_coeff(struct snd_soc_codec *codec,
-				int iir_idx, int band_idx,
-				uint32_t value)
-{
-	snd_soc_write(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
-		(value & 0xFF));
-
-	snd_soc_write(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
-		(value >> 8) & 0xFF);
-
-	snd_soc_write(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
-		(value >> 16) & 0xFF);
-
-	/* Mask top 2 bits, 7-8 are reserved */
-	snd_soc_write(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
-		(value >> 24) & 0x3F);
-}
-
-static int tomtom_put_iir_band_audio_mixer(
-					struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	int iir_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->reg;
-	int band_idx = ((struct soc_multi_mixer_control *)
-					kcontrol->private_value)->shift;
-
-	/* Mask top bit it is reserved */
-	/* Updates addr automatically for each B2 write */
-	snd_soc_write(codec,
-		(TOMTOM_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
-		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
-
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[0]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[1]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[2]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[3]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[4]);
-
-	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
-		"%s: IIR #%d band #%d b1 = 0x%x\n"
-		"%s: IIR #%d band #%d b2 = 0x%x\n"
-		"%s: IIR #%d band #%d a1 = 0x%x\n"
-		"%s: IIR #%d band #%d a2 = 0x%x\n",
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 0),
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 1),
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 2),
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 3),
-		__func__, iir_idx, band_idx,
-		get_iir_band_coeff(codec, iir_idx, band_idx, 4));
-	return 0;
-}
-
-static int tomtom_get_compander(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	int comp = ((struct soc_multi_mixer_control *)
-		    kcontrol->private_value)->shift;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.integer.value[0] = tomtom->comp_enabled[comp];
-	return 0;
-}
-
-static int tomtom_set_compander(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	int comp = ((struct soc_multi_mixer_control *)
-		    kcontrol->private_value)->shift;
-	int value = ucontrol->value.integer.value[0];
-
-	pr_debug("%s: Compander %d enable current %d, new %d\n",
-		 __func__, comp, tomtom->comp_enabled[comp], value);
-	tomtom->comp_enabled[comp] = value;
-
-	if (comp == COMPANDER_1 &&
-			tomtom->comp_enabled[comp] == 1) {
-		/* Wavegen to 5 msec */
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_CNP_WG_CTL, 0xDB);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_CNP_WG_TIME, 0x2A);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_BIAS_WG_OCP, 0x2A);
-
-		/* Enable Chopper */
-		snd_soc_update_bits(codec,
-			TOMTOM_A_RX_HPH_CHOP_CTL, 0x80, 0x80);
-
-		snd_soc_write(codec, TOMTOM_A_NCP_DTEST, 0x20);
-		pr_debug("%s: Enabled Chopper and set wavegen to 5 msec\n",
-				__func__);
-	} else if (comp == COMPANDER_1 &&
-			tomtom->comp_enabled[comp] == 0) {
-		/* Wavegen to 20 msec */
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_CNP_WG_CTL, 0xDB);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_CNP_WG_TIME, 0x58);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_BIAS_WG_OCP, 0x1A);
-
-		/* Disable CHOPPER block */
-		snd_soc_update_bits(codec,
-			TOMTOM_A_RX_HPH_CHOP_CTL, 0x80, 0x00);
-
-		snd_soc_write(codec, TOMTOM_A_NCP_DTEST, 0x10);
-		pr_debug("%s: Disabled Chopper and set wavegen to 20 msec\n",
-				__func__);
-	}
-	return 0;
-}
-
-static int tomtom_config_gain_compander(struct snd_soc_codec *codec,
-				       int comp, bool enable)
-{
-	int ret = 0;
-
-	switch (comp) {
-	case COMPANDER_0:
-		snd_soc_update_bits(codec, TOMTOM_A_SPKR_DRV1_GAIN,
-				    1 << 2, !enable << 2);
-		snd_soc_update_bits(codec, TOMTOM_A_SPKR_DRV2_GAIN,
-				    1 << 2, !enable << 2);
-		break;
-	case COMPANDER_1:
-		snd_soc_update_bits(codec, TOMTOM_A_RX_HPH_L_GAIN,
-				    1 << 5, !enable << 5);
-		snd_soc_update_bits(codec, TOMTOM_A_RX_HPH_R_GAIN,
-				    1 << 5, !enable << 5);
-		break;
-	case COMPANDER_2:
-		snd_soc_update_bits(codec, TOMTOM_A_RX_LINE_1_GAIN,
-				    1 << 5, !enable << 5);
-		snd_soc_update_bits(codec, TOMTOM_A_RX_LINE_3_GAIN,
-				    1 << 5, !enable << 5);
-		snd_soc_update_bits(codec, TOMTOM_A_RX_LINE_2_GAIN,
-				    1 << 5, !enable << 5);
-		snd_soc_update_bits(codec, TOMTOM_A_RX_LINE_4_GAIN,
-				    1 << 5, !enable << 5);
-		break;
-	default:
-		WARN_ON(1);
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static void tomtom_discharge_comp(struct snd_soc_codec *codec, int comp)
-{
-	/* Level meter DIV Factor to 5*/
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_COMP0_B2_CTL + (comp * 8), 0xF0,
-			    0x05 << 4);
-	/* RMS meter Sampling to 0x01 */
-	snd_soc_write(codec, TOMTOM_A_CDC_COMP0_B3_CTL + (comp * 8), 0x01);
-
-	/* Worst case timeout for compander CnP sleep timeout */
-	usleep_range(3000, 3100);
-}
-
-static enum wcd9xxx_buck_volt tomtom_codec_get_buck_mv(
-	struct snd_soc_codec *codec)
-{
-	int buck_volt = WCD9XXX_CDC_BUCK_UNSUPPORTED;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx_pdata *pdata = tomtom->resmgr.pdata;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
-		if (!strcmp(pdata->regulator[i].name,
-					 WCD9XXX_SUPPLY_BUCK_NAME)) {
-			if ((pdata->regulator[i].min_uV ==
-					WCD9XXX_CDC_BUCK_MV_1P8) ||
-				(pdata->regulator[i].min_uV ==
-					WCD9XXX_CDC_BUCK_MV_2P15))
-				buck_volt = pdata->regulator[i].min_uV;
-			break;
-		}
-	}
-	return buck_volt;
-}
-
-static int tomtom_config_compander(struct snd_soc_dapm_widget *w,
-				  struct snd_kcontrol *kcontrol, int event)
-{
-	int mask, enable_mask;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	const int comp = w->shift;
-	const u32 rate = tomtom->comp_fs[comp];
-	const struct comp_sample_dependent_params *comp_params =
-	    &comp_samp_params[rate];
-	enum wcd9xxx_buck_volt buck_mv;
-
-	pr_debug("%s: %s event %d compander %d, enabled %d", __func__,
-		 w->name, event, comp, tomtom->comp_enabled[comp]);
-
-	if (!tomtom->comp_enabled[comp])
-		return 0;
-
-	/* Compander 0 has two channels */
-	mask = enable_mask = 0x03;
-	buck_mv = tomtom_codec_get_buck_mv(codec);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		/* Set compander Sample rate */
-		snd_soc_update_bits(codec,
-				    TOMTOM_A_CDC_COMP0_FS_CFG + (comp * 8),
-				    0x07, rate);
-		/* Set the static gain offset for HPH Path */
-		if (comp == COMPANDER_1) {
-			if (buck_mv == WCD9XXX_CDC_BUCK_MV_2P15) {
-				snd_soc_update_bits(codec,
-					TOMTOM_A_CDC_COMP0_B4_CTL + (comp * 8),
-					0x80, 0x00);
-			} else {
-				snd_soc_update_bits(codec,
-					TOMTOM_A_CDC_COMP0_B4_CTL + (comp * 8),
-					0x80, 0x80);
-			}
-		}
-		/* Enable RX interpolation path compander clocks */
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_RX_B2_CTL,
-				    mask << comp_shift[comp],
-				    mask << comp_shift[comp]);
-		/* Toggle compander reset bits */
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL,
-				    mask << comp_shift[comp],
-				    mask << comp_shift[comp]);
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL,
-				    mask << comp_shift[comp], 0);
-
-		/* Set gain source to compander */
-		tomtom_config_gain_compander(codec, comp, true);
-
-		/* Compander enable */
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_COMP0_B1_CTL +
-				    (comp * 8), enable_mask, enable_mask);
-
-		tomtom_discharge_comp(codec, comp);
-
-		/* Set sample rate dependent parameter */
-		snd_soc_write(codec, TOMTOM_A_CDC_COMP0_B3_CTL + (comp * 8),
-			      comp_params->rms_meter_resamp_fact);
-		snd_soc_update_bits(codec,
-				    TOMTOM_A_CDC_COMP0_B2_CTL + (comp * 8),
-				    0xF0, comp_params->rms_meter_div_fact << 4);
-		snd_soc_update_bits(codec,
-					TOMTOM_A_CDC_COMP0_B2_CTL + (comp * 8),
-					0x0F, comp_params->peak_det_timeout);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		/* Disable compander */
-		snd_soc_update_bits(codec,
-				    TOMTOM_A_CDC_COMP0_B1_CTL + (comp * 8),
-				    enable_mask, 0x00);
-
-		/* Toggle compander reset bits */
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL,
-				    mask << comp_shift[comp],
-				    mask << comp_shift[comp]);
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_OTHR_RESET_B2_CTL,
-				    mask << comp_shift[comp], 0);
-
-		/* Turn off the clock for compander in pair */
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_RX_B2_CTL,
-				    mask << comp_shift[comp], 0);
-
-		/* Set gain source to register */
-		tomtom_config_gain_compander(codec, comp, false);
-		break;
-	}
-	return 0;
-}
-
-
-
-static const char *const tomtom_anc_func_text[] = {"OFF", "ON"};
-static const struct soc_enum tomtom_anc_func_enum =
-		SOC_ENUM_SINGLE_EXT(2, tomtom_anc_func_text);
-
-static const char *const tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
-static const struct soc_enum tabla_ear_pa_gain_enum[] = {
-		SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
-};
-
-/*cut of frequency for high pass filter*/
-static const char * const cf_text[] = {
-	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
-};
-
-static const char * const rx_cf_text[] = {
-	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz",
-	"MIN_3DB_0P48Hz"
-};
-
-static const struct soc_enum cf_dec1_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec2_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec3_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec4_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec5_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec6_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec7_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec8_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec9_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec10_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_rxmix1_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_RX1_B4_CTL, 0, 4, rx_cf_text);
-
-static const struct soc_enum cf_rxmix2_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_RX2_B4_CTL, 0, 4, rx_cf_text);
-
-static const struct soc_enum cf_rxmix3_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_RX3_B4_CTL, 0, 4, rx_cf_text);
-
-static const struct soc_enum cf_rxmix4_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_RX4_B4_CTL, 0, 4, rx_cf_text);
-
-static const struct soc_enum cf_rxmix5_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_RX5_B4_CTL, 0, 4, rx_cf_text)
-;
-static const struct soc_enum cf_rxmix6_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_RX6_B4_CTL, 0, 4, rx_cf_text);
-
-static const struct soc_enum cf_rxmix7_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_RX7_B4_CTL, 0, 4, rx_cf_text);
-
-static const struct soc_enum cf_rxmix8_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_RX8_B4_CTL, 0, 4, rx_cf_text);
-
-static const char * const class_h_dsm_text[] = {
-	"ZERO", "DSM_HPHL_RX1", "DSM_SPKR_RX7"
-};
-
-static const struct soc_enum class_h_dsm_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_CLSH_CTL, 4, 3, class_h_dsm_text);
-
-static const struct snd_kcontrol_new class_h_dsm_mux =
-	SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
-
-static const char * const rx1_interp_text[] = {
-	"ZERO", "RX1 MIX2"
-};
-
-static const struct soc_enum rx1_interp_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CLK_RX_B1_CTL, 0, 2, rx1_interp_text);
-
-static const struct snd_kcontrol_new rx1_interp_mux =
-	SOC_DAPM_ENUM("RX1 INTERP MUX Mux", rx1_interp_enum);
-
-static const char * const rx2_interp_text[] = {
-	"ZERO", "RX2 MIX2"
-};
-
-static const struct soc_enum rx2_interp_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CLK_RX_B1_CTL, 1, 2, rx2_interp_text);
-
-static const struct snd_kcontrol_new rx2_interp_mux =
-	SOC_DAPM_ENUM("RX2 INTERP MUX Mux", rx2_interp_enum);
-
-static const char *const tomtom_conn_mad_text[] = {
-	"ADC_MB", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "NOTUSED1",
-	"DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6", "NOTUSED2",
-	"NOTUSED3"};
-
-static const struct soc_enum tomtom_conn_mad_enum =
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tomtom_conn_mad_text),
-			tomtom_conn_mad_text);
-
-
-static int tomtom_mad_input_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	u8 tomtom_mad_input;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
-	tomtom_mad_input = snd_soc_read(codec, TOMTOM_A_CDC_MAD_INP_SEL);
-
-	tomtom_mad_input = tomtom_mad_input & 0x0F;
-
-	ucontrol->value.integer.value[0] = tomtom_mad_input;
-
-	pr_debug("%s: tomtom_mad_input = %s\n", __func__,
-			tomtom_conn_mad_text[tomtom_mad_input]);
-
-	return 0;
-}
-
-static int tomtom_mad_input_put(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	u8 tomtom_mad_input;
-	u16 micb_int_reg, micb_4_int_reg;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct snd_soc_card *card = codec->component.card;
-	char mad_amic_input_widget[6];
-	u32 adc;
-	const char *mad_input_widget;
-	const char *source_widget = NULL;
-	u32  mic_bias_found = 0;
-	u32 i;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	int ret = 0;
-	char *mad_input;
-
-	tomtom_mad_input = ucontrol->value.integer.value[0];
-	micb_4_int_reg = tomtom->resmgr.reg_addr->micb_4_int_rbias;
-
-	if (tomtom_mad_input >= ARRAY_SIZE(tomtom_conn_mad_text)) {
-		dev_err(codec->dev,
-			"%s: tomtom_mad_input = %d out of bounds\n",
-			__func__, tomtom_mad_input);
-		return -EINVAL;
-	}
-
-	pr_debug("%s: tomtom_mad_input = %s\n", __func__,
-			tomtom_conn_mad_text[tomtom_mad_input]);
-
-	if (!strcmp(tomtom_conn_mad_text[tomtom_mad_input], "NOTUSED1") ||
-		!strcmp(tomtom_conn_mad_text[tomtom_mad_input], "NOTUSED2") ||
-		!strcmp(tomtom_conn_mad_text[tomtom_mad_input], "NOTUSED3") ||
-		!strcmp(tomtom_conn_mad_text[tomtom_mad_input], "ADC_MB")) {
-		pr_info("%s: tomtom mad input is set to unsupported input = %s\n",
-			__func__, tomtom_conn_mad_text[tomtom_mad_input]);
-		return -EINVAL;
-	}
-
-	if (strnstr(tomtom_conn_mad_text[tomtom_mad_input],
-				"ADC", sizeof("ADC"))) {
-		mad_input = strpbrk(tomtom_conn_mad_text[tomtom_mad_input],
-				"123456");
-		if (!mad_input) {
-			dev_err(codec->dev, "%s: Invalid MAD input %s\n",
-			__func__, tomtom_conn_mad_text[tomtom_mad_input]);
-			return -EINVAL;
-		}
-		ret = kstrtouint(mad_input, 10, &adc);
-		if ((ret < 0) || (adc > 6)) {
-			pr_err("%s: Invalid ADC = %s\n", __func__,
-				tomtom_conn_mad_text[tomtom_mad_input]);
-			ret =  -EINVAL;
-		}
-
-		snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc);
-
-		mad_input_widget = mad_amic_input_widget;
-		pr_debug("%s: tomtom amic input widget = %s\n", __func__,
-			  mad_amic_input_widget);
-	} else {
-		/* DMIC type input widget*/
-		mad_input_widget = tomtom_conn_mad_text[tomtom_mad_input];
-	}
-
-	pr_debug("%s: tomtom input widget = %s\n", __func__, mad_input_widget);
-
-	for (i = 0; i < card->num_dapm_routes; i++) {
-
-		if (!strcmp(card->dapm_routes[i].sink, mad_input_widget)) {
-
-			source_widget = card->dapm_routes[i].source;
-			if (!source_widget) {
-				dev_err(codec->dev,
-					"%s: invalid source widget\n",
-					__func__);
-				return -EINVAL;
-			}
-
-			if (strnstr(source_widget,
-				"MIC BIAS1", sizeof("MIC BIAS1"))) {
-				mic_bias_found = 1;
-				micb_int_reg = TOMTOM_A_MICB_1_INT_RBIAS;
-				break;
-			} else if (strnstr(source_widget,
-				"MIC BIAS2", sizeof("MIC BIAS2"))) {
-				mic_bias_found = 2;
-				micb_int_reg = TOMTOM_A_MICB_2_INT_RBIAS;
-				break;
-			} else if (strnstr(source_widget,
-				"MIC BIAS3", sizeof("MIC BIAS3"))) {
-				mic_bias_found = 3;
-				micb_int_reg = TOMTOM_A_MICB_3_INT_RBIAS;
-				break;
-			} else if (strnstr(source_widget,
-				"MIC BIAS4", sizeof("MIC BIAS4"))) {
-				mic_bias_found = 4;
-				micb_int_reg = micb_4_int_reg;
-				break;
-			}
-		}
-	}
-
-	if (mic_bias_found) {
-		pr_debug("%s: source mic bias = %s. sink = %s\n", __func__,
-				card->dapm_routes[i].source,
-				card->dapm_routes[i].sink);
-
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_MAD_INP_SEL,
-					0x0F, tomtom_mad_input);
-		snd_soc_update_bits(codec, TOMTOM_A_MAD_ANA_CTRL,
-					0x07, mic_bias_found);
-
-		/* Setup internal micbias */
-
-		if (strnstr(source_widget, "Internal1", strlen(source_widget)))
-			snd_soc_update_bits(codec,
-					micb_int_reg,
-					0xE0, 0xE0);
-		else if (strnstr(source_widget, "Internal2",
-				strlen(source_widget)))
-			snd_soc_update_bits(codec,
-					micb_int_reg,
-					0x1C, 0x1C);
-		else if (strnstr(source_widget, "Internal3",
-				strlen(source_widget)))
-			snd_soc_update_bits(codec,
-					micb_int_reg,
-					0x3, 0x3);
-		else
-			/*
-			 *  If not internal, make sure to write the
-			 *  register to default value
-			 */
-			snd_soc_write(codec, micb_int_reg, 0x24);
-		return 0;
-	}
-
-	pr_err("%s: mic bias source not found for input = %s\n",
-		__func__, mad_input_widget);
-	return -EINVAL;
-}
-
-static int tomtom_tx_hpf_bypass_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	u32	tx_index;
-
-	tx_index = (u32)kcontrol->private_value;
-
-	if (tx_index > NUM_DECIMATORS) {
-		pr_err("%s: Invalid TX decimator %d\n", __func__,
-			   tx_index);
-		return -EINVAL;
-	}
-
-	ucontrol->value.integer.value[0] =
-		tx_hpf_work[tx_index-1].tx_hpf_bypass;
-
-	return 0;
-}
-
-static int tomtom_tx_hpf_bypass_put(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	bool tx_hpf_bypass_cfg;
-	u32	tx_index;
-
-	tx_hpf_bypass_cfg = (bool)ucontrol->value.integer.value[0];
-
-	pr_debug("%s: tx_hpf_bypass = %d\n", __func__,
-			tx_hpf_bypass_cfg);
-
-	tx_index = (u32)kcontrol->private_value;
-
-	if (tx_index > NUM_DECIMATORS) {
-		pr_err("%s: Invalid TX decimator %d\n", __func__,
-			   tx_index);
-		return -EINVAL;
-	}
-	if (tx_hpf_work[tx_index-1].tx_hpf_bypass != tx_hpf_bypass_cfg)
-		tx_hpf_work[tx_index-1].tx_hpf_bypass = tx_hpf_bypass_cfg;
-
-	pr_debug("%s: Set TX%d HPF bypass configuration %d",
-			 __func__, tx_index,
-			 tx_hpf_work[tx_index-1].tx_hpf_bypass);
-
-	return 0;
-}
-
-static const struct snd_kcontrol_new tomtom_snd_controls[] = {
-
-	SOC_SINGLE_SX_TLV("RX1 Digital Volume", TOMTOM_A_CDC_RX1_VOL_CTL_B2_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX2 Digital Volume", TOMTOM_A_CDC_RX2_VOL_CTL_B2_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX3 Digital Volume", TOMTOM_A_CDC_RX3_VOL_CTL_B2_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX4 Digital Volume", TOMTOM_A_CDC_RX4_VOL_CTL_B2_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX5 Digital Volume", TOMTOM_A_CDC_RX5_VOL_CTL_B2_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX6 Digital Volume", TOMTOM_A_CDC_RX6_VOL_CTL_B2_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX7 Digital Volume", TOMTOM_A_CDC_RX7_VOL_CTL_B2_CTL,
-		0, -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("RX8 Digital Volume", TOMTOM_A_CDC_RX8_VOL_CTL_B2_CTL,
-		0, -84, 40, digital_gain),
-
-	SOC_SINGLE_SX_TLV("DEC1 Volume", TOMTOM_A_CDC_TX1_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC2 Volume", TOMTOM_A_CDC_TX2_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC3 Volume", TOMTOM_A_CDC_TX3_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC4 Volume", TOMTOM_A_CDC_TX4_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC5 Volume", TOMTOM_A_CDC_TX5_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC6 Volume", TOMTOM_A_CDC_TX6_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC7 Volume", TOMTOM_A_CDC_TX7_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC8 Volume", TOMTOM_A_CDC_TX8_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC9 Volume", TOMTOM_A_CDC_TX9_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("DEC10 Volume", TOMTOM_A_CDC_TX10_VOL_CTL_GAIN, 0,
-					  -84, 40, digital_gain),
-
-	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", TOMTOM_A_CDC_IIR1_GAIN_B1_CTL, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", TOMTOM_A_CDC_IIR1_GAIN_B2_CTL, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", TOMTOM_A_CDC_IIR1_GAIN_B3_CTL, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", TOMTOM_A_CDC_IIR1_GAIN_B4_CTL, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR2 INP1 Volume", TOMTOM_A_CDC_IIR2_GAIN_B1_CTL, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR2 INP2 Volume", TOMTOM_A_CDC_IIR2_GAIN_B2_CTL, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR2 INP3 Volume", TOMTOM_A_CDC_IIR2_GAIN_B3_CTL, 0,
-					  -84, 40, digital_gain),
-	SOC_SINGLE_SX_TLV("IIR2 INP4 Volume", TOMTOM_A_CDC_IIR2_GAIN_B4_CTL, 0,
-					  -84, 40, digital_gain),
-
-	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tomtom_get_anc_slot,
-		tomtom_put_anc_slot),
-	SOC_ENUM_EXT("ANC Function", tomtom_anc_func_enum, tomtom_get_anc_func,
-		tomtom_put_anc_func),
-
-	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
-	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
-	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
-	SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
-	SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
-	SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
-	SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
-	SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
-	SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
-	SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
-
-	SOC_SINGLE_BOOL_EXT("TX1 HPF Switch", 1,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-	SOC_SINGLE_BOOL_EXT("TX2 HPF Switch", 2,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-	SOC_SINGLE_BOOL_EXT("TX3 HPF Switch", 3,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-	SOC_SINGLE_BOOL_EXT("TX4 HPF Switch", 4,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-	SOC_SINGLE_BOOL_EXT("TX5 HPF Switch", 5,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-	SOC_SINGLE_BOOL_EXT("TX6 HPF Switch", 6,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-	SOC_SINGLE_BOOL_EXT("TX7 HPF Switch", 7,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-	SOC_SINGLE_BOOL_EXT("TX8 HPF Switch", 8,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-	SOC_SINGLE_BOOL_EXT("TX9 HPF Switch", 9,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-	SOC_SINGLE_BOOL_EXT("TX10 HPF Switch", 10,
-				tomtom_tx_hpf_bypass_get,
-				tomtom_tx_hpf_bypass_put),
-
-	SOC_SINGLE("RX1 HPF Switch", TOMTOM_A_CDC_RX1_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX2 HPF Switch", TOMTOM_A_CDC_RX2_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX3 HPF Switch", TOMTOM_A_CDC_RX3_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX4 HPF Switch", TOMTOM_A_CDC_RX4_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX5 HPF Switch", TOMTOM_A_CDC_RX5_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX6 HPF Switch", TOMTOM_A_CDC_RX6_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX7 HPF Switch", TOMTOM_A_CDC_RX7_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX8 HPF Switch", TOMTOM_A_CDC_RX8_B5_CTL, 2, 1, 0),
-
-	SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
-	SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
-	SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
-	SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
-	SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
-	SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
-	SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
-	SOC_ENUM("RX8 HPF cut off", cf_rxmix8_enum),
-
-	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-	SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
-	tomtom_get_iir_enable_audio_mixer, tomtom_put_iir_enable_audio_mixer),
-
-	SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
-	tomtom_get_iir_band_audio_mixer, tomtom_put_iir_band_audio_mixer),
-
-	SOC_SINGLE_EXT("COMP0 Switch", SND_SOC_NOPM, COMPANDER_0, 1, 0,
-		       tomtom_get_compander, tomtom_set_compander),
-	SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
-		       tomtom_get_compander, tomtom_set_compander),
-	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
-		       tomtom_get_compander, tomtom_set_compander),
-
-	SOC_ENUM_EXT("MAD Input", tomtom_conn_mad_enum,
-			tomtom_mad_input_get, tomtom_mad_input_put),
-
-};
-
-static int tomtom_pa_gain_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	u8 ear_pa_gain;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
-	ear_pa_gain = snd_soc_read(codec, TOMTOM_A_RX_EAR_GAIN);
-
-	ear_pa_gain = ear_pa_gain >> 5;
-
-	ucontrol->value.integer.value[0] = ear_pa_gain;
-
-	pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
-
-	return 0;
-}
-
-static int tomtom_pa_gain_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	u8 ear_pa_gain;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
-	pr_debug("%s: ucontrol->value.integer.value[0]  = %ld\n", __func__,
-			ucontrol->value.integer.value[0]);
-
-	ear_pa_gain =  ucontrol->value.integer.value[0] << 5;
-
-	snd_soc_update_bits(codec, TOMTOM_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
-	return 0;
-}
-
-static const char * const tomtom_1_x_ear_pa_gain_text[] = {
-	"POS_6_DB", "POS_4P5_DB", "POS_3_DB", "POS_1P5_DB",
-	"POS_0_DB", "NEG_2P5_DB", "UNDEFINED", "NEG_12_DB"
-};
-
-static const struct soc_enum tomtom_1_x_ear_pa_gain_enum =
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tomtom_1_x_ear_pa_gain_text),
-			tomtom_1_x_ear_pa_gain_text);
-
-static const struct snd_kcontrol_new tomtom_1_x_analog_gain_controls[] = {
-
-	SOC_ENUM_EXT("EAR PA Gain", tomtom_1_x_ear_pa_gain_enum,
-		tomtom_pa_gain_get, tomtom_pa_gain_put),
-
-	SOC_SINGLE_TLV("HPHL Volume", TOMTOM_A_RX_HPH_L_GAIN, 0, 20, 1,
-		line_gain),
-	SOC_SINGLE_TLV("HPHR Volume", TOMTOM_A_RX_HPH_R_GAIN, 0, 20, 1,
-		line_gain),
-
-	SOC_SINGLE_TLV("LINEOUT1 Volume", TOMTOM_A_RX_LINE_1_GAIN, 0, 20, 1,
-		line_gain),
-	SOC_SINGLE_TLV("LINEOUT2 Volume", TOMTOM_A_RX_LINE_2_GAIN, 0, 20, 1,
-		line_gain),
-	SOC_SINGLE_TLV("LINEOUT3 Volume", TOMTOM_A_RX_LINE_3_GAIN, 0, 20, 1,
-		line_gain),
-	SOC_SINGLE_TLV("LINEOUT4 Volume", TOMTOM_A_RX_LINE_4_GAIN, 0, 20, 1,
-		line_gain),
-
-	SOC_SINGLE_TLV("SPK DRV Volume", TOMTOM_A_SPKR_DRV1_GAIN, 3, 8, 1,
-		line_gain),
-	SOC_SINGLE_TLV("SPK DRV2 Volume", TOMTOM_A_SPKR_DRV2_GAIN, 3, 8, 1,
-		line_gain),
-
-	SOC_SINGLE_TLV("ADC1 Volume", TOMTOM_A_TX_1_GAIN, 2, 19, 0,
-			analog_gain),
-	SOC_SINGLE_TLV("ADC2 Volume", TOMTOM_A_TX_2_GAIN, 2, 19, 0,
-			analog_gain),
-	SOC_SINGLE_TLV("ADC3 Volume", TOMTOM_A_TX_3_GAIN, 2, 19, 0,
-			analog_gain),
-	SOC_SINGLE_TLV("ADC4 Volume", TOMTOM_A_TX_4_GAIN, 2, 19, 0,
-			analog_gain),
-	SOC_SINGLE_TLV("ADC5 Volume", TOMTOM_A_TX_5_GAIN, 2, 19, 0,
-			analog_gain),
-	SOC_SINGLE_TLV("ADC6 Volume", TOMTOM_A_TX_6_GAIN, 2, 19, 0,
-			analog_gain),
-};
-
-static int tomtom_hph_impedance_get(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	uint32_t zl, zr;
-	bool hphr;
-	struct soc_multi_mixer_control *mc;
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tomtom_priv *priv = snd_soc_codec_get_drvdata(codec);
-
-	mc = (struct soc_multi_mixer_control *)(kcontrol->private_value);
-
-	hphr = mc->shift;
-	wcd9xxx_mbhc_get_impedance(&priv->mbhc, &zl, &zr);
-	pr_debug("%s: zl %u, zr %u\n", __func__, zl, zr);
-	ucontrol->value.integer.value[0] = hphr ? zr : zl;
-
-	return 0;
-}
-
-static const struct snd_kcontrol_new impedance_detect_controls[] = {
-	SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0,
-		       tomtom_hph_impedance_get, NULL),
-	SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0,
-		       tomtom_hph_impedance_get, NULL),
-};
-
-static int tomtom_get_hph_type(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-	struct tomtom_priv *priv = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx_mbhc *mbhc;
-
-	if (!priv) {
-		pr_debug("%s: wcd9330 private data is NULL\n", __func__);
-		return 0;
-	}
-
-	mbhc = &priv->mbhc;
-	if (!mbhc) {
-		pr_debug("%s: mbhc not initialized\n", __func__);
-		return 0;
-	}
-
-	ucontrol->value.integer.value[0] = (u32) mbhc->hph_type;
-	pr_debug("%s: hph_type = %u\n", __func__, mbhc->hph_type);
-
-	return 0;
-}
-
-static const struct snd_kcontrol_new hph_type_detect_controls[] = {
-	SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0,
-		       tomtom_get_hph_type, NULL),
-};
-
-static const char * const rx_mix1_text[] = {
-	"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
-		"RX5", "RX6", "RX7"
-};
-
-static const char * const rx8_mix1_text[] = {
-	"ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
-		"RX5", "RX6", "RX7", "RX8"
-};
-
-static const char * const rx_mix2_text[] = {
-	"ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
-};
-
-static const char * const rx_rdac5_text[] = {
-	"DEM4", "DEM3_INV"
-};
-
-static const char * const rx_rdac7_text[] = {
-	"DEM6", "DEM5_INV"
-};
-
-static const char * const mad_sel_text[] = {
-	"SPE", "MSM"
-};
-
-static const char * const sb_tx1_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC1", "RMIX8"
-};
-
-static const char * const sb_tx2_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC2", "RMIX8"
-};
-
-static const char * const sb_tx3_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC3", "RMIX8"
-};
-
-static const char * const sb_tx4_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC4", "RMIX8"
-};
-
-static const char * const sb_tx5_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC5", "RMIX8"
-};
-
-static const char * const sb_tx6_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC6", "RMIX8"
-};
-
-static const char * const sb_tx7_to_tx10_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
-		"DEC9", "DEC10"
-};
-
-static const char * const dec1_mux_text[] = {
-	"ZERO", "DMIC1", "ADC6",
-};
-
-static const char * const dec2_mux_text[] = {
-	"ZERO", "DMIC2", "ADC5",
-};
-
-static const char * const dec3_mux_text[] = {
-	"ZERO", "DMIC3", "ADC4",
-};
-
-static const char * const dec4_mux_text[] = {
-	"ZERO", "DMIC4", "ADC3",
-};
-
-static const char * const dec5_mux_text[] = {
-	"ZERO", "DMIC5", "ADC2",
-};
-
-static const char * const dec6_mux_text[] = {
-	"ZERO", "DMIC6", "ADC1",
-};
-
-static const char * const dec7_mux_text[] = {
-	"ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
-};
-
-static const char * const dec8_mux_text[] = {
-	"ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5", "ANC1_FB", "ANC2_FB",
-};
-
-static const char * const dec9_mux_text[] = {
-	"ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
-};
-
-static const char * const dec10_mux_text[] = {
-	"ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
-};
-
-static const char * const anc_mux_text[] = {
-	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
-		"RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
-};
-
-static const char * const anc1_fb_mux_text[] = {
-	"ZERO", "EAR_HPH_L", "EAR_LINE_1",
-};
-
-static const char * const iir_inp1_text[] = {
-	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
-	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
-};
-
-static const char * const iir_inp2_text[] = {
-	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
-	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
-};
-
-static const char * const iir_inp3_text[] = {
-	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
-	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
-};
-
-static const char * const iir_inp4_text[] = {
-	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
-	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
-};
-
-static const struct soc_enum rx_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
-
-static const struct soc_enum rx_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
-
-static const struct soc_enum rx_mix1_inp3_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_mix1_text);
-
-static const struct soc_enum rx2_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
-
-static const struct soc_enum rx2_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
-
-static const struct soc_enum rx3_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
-
-static const struct soc_enum rx3_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
-
-static const struct soc_enum rx4_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
-
-static const struct soc_enum rx4_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
-
-static const struct soc_enum rx5_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
-
-static const struct soc_enum rx5_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
-
-static const struct soc_enum rx6_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
-
-static const struct soc_enum rx6_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
-
-static const struct soc_enum rx7_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
-
-static const struct soc_enum rx7_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
-
-static const struct soc_enum rx8_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX8_B1_CTL, 0, 11, rx8_mix1_text);
-
-static const struct soc_enum rx8_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX8_B1_CTL, 4, 11, rx8_mix1_text);
-
-static const struct soc_enum rx1_mix2_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
-
-static const struct soc_enum rx1_mix2_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
-
-static const struct soc_enum rx2_mix2_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
-
-static const struct soc_enum rx2_mix2_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
-
-static const struct soc_enum rx7_mix2_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX7_B3_CTL, 0, 5, rx_mix2_text);
-
-static const struct soc_enum rx7_mix2_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_RX7_B3_CTL, 3, 5, rx_mix2_text);
-
-static const struct soc_enum rx_rdac5_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
-
-static const struct soc_enum rx_rdac7_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_MISC, 1, 2, rx_rdac7_text);
-
-static const struct soc_enum mad_sel_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_SVASS_CFG, 0, 2, mad_sel_text);
-
-static const struct soc_enum sb_tx1_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B1_CTL, 0, 10, sb_tx1_mux_text);
-
-static const struct soc_enum sb_tx2_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B2_CTL, 0, 10, sb_tx2_mux_text);
-
-static const struct soc_enum sb_tx3_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B3_CTL, 0, 10, sb_tx3_mux_text);
-
-static const struct soc_enum sb_tx4_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B4_CTL, 0, 10, sb_tx4_mux_text);
-
-static const struct soc_enum sb_tx5_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B5_CTL, 0, 10, sb_tx5_mux_text);
-
-static const struct soc_enum sb_tx6_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B6_CTL, 0, 10, sb_tx6_mux_text);
-
-static const struct soc_enum sb_tx7_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
-			sb_tx7_to_tx10_mux_text);
-
-static const struct soc_enum sb_tx8_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
-			sb_tx7_to_tx10_mux_text);
-
-static const struct soc_enum sb_tx9_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
-			sb_tx7_to_tx10_mux_text);
-
-static const struct soc_enum sb_tx10_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
-			sb_tx7_to_tx10_mux_text);
-
-static const struct soc_enum dec1_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
-
-static const struct soc_enum dec2_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
-
-static const struct soc_enum dec3_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
-
-static const struct soc_enum dec4_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
-
-static const struct soc_enum dec5_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
-
-static const struct soc_enum dec6_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
-
-static const struct soc_enum dec7_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
-
-static const struct soc_enum dec8_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
-
-static const struct soc_enum dec9_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
-
-static const struct soc_enum dec10_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
-
-static const struct soc_enum anc1_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_ANC_B1_CTL, 0, 15, anc_mux_text);
-
-static const struct soc_enum anc2_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_ANC_B1_CTL, 4, 15, anc_mux_text);
-
-static const struct soc_enum anc1_fb_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
-
-static const struct soc_enum iir1_inp1_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir_inp1_text);
-
-static const struct soc_enum iir2_inp1_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_EQ2_B1_CTL, 0, 18, iir_inp1_text);
-
-static const struct soc_enum iir1_inp2_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_EQ1_B2_CTL, 0, 18, iir_inp2_text);
-
-static const struct soc_enum iir2_inp2_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_EQ2_B2_CTL, 0, 18, iir_inp2_text);
-
-static const struct soc_enum iir1_inp3_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_EQ1_B3_CTL, 0, 18, iir_inp3_text);
-
-static const struct soc_enum iir2_inp3_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_EQ2_B3_CTL, 0, 18, iir_inp3_text);
-
-static const struct soc_enum iir1_inp4_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_EQ1_B4_CTL, 0, 18, iir_inp4_text);
-
-static const struct soc_enum iir2_inp4_mux_enum =
-	SOC_ENUM_SINGLE(TOMTOM_A_CDC_CONN_EQ2_B4_CTL, 0, 18, iir_inp4_text);
-
-static const struct snd_kcontrol_new rx_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp3_mux =
-	SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx8_mix1_inp1_mux =
-	SOC_DAPM_ENUM("RX8 MIX1 INP1 Mux", rx8_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx8_mix1_inp2_mux =
-	SOC_DAPM_ENUM("RX8 MIX1 INP2 Mux", rx8_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
-	SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
-	SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
-	SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
-	SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx7_mix2_inp1_mux =
-	SOC_DAPM_ENUM("RX7 MIX2 INP1 Mux", rx7_mix2_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx7_mix2_inp2_mux =
-	SOC_DAPM_ENUM("RX7 MIX2 INP2 Mux", rx7_mix2_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx_dac5_mux =
-	SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
-
-static const struct snd_kcontrol_new rx_dac7_mux =
-	SOC_DAPM_ENUM("RDAC7 MUX Mux", rx_rdac7_enum);
-
-static const struct snd_kcontrol_new mad_sel_mux =
-	SOC_DAPM_ENUM("MAD_SEL MUX Mux", mad_sel_enum);
-
-static const struct snd_kcontrol_new sb_tx1_mux =
-	SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
-
-static const struct snd_kcontrol_new sb_tx2_mux =
-	SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
-
-static const struct snd_kcontrol_new sb_tx3_mux =
-	SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
-
-static const struct snd_kcontrol_new sb_tx4_mux =
-	SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
-
-static const struct snd_kcontrol_new sb_tx5_mux =
-	SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
-
-static const struct snd_kcontrol_new sb_tx6_mux =
-	SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
-
-static const struct snd_kcontrol_new sb_tx7_mux =
-	SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
-
-static const struct snd_kcontrol_new sb_tx8_mux =
-	SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
-
-static const struct snd_kcontrol_new sb_tx9_mux =
-	SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
-
-static const struct snd_kcontrol_new sb_tx10_mux =
-	SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
-
-
-static int wcd9330_put_dec_enum(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist =
-					dapm_kcontrol_get_wlist(kcontrol);
-	struct snd_soc_dapm_widget *w = wlist->widgets[0];
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-	unsigned int dec_mux, decimator;
-	char *dec_name = NULL;
-	char *widget_name = NULL;
-	char *temp;
-	u16 tx_mux_ctl_reg;
-	u8 adc_dmic_sel = 0x0;
-	int ret = 0;
-	char *dec;
-
-	if (ucontrol->value.enumerated.item[0] >= e->items)
-		return -EINVAL;
-
-	dec_mux = ucontrol->value.enumerated.item[0];
-
-	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
-	if (!widget_name)
-		return -ENOMEM;
-	temp = widget_name;
-
-	dec_name = strsep(&widget_name, " ");
-	widget_name = temp;
-	if (!dec_name) {
-		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
-		ret =  -EINVAL;
-		goto out;
-	}
-	dec = strpbrk(dec_name, "123456789");
-	if (!dec) {
-		dev_err(w->dapm->dev, "%s: decimator index not found\n",
-			__func__);
-		ret =  -EINVAL;
-		goto out;
-	}
-	ret = kstrtouint(dec, 10, &decimator);
-	if (ret < 0) {
-		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
-		ret =  -EINVAL;
-		goto out;
-	}
-
-	dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
-		, __func__, w->name, decimator, dec_mux);
-
-
-	switch (decimator) {
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-	case 6:
-		if (dec_mux == 1)
-			adc_dmic_sel = 0x1;
-		else
-			adc_dmic_sel = 0x0;
-		break;
-	case 7:
-	case 8:
-	case 9:
-	case 10:
-		if ((dec_mux == 1) || (dec_mux == 2))
-			adc_dmic_sel = 0x1;
-		else
-			adc_dmic_sel = 0x0;
-		break;
-	default:
-		pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	tx_mux_ctl_reg = TOMTOM_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
-
-	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
-
-	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
-out:
-	kfree(widget_name);
-	return ret;
-}
-
-#define WCD9330_DEC_ENUM(xname, xenum) \
-{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-	.info = snd_soc_info_enum_double, \
-	.get = snd_soc_dapm_get_enum_double, \
-	.put = wcd9330_put_dec_enum, \
-	.private_value = (unsigned long)&xenum }
-
-static const struct snd_kcontrol_new dec1_mux =
-	WCD9330_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
-
-static const struct snd_kcontrol_new dec2_mux =
-	WCD9330_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
-
-static const struct snd_kcontrol_new dec3_mux =
-	WCD9330_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
-
-static const struct snd_kcontrol_new dec4_mux =
-	WCD9330_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
-
-static const struct snd_kcontrol_new dec5_mux =
-	WCD9330_DEC_ENUM("DEC5 MUX Mux", dec5_mux_enum);
-
-static const struct snd_kcontrol_new dec6_mux =
-	WCD9330_DEC_ENUM("DEC6 MUX Mux", dec6_mux_enum);
-
-static const struct snd_kcontrol_new dec7_mux =
-	WCD9330_DEC_ENUM("DEC7 MUX Mux", dec7_mux_enum);
-
-static const struct snd_kcontrol_new dec8_mux =
-	WCD9330_DEC_ENUM("DEC8 MUX Mux", dec8_mux_enum);
-
-static const struct snd_kcontrol_new dec9_mux =
-	WCD9330_DEC_ENUM("DEC9 MUX Mux", dec9_mux_enum);
-
-static const struct snd_kcontrol_new dec10_mux =
-	WCD9330_DEC_ENUM("DEC10 MUX Mux", dec10_mux_enum);
-
-static const struct snd_kcontrol_new iir1_inp1_mux =
-	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
-
-static const struct snd_kcontrol_new iir2_inp1_mux =
-	SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
-
-static const struct snd_kcontrol_new iir1_inp2_mux =
-	SOC_DAPM_ENUM("IIR1 INP2 Mux", iir1_inp2_mux_enum);
-
-static const struct snd_kcontrol_new iir2_inp2_mux =
-	SOC_DAPM_ENUM("IIR2 INP2 Mux", iir2_inp2_mux_enum);
-
-static const struct snd_kcontrol_new iir1_inp3_mux =
-	SOC_DAPM_ENUM("IIR1 INP3 Mux", iir1_inp3_mux_enum);
-
-static const struct snd_kcontrol_new iir2_inp3_mux =
-	SOC_DAPM_ENUM("IIR2 INP3 Mux", iir2_inp3_mux_enum);
-
-static const struct snd_kcontrol_new iir1_inp4_mux =
-	SOC_DAPM_ENUM("IIR1 INP4 Mux", iir1_inp4_mux_enum);
-
-static const struct snd_kcontrol_new iir2_inp4_mux =
-	SOC_DAPM_ENUM("IIR2 INP4 Mux", iir2_inp4_mux_enum);
-
-static const struct snd_kcontrol_new anc1_mux =
-	SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
-
-static const struct snd_kcontrol_new anc2_mux =
-	SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
-
-static const struct snd_kcontrol_new anc1_fb_mux =
-	SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
-
-static const struct snd_kcontrol_new dac1_switch[] = {
-	SOC_DAPM_SINGLE("Switch", TOMTOM_A_RX_EAR_EN, 5, 1, 0)
-};
-static const struct snd_kcontrol_new hphl_switch[] = {
-	SOC_DAPM_SINGLE("Switch", TOMTOM_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
-};
-
-static const struct snd_kcontrol_new hphl_pa_mix[] = {
-	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TOMTOM_A_RX_PA_AUX_IN_CONN,
-					7, 1, 0),
-};
-
-static const struct snd_kcontrol_new hphr_pa_mix[] = {
-	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TOMTOM_A_RX_PA_AUX_IN_CONN,
-					6, 1, 0),
-};
-
-static const struct snd_kcontrol_new ear_pa_mix[] = {
-	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TOMTOM_A_RX_PA_AUX_IN_CONN,
-					5, 1, 0),
-};
-static const struct snd_kcontrol_new lineout1_pa_mix[] = {
-	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TOMTOM_A_RX_PA_AUX_IN_CONN,
-					4, 1, 0),
-};
-
-static const struct snd_kcontrol_new lineout2_pa_mix[] = {
-	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TOMTOM_A_RX_PA_AUX_IN_CONN,
-					3, 1, 0),
-};
-
-static const struct snd_kcontrol_new lineout3_pa_mix[] = {
-	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TOMTOM_A_RX_PA_AUX_IN_CONN,
-					2, 1, 0),
-};
-
-static const struct snd_kcontrol_new lineout4_pa_mix[] = {
-	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TOMTOM_A_RX_PA_AUX_IN_CONN,
-					1, 1, 0),
-};
-
-static const struct snd_kcontrol_new lineout3_ground_switch =
-	SOC_DAPM_SINGLE("Switch", TOMTOM_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
-
-static const struct snd_kcontrol_new lineout4_ground_switch =
-	SOC_DAPM_SINGLE("Switch", TOMTOM_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
-
-static const struct snd_kcontrol_new aif4_mad_switch =
-	SOC_DAPM_SINGLE("Switch", TOMTOM_A_SVASS_CLKRST_CTL, 0, 1, 0);
-
-static const struct snd_kcontrol_new aif4_vi_switch =
-	SOC_DAPM_SINGLE("Switch", TOMTOM_A_SPKR1_PROT_EN, 3, 1, 0);
-
-/* virtual port entries */
-static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
-			     struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist =
-					dapm_kcontrol_get_wlist(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.integer.value[0] = tomtom_p->tx_port_value;
-	return 0;
-}
-
-static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
-			     struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist =
-					dapm_kcontrol_get_wlist(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
-	struct snd_soc_dapm_update *update = NULL;
-	struct soc_multi_mixer_control *mixer =
-		((struct soc_multi_mixer_control *)kcontrol->private_value);
-	u32 dai_id = widget->shift;
-	u32 port_id = mixer->shift;
-	u32 enable = ucontrol->value.integer.value[0];
-	u32 vtable = vport_check_table[dai_id];
-
-
-	pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
-		widget->name, ucontrol->id.name, tomtom_p->tx_port_value,
-		widget->shift, ucontrol->value.integer.value[0]);
-
-	mutex_lock(&tomtom_p->codec_mutex);
-
-	if (tomtom_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
-		if (dai_id != AIF1_CAP) {
-			dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
-				__func__);
-			mutex_unlock(&tomtom_p->codec_mutex);
-			return -EINVAL;
-		}
-	}
-	switch (dai_id) {
-	case AIF1_CAP:
-	case AIF2_CAP:
-	case AIF3_CAP:
-		/* only add to the list if value not set
-		 */
-		if (enable && !(tomtom_p->tx_port_value & 1 << port_id)) {
-
-			if (tomtom_p->intf_type ==
-				WCD9XXX_INTERFACE_TYPE_SLIMBUS)
-				vtable = vport_check_table[dai_id];
-			if (tomtom_p->intf_type ==
-				WCD9XXX_INTERFACE_TYPE_I2C)
-				vtable = vport_i2s_check_table[dai_id];
-
-			if (wcd9xxx_tx_vport_validation(
-					vtable,
-					port_id,
-					tomtom_p->dai, NUM_CODEC_DAIS)) {
-				dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
-					__func__, port_id + 1);
-				mutex_unlock(&tomtom_p->codec_mutex);
-				return 0;
-			}
-			tomtom_p->tx_port_value |= 1 << port_id;
-			list_add_tail(&core->tx_chs[port_id].list,
-			      &tomtom_p->dai[dai_id].wcd9xxx_ch_list
-					      );
-		} else if (!enable && (tomtom_p->tx_port_value &
-					1 << port_id)) {
-			tomtom_p->tx_port_value &= ~(1 << port_id);
-			list_del_init(&core->tx_chs[port_id].list);
-		} else {
-			if (enable)
-				dev_dbg(codec->dev, "%s: TX%u port is used by\n"
-					"this virtual port\n",
-					__func__, port_id + 1);
-			else
-				dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
-					"this virtual port\n",
-					__func__, port_id + 1);
-			/* avoid update power function */
-			mutex_unlock(&tomtom_p->codec_mutex);
-			return 0;
-		}
-		break;
-	default:
-		pr_err("Unknown AIF %d\n", dai_id);
-		mutex_unlock(&tomtom_p->codec_mutex);
-		return -EINVAL;
-	}
-	pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
-		widget->name, widget->sname, tomtom_p->tx_port_value,
-		widget->shift);
-
-	mutex_unlock(&tomtom_p->codec_mutex);
-	snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
-
-	return 0;
-}
-
-static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist =
-					dapm_kcontrol_get_wlist(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.enumerated.item[0] = tomtom_p->rx_port_value;
-	return 0;
-}
-
-static const char *const slim_rx_mux_text[] = {
-	"ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB"
-};
-
-static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_dapm_widget_list *wlist =
-					dapm_kcontrol_get_wlist(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
-	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-	struct snd_soc_dapm_update *update = NULL;
-	u32 port_id = widget->shift;
-
-	pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
-		widget->name, ucontrol->id.name, tomtom_p->rx_port_value,
-		widget->shift, ucontrol->value.integer.value[0]);
-
-	tomtom_p->rx_port_value = ucontrol->value.enumerated.item[0];
-
-	mutex_lock(&tomtom_p->codec_mutex);
-
-	if (tomtom_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
-		if (tomtom_p->rx_port_value > 2) {
-			dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
-				__func__);
-			goto err;
-		}
-	}
-	/* value need to match the Virtual port and AIF number
-	 */
-	switch (tomtom_p->rx_port_value) {
-	case 0:
-		list_del_init(&core->rx_chs[port_id].list);
-		break;
-	case 1:
-		if (wcd9xxx_rx_vport_validation(port_id +
-			TOMTOM_RX_PORT_START_NUMBER,
-			&tomtom_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
-			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
-				__func__, port_id + 1);
-			goto rtn;
-		}
-		list_add_tail(&core->rx_chs[port_id].list,
-			      &tomtom_p->dai[AIF1_PB].wcd9xxx_ch_list);
-		break;
-	case 2:
-		if (wcd9xxx_rx_vport_validation(port_id +
-			TOMTOM_RX_PORT_START_NUMBER,
-			&tomtom_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
-			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
-				__func__, port_id + 1);
-			goto rtn;
-		}
-		list_add_tail(&core->rx_chs[port_id].list,
-			      &tomtom_p->dai[AIF2_PB].wcd9xxx_ch_list);
-		break;
-	case 3:
-		if (wcd9xxx_rx_vport_validation(port_id +
-			TOMTOM_RX_PORT_START_NUMBER,
-			&tomtom_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
-			dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
-				__func__, port_id + 1);
-			goto rtn;
-		}
-		list_add_tail(&core->rx_chs[port_id].list,
-			      &tomtom_p->dai[AIF3_PB].wcd9xxx_ch_list);
-		break;
-	default:
-		pr_err("Unknown AIF %d\n", tomtom_p->rx_port_value);
-		goto err;
-	}
-rtn:
-	mutex_unlock(&tomtom_p->codec_mutex);
-	snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
-					tomtom_p->rx_port_value, e, update);
-
-	return 0;
-err:
-	mutex_unlock(&tomtom_p->codec_mutex);
-	return -EINVAL;
-}
-
-static const struct soc_enum slim_rx_mux_enum =
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
-
-static const struct snd_kcontrol_new slim_rx_mux[TOMTOM_RX_MAX] = {
-	SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-	SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-	SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-	SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-	SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-	SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-	SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-	SOC_DAPM_ENUM_EXT("SLIM RX8 Mux", slim_rx_mux_enum,
-			  slim_rx_mux_get, slim_rx_mux_put),
-};
-
-static const struct snd_kcontrol_new aif1_cap_mixer[] = {
-	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TOMTOM_TX1, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TOMTOM_TX2, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TOMTOM_TX3, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TOMTOM_TX4, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TOMTOM_TX5, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TOMTOM_TX6, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TOMTOM_TX7, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TOMTOM_TX8, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TOMTOM_TX9, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TOMTOM_TX10, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-};
-
-static const struct snd_kcontrol_new aif2_cap_mixer[] = {
-	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TOMTOM_TX1, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TOMTOM_TX2, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TOMTOM_TX3, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TOMTOM_TX4, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TOMTOM_TX5, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TOMTOM_TX6, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TOMTOM_TX7, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TOMTOM_TX8, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TOMTOM_TX9, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TOMTOM_TX10, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-};
-
-static const struct snd_kcontrol_new aif3_cap_mixer[] = {
-	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TOMTOM_TX1, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TOMTOM_TX2, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TOMTOM_TX3, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TOMTOM_TX4, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TOMTOM_TX5, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TOMTOM_TX6, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TOMTOM_TX7, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TOMTOM_TX8, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TOMTOM_TX9, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TOMTOM_TX10, 1, 0,
-			slim_tx_mixer_get, slim_tx_mixer_put),
-};
-
-static void tomtom_codec_enable_adc_block(struct snd_soc_codec *codec,
-					 int enable)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s %d\n", __func__, enable);
-
-	if (enable) {
-		tomtom->adc_count++;
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
-						0x2, 0x2);
-	} else {
-		tomtom->adc_count--;
-		if (!tomtom->adc_count)
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
-					    0x2, 0x0);
-	}
-}
-
-static int tomtom_codec_enable_adc(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *priv = snd_soc_codec_get_drvdata(codec);
-	u16 adc_reg;
-	u16 tx_fe_clkdiv_reg;
-	u8 tx_fe_clkdiv_mask;
-	u8 init_bit_shift;
-	u8 bit_pos;
-
-	pr_debug("%s %d\n", __func__, event);
-
-	switch (w->reg) {
-	case TOMTOM_A_TX_1_GAIN:
-		adc_reg = TOMTOM_A_TX_1_2_TEST_CTL;
-		tx_fe_clkdiv_reg = TOMTOM_A_TX_1_2_TXFE_CLKDIV;
-		tx_fe_clkdiv_mask = 0x0F;
-		init_bit_shift = 7;
-		bit_pos = ADC1_TXFE;
-		break;
-	case TOMTOM_A_TX_2_GAIN:
-		adc_reg = TOMTOM_A_TX_1_2_TEST_CTL;
-		tx_fe_clkdiv_reg = TOMTOM_A_TX_1_2_TXFE_CLKDIV;
-		tx_fe_clkdiv_mask = 0xF0;
-		init_bit_shift = 6;
-		bit_pos = ADC2_TXFE;
-		break;
-	case TOMTOM_A_TX_3_GAIN:
-		adc_reg = TOMTOM_A_TX_3_4_TEST_CTL;
-		init_bit_shift = 7;
-		tx_fe_clkdiv_reg = TOMTOM_A_TX_3_4_TXFE_CKDIV;
-		tx_fe_clkdiv_mask = 0x0F;
-		bit_pos = ADC3_TXFE;
-		break;
-	case TOMTOM_A_TX_4_GAIN:
-		adc_reg = TOMTOM_A_TX_3_4_TEST_CTL;
-		init_bit_shift = 6;
-		tx_fe_clkdiv_reg = TOMTOM_A_TX_3_4_TXFE_CKDIV;
-		tx_fe_clkdiv_mask = 0xF0;
-		bit_pos = ADC4_TXFE;
-		break;
-	case TOMTOM_A_TX_5_GAIN:
-		adc_reg = TOMTOM_A_TX_5_6_TEST_CTL;
-		init_bit_shift = 7;
-		tx_fe_clkdiv_reg = TOMTOM_A_TX_5_6_TXFE_CKDIV;
-		tx_fe_clkdiv_mask = 0x0F;
-		bit_pos = ADC5_TXFE;
-		break;
-	case TOMTOM_A_TX_6_GAIN:
-		adc_reg = TOMTOM_A_TX_5_6_TEST_CTL;
-		init_bit_shift = 6;
-		tx_fe_clkdiv_reg = TOMTOM_A_TX_5_6_TXFE_CKDIV;
-		tx_fe_clkdiv_mask = 0xF0;
-		bit_pos = ADC6_TXFE;
-		break;
-	default:
-		pr_err("%s: Error, invalid adc register\n", __func__);
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, tx_fe_clkdiv_reg, tx_fe_clkdiv_mask,
-				    0x0);
-		set_bit(bit_pos, &priv->status_mask);
-		tomtom_codec_enable_adc_block(codec, 1);
-		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
-				1 << init_bit_shift);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		tomtom_codec_enable_adc_block(codec, 0);
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_ext_clk_en(struct snd_soc_codec *codec,
-		int enable, bool dapm)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	if (!tomtom->codec_ext_clk_en_cb) {
-		dev_err(codec->dev,
-			"%s: Invalid ext_clk_callback\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	return tomtom->codec_ext_clk_en_cb(codec, enable, dapm);
-}
-
-static int __tomtom_mclk_enable(struct tomtom_priv *tomtom, int mclk_enable)
-{
-	int ret = 0;
-
-	WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-	if (mclk_enable) {
-		tomtom->ext_clk_users++;
-		if (tomtom->ext_clk_users > 1)
-			goto bg_clk_unlock;
-		ret = clk_prepare_enable(tomtom->wcd_ext_clk);
-		if (ret) {
-			pr_err("%s: ext clk enable failed\n",
-				__func__);
-			tomtom->ext_clk_users--;
-			goto bg_clk_unlock;
-		}
-		wcd9xxx_resmgr_get_bandgap(&tomtom->resmgr,
-					   WCD9XXX_BANDGAP_AUDIO_MODE);
-		wcd9xxx_resmgr_get_clk_block(&tomtom->resmgr, WCD9XXX_CLK_MCLK);
-	} else {
-		tomtom->ext_clk_users--;
-		if (tomtom->ext_clk_users == 0) {
-			/* Put clock and BG */
-			wcd9xxx_resmgr_put_clk_block(&tomtom->resmgr,
-						     WCD9XXX_CLK_MCLK);
-			wcd9xxx_resmgr_put_bandgap(&tomtom->resmgr,
-					WCD9XXX_BANDGAP_AUDIO_MODE);
-			clk_disable_unprepare(tomtom->wcd_ext_clk);
-		}
-	}
-bg_clk_unlock:
-	WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-
-	return ret;
-}
-
-int tomtom_codec_mclk_enable(struct snd_soc_codec *codec,
-			     int enable, bool dapm)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	if (tomtom->wcd_ext_clk) {
-		dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
-			__func__, enable, dapm);
-		return __tomtom_mclk_enable(tomtom, enable);
-	} else if (tomtom->codec_ext_clk_en_cb)
-		return tomtom_codec_ext_clk_en(codec, enable, dapm);
-	else {
-		dev_err(codec->dev,
-			"%s: Cannot turn on MCLK\n",
-			__func__);
-		return -EINVAL;
-	}
-}
-EXPORT_SYMBOL(tomtom_codec_mclk_enable);
-
-static int tomtom_codec_get_ext_clk_users(struct tomtom_priv *tomtom)
-{
-	if (tomtom->wcd_ext_clk)
-		return tomtom->ext_clk_users;
-	else if (tomtom->codec_get_ext_clk_cnt)
-		return tomtom->codec_get_ext_clk_cnt();
-	else
-		return 0;
-}
-
-/* tomtom_codec_internal_rco_ctrl( )
- * Make sure that BG_CLK_LOCK is not acquired. Exit if acquired to avoid
- * potential deadlock as ext_clk_en_cb() also tries to acquire the same
- * lock to enable MCLK for RCO calibration
- */
-static int tomtom_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
-					  bool enable)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	int ret = 0;
-
-	if (enable) {
-		if (wcd9xxx_resmgr_get_clk_type(&tomtom->resmgr) ==
-		    WCD9XXX_CLK_RCO) {
-			WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-			wcd9xxx_resmgr_get_clk_block(&tomtom->resmgr,
-						     WCD9XXX_CLK_RCO);
-			WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-		} else {
-			tomtom_codec_mclk_enable(codec, true, false);
-			WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-			tomtom->resmgr.ext_clk_users =
-					tomtom_codec_get_ext_clk_users(tomtom);
-			wcd9xxx_resmgr_get_clk_block(&tomtom->resmgr,
-						     WCD9XXX_CLK_RCO);
-			WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-			tomtom_codec_mclk_enable(codec, false, false);
-		}
-
-	} else {
-		WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-		wcd9xxx_resmgr_put_clk_block(&tomtom->resmgr,
-					     WCD9XXX_CLK_RCO);
-		WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-	}
-
-	return ret;
-}
-
-static int tomtom_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s: %d\n", __func__, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-		wcd9xxx_resmgr_get_bandgap(&tomtom->resmgr,
-					   WCD9XXX_BANDGAP_AUDIO_MODE);
-		WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-		/* AUX PGA requires RCO or MCLK */
-		tomtom_codec_internal_rco_ctrl(codec, true);
-		WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-		wcd9xxx_resmgr_enable_rx_bias(&tomtom->resmgr, 1);
-		WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-		break;
-
-	case SND_SOC_DAPM_POST_PMD:
-		WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-		wcd9xxx_resmgr_enable_rx_bias(&tomtom->resmgr, 0);
-		WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-		tomtom_codec_internal_rco_ctrl(codec, false);
-		WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-		wcd9xxx_resmgr_put_bandgap(&tomtom->resmgr,
-					   WCD9XXX_BANDGAP_AUDIO_MODE);
-		WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_enable_lineout(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	u16 lineout_gain_reg;
-
-	pr_debug("%s %d %s\n", __func__, event, w->name);
-
-	switch (w->shift) {
-	case 0:
-		lineout_gain_reg = TOMTOM_A_RX_LINE_1_GAIN;
-		break;
-	case 1:
-		lineout_gain_reg = TOMTOM_A_RX_LINE_2_GAIN;
-		break;
-	case 2:
-		lineout_gain_reg = TOMTOM_A_RX_LINE_3_GAIN;
-		break;
-	case 3:
-		lineout_gain_reg = TOMTOM_A_RX_LINE_4_GAIN;
-		break;
-	default:
-		pr_err("%s: Error, incorrect lineout register value\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		wcd9xxx_clsh_fsm(codec, &tomtom->clsh_d,
-						 WCD9XXX_CLSH_STATE_LO,
-						 WCD9XXX_CLSH_REQ_ENABLE,
-						 WCD9XXX_CLSH_EVENT_POST_PA);
-		pr_debug("%s: sleeping 5 ms after %s PA turn on\n",
-				__func__, w->name);
-		/* Wait for CnP time after PA enable */
-		usleep_range(5000, 5100);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
-		pr_debug("%s: sleeping 5 ms after %s PA turn off\n",
-			 __func__, w->name);
-		/* Wait for CnP time after PA disable */
-		usleep_range(5000, 5100);
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
-				     struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	u16 spk_drv_reg;
-
-	pr_debug("%s: %d %s\n", __func__, event, w->name);
-	if (strnstr(w->name, "SPK2 PA", sizeof("SPK2 PA")))
-		spk_drv_reg = TOMTOM_A_SPKR_DRV2_EN;
-	else
-		spk_drv_reg = TOMTOM_A_SPKR_DRV1_EN;
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		tomtom->spkr_pa_widget_on = true;
-		snd_soc_update_bits(codec, spk_drv_reg, 0x80, 0x80);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		tomtom->spkr_pa_widget_on = false;
-		snd_soc_update_bits(codec, spk_drv_reg, 0x80, 0x00);
-		break;
-	}
-	return 0;
-}
-
-static u8 tomtom_get_dmic_clk_val(struct snd_soc_codec *codec,
-	u32 mclk_rate, u32 dmic_clk_rate)
-{
-	u32 div_factor;
-	u8 dmic_ctl_val;
-
-	dev_dbg(codec->dev,
-		"%s: mclk_rate = %d, dmic_sample_rate = %d\n",
-		__func__, mclk_rate, dmic_clk_rate);
-
-	/* Default value to return in case of error */
-	if (mclk_rate == TOMTOM_MCLK_CLK_9P6MHZ)
-		dmic_ctl_val = WCD9330_DMIC_CLK_DIV_2;
-	else
-		dmic_ctl_val = WCD9330_DMIC_CLK_DIV_3;
-
-	if (dmic_clk_rate == 0) {
-		dev_err(codec->dev,
-			"%s: dmic_sample_rate cannot be 0\n",
-			__func__);
-		goto done;
-	}
-
-	div_factor = mclk_rate / dmic_clk_rate;
-	switch (div_factor) {
-	case 2:
-		dmic_ctl_val = WCD9330_DMIC_CLK_DIV_2;
-		break;
-	case 3:
-		dmic_ctl_val = WCD9330_DMIC_CLK_DIV_3;
-		break;
-	case 4:
-		dmic_ctl_val = WCD9330_DMIC_CLK_DIV_4;
-		break;
-	case 6:
-		dmic_ctl_val = WCD9330_DMIC_CLK_DIV_6;
-		break;
-	case 16:
-		dmic_ctl_val = WCD9330_DMIC_CLK_DIV_16;
-		break;
-	default:
-		dev_err(codec->dev,
-			"%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n",
-			__func__, div_factor, mclk_rate, dmic_clk_rate);
-		break;
-	}
-
-done:
-	return dmic_ctl_val;
-}
-
-static int tomtom_codec_enable_dmic(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx_pdata *pdata = tomtom->resmgr.pdata;
-	u8  dmic_clk_en;
-	u16 dmic_clk_reg;
-	s32 *dmic_clk_cnt;
-	u8 dmic_rate_val, dmic_rate_shift;
-	unsigned int dmic;
-	int ret;
-	char *wname;
-
-	wname = strpbrk(w->name, "123456");
-	if (!wname) {
-		dev_err(codec->dev, "%s: widget not found\n", __func__);
-		return -EINVAL;
-	}
-
-	ret = kstrtouint(wname, 10, &dmic);
-	if (ret < 0) {
-		pr_err("%s: Invalid DMIC line on the codec\n", __func__);
-		return -EINVAL;
-	}
-
-	switch (dmic) {
-	case 1:
-	case 2:
-		dmic_clk_en = 0x01;
-		dmic_clk_cnt = &(tomtom->dmic_1_2_clk_cnt);
-		dmic_clk_reg = TOMTOM_A_DMIC_B1_CTL;
-		dmic_rate_shift = 5;
-		pr_debug("%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
-			__func__, event,  dmic, *dmic_clk_cnt);
-
-		break;
-
-	case 3:
-	case 4:
-		dmic_clk_en = 0x02;
-		dmic_clk_cnt = &(tomtom->dmic_3_4_clk_cnt);
-		dmic_clk_reg = TOMTOM_A_DMIC_B2_CTL;
-		dmic_rate_shift = 1;
-		pr_debug("%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
-			__func__, event,  dmic, *dmic_clk_cnt);
-		break;
-
-	case 5:
-	case 6:
-		dmic_clk_en = 0x04;
-		dmic_clk_cnt = &(tomtom->dmic_5_6_clk_cnt);
-		dmic_clk_reg = TOMTOM_A_DMIC_B2_CTL;
-		dmic_rate_shift = 4;
-		pr_debug("%s() event %d DMIC%d dmic_5_6_clk_cnt %d\n",
-			__func__, event,  dmic, *dmic_clk_cnt);
-
-		break;
-
-	default:
-		pr_err("%s: Invalid DMIC Selection\n", __func__);
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-
-		dmic_rate_val =
-			tomtom_get_dmic_clk_val(codec,
-					pdata->mclk_rate,
-					pdata->dmic_sample_rate);
-
-		(*dmic_clk_cnt)++;
-		if (*dmic_clk_cnt == 1) {
-			snd_soc_update_bits(codec, dmic_clk_reg,
-				0x07 << dmic_rate_shift,
-				dmic_rate_val << dmic_rate_shift);
-			snd_soc_update_bits(codec, TOMTOM_A_DMIC_B1_CTL,
-					dmic_clk_en, dmic_clk_en);
-		}
-
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-
-		dmic_rate_val =
-			tomtom_get_dmic_clk_val(codec,
-					pdata->mclk_rate,
-					pdata->mad_dmic_sample_rate);
-		(*dmic_clk_cnt)--;
-		if (*dmic_clk_cnt  == 0) {
-			snd_soc_update_bits(codec, TOMTOM_A_DMIC_B1_CTL,
-					dmic_clk_en, 0);
-			snd_soc_update_bits(codec, dmic_clk_reg,
-				0x07 << dmic_rate_shift,
-				dmic_rate_val << dmic_rate_shift);
-		}
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_config_mad(struct snd_soc_codec *codec)
-{
-	int ret = 0;
-	const struct firmware *fw;
-	struct firmware_cal *hwdep_cal = NULL;
-	struct mad_audio_cal *mad_cal;
-	const void *data;
-	const char *filename = TOMTOM_MAD_AUDIO_FIRMWARE_PATH;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	size_t cal_size;
-	int idx;
-
-	pr_debug("%s: enter\n", __func__);
-
-	if (!tomtom->fw_data) {
-		dev_err(codec->dev, "%s: invalid cal data\n",
-				__func__);
-		return -ENODEV;
-	}
-
-	hwdep_cal = wcdcal_get_fw_cal(tomtom->fw_data, WCD9XXX_MAD_CAL);
-	if (hwdep_cal) {
-		data = hwdep_cal->data;
-		cal_size = hwdep_cal->size;
-		dev_dbg(codec->dev, "%s: using hwdep calibration\n",
-				__func__);
-	} else {
-		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) {
-			dev_err(codec->dev, "failed to get mad fw");
-			return -ENODEV;
-		}
-		data = fw->data;
-		cal_size = fw->size;
-		dev_dbg(codec->dev, "%s: using request_firmware calibration\n",
-				__func__);
-	}
-	if (cal_size < sizeof(struct mad_audio_cal)) {
-		pr_err("%s: incorrect hwdep cal size %zu\n",
-			__func__, cal_size);
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	mad_cal = (struct mad_audio_cal *)(data);
-	if (!mad_cal) {
-		dev_err(codec->dev, "%s: Invalid calibration data\n",
-				__func__);
-		ret =  -EINVAL;
-		goto err;
-	}
-
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_MAIN_CTL_2,
-		      mad_cal->microphone_info.cycle_time);
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_MAD_MAIN_CTL_1, 0xFF << 3,
-			    ((uint16_t)mad_cal->microphone_info.settle_time)
-			    << 3);
-
-	/* Audio */
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_AUDIO_CTL_8,
-		      mad_cal->audio_info.rms_omit_samples);
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_MAD_AUDIO_CTL_1,
-			    0x07 << 4, mad_cal->audio_info.rms_comp_time << 4);
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_MAD_AUDIO_CTL_2, 0x03 << 2,
-			    mad_cal->audio_info.detection_mechanism << 2);
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_AUDIO_CTL_7,
-		      mad_cal->audio_info.rms_diff_threshold & 0x3F);
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_AUDIO_CTL_5,
-		      mad_cal->audio_info.rms_threshold_lsb);
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_AUDIO_CTL_6,
-		      mad_cal->audio_info.rms_threshold_msb);
-
-	for (idx = 0; idx < ARRAY_SIZE(mad_cal->audio_info.iir_coefficients);
-	     idx++) {
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_PTR,
-				    0x3F, idx);
-		snd_soc_write(codec, TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_VAL,
-			      mad_cal->audio_info.iir_coefficients[idx]);
-		dev_dbg(codec->dev, "%s:MAD Audio IIR Coef[%d] = 0X%x",
-			__func__, idx,
-			mad_cal->audio_info.iir_coefficients[idx]);
-	}
-
-	/* Beacon */
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_BEACON_CTL_8,
-		      mad_cal->beacon_info.rms_omit_samples);
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_MAD_BEACON_CTL_1,
-			    0x07 << 4, mad_cal->beacon_info.rms_comp_time);
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_MAD_BEACON_CTL_2, 0x03 << 2,
-			    mad_cal->beacon_info.detection_mechanism << 2);
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_BEACON_CTL_7,
-		      mad_cal->beacon_info.rms_diff_threshold & 0x1F);
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_BEACON_CTL_5,
-		      mad_cal->beacon_info.rms_threshold_lsb);
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_BEACON_CTL_6,
-		      mad_cal->beacon_info.rms_threshold_msb);
-
-	/* Ultrasound */
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_MAD_BEACON_CTL_1,
-			    0x07 << 4, mad_cal->beacon_info.rms_comp_time);
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_MAD_ULTR_CTL_2, 0x03 << 2,
-			    mad_cal->ultrasound_info.detection_mechanism);
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_ULTR_CTL_7,
-		      mad_cal->ultrasound_info.rms_diff_threshold & 0x1F);
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_ULTR_CTL_5,
-		      mad_cal->ultrasound_info.rms_threshold_lsb);
-	snd_soc_write(codec, TOMTOM_A_CDC_MAD_ULTR_CTL_6,
-		      mad_cal->ultrasound_info.rms_threshold_msb);
-
-	/* Set MAD intr time to 20 msec */
-	snd_soc_update_bits(codec, 0x4E, 0x01F, 0x13);
-
-	pr_debug("%s: leave ret %d\n", __func__, ret);
-err:
-	if (!hwdep_cal)
-		release_firmware(fw);
-	return ret;
-}
-
-static int tomtom_codec_enable_mad(struct snd_soc_dapm_widget *w,
-				  struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	int ret = 0;
-	u8 mad_micb, mad_cfilt;
-	u16 mad_cfilt_reg;
-
-	mad_micb = snd_soc_read(codec, TOMTOM_A_MAD_ANA_CTRL) & 0x07;
-	switch (mad_micb) {
-	case 1:
-		mad_cfilt = tomtom->resmgr.pdata->micbias.bias1_cfilt_sel;
-		break;
-	case 2:
-		mad_cfilt = tomtom->resmgr.pdata->micbias.bias2_cfilt_sel;
-		break;
-	case 3:
-		mad_cfilt = tomtom->resmgr.pdata->micbias.bias3_cfilt_sel;
-		break;
-	case 4:
-		mad_cfilt = tomtom->resmgr.pdata->micbias.bias4_cfilt_sel;
-		break;
-	default:
-		dev_err(codec->dev,
-			"%s: Invalid micbias selection 0x%x\n",
-			__func__, mad_micb);
-		return -EINVAL;
-	}
-
-	switch (mad_cfilt) {
-	case WCD9XXX_CFILT1_SEL:
-		mad_cfilt_reg = TOMTOM_A_MICB_CFILT_1_VAL;
-		break;
-	case WCD9XXX_CFILT2_SEL:
-		mad_cfilt_reg = TOMTOM_A_MICB_CFILT_2_VAL;
-		break;
-	case WCD9XXX_CFILT3_SEL:
-		mad_cfilt_reg = TOMTOM_A_MICB_CFILT_3_VAL;
-		break;
-	default:
-		dev_err(codec->dev,
-			"%s: invalid cfilt 0x%x for micb 0x%x\n",
-			__func__, mad_cfilt, mad_micb);
-		return -EINVAL;
-	}
-
-	dev_dbg(codec->dev,
-		"%s event = %d, mad_cfilt_reg = 0x%x\n",
-		__func__, event, mad_cfilt_reg);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		/* Undo reset for MAD */
-		snd_soc_update_bits(codec, TOMTOM_A_SVASS_CLKRST_CTL,
-				    0x02, 0x00);
-
-		ret = tomtom_codec_config_mad(codec);
-		if (ret) {
-			pr_err("%s: Failed to config MAD\n", __func__);
-			break;
-		}
-
-		/* setup MAD micbias to VDDIO */
-		snd_soc_update_bits(codec, mad_cfilt_reg,
-				    0x02, 0x02);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		/* Reset the MAD block */
-		snd_soc_update_bits(codec, TOMTOM_A_SVASS_CLKRST_CTL,
-				    0x02, 0x02);
-
-		/* Undo setup of MAD micbias to VDDIO */
-		snd_soc_update_bits(codec, mad_cfilt_reg,
-				    0x02, 0x00);
-	}
-	return ret;
-}
-
-static int tomtom_codec_enable_micbias(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	u16 micb_int_reg = 0, micb_ctl_reg = 0;
-	u8 cfilt_sel_val = 0;
-	char *internal1_text = "Internal1";
-	char *internal2_text = "Internal2";
-	char *internal3_text = "Internal3";
-	enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
-
-	pr_debug("%s: w->name %s event %d\n", __func__, w->name, event);
-	if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) {
-		micb_ctl_reg = TOMTOM_A_MICB_1_CTL;
-		micb_int_reg = TOMTOM_A_MICB_1_INT_RBIAS;
-		cfilt_sel_val = tomtom->resmgr.pdata->micbias.bias1_cfilt_sel;
-		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
-		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
-		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
-	} else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) {
-		micb_ctl_reg = TOMTOM_A_MICB_2_CTL;
-		micb_int_reg = TOMTOM_A_MICB_2_INT_RBIAS;
-		cfilt_sel_val = tomtom->resmgr.pdata->micbias.bias2_cfilt_sel;
-		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_2_ON;
-		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
-		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
-	} else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) {
-		micb_ctl_reg = TOMTOM_A_MICB_3_CTL;
-		micb_int_reg = TOMTOM_A_MICB_3_INT_RBIAS;
-		cfilt_sel_val = tomtom->resmgr.pdata->micbias.bias3_cfilt_sel;
-		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
-		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
-		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
-	} else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) {
-		micb_ctl_reg = TOMTOM_A_MICB_4_CTL;
-		micb_int_reg = tomtom->resmgr.reg_addr->micb_4_int_rbias;
-		cfilt_sel_val = tomtom->resmgr.pdata->micbias.bias4_cfilt_sel;
-		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_4_ON;
-		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_4_ON;
-		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_4_OFF;
-	} else {
-		pr_err("%s: Error, invalid micbias %s\n", __func__, w->name);
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		/* Let MBHC module know so micbias switch to be off */
-		wcd9xxx_resmgr_notifier_call(&tomtom->resmgr, e_pre_on);
-
-		/* Get cfilt */
-		wcd9xxx_resmgr_cfilt_get(&tomtom->resmgr, cfilt_sel_val);
-
-		if (strnstr(w->name, internal1_text, 30))
-			snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
-		else if (strnstr(w->name, internal2_text, 30))
-			snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
-		else if (strnstr(w->name, internal3_text, 30))
-			snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
-		else
-			/*
-			 *  If not internal, make sure to write the
-			 *  register to default value
-			 */
-			snd_soc_write(codec, micb_int_reg, 0x24);
-		if (tomtom->mbhc_started && micb_ctl_reg ==
-		    TOMTOM_A_MICB_2_CTL) {
-			if (++tomtom->micb_2_users == 1) {
-				if (tomtom->resmgr.pdata->
-				    micbias.bias2_is_headset_only)
-					wcd9xxx_resmgr_add_cond_update_bits(
-							 &tomtom->resmgr,
-							 WCD9XXX_COND_HPH_MIC,
-							 micb_ctl_reg, w->shift,
-							 false);
-				else
-					snd_soc_update_bits(codec, micb_ctl_reg,
-							    1 << w->shift,
-							    1 << w->shift);
-			}
-			pr_debug("%s: micb_2_users %d\n", __func__,
-				 tomtom->micb_2_users);
-		} else {
-			snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
-					    1 << w->shift);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(5000, 5100);
-		/* Let MBHC module know so micbias is on */
-		wcd9xxx_resmgr_notifier_call(&tomtom->resmgr, e_post_on);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (tomtom->mbhc_started && micb_ctl_reg ==
-		    TOMTOM_A_MICB_2_CTL) {
-			if (--tomtom->micb_2_users == 0) {
-				if (tomtom->resmgr.pdata->
-				    micbias.bias2_is_headset_only)
-					wcd9xxx_resmgr_rm_cond_update_bits(
-							&tomtom->resmgr,
-							WCD9XXX_COND_HPH_MIC,
-							micb_ctl_reg, 7, false);
-				else
-					snd_soc_update_bits(codec, micb_ctl_reg,
-							    1 << w->shift, 0);
-			}
-			pr_debug("%s: micb_2_users %d\n", __func__,
-				 tomtom->micb_2_users);
-			WARN(tomtom->micb_2_users < 0,
-			     "Unexpected micbias users %d\n",
-			     tomtom->micb_2_users);
-		} else {
-			snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
-					    0);
-		}
-
-		/* Let MBHC module know so micbias switch to be off */
-		wcd9xxx_resmgr_notifier_call(&tomtom->resmgr, e_post_off);
-
-		if (strnstr(w->name, internal1_text, 30))
-			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
-		else if (strnstr(w->name, internal2_text, 30))
-			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
-		else if (strnstr(w->name, internal3_text, 30))
-			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
-
-		/* Put cfilt */
-		wcd9xxx_resmgr_cfilt_put(&tomtom->resmgr, cfilt_sel_val);
-		break;
-	}
-
-	return 0;
-}
-
-/* called under codec_resource_lock acquisition */
-static int tomtom_enable_mbhc_micbias(struct snd_soc_codec *codec, bool enable,
-				enum wcd9xxx_micbias_num micb_num)
-{
-	int rc;
-
-	if (micb_num != MBHC_MICBIAS2) {
-		dev_err(codec->dev, "%s: Unsupported micbias, micb_num=%d\n",
-			__func__, micb_num);
-		return -EINVAL;
-	}
-
-	if (enable)
-		rc = snd_soc_dapm_force_enable_pin(
-					     snd_soc_codec_get_dapm(codec),
-					     DAPM_MICBIAS2_EXTERNAL_STANDALONE);
-	else
-		rc = snd_soc_dapm_disable_pin(snd_soc_codec_get_dapm(codec),
-					     DAPM_MICBIAS2_EXTERNAL_STANDALONE);
-	if (!rc)
-		snd_soc_dapm_sync(snd_soc_codec_get_dapm(codec));
-	pr_debug("%s: leave ret %d\n", __func__, rc);
-	return rc;
-}
-
-static void txfe_clkdiv_update(struct snd_soc_codec *codec)
-{
-	struct tomtom_priv *priv = snd_soc_codec_get_drvdata(codec);
-
-	if (test_bit(ADC1_TXFE, &priv->status_mask)) {
-		snd_soc_update_bits(codec, TOMTOM_A_TX_1_2_TXFE_CLKDIV,
-				    0x0F, 0x05);
-		clear_bit(ADC1_TXFE, &priv->status_mask);
-	}
-	if (test_bit(ADC2_TXFE, &priv->status_mask)) {
-		snd_soc_update_bits(codec, TOMTOM_A_TX_1_2_TXFE_CLKDIV,
-				    0xF0, 0x50);
-		clear_bit(ADC2_TXFE, &priv->status_mask);
-	}
-	if (test_bit(ADC3_TXFE, &priv->status_mask)) {
-		snd_soc_update_bits(codec, TOMTOM_A_TX_3_4_TXFE_CKDIV,
-				    0x0F, 0x05);
-		clear_bit(ADC3_TXFE, &priv->status_mask);
-	}
-	if (test_bit(ADC4_TXFE, &priv->status_mask)) {
-		snd_soc_update_bits(codec, TOMTOM_A_TX_3_4_TXFE_CKDIV,
-				    0xF0, 0x50);
-		clear_bit(ADC4_TXFE, &priv->status_mask);
-	}
-	if (test_bit(ADC5_TXFE, &priv->status_mask)) {
-		snd_soc_update_bits(codec, TOMTOM_A_TX_5_6_TXFE_CKDIV,
-				    0x0F, 0x05);
-		clear_bit(ADC5_TXFE, &priv->status_mask);
-	}
-	if (test_bit(ADC6_TXFE, &priv->status_mask)) {
-		snd_soc_update_bits(codec, TOMTOM_A_TX_5_6_TXFE_CKDIV,
-				    0xF0, 0x50);
-		clear_bit(ADC6_TXFE, &priv->status_mask);
-	}
-}
-
-static void tx_hpf_corner_freq_callback(struct work_struct *work)
-{
-	struct delayed_work *hpf_delayed_work;
-	struct hpf_work *hpf_work;
-	struct tomtom_priv *tomtom;
-	struct snd_soc_codec *codec;
-	u16 tx_mux_ctl_reg;
-	u8 hpf_cut_of_freq;
-
-	hpf_delayed_work = to_delayed_work(work);
-	hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
-	tomtom = hpf_work->tomtom;
-	codec = hpf_work->tomtom->codec;
-	hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
-
-	tx_mux_ctl_reg = TOMTOM_A_CDC_TX1_MUX_CTL +
-			(hpf_work->decimator - 1) * 8;
-
-	pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
-		hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
-
-	/*
-	 * Restore TXFE ClkDiv registers to default.
-	 * If any of these registers are modified during analog
-	 * front-end enablement, they will be restored back to the
-	 * default
-	 */
-	txfe_clkdiv_update(codec);
-
-	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
-}
-
-#define  TX_MUX_CTL_CUT_OFF_FREQ_MASK	0x30
-#define  CF_MIN_3DB_4HZ			0x0
-#define  CF_MIN_3DB_75HZ		0x1
-#define  CF_MIN_3DB_150HZ		0x2
-
-static int tomtom_codec_enable_dec(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	unsigned int decimator;
-	char *dec_name = NULL;
-	char *widget_name = NULL;
-	char *temp;
-	int ret = 0;
-	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
-	u8 dec_hpf_cut_of_freq;
-	int offset;
-	char *dec;
-
-	pr_debug("%s %d\n", __func__, event);
-
-	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
-	if (!widget_name)
-		return -ENOMEM;
-	temp = widget_name;
-
-	dec_name = strsep(&widget_name, " ");
-	widget_name = temp;
-	if (!dec_name) {
-		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
-		ret =  -EINVAL;
-		goto out;
-	}
-
-	dec = strpbrk(dec_name, "123456789");
-	if (!dec) {
-		dev_err(codec->dev, "%s: decimator index not found\n",
-			__func__);
-		ret =  -EINVAL;
-		goto out;
-	}
-
-	ret = kstrtouint(dec, 10, &decimator);
-	if (ret < 0) {
-		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
-		ret =  -EINVAL;
-		goto out;
-	}
-
-	pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
-			w->name, dec_name, decimator);
-
-	if (w->reg == TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
-		dec_reset_reg = TOMTOM_A_CDC_CLK_TX_RESET_B1_CTL;
-		offset = 0;
-	} else if (w->reg == TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
-		dec_reset_reg = TOMTOM_A_CDC_CLK_TX_RESET_B2_CTL;
-		offset = 8;
-	} else {
-		pr_err("%s: Error, incorrect dec\n", __func__);
-		return -EINVAL;
-	}
-
-	tx_vol_ctl_reg = TOMTOM_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
-	tx_mux_ctl_reg = TOMTOM_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-
-		/* Enableable TX digital mute */
-		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
-
-		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
-			1 << w->shift);
-		snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
-
-		pr_debug("%s: decimator = %u, bypass = %d\n", __func__,
-			decimator, tx_hpf_work[decimator - 1].tx_hpf_bypass);
-		if (tx_hpf_work[decimator - 1].tx_hpf_bypass != true) {
-			dec_hpf_cut_of_freq = snd_soc_read(codec,
-							tx_mux_ctl_reg);
-
-			dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
-
-			tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
-				dec_hpf_cut_of_freq;
-
-			if (dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ) {
-
-				/* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
-				snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
-							CF_MIN_3DB_150HZ << 4);
-			}
-
-			/* enable HPF */
-			snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x00);
-		} else
-			/* bypass HPF */
-			snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
-
-		break;
-
-	case SND_SOC_DAPM_POST_PMU:
-
-		/* Disable TX digital mute */
-		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
-
-		if ((tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
-				CF_MIN_3DB_150HZ) &&
-			(tx_hpf_work[decimator - 1].tx_hpf_bypass != true)) {
-
-			schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
-					msecs_to_jiffies(300));
-		}
-		/* apply the digital gain after the decimator is enabled*/
-		if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
-			snd_soc_write(codec,
-				  tx_digital_gain_reg[w->shift + offset],
-				  snd_soc_read(codec,
-				  tx_digital_gain_reg[w->shift + offset])
-				  );
-
-		break;
-
-	case SND_SOC_DAPM_PRE_PMD:
-
-		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
-		cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
-		break;
-
-	case SND_SOC_DAPM_POST_PMD:
-
-		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
-		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
-			(tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
-
-		break;
-	}
-out:
-	kfree(widget_name);
-	return ret;
-}
-
-static int tomtom_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
-				       struct snd_kcontrol *kcontrol, int event)
-{
-	int ret = 0;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *priv = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s: %d %s\n", __func__, event, w->name);
-
-	WARN_ONCE(!priv->spkdrv_reg, "SPKDRV supply %s isn't defined\n",
-		  WCD9XXX_VDD_SPKDRV_NAME);
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (priv->spkdrv_reg) {
-			ret = regulator_enable(priv->spkdrv_reg);
-			if (ret)
-				pr_err("%s: Failed to enable spkdrv_reg %s\n",
-				       __func__, WCD9XXX_VDD_SPKDRV_NAME);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (priv->spkdrv_reg) {
-			ret = regulator_disable(priv->spkdrv_reg);
-			if (ret)
-				pr_err("%s: Failed to disable spkdrv_reg %s\n",
-				       __func__, WCD9XXX_VDD_SPKDRV_NAME);
-		}
-		break;
-	}
-
-	return ret;
-}
-
-static int tomtom_codec_enable_vdd_spkr2(struct snd_soc_dapm_widget *w,
-				       struct snd_kcontrol *kcontrol, int event)
-{
-	int ret = 0;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *priv = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s: %d %s\n", __func__, event, w->name);
-
-	/*
-	 * If on-demand voltage regulators of spkr1 and spkr2 has been derived
-	 * from same power rail then same on-demand voltage regulator can be
-	 * used by both spkr1 and spkr2, if a separate device tree entry has
-	 * not been defined for on-demand voltage regulator for spkr2.
-	 */
-	if (!priv->spkdrv2_reg) {
-		if (priv->spkdrv_reg) {
-			priv->spkdrv2_reg = priv->spkdrv_reg;
-		} else {
-			WARN_ONCE(!priv->spkdrv2_reg,
-					"SPKDRV2 supply %s isn't defined\n",
-					WCD9XXX_VDD_SPKDRV2_NAME);
-			return 0;
-		}
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (priv->spkdrv2_reg) {
-			ret = regulator_enable(priv->spkdrv2_reg);
-			if (ret)
-				pr_err("%s: Failed to enable spkdrv2_reg %s ret:%d\n",
-				       __func__, WCD9XXX_VDD_SPKDRV2_NAME, ret);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (priv->spkdrv2_reg) {
-			ret = regulator_disable(priv->spkdrv2_reg);
-			if (ret)
-				pr_err("%s: Failed to disable spkdrv2_reg %s ret:%d\n",
-				       __func__, WCD9XXX_VDD_SPKDRV2_NAME, ret);
-		}
-		break;
-	}
-
-	return ret;
-}
-
-static int tomtom_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-	pr_debug("%s %d %s\n", __func__, event, w->name);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_RX_RESET_CTL,
-			1 << w->shift, 1 << w->shift);
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_RX_RESET_CTL,
-			1 << w->shift, 0x0);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		/* apply the digital gain after the interpolator is enabled*/
-		if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
-			snd_soc_write(codec,
-				  rx_digital_gain_reg[w->shift],
-				  snd_soc_read(codec,
-				  rx_digital_gain_reg[w->shift])
-				  );
-		/* Check for Rx1 and Rx2 paths for uhqa mode update */
-		if (w->shift == 0 || w->shift == 1)
-			tomtom_update_uhqa_mode(codec, (1 << w->shift));
-
-		break;
-	}
-	return 0;
-}
-
-/* called under codec_resource_lock acquisition */
-static int __tomtom_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
-				      struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *priv = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s: enter\n", __func__);
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		/*
-		 * ldo_h_users is protected by tomtom->codec_mutex, don't need
-		 * additional mutex
-		 */
-		if (++priv->ldo_h_users == 1) {
-			WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
-			wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
-						   WCD9XXX_BANDGAP_AUDIO_MODE);
-			WCD9XXX_BG_CLK_UNLOCK(&priv->resmgr);
-			tomtom_codec_internal_rco_ctrl(codec, true);
-			snd_soc_update_bits(codec, TOMTOM_A_LDO_H_MODE_1,
-					    1 << 7, 1 << 7);
-			tomtom_codec_internal_rco_ctrl(codec, false);
-			pr_debug("%s: ldo_h_users %d\n", __func__,
-				 priv->ldo_h_users);
-			/* LDO enable requires 1ms to settle down */
-			usleep_range(1000, 1100);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (--priv->ldo_h_users == 0) {
-			tomtom_codec_internal_rco_ctrl(codec, true);
-			snd_soc_update_bits(codec, TOMTOM_A_LDO_H_MODE_1,
-					    1 << 7, 0);
-			tomtom_codec_internal_rco_ctrl(codec, false);
-			WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
-			wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
-						   WCD9XXX_BANDGAP_AUDIO_MODE);
-			WCD9XXX_BG_CLK_UNLOCK(&priv->resmgr);
-			pr_debug("%s: ldo_h_users %d\n", __func__,
-				 priv->ldo_h_users);
-		}
-		WARN(priv->ldo_h_users < 0, "Unexpected ldo_h users %d\n",
-		     priv->ldo_h_users);
-		break;
-	}
-	pr_debug("%s: leave\n", __func__);
-	return 0;
-}
-
-static int tomtom_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
-				    struct snd_kcontrol *kcontrol, int event)
-{
-	int rc;
-
-	rc = __tomtom_codec_enable_ldo_h(w, kcontrol, event);
-	return rc;
-}
-
-static int tomtom_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s %d\n", __func__, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		wcd9xxx_resmgr_enable_rx_bias(&tomtom->resmgr, 1);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		wcd9xxx_resmgr_enable_rx_bias(&tomtom->resmgr, 0);
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	const char *filename;
-	const struct firmware *fw;
-	int i;
-	int ret = 0;
-	int num_anc_slots;
-	struct wcd9xxx_anc_header *anc_head;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	struct firmware_cal *hwdep_cal = NULL;
-	u32 anc_writes_size = 0;
-	u32 anc_cal_size = 0;
-	int anc_size_remaining;
-	u32 *anc_ptr;
-	u16 reg;
-	u8 mask, val, old_val;
-	size_t cal_size;
-	const void *data;
-
-	if (tomtom->anc_func == 0)
-		return 0;
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		filename = "wcd9320/wcd9320_anc.bin";
-
-		hwdep_cal = wcdcal_get_fw_cal(tomtom->fw_data, WCD9XXX_ANC_CAL);
-		if (hwdep_cal) {
-			data = hwdep_cal->data;
-			cal_size = hwdep_cal->size;
-			dev_dbg(codec->dev, "%s: using hwdep calibration\n",
-				__func__);
-		} else {
-			ret = request_firmware(&fw, filename, codec->dev);
-			if (ret != 0) {
-				dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
-					ret);
-				return -ENODEV;
-			}
-			if (!fw) {
-				dev_err(codec->dev, "failed to get anc fw");
-				return -ENODEV;
-			}
-			data = fw->data;
-			cal_size = fw->size;
-			dev_dbg(codec->dev, "%s: using request_firmware calibration\n",
-				__func__);
-		}
-		if (cal_size < sizeof(struct wcd9xxx_anc_header)) {
-			dev_err(codec->dev, "Not enough data\n");
-			ret = -ENOMEM;
-			goto err;
-		}
-		/* First number is the number of register writes */
-		anc_head = (struct wcd9xxx_anc_header *)(data);
-		anc_ptr = (u32 *)(data +
-				  sizeof(struct wcd9xxx_anc_header));
-		anc_size_remaining = cal_size -
-				     sizeof(struct wcd9xxx_anc_header);
-		num_anc_slots = anc_head->num_anc_slots;
-
-		if (tomtom->anc_slot >= num_anc_slots) {
-			dev_err(codec->dev, "Invalid ANC slot selected\n");
-			ret = -EINVAL;
-			goto err;
-		}
-		for (i = 0; i < num_anc_slots; i++) {
-			if (anc_size_remaining < TOMTOM_PACKED_REG_SIZE) {
-				dev_err(codec->dev, "Invalid register format\n");
-				ret = -EINVAL;
-				goto err;
-			}
-			anc_writes_size = (u32)(*anc_ptr);
-			anc_size_remaining -= sizeof(u32);
-			anc_ptr += 1;
-
-			if (anc_writes_size * TOMTOM_PACKED_REG_SIZE
-				> anc_size_remaining) {
-				dev_err(codec->dev, "Invalid register format\n");
-				ret = -EINVAL;
-				goto err;
-			}
-
-			if (tomtom->anc_slot == i)
-				break;
-
-			anc_size_remaining -= (anc_writes_size *
-				TOMTOM_PACKED_REG_SIZE);
-			anc_ptr += anc_writes_size;
-		}
-		if (i == num_anc_slots) {
-			dev_err(codec->dev, "Selected ANC slot not present\n");
-			ret = -EINVAL;
-			goto err;
-		}
-
-		i = 0;
-		anc_cal_size = anc_writes_size;
-		if (w->reg == TOMTOM_A_RX_HPH_L_DAC_CTL) {
-			snd_soc_update_bits(codec,
-				TOMTOM_A_CDC_CLK_ANC_RESET_CTL, 0x03, 0x03);
-			anc_writes_size = (anc_cal_size/2);
-		}
-
-		if (w->reg == TOMTOM_A_RX_HPH_R_DAC_CTL) {
-			snd_soc_update_bits(codec,
-				TOMTOM_A_CDC_CLK_ANC_RESET_CTL, 0x0C, 0x0C);
-			i = (anc_cal_size/2);
-			anc_writes_size = anc_cal_size;
-		}
-
-		for (; i < anc_writes_size; i++) {
-			TOMTOM_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
-				mask, val);
-			/*
-			 * ANC Soft reset register is ignored from ACDB
-			 * because ANC left soft reset bits will be called
-			 * while enabling ANC HPH Right DAC.
-			 */
-			if ((reg == TOMTOM_A_CDC_CLK_ANC_RESET_CTL) &&
-				((w->reg == TOMTOM_A_RX_HPH_L_DAC_CTL) ||
-				(w->reg == TOMTOM_A_RX_HPH_R_DAC_CTL))) {
-				continue;
-			}
-			old_val = snd_soc_read(codec, reg);
-			snd_soc_write(codec, reg, (old_val & ~mask) |
-				(val & mask));
-		}
-		if (w->reg == TOMTOM_A_RX_HPH_L_DAC_CTL)
-			snd_soc_update_bits(codec,
-				TOMTOM_A_CDC_CLK_ANC_RESET_CTL, 0x03, 0x00);
-
-		if (w->reg == TOMTOM_A_RX_HPH_R_DAC_CTL)
-			snd_soc_update_bits(codec,
-				TOMTOM_A_CDC_CLK_ANC_RESET_CTL, 0x0C, 0x00);
-		if (!hwdep_cal)
-			release_firmware(fw);
-		txfe_clkdiv_update(codec);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		msleep(40);
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_ANC1_B1_CTL, 0x01,
-				    0x00);
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_ANC2_B1_CTL, 0x02,
-				    0x00);
-		msleep(20);
-		snd_soc_write(codec, TOMTOM_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
-		snd_soc_write(codec, TOMTOM_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
-		snd_soc_write(codec, TOMTOM_A_CDC_CLK_ANC_RESET_CTL, 0x00);
-		break;
-	}
-	return 0;
-err:
-	if (!hwdep_cal)
-		release_firmware(fw);
-	return ret;
-}
-
-static int tomtom_hphl_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-	uint32_t impedl, impedr;
-	int ret = 0;
-
-	pr_debug("%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (tomtom_p->anc_func) {
-			tomtom_codec_enable_anc(w, kcontrol, event);
-			msleep(50);
-		}
-
-		if (!high_perf_mode && !tomtom_p->uhqa_mode) {
-			wcd9xxx_clsh_fsm(codec, &tomtom_p->clsh_d,
-						 WCD9XXX_CLSH_STATE_HPHL,
-						 WCD9XXX_CLSH_REQ_ENABLE,
-						 WCD9XXX_CLSH_EVENT_PRE_DAC);
-		} else {
-			wcd9xxx_enable_high_perf_mode(codec, &tomtom_p->clsh_d,
-						tomtom_p->uhqa_mode,
-						WCD9XXX_CLSAB_STATE_HPHL,
-						WCD9XXX_CLSAB_REQ_ENABLE);
-		}
-		ret = wcd9xxx_mbhc_get_impedance(&tomtom_p->mbhc,
-					&impedl, &impedr);
-		if (!ret)
-			wcd9xxx_clsh_imped_config(codec, impedl);
-		else
-			dev_dbg(codec->dev, "%s: Failed to get mbhc impedance %d\n",
-						__func__, ret);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_RX1_B3_CTL, 0xBC, 0x94);
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_RX1_B4_CTL, 0x30, 0x10);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_RX1_B3_CTL, 0xBC, 0x00);
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_RX1_B4_CTL, 0x30, 0x00);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (!high_perf_mode && !tomtom_p->uhqa_mode) {
-			wcd9xxx_clsh_fsm(codec, &tomtom_p->clsh_d,
-						 WCD9XXX_CLSH_STATE_HPHL,
-						 WCD9XXX_CLSH_REQ_DISABLE,
-						 WCD9XXX_CLSH_EVENT_POST_PA);
-		} else {
-			wcd9xxx_enable_high_perf_mode(codec, &tomtom_p->clsh_d,
-						tomtom_p->uhqa_mode,
-						WCD9XXX_CLSAB_STATE_HPHL,
-						WCD9XXX_CLSAB_REQ_DISABLE);
-		}
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_hphr_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (tomtom_p->anc_func) {
-			tomtom_codec_enable_anc(w, kcontrol, event);
-			msleep(50);
-		}
-
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
-		if (!high_perf_mode && !tomtom_p->uhqa_mode) {
-			wcd9xxx_clsh_fsm(codec, &tomtom_p->clsh_d,
-						 WCD9XXX_CLSH_STATE_HPHR,
-						 WCD9XXX_CLSH_REQ_ENABLE,
-						 WCD9XXX_CLSH_EVENT_PRE_DAC);
-		} else {
-			wcd9xxx_enable_high_perf_mode(codec, &tomtom_p->clsh_d,
-						tomtom_p->uhqa_mode,
-						WCD9XXX_CLSAB_STATE_HPHR,
-						WCD9XXX_CLSAB_REQ_ENABLE);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_RX2_B3_CTL, 0xBC, 0x94);
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_RX2_B4_CTL, 0x30, 0x10);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_RX2_B3_CTL, 0xBC, 0x00);
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_RX2_B4_CTL, 0x30, 0x00);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
-		if (!high_perf_mode && !tomtom_p->uhqa_mode) {
-			wcd9xxx_clsh_fsm(codec, &tomtom_p->clsh_d,
-						 WCD9XXX_CLSH_STATE_HPHR,
-						 WCD9XXX_CLSH_REQ_DISABLE,
-						 WCD9XXX_CLSH_EVENT_POST_PA);
-		} else {
-			wcd9xxx_enable_high_perf_mode(codec, &tomtom_p->clsh_d,
-						tomtom_p->uhqa_mode,
-						WCD9XXX_CLSAB_STATE_HPHR,
-						WCD9XXX_CLSAB_REQ_DISABLE);
-		}
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_hph_pa_event(struct snd_soc_dapm_widget *w,
-			      struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	enum wcd9xxx_notify_event e_pre_on, e_post_off;
-	u8 req_clsh_state;
-	u32 pa_settle_time = TOMTOM_HPH_PA_SETTLE_COMP_OFF;
-
-	pr_debug("%s: %s event = %d\n", __func__, w->name, event);
-	if (w->shift == 5) {
-		e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
-		e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
-		req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
-	} else if (w->shift == 4) {
-		e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
-		e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
-		req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
-	} else {
-		pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
-		return -EINVAL;
-	}
-
-	if (tomtom->comp_enabled[COMPANDER_1])
-		pa_settle_time = TOMTOM_HPH_PA_SETTLE_COMP_ON;
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		set_bit(HPH_DELAY, &tomtom->status_mask);
-		/* Let MBHC module know PA is turning on */
-		wcd9xxx_resmgr_notifier_call(&tomtom->resmgr, e_pre_on);
-		break;
-
-	case SND_SOC_DAPM_POST_PMU:
-		if (test_bit(HPH_DELAY, &tomtom->status_mask)) {
-			/*
-			 * Make sure to wait 10ms after enabling HPHR_HPHL
-			 * in register 0x1AB
-			 */
-			usleep_range(pa_settle_time, pa_settle_time + 1000);
-			clear_bit(HPH_DELAY, &tomtom->status_mask);
-			pr_debug("%s: sleep %d us after %s PA enable\n",
-				__func__, pa_settle_time, w->name);
-		}
-		if (!high_perf_mode && !tomtom->uhqa_mode) {
-			wcd9xxx_clsh_fsm(codec, &tomtom->clsh_d,
-						 req_clsh_state,
-						 WCD9XXX_CLSH_REQ_ENABLE,
-						 WCD9XXX_CLSH_EVENT_POST_PA);
-		}
-		break;
-
-	case SND_SOC_DAPM_PRE_PMD:
-		set_bit(HPH_DELAY, &tomtom->status_mask);
-		break;
-
-	case SND_SOC_DAPM_POST_PMD:
-		/* Let MBHC module know PA turned off */
-		wcd9xxx_resmgr_notifier_call(&tomtom->resmgr, e_post_off);
-		if (test_bit(HPH_DELAY, &tomtom->status_mask)) {
-			/*
-			 * Make sure to wait 10ms after disabling HPHR_HPHL
-			 * in register 0x1AB
-			 */
-			usleep_range(pa_settle_time, pa_settle_time + 1000);
-			clear_bit(HPH_DELAY, &tomtom->status_mask);
-			pr_debug("%s: sleep %d us after %s PA disable\n",
-				__func__, pa_settle_time, w->name);
-		}
-
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_enable_anc_hph(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	int ret = 0;
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		ret = tomtom_hph_pa_event(w, kcontrol, event);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		if ((snd_soc_read(codec, TOMTOM_A_RX_HPH_L_DAC_CTL) & 0x80) &&
-			(snd_soc_read(codec, TOMTOM_A_RX_HPH_R_DAC_CTL)
-								& 0x80)) {
-			snd_soc_update_bits(codec,
-					TOMTOM_A_RX_HPH_CNP_EN, 0x30, 0x30);
-			msleep(30);
-		}
-		ret = tomtom_hph_pa_event(w, kcontrol, event);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		if (w->shift == 5) {
-			snd_soc_update_bits(codec,
-					TOMTOM_A_RX_HPH_CNP_EN, 0x30, 0x00);
-			msleep(40);
-			snd_soc_update_bits(codec,
-					TOMTOM_A_TX_7_MBHC_EN, 0x80, 00);
-			ret |= tomtom_codec_enable_anc(w, kcontrol, event);
-		}
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		ret = tomtom_hph_pa_event(w, kcontrol, event);
-		break;
-	}
-	return ret;
-}
-
-static const struct snd_soc_dapm_widget tomtom_dapm_i2s_widgets[] = {
-	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TOMTOM_A_CDC_CLK_RX_I2S_CTL,
-	4, 0, NULL, 0),
-	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TOMTOM_A_CDC_CLK_TX_I2S_CTL, 4,
-	0, NULL, 0),
-};
-
-static int tomtom_lineout_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		wcd9xxx_clsh_fsm(codec, &tomtom->clsh_d,
-						 WCD9XXX_CLSH_STATE_LO,
-						 WCD9XXX_CLSH_REQ_ENABLE,
-						 WCD9XXX_CLSH_EVENT_PRE_DAC);
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
-		break;
-
-	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
-		wcd9xxx_clsh_fsm(codec, &tomtom->clsh_d,
-						 WCD9XXX_CLSH_STATE_LO,
-						 WCD9XXX_CLSH_REQ_DISABLE,
-						 WCD9XXX_CLSH_EVENT_POST_PA);
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_spk_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-	pr_debug("%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
-							0x80, 0x80);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if ((snd_soc_read(codec, w->reg) & 0x03) == 0)
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
-							0x80, 0x00);
-		break;
-	}
-	return 0;
-}
-
-static const struct snd_soc_dapm_route audio_i2s_map[] = {
-	{"SLIM RX1", NULL, "RX_I2S_CLK"},
-	{"SLIM RX2", NULL, "RX_I2S_CLK"},
-	{"SLIM RX3", NULL, "RX_I2S_CLK"},
-	{"SLIM RX4", NULL, "RX_I2S_CLK"},
-
-	{"SLIM TX7 MUX", NULL, "TX_I2S_CLK"},
-	{"SLIM TX8 MUX", NULL, "TX_I2S_CLK"},
-	{"SLIM TX9 MUX", NULL, "TX_I2S_CLK"},
-	{"SLIM TX10 MUX", NULL, "TX_I2S_CLK"},
-
-	{"RX_I2S_CLK", NULL, "CDC_I2S_RX_CONN"},
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-	/* SLIMBUS Connections */
-	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
-	{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
-	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
-
-	/* VI Feedback */
-	{"AIF4 VI", NULL, "VIONOFF"},
-	{"VIONOFF", "Switch", "VIINPUT"},
-
-	/* MAD */
-	{"MAD_SEL MUX", "SPE", "MAD_CPE_INPUT"},
-	{"MAD_SEL MUX", "MSM", "MADINPUT"},
-	{"MADONOFF", "Switch", "MAD_SEL MUX"},
-	{"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"},
-	{"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
-	/* SLIM_MIXER("AIF2_CAP Mixer"),*/
-	{"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
-	/* SLIM_MIXER("AIF3_CAP Mixer"),*/
-	{"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
-
-	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
-	{"SLIM TX1 MUX", "RMIX5", "RX5 MIX1"},
-	{"SLIM TX1 MUX", "RMIX6", "RX6 MIX1"},
-	{"SLIM TX1 MUX", "RMIX7", "RX7 MIX1"},
-	{"SLIM TX1 MUX", "RMIX8", "RX8 MIX1"},
-
-	{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
-	{"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
-	{"SLIM TX2 MUX", "RMIX5", "RX5 MIX1"},
-	{"SLIM TX2 MUX", "RMIX6", "RX6 MIX1"},
-	{"SLIM TX2 MUX", "RMIX7", "RX7 MIX1"},
-	{"SLIM TX2 MUX", "RMIX8", "RX8 MIX1"},
-
-	{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
-	{"SLIM TX3 MUX", "RMIX5", "RX5 MIX1"},
-	{"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
-	{"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
-	{"SLIM TX3 MUX", "RMIX8", "RX8 MIX1"},
-
-	{"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
-	{"SLIM TX4 MUX", "RMIX5", "RX5 MIX1"},
-	{"SLIM TX4 MUX", "RMIX6", "RX6 MIX1"},
-	{"SLIM TX4 MUX", "RMIX7", "RX7 MIX1"},
-	{"SLIM TX4 MUX", "RMIX8", "RX8 MIX1"},
-
-	{"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
-	{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
-	{"SLIM TX5 MUX", "RMIX5", "RX5 MIX1"},
-	{"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
-	{"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
-	{"SLIM TX5 MUX", "RMIX8", "RX8 MIX1"},
-
-	{"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
-
-	{"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
-	{"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
-	{"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
-	{"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
-	{"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
-	{"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
-	{"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
-	{"SLIM TX7 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX7 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX7 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX7 MUX", "RMIX4", "RX4 MIX1"},
-	{"SLIM TX7 MUX", "RMIX5", "RX5 MIX1"},
-	{"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
-	{"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
-
-	{"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
-	{"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
-	{"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
-	{"SLIM TX8 MUX", "DEC7", "DEC7 MUX"},
-	{"SLIM TX8 MUX", "DEC8", "DEC8 MUX"},
-	{"SLIM TX8 MUX", "DEC9", "DEC9 MUX"},
-	{"SLIM TX8 MUX", "DEC10", "DEC10 MUX"},
-
-	{"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
-	{"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
-	{"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
-	{"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
-	{"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
-	{"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
-	{"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
-
-	{"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
-	{"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
-	{"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
-	{"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
-	{"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
-	{"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
-	{"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
-
-	/* Earpiece (RX MIX1) */
-	{"EAR", NULL, "EAR PA"},
-	{"EAR PA", NULL, "EAR_PA_MIXER"},
-	{"EAR_PA_MIXER", NULL, "DAC1"},
-	{"DAC1", NULL, "RX_BIAS"},
-
-	{"ANC EAR", NULL, "ANC EAR PA"},
-	{"ANC EAR PA", NULL, "EAR_PA_MIXER"},
-	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
-	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
-
-	/* Headset (RX MIX1 and RX MIX2) */
-	{"HEADPHONE", NULL, "HPHL"},
-	{"HEADPHONE", NULL, "HPHR"},
-
-	{"HPHL", NULL, "HPHL_PA_MIXER"},
-	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
-	{"HPHL DAC", NULL, "RX_BIAS"},
-
-	{"HPHR", NULL, "HPHR_PA_MIXER"},
-	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
-	{"HPHR DAC", NULL, "RX_BIAS"},
-
-	{"ANC HEADPHONE", NULL, "ANC HPHL"},
-	{"ANC HEADPHONE", NULL, "ANC HPHR"},
-
-	{"ANC HPHL", NULL, "HPHL_PA_MIXER"},
-	{"ANC HPHR", NULL, "HPHR_PA_MIXER"},
-
-	{"ANC1 MUX", "ADC1", "ADC1"},
-	{"ANC1 MUX", "ADC2", "ADC2"},
-	{"ANC1 MUX", "ADC3", "ADC3"},
-	{"ANC1 MUX", "ADC4", "ADC4"},
-	{"ANC1 MUX", "ADC5", "ADC5"},
-	{"ANC1 MUX", "ADC6", "ADC6"},
-	{"ANC1 MUX", "DMIC1", "DMIC1"},
-	{"ANC1 MUX", "DMIC2", "DMIC2"},
-	{"ANC1 MUX", "DMIC3", "DMIC3"},
-	{"ANC1 MUX", "DMIC4", "DMIC4"},
-	{"ANC1 MUX", "DMIC5", "DMIC5"},
-	{"ANC1 MUX", "DMIC6", "DMIC6"},
-	{"ANC2 MUX", "ADC1", "ADC1"},
-	{"ANC2 MUX", "ADC2", "ADC2"},
-	{"ANC2 MUX", "ADC3", "ADC3"},
-	{"ANC2 MUX", "ADC4", "ADC4"},
-	{"ANC2 MUX", "ADC5", "ADC5"},
-	{"ANC2 MUX", "ADC6", "ADC6"},
-	{"ANC2 MUX", "DMIC1", "DMIC1"},
-	{"ANC2 MUX", "DMIC2", "DMIC2"},
-	{"ANC2 MUX", "DMIC3", "DMIC3"},
-	{"ANC2 MUX", "DMIC4", "DMIC4"},
-	{"ANC2 MUX", "DMIC5", "DMIC5"},
-	{"ANC2 MUX", "DMIC6", "DMIC6"},
-
-	{"ANC HPHR", NULL, "CDC_CONN"},
-
-	{"DAC1", "Switch", "CLASS_H_DSM MUX"},
-	{"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
-	{"HPHR DAC", NULL, "RX2 CHAIN"},
-
-	{"LINEOUT1", NULL, "LINEOUT1 PA"},
-	{"LINEOUT2", NULL, "LINEOUT2 PA"},
-	{"LINEOUT3", NULL, "LINEOUT3 PA"},
-	{"LINEOUT4", NULL, "LINEOUT4 PA"},
-	{"SPK_OUT", NULL, "SPK PA"},
-	{"SPK_OUT", NULL, "SPK2 PA"},
-
-	{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
-	{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
-
-	{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
-	{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
-
-	{"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
-	{"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
-
-	{"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
-	{"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
-
-	{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
-
-	{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
-	{"RDAC5 MUX", "DEM4", "RX4 MIX1"},
-
-	{"LINEOUT3 DAC", NULL, "RDAC5 MUX"},
-
-	{"LINEOUT2 DAC", NULL, "RX5 MIX1"},
-
-	{"RDAC7 MUX", "DEM5_INV", "RX5 MIX1"},
-	{"RDAC7 MUX", "DEM6", "RX6 MIX1"},
-
-	{"LINEOUT4 DAC", NULL, "RDAC7 MUX"},
-
-	{"SPK PA", NULL, "SPK DAC"},
-	{"SPK DAC", NULL, "RX7 MIX2"},
-	{"SPK DAC", NULL, "VDD_SPKDRV"},
-
-	{"SPK2 PA", NULL, "SPK2 DAC"},
-	{"SPK2 DAC", NULL, "RX8 MIX1"},
-	{"SPK2 DAC", NULL, "VDD_SPKDRV2"},
-
-	{"CLASS_H_DSM MUX", "DSM_HPHL_RX1", "RX1 CHAIN"},
-
-	{"RX1 INTERP", NULL, "RX1 MIX2"},
-	{"RX1 CHAIN", NULL, "RX1 INTERP"},
-	{"RX2 INTERP", NULL, "RX2 MIX2"},
-	{"RX2 CHAIN", NULL, "RX2 INTERP"},
-	{"RX1 MIX2", NULL, "ANC1 MUX"},
-	{"RX2 MIX2", NULL, "ANC2 MUX"},
-
-	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
-	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
-	{"LINEOUT3 DAC", NULL, "RX_BIAS"},
-	{"LINEOUT4 DAC", NULL, "RX_BIAS"},
-	{"SPK DAC", NULL, "RX_BIAS"},
-	{"SPK2 DAC", NULL, "RX_BIAS"},
-
-	{"RX7 MIX1", NULL, "COMP0_CLK"},
-	{"RX8 MIX1", NULL, "COMP0_CLK"},
-	{"RX1 MIX1", NULL, "COMP1_CLK"},
-	{"RX2 MIX1", NULL, "COMP1_CLK"},
-	{"RX3 MIX1", NULL, "COMP2_CLK"},
-	{"RX5 MIX1", NULL, "COMP2_CLK"},
-
-	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
-	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
-	{"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
-	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
-	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
-	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
-	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
-	{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
-	{"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
-	{"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
-	{"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
-	{"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
-	{"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
-	{"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
-	{"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
-	{"RX8 MIX1", NULL, "RX8 MIX1 INP1"},
-	{"RX8 MIX1", NULL, "RX8 MIX1 INP2"},
-	{"RX1 MIX2", NULL, "RX1 MIX1"},
-	{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
-	{"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
-	{"RX2 MIX2", NULL, "RX2 MIX1"},
-	{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
-	{"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
-	{"RX7 MIX2", NULL, "RX7 MIX1"},
-	{"RX7 MIX2", NULL, "RX7 MIX2 INP1"},
-	{"RX7 MIX2", NULL, "RX7 MIX2 INP2"},
-
-	/* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
-	{"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
-	{"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
-	{"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
-	{"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
-	{"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
-	{"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
-	{"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
-	{"SLIM RX8 MUX", "AIF1_PB", "AIF1 PB"},
-	/* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
-	{"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
-	{"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
-	{"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
-	{"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
-	{"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
-	{"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
-	{"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
-	{"SLIM RX8 MUX", "AIF2_PB", "AIF2 PB"},
-	/* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
-	{"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
-	{"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
-	{"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
-	{"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
-	{"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
-	{"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
-	{"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
-	{"SLIM RX8 MUX", "AIF3_PB", "AIF3 PB"},
-
-	{"SLIM RX1", NULL, "SLIM RX1 MUX"},
-	{"SLIM RX2", NULL, "SLIM RX2 MUX"},
-	{"SLIM RX3", NULL, "SLIM RX3 MUX"},
-	{"SLIM RX4", NULL, "SLIM RX4 MUX"},
-	{"SLIM RX5", NULL, "SLIM RX5 MUX"},
-	{"SLIM RX6", NULL, "SLIM RX6 MUX"},
-	{"SLIM RX7", NULL, "SLIM RX7 MUX"},
-	{"SLIM RX8", NULL, "SLIM RX8 MUX"},
-
-	{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX1 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX1 MIX1 INP2", "IIR2", "IIR2"},
-	{"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
-	{"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
-	{"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
-	{"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
-	{"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
-	{"RX1 MIX1 INP3", "RX6", "SLIM RX6"},
-	{"RX1 MIX1 INP3", "RX7", "SLIM RX7"},
-	{"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX2 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX2 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX2 MIX1 INP2", "IIR2", "IIR2"},
-	{"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX3 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX3 MIX1 INP2", "IIR2", "IIR2"},
-	{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX4 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX4 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX4 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX4 MIX1 INP2", "IIR2", "IIR2"},
-	{"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX5 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX5 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX5 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX5 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX5 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX5 MIX1 INP2", "IIR2", "IIR2"},
-	{"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX6 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX6 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX6 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX6 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX6 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX6 MIX1 INP2", "IIR2", "IIR2"},
-	{"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX7 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX7 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX7 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX7 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX7 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX7 MIX1 INP2", "IIR2", "IIR2"},
-	{"RX8 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX8 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX8 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX8 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX8 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX8 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX8 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX8 MIX1 INP1", "RX8", "SLIM RX8"},
-	{"RX8 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX8 MIX1 INP1", "IIR2", "IIR2"},
-	{"RX8 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX8 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX8 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX8 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX8 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX8 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX8 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX8 MIX1 INP2", "RX8", "SLIM RX8"},
-	{"RX8 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX8 MIX1 INP2", "IIR2", "IIR2"},
-
-	/* IIR1, IIR2 inputs to Second RX Mixer on RX1, RX2 and RX7 chains. */
-	{"RX1 MIX2 INP1", "IIR1", "IIR1"},
-	{"RX1 MIX2 INP2", "IIR1", "IIR1"},
-	{"RX2 MIX2 INP1", "IIR1", "IIR1"},
-	{"RX2 MIX2 INP2", "IIR1", "IIR1"},
-	{"RX7 MIX2 INP1", "IIR1", "IIR1"},
-	{"RX7 MIX2 INP2", "IIR1", "IIR1"},
-	{"RX1 MIX2 INP1", "IIR2", "IIR2"},
-	{"RX1 MIX2 INP2", "IIR2", "IIR2"},
-	{"RX2 MIX2 INP1", "IIR2", "IIR2"},
-	{"RX2 MIX2 INP2", "IIR2", "IIR2"},
-	{"RX7 MIX2 INP1", "IIR2", "IIR2"},
-	{"RX7 MIX2 INP2", "IIR2", "IIR2"},
-
-	/* Decimator Inputs */
-	{"DEC1 MUX", "DMIC1", "DMIC1"},
-	{"DEC1 MUX", "ADC6", "ADC6"},
-	{"DEC1 MUX", NULL, "CDC_CONN"},
-	{"DEC2 MUX", "DMIC2", "DMIC2"},
-	{"DEC2 MUX", "ADC5", "ADC5"},
-	{"DEC2 MUX", NULL, "CDC_CONN"},
-	{"DEC3 MUX", "DMIC3", "DMIC3"},
-	{"DEC3 MUX", "ADC4", "ADC4"},
-	{"DEC3 MUX", NULL, "CDC_CONN"},
-	{"DEC4 MUX", "DMIC4", "DMIC4"},
-	{"DEC4 MUX", "ADC3", "ADC3"},
-	{"DEC4 MUX", NULL, "CDC_CONN"},
-	{"DEC5 MUX", "DMIC5", "DMIC5"},
-	{"DEC5 MUX", "ADC2", "ADC2"},
-	{"DEC5 MUX", NULL, "CDC_CONN"},
-	{"DEC6 MUX", "DMIC6", "DMIC6"},
-	{"DEC6 MUX", "ADC1", "ADC1"},
-	{"DEC6 MUX", NULL, "CDC_CONN"},
-	{"DEC7 MUX", "DMIC1", "DMIC1"},
-	{"DEC7 MUX", "DMIC6", "DMIC6"},
-	{"DEC7 MUX", "ADC1", "ADC1"},
-	{"DEC7 MUX", "ADC6", "ADC6"},
-	{"DEC7 MUX", "ANC1_FB", "ANC1 MUX"},
-	{"DEC7 MUX", "ANC2_FB", "ANC2 MUX"},
-	{"DEC7 MUX", NULL, "CDC_CONN"},
-	{"DEC8 MUX", "DMIC2", "DMIC2"},
-	{"DEC8 MUX", "DMIC5", "DMIC5"},
-	{"DEC8 MUX", "ADC2", "ADC2"},
-	{"DEC8 MUX", "ADC5", "ADC5"},
-	{"DEC8 MUX", "ANC1_FB", "ANC1 MUX"},
-	{"DEC8 MUX", "ANC2_FB", "ANC2 MUX"},
-	{"DEC8 MUX", NULL, "CDC_CONN"},
-	{"DEC9 MUX", "DMIC4", "DMIC4"},
-	{"DEC9 MUX", "DMIC5", "DMIC5"},
-	{"DEC9 MUX", "ADC2", "ADC2"},
-	{"DEC9 MUX", "ADC3", "ADC3"},
-	{"DEC9 MUX", "ANC1_FB", "ANC1 MUX"},
-	{"DEC9 MUX", "ANC2_FB", "ANC2 MUX"},
-	{"DEC9 MUX", NULL, "CDC_CONN"},
-	{"DEC10 MUX", "DMIC3", "DMIC3"},
-	{"DEC10 MUX", "DMIC6", "DMIC6"},
-	{"DEC10 MUX", "ADC1", "ADC1"},
-	{"DEC10 MUX", "ADC4", "ADC4"},
-	{"DEC10 MUX", "ANC1_FB", "ANC1 MUX"},
-	{"DEC10 MUX", "ANC2_FB", "ANC2 MUX"},
-	{"DEC10 MUX", NULL, "CDC_CONN"},
-
-	/* ADC Connections */
-	{"ADC1", NULL, "AMIC1"},
-	{"ADC2", NULL, "AMIC2"},
-	{"ADC3", NULL, "AMIC3"},
-	{"ADC4", NULL, "AMIC4"},
-	{"ADC5", NULL, "AMIC5"},
-	{"ADC6", NULL, "AMIC6"},
-
-	/* AUX PGA Connections */
-	{"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"AUX_PGA_Left", NULL, "AMIC5"},
-	{"AUX_PGA_Right", NULL, "AMIC6"},
-
-	{"IIR1", NULL, "IIR1 INP1 MUX"},
-	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
-	{"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
-	{"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
-	{"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
-	{"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
-	{"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
-	{"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
-	{"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
-	{"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
-	{"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
-	{"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
-	{"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
-	{"IIR1 INP1 MUX", "RX6", "SLIM RX6"},
-	{"IIR1 INP1 MUX", "RX7", "SLIM RX7"},
-
-	{"IIR2", NULL, "IIR2 INP1 MUX"},
-	{"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR2 INP1 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR2 INP1 MUX", "DEC4", "DEC4 MUX"},
-	{"IIR2 INP1 MUX", "DEC5", "DEC5 MUX"},
-	{"IIR2 INP1 MUX", "DEC6", "DEC6 MUX"},
-	{"IIR2 INP1 MUX", "DEC7", "DEC7 MUX"},
-	{"IIR2 INP1 MUX", "DEC8", "DEC8 MUX"},
-	{"IIR2 INP1 MUX", "DEC9", "DEC9 MUX"},
-	{"IIR2 INP1 MUX", "DEC10", "DEC10 MUX"},
-	{"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
-	{"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
-	{"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
-	{"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
-	{"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
-	{"IIR2 INP1 MUX", "RX6", "SLIM RX6"},
-	{"IIR2 INP1 MUX", "RX7", "SLIM RX7"},
-
-	{"IIR1", NULL, "IIR1 INP2 MUX"},
-	{"IIR1 INP2 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR1 INP2 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR1 INP2 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR1 INP2 MUX", "DEC4", "DEC4 MUX"},
-	{"IIR1 INP2 MUX", "DEC5", "DEC5 MUX"},
-	{"IIR1 INP2 MUX", "DEC6", "DEC6 MUX"},
-	{"IIR1 INP2 MUX", "DEC7", "DEC7 MUX"},
-	{"IIR1 INP2 MUX", "DEC8", "DEC8 MUX"},
-	{"IIR1 INP2 MUX", "DEC9", "DEC9 MUX"},
-	{"IIR1 INP2 MUX", "DEC10", "DEC10 MUX"},
-	{"IIR1 INP2 MUX", "RX1", "SLIM RX1"},
-	{"IIR1 INP2 MUX", "RX2", "SLIM RX2"},
-	{"IIR1 INP2 MUX", "RX3", "SLIM RX3"},
-	{"IIR1 INP2 MUX", "RX4", "SLIM RX4"},
-	{"IIR1 INP2 MUX", "RX5", "SLIM RX5"},
-	{"IIR1 INP2 MUX", "RX6", "SLIM RX6"},
-	{"IIR1 INP2 MUX", "RX7", "SLIM RX7"},
-
-	{"IIR2", NULL, "IIR2 INP2 MUX"},
-	{"IIR2 INP2 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR2 INP2 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR2 INP2 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR2 INP2 MUX", "DEC4", "DEC4 MUX"},
-	{"IIR2 INP2 MUX", "DEC5", "DEC5 MUX"},
-	{"IIR2 INP2 MUX", "DEC6", "DEC6 MUX"},
-	{"IIR2 INP2 MUX", "DEC7", "DEC7 MUX"},
-	{"IIR2 INP2 MUX", "DEC8", "DEC8 MUX"},
-	{"IIR2 INP2 MUX", "DEC9", "DEC9 MUX"},
-	{"IIR2 INP2 MUX", "DEC10", "DEC10 MUX"},
-	{"IIR2 INP2 MUX", "RX1", "SLIM RX1"},
-	{"IIR2 INP2 MUX", "RX2", "SLIM RX2"},
-	{"IIR2 INP2 MUX", "RX3", "SLIM RX3"},
-	{"IIR2 INP2 MUX", "RX4", "SLIM RX4"},
-	{"IIR2 INP2 MUX", "RX5", "SLIM RX5"},
-	{"IIR2 INP2 MUX", "RX6", "SLIM RX6"},
-	{"IIR2 INP2 MUX", "RX7", "SLIM RX7"},
-
-	{"IIR1", NULL, "IIR1 INP3 MUX"},
-	{"IIR1 INP3 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR1 INP3 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR1 INP3 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR1 INP3 MUX", "DEC4", "DEC4 MUX"},
-	{"IIR1 INP3 MUX", "DEC5", "DEC5 MUX"},
-	{"IIR1 INP3 MUX", "DEC6", "DEC6 MUX"},
-	{"IIR1 INP3 MUX", "DEC7", "DEC7 MUX"},
-	{"IIR1 INP3 MUX", "DEC8", "DEC8 MUX"},
-	{"IIR1 INP3 MUX", "DEC9", "DEC9 MUX"},
-	{"IIR1 INP3 MUX", "DEC10", "DEC10 MUX"},
-	{"IIR1 INP3 MUX", "RX1", "SLIM RX1"},
-	{"IIR1 INP3 MUX", "RX2", "SLIM RX2"},
-	{"IIR1 INP3 MUX", "RX3", "SLIM RX3"},
-	{"IIR1 INP3 MUX", "RX4", "SLIM RX4"},
-	{"IIR1 INP3 MUX", "RX5", "SLIM RX5"},
-	{"IIR1 INP3 MUX", "RX6", "SLIM RX6"},
-	{"IIR1 INP3 MUX", "RX7", "SLIM RX7"},
-
-	{"IIR2", NULL, "IIR2 INP3 MUX"},
-	{"IIR2 INP3 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR2 INP3 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR2 INP3 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR2 INP3 MUX", "DEC4", "DEC4 MUX"},
-	{"IIR2 INP3 MUX", "DEC5", "DEC5 MUX"},
-	{"IIR2 INP3 MUX", "DEC6", "DEC6 MUX"},
-	{"IIR2 INP3 MUX", "DEC7", "DEC7 MUX"},
-	{"IIR2 INP3 MUX", "DEC8", "DEC8 MUX"},
-	{"IIR2 INP3 MUX", "DEC9", "DEC9 MUX"},
-	{"IIR2 INP3 MUX", "DEC10", "DEC10 MUX"},
-	{"IIR2 INP3 MUX", "RX1", "SLIM RX1"},
-	{"IIR2 INP3 MUX", "RX2", "SLIM RX2"},
-	{"IIR2 INP3 MUX", "RX3", "SLIM RX3"},
-	{"IIR2 INP3 MUX", "RX4", "SLIM RX4"},
-	{"IIR2 INP3 MUX", "RX5", "SLIM RX5"},
-	{"IIR2 INP3 MUX", "RX6", "SLIM RX6"},
-	{"IIR2 INP3 MUX", "RX7", "SLIM RX7"},
-
-	{"IIR1", NULL, "IIR1 INP4 MUX"},
-	{"IIR1 INP4 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR1 INP4 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR1 INP4 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR1 INP4 MUX", "DEC4", "DEC4 MUX"},
-	{"IIR1 INP4 MUX", "DEC5", "DEC5 MUX"},
-	{"IIR1 INP4 MUX", "DEC6", "DEC6 MUX"},
-	{"IIR1 INP4 MUX", "DEC7", "DEC7 MUX"},
-	{"IIR1 INP4 MUX", "DEC8", "DEC8 MUX"},
-	{"IIR1 INP4 MUX", "DEC9", "DEC9 MUX"},
-	{"IIR1 INP4 MUX", "DEC10", "DEC10 MUX"},
-	{"IIR1 INP4 MUX", "RX1", "SLIM RX1"},
-	{"IIR1 INP4 MUX", "RX2", "SLIM RX2"},
-	{"IIR1 INP4 MUX", "RX3", "SLIM RX3"},
-	{"IIR1 INP4 MUX", "RX4", "SLIM RX4"},
-	{"IIR1 INP4 MUX", "RX5", "SLIM RX5"},
-	{"IIR1 INP4 MUX", "RX6", "SLIM RX6"},
-	{"IIR1 INP4 MUX", "RX7", "SLIM RX7"},
-
-	{"IIR2", NULL, "IIR2 INP4 MUX"},
-	{"IIR2 INP4 MUX", "DEC1", "DEC1 MUX"},
-	{"IIR2 INP4 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR2 INP4 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR2 INP4 MUX", "DEC4", "DEC4 MUX"},
-	{"IIR2 INP4 MUX", "DEC5", "DEC5 MUX"},
-	{"IIR2 INP4 MUX", "DEC6", "DEC6 MUX"},
-	{"IIR2 INP4 MUX", "DEC7", "DEC7 MUX"},
-	{"IIR2 INP4 MUX", "DEC8", "DEC8 MUX"},
-	{"IIR2 INP4 MUX", "DEC9", "DEC9 MUX"},
-	{"IIR2 INP4 MUX", "DEC10", "DEC10 MUX"},
-	{"IIR2 INP4 MUX", "RX1", "SLIM RX1"},
-	{"IIR2 INP4 MUX", "RX2", "SLIM RX2"},
-	{"IIR2 INP4 MUX", "RX3", "SLIM RX3"},
-	{"IIR2 INP4 MUX", "RX4", "SLIM RX4"},
-	{"IIR2 INP4 MUX", "RX5", "SLIM RX5"},
-	{"IIR2 INP4 MUX", "RX6", "SLIM RX6"},
-	{"IIR2 INP4 MUX", "RX7", "SLIM RX7"},
-
-	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
-	{"MIC BIAS1 Internal2", NULL, "LDO_H"},
-	{"MIC BIAS1 External", NULL, "LDO_H"},
-	{"MIC BIAS2 Internal1", NULL, "LDO_H"},
-	{"MIC BIAS2 Internal2", NULL, "LDO_H"},
-	{"MIC BIAS2 Internal3", NULL, "LDO_H"},
-	{"MIC BIAS2 External", NULL, "LDO_H"},
-	{"MIC BIAS3 Internal1", NULL, "LDO_H"},
-	{"MIC BIAS3 Internal2", NULL, "LDO_H"},
-	{"MIC BIAS3 External", NULL, "LDO_H"},
-	{"MIC BIAS4 External", NULL, "LDO_H"},
-	{DAPM_MICBIAS2_EXTERNAL_STANDALONE, NULL, "LDO_H Standalone"},
-};
-
-static int tomtom_startup(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
-{
-	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
-		 substream->name, substream->stream);
-
-	return 0;
-}
-
-static void tomtom_shutdown(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
-{
-	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
-		 substream->name, substream->stream);
-}
-
-int tomtom_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
-		 dapm);
-
-	WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-	if (mclk_enable) {
-		wcd9xxx_resmgr_get_bandgap(&tomtom->resmgr,
-					   WCD9XXX_BANDGAP_AUDIO_MODE);
-		wcd9xxx_resmgr_get_clk_block(&tomtom->resmgr, WCD9XXX_CLK_MCLK);
-	} else {
-		/* Put clock and BG */
-		wcd9xxx_resmgr_put_clk_block(&tomtom->resmgr, WCD9XXX_CLK_MCLK);
-		wcd9xxx_resmgr_put_bandgap(&tomtom->resmgr,
-					   WCD9XXX_BANDGAP_AUDIO_MODE);
-	}
-	WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-
-	return 0;
-}
-
-static int tomtom_set_dai_sysclk(struct snd_soc_dai *dai,
-		int clk_id, unsigned int freq, int dir)
-{
-	pr_debug("%s\n", __func__);
-	return 0;
-}
-
-static int tomtom_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-	u8 val = 0;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(dai->codec);
-
-	pr_debug("%s\n", __func__);
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBS_CFS:
-		/* CPU is master */
-		if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
-			if (dai->id == AIF1_CAP)
-				snd_soc_update_bits(dai->codec,
-					TOMTOM_A_CDC_CLK_TX_I2S_CTL,
-					TOMTOM_I2S_MASTER_MODE_MASK, 0);
-			else if (dai->id == AIF1_PB)
-				snd_soc_update_bits(dai->codec,
-					TOMTOM_A_CDC_CLK_RX_I2S_CTL,
-					TOMTOM_I2S_MASTER_MODE_MASK, 0);
-		}
-		break;
-	case SND_SOC_DAIFMT_CBM_CFM:
-	/* CPU is slave */
-		if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
-			val = TOMTOM_I2S_MASTER_MODE_MASK;
-			if (dai->id == AIF1_CAP)
-				snd_soc_update_bits(dai->codec,
-					TOMTOM_A_CDC_CLK_TX_I2S_CTL, val, val);
-			else if (dai->id == AIF1_PB)
-				snd_soc_update_bits(dai->codec,
-					TOMTOM_A_CDC_CLK_RX_I2S_CTL, val, val);
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int tomtom_set_channel_map(struct snd_soc_dai *dai,
-				unsigned int tx_num, unsigned int *tx_slot,
-				unsigned int rx_num, unsigned int *rx_slot)
-
-{
-	struct wcd9xxx_codec_dai_data *dai_data = NULL;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(dai->codec);
-	struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
-
-	if (!tx_slot || !rx_slot) {
-		pr_err("%s: Invalid tx_slot=%pK, rx_slot=%pK\n",
-			__func__, tx_slot, rx_slot);
-		return -EINVAL;
-	}
-	pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n"
-		 "tomtom->intf_type %d\n",
-		 __func__, dai->name, dai->id, tx_num, rx_num,
-		 tomtom->intf_type);
-
-	if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
-		wcd9xxx_init_slimslave(core, core->slim->laddr,
-					   tx_num, tx_slot, rx_num, rx_slot);
-		/*Reserve tx11 and tx12 for VI feedback path*/
-		dai_data = &tomtom->dai[AIF4_VIFEED];
-		if (dai_data) {
-			list_add_tail(&core->tx_chs[TOMTOM_TX11].list,
-			&dai_data->wcd9xxx_ch_list);
-			list_add_tail(&core->tx_chs[TOMTOM_TX12].list,
-			&dai_data->wcd9xxx_ch_list);
-		}
-
-		/* Reserve TX13 for MAD data channel */
-		dai_data = &tomtom->dai[AIF4_MAD_TX];
-		if (dai_data)
-			list_add_tail(&core->tx_chs[TOMTOM_TX13].list,
-				      &dai_data->wcd9xxx_ch_list);
-	}
-
-	return 0;
-}
-
-static int tomtom_get_channel_map(struct snd_soc_dai *dai,
-				 unsigned int *tx_num, unsigned int *tx_slot,
-				 unsigned int *rx_num, unsigned int *rx_slot)
-
-{
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(dai->codec);
-	u32 i = 0;
-	struct wcd9xxx_ch *ch;
-
-	switch (dai->id) {
-	case AIF1_PB:
-	case AIF2_PB:
-	case AIF3_PB:
-		if (!rx_slot || !rx_num) {
-			pr_err("%s: Invalid rx_slot %pK or rx_num %pK\n",
-				 __func__, rx_slot, rx_num);
-			return -EINVAL;
-		}
-		list_for_each_entry(ch, &tomtom_p->dai[dai->id].wcd9xxx_ch_list,
-				    list) {
-			pr_debug("%s: slot_num %u ch->ch_num %d\n",
-				 __func__, i, ch->ch_num);
-			rx_slot[i++] = ch->ch_num;
-		}
-		pr_debug("%s: rx_num %d\n", __func__, i);
-		*rx_num = i;
-		break;
-	case AIF1_CAP:
-	case AIF2_CAP:
-	case AIF3_CAP:
-	case AIF4_VIFEED:
-	case AIF4_MAD_TX:
-		if (!tx_slot || !tx_num) {
-			pr_err("%s: Invalid tx_slot %pK or tx_num %pK\n",
-				 __func__, tx_slot, tx_num);
-			return -EINVAL;
-		}
-		list_for_each_entry(ch, &tomtom_p->dai[dai->id].wcd9xxx_ch_list,
-				    list) {
-			pr_debug("%s: slot_num %u ch->ch_num %d\n",
-				 __func__, i,  ch->ch_num);
-			tx_slot[i++] = ch->ch_num;
-		}
-		pr_debug("%s: tx_num %d\n", __func__, i);
-		*tx_num = i;
-		break;
-
-	default:
-		pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id);
-		break;
-	}
-
-	return 0;
-}
-
-static int tomtom_set_interpolator_rate(struct snd_soc_dai *dai,
-	u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
-{
-	u32 j;
-	u8 rx_mix1_inp, rx8_mix1_inp;
-	u16 rx_mix_1_reg_1, rx_mix_1_reg_2;
-	u16 rx_fs_reg;
-	u8 rx_mix_1_reg_1_val, rx_mix_1_reg_2_val;
-	struct snd_soc_codec *codec = dai->codec;
-	struct wcd9xxx_ch *ch;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	int port_rx_8 = TOMTOM_RX_PORT_START_NUMBER + NUM_INTERPOLATORS - 1;
-
-	list_for_each_entry(ch, &tomtom->dai[dai->id].wcd9xxx_ch_list, list) {
-		/* for RX port starting from 16 instead of 10 like tabla */
-		rx_mix1_inp = ch->port + RX_MIX1_INP_SEL_RX1 -
-			      TOMTOM_TX_PORT_NUMBER;
-		rx8_mix1_inp = ch->port + RX8_MIX1_INP_SEL_RX1 -
-			       TOMTOM_RX_PORT_START_NUMBER;
-		if (((ch->port < port_rx_8) &&
-		     ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
-		      (rx_mix1_inp > RX_MIX1_INP_SEL_RX7))) ||
-		    ((rx8_mix1_inp < RX8_MIX1_INP_SEL_RX1) ||
-		     (rx8_mix1_inp > RX8_MIX1_INP_SEL_RX8))) {
-			pr_err("%s: Invalid TOMTOM_RX%u port. Dai ID is %d\n",
-					__func__,  rx8_mix1_inp - 2,
-					dai->id);
-			return -EINVAL;
-		}
-
-		rx_mix_1_reg_1 = TOMTOM_A_CDC_CONN_RX1_B1_CTL;
-
-		for (j = 0; j < NUM_INTERPOLATORS - 1; j++) {
-			rx_mix_1_reg_2 = rx_mix_1_reg_1 + 1;
-
-			rx_mix_1_reg_1_val = snd_soc_read(codec,
-							  rx_mix_1_reg_1);
-			rx_mix_1_reg_2_val = snd_soc_read(codec,
-							  rx_mix_1_reg_2);
-
-			if (((rx_mix_1_reg_1_val & 0x0F) == rx_mix1_inp) ||
-			    (((rx_mix_1_reg_1_val >> 4) & 0x0F)
-				== rx_mix1_inp) ||
-			    ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
-
-				rx_fs_reg = TOMTOM_A_CDC_RX1_B5_CTL + 8 * j;
-
-				pr_debug("%s: AIF_PB DAI(%d) connected to RX%u\n",
-					__func__, dai->id, j + 1);
-
-				pr_debug("%s: set RX%u sample rate to %u\n",
-					__func__, j + 1, sample_rate);
-
-				snd_soc_update_bits(codec, rx_fs_reg,
-						0xE0, rx_fs_rate_reg_val);
-
-				if (comp_rx_path[j] < COMPANDER_MAX)
-					tomtom->comp_fs[comp_rx_path[j]]
-					= compander_fs;
-			}
-			if (j < 2)
-				rx_mix_1_reg_1 += 3;
-			else
-				rx_mix_1_reg_1 += 2;
-		}
-
-		/* RX8 interpolator path */
-		rx_mix_1_reg_1_val = snd_soc_read(codec,
-						TOMTOM_A_CDC_CONN_RX8_B1_CTL);
-		if (((rx_mix_1_reg_1_val & 0x0F) == rx8_mix1_inp) ||
-		    (((rx_mix_1_reg_1_val >> 4) & 0x0F) == rx8_mix1_inp)) {
-			snd_soc_update_bits(codec, TOMTOM_A_CDC_RX8_B5_CTL,
-					    0xE0, rx_fs_rate_reg_val);
-			pr_debug("%s: AIF_PB DAI(%d) connected to RX%u\n",
-					__func__, dai->id, NUM_INTERPOLATORS);
-
-			pr_debug("%s: set RX%u sample rate to %u\n",
-					__func__, NUM_INTERPOLATORS,
-					sample_rate);
-			if (comp_rx_path[NUM_INTERPOLATORS - 1] < COMPANDER_MAX)
-				tomtom->comp_fs[comp_rx_path[j]] =
-							compander_fs;
-		}
-	}
-	return 0;
-}
-
-static int tomtom_set_decimator_rate(struct snd_soc_dai *dai,
-	u8 tx_fs_rate_reg_val, u32 sample_rate)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	struct wcd9xxx_ch *ch;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	u32 tx_port;
-	u16 tx_port_reg, tx_fs_reg;
-	u8 tx_port_reg_val;
-	s8 decimator;
-
-	list_for_each_entry(ch, &tomtom->dai[dai->id].wcd9xxx_ch_list, list) {
-
-		tx_port = ch->port + 1;
-		pr_debug("%s: dai->id = %d, tx_port = %d",
-			__func__, dai->id, tx_port);
-
-		if ((tx_port < 1) || (tx_port > NUM_DECIMATORS)) {
-			pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
-				__func__, tx_port, dai->id);
-			return -EINVAL;
-		}
-
-		tx_port_reg = TOMTOM_A_CDC_CONN_TX_SB_B1_CTL + (tx_port - 1);
-		tx_port_reg_val =  snd_soc_read(codec, tx_port_reg);
-
-		decimator = 0;
-
-		if ((tx_port >= 1) && (tx_port <= 6)) {
-
-			tx_port_reg_val =  tx_port_reg_val & 0x0F;
-			if (tx_port_reg_val == 0x8)
-				decimator = tx_port;
-
-		} else if ((tx_port >= 7) && (tx_port <= NUM_DECIMATORS)) {
-
-			tx_port_reg_val =  tx_port_reg_val & 0x1F;
-
-			if ((tx_port_reg_val >= 0x8) &&
-			    (tx_port_reg_val <= 0x11)) {
-
-				decimator = (tx_port_reg_val - 0x8) + 1;
-			}
-		}
-
-		if (decimator) { /* SLIM_TX port has a DEC as input */
-
-			tx_fs_reg = TOMTOM_A_CDC_TX1_CLK_FS_CTL +
-				    8 * (decimator - 1);
-
-			pr_debug("%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
-				__func__, decimator, tx_port, sample_rate);
-
-			snd_soc_update_bits(codec, tx_fs_reg, 0x07,
-					    tx_fs_rate_reg_val);
-
-		} else {
-			if ((tx_port_reg_val >= 0x1) &&
-			    (tx_port_reg_val <= 0x7)) {
-
-				pr_debug("%s: RMIX%u going to SLIM TX%u\n",
-					__func__, tx_port_reg_val, tx_port);
-
-			} else if  ((tx_port_reg_val >= 0x8) &&
-				    (tx_port_reg_val <= 0x11)) {
-
-				pr_err("%s: ERROR: Should not be here\n",
-				       __func__);
-				pr_err("%s: ERROR: DEC connected to SLIM TX%u\n",
-					__func__, tx_port);
-				return -EINVAL;
-
-			} else if (tx_port_reg_val == 0) {
-				pr_debug("%s: no signal to SLIM TX%u\n",
-					__func__, tx_port);
-			} else {
-				pr_err("%s: ERROR: wrong signal to SLIM TX%u\n",
-					__func__, tx_port);
-				pr_err("%s: ERROR: wrong signal = %u\n",
-					__func__, tx_port_reg_val);
-				return -EINVAL;
-			}
-		}
-	}
-	return 0;
-}
-
-static void tomtom_set_rxsb_port_format(struct snd_pcm_hw_params *params,
-				       struct snd_soc_dai *dai)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx_codec_dai_data *cdc_dai;
-	struct wcd9xxx_ch *ch;
-	int port;
-	u8 bit_sel;
-	u16 sb_ctl_reg, field_shift;
-
-	switch (params_width(params)) {
-	case 16:
-		bit_sel = 0x2;
-		tomtom_p->dai[dai->id].bit_width = 16;
-		break;
-	case 24:
-		bit_sel = 0x0;
-		tomtom_p->dai[dai->id].bit_width = 24;
-		break;
-	default:
-		dev_err(codec->dev, "Invalid format\n");
-		return;
-	}
-
-	cdc_dai = &tomtom_p->dai[dai->id];
-
-	list_for_each_entry(ch, &cdc_dai->wcd9xxx_ch_list, list) {
-		port = wcd9xxx_get_slave_port(ch->ch_num);
-		if (port < 0 ||
-		    !TOMTOM_VALIDATE_RX_SBPORT_RANGE(port)) {
-			dev_warn(codec->dev,
-				 "%s: invalid port ID %d returned for RX DAI\n",
-				 __func__, port);
-			return;
-		}
-
-		port = TOMTOM_CONVERT_RX_SBPORT_ID(port);
-
-		if (port <= 3) {
-			sb_ctl_reg = TOMTOM_A_CDC_CONN_RX_SB_B1_CTL;
-			field_shift = port << 1;
-		} else if (port <= 7) {
-			sb_ctl_reg = TOMTOM_A_CDC_CONN_RX_SB_B2_CTL;
-			field_shift = (port - 4) << 1;
-		} else { /* should not happen */
-			dev_warn(codec->dev,
-				 "%s: bad port ID %d\n", __func__, port);
-			return;
-		}
-
-		dev_dbg(codec->dev, "%s: sb_ctl_reg %x field_shift %x\n",
-			__func__, sb_ctl_reg, field_shift);
-		snd_soc_update_bits(codec, sb_ctl_reg, 0x3 << field_shift,
-				    bit_sel << field_shift);
-	}
-}
-
-static void tomtom_set_tx_sb_port_format(struct snd_pcm_hw_params *params,
-					 struct snd_soc_dai *dai)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx_codec_dai_data *cdc_dai;
-	struct wcd9xxx_ch *ch;
-	int port;
-	u8 bit_sel, bit_shift;
-	u16 sb_ctl_reg;
-
-	switch (params_width(params)) {
-	case 16:
-		bit_sel = 0x2;
-		tomtom_p->dai[dai->id].bit_width = 16;
-		break;
-	case 24:
-		bit_sel = 0x0;
-		tomtom_p->dai[dai->id].bit_width = 24;
-		break;
-	default:
-		dev_err(codec->dev, "%s: Invalid format %d\n", __func__,
-			params_width(params));
-		return;
-	}
-
-	cdc_dai = &tomtom_p->dai[dai->id];
-
-	list_for_each_entry(ch, &cdc_dai->wcd9xxx_ch_list, list) {
-		port = wcd9xxx_get_slave_port(ch->ch_num);
-		if (port < 0 ||
-		    !TOMTOM_VALIDATE_TX_SBPORT_RANGE(port)) {
-			dev_warn(codec->dev,
-				 "%s: invalid port ID %d returned for TX DAI\n",
-				 __func__, port);
-			return;
-		}
-
-		if (port < 6) /* 6 = SLIMBUS TX7 */
-			bit_shift = TOMTOM_BIT_ADJ_SHIFT_PORT1_6;
-		else if (port < 10)
-			bit_shift = TOMTOM_BIT_ADJ_SHIFT_PORT7_10;
-		else {
-			dev_warn(codec->dev,
-				 "%s: port ID %d bitwidth is fixed\n",
-				 __func__, port);
-			return;
-		}
-
-		sb_ctl_reg = (TOMTOM_A_CDC_CONN_TX_SB_B1_CTL + port);
-
-		dev_dbg(codec->dev, "%s: reg %x bit_sel %x bit_shift %x\n",
-			__func__, sb_ctl_reg, bit_sel, bit_shift);
-		snd_soc_update_bits(codec, sb_ctl_reg, 0x3 <<
-				    bit_shift, bit_sel << bit_shift);
-	}
-}
-
-static int tomtom_hw_params(struct snd_pcm_substream *substream,
-			    struct snd_pcm_hw_params *params,
-			    struct snd_soc_dai *dai)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(dai->codec);
-	u8 tx_fs_rate, rx_fs_rate, i2s_bit_mode;
-	u32 compander_fs;
-	int ret;
-
-	pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
-		 dai->name, dai->id, params_rate(params),
-		 params_channels(params));
-
-	switch (params_rate(params)) {
-	case 8000:
-		tx_fs_rate = 0x00;
-		rx_fs_rate = 0x00;
-		compander_fs = COMPANDER_FS_8KHZ;
-		break;
-	case 16000:
-		tx_fs_rate = 0x01;
-		rx_fs_rate = 0x20;
-		compander_fs = COMPANDER_FS_16KHZ;
-		break;
-	case 32000:
-		tx_fs_rate = 0x02;
-		rx_fs_rate = 0x40;
-		compander_fs = COMPANDER_FS_32KHZ;
-		break;
-	case 48000:
-		tx_fs_rate = 0x03;
-		rx_fs_rate = 0x60;
-		compander_fs = COMPANDER_FS_48KHZ;
-		break;
-	case 96000:
-		tx_fs_rate = 0x04;
-		rx_fs_rate = 0x80;
-		compander_fs = COMPANDER_FS_96KHZ;
-		break;
-	case 192000:
-		tx_fs_rate = 0x05;
-		rx_fs_rate = 0xA0;
-		compander_fs = COMPANDER_FS_192KHZ;
-		break;
-	default:
-		pr_err("%s: Invalid sampling rate %d\n", __func__,
-			params_rate(params));
-		return -EINVAL;
-	}
-
-	switch (substream->stream) {
-	case SNDRV_PCM_STREAM_CAPTURE:
-		if (dai->id != AIF4_VIFEED &&
-		    dai->id != AIF4_MAD_TX) {
-			ret = tomtom_set_decimator_rate(dai, tx_fs_rate,
-							   params_rate(params));
-			if (ret < 0) {
-				pr_err("%s: set decimator rate failed %d\n",
-					__func__, ret);
-				return ret;
-			}
-		}
-
-		tomtom->dai[dai->id].rate   = params_rate(params);
-
-		switch (params_format(params)) {
-		case SNDRV_PCM_FORMAT_S16_LE:
-			i2s_bit_mode = 0x01;
-			tomtom->dai[dai->id].bit_width = 16;
-			break;
-		case SNDRV_PCM_FORMAT_S24_LE:
-			tomtom->dai[dai->id].bit_width = 24;
-			i2s_bit_mode = 0x00;
-			break;
-		case SNDRV_PCM_FORMAT_S32_LE:
-			tomtom->dai[dai->id].bit_width = 32;
-			i2s_bit_mode = 0x00;
-			break;
-		default:
-			dev_err(codec->dev,
-				"%s: Invalid format 0x%x\n",
-				 __func__, params_format(params));
-			return -EINVAL;
-		}
-
-		if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
-			snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_TX_I2S_CTL,
-					    0x20, i2s_bit_mode << 5);
-			snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_TX_I2S_CTL,
-					    0x07, tx_fs_rate);
-		} else {
-			/* only generic ports can have sample bit adjustment */
-			if (dai->id != AIF4_VIFEED &&
-			    dai->id != AIF4_MAD_TX)
-				tomtom_set_tx_sb_port_format(params, dai);
-		}
-
-		break;
-
-	case SNDRV_PCM_STREAM_PLAYBACK:
-		ret = tomtom_set_interpolator_rate(dai, rx_fs_rate,
-						  compander_fs,
-						  params_rate(params));
-		if (ret < 0) {
-			pr_err("%s: set decimator rate failed %d\n", __func__,
-				ret);
-			return ret;
-		}
-		if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
-			switch (params_format(params)) {
-			case SNDRV_PCM_FORMAT_S16_LE:
-				snd_soc_update_bits(codec,
-					TOMTOM_A_CDC_CLK_RX_I2S_CTL,
-					0x20, 0x20);
-				break;
-			case SNDRV_PCM_FORMAT_S32_LE:
-				snd_soc_update_bits(codec,
-					TOMTOM_A_CDC_CLK_RX_I2S_CTL,
-					0x20, 0x00);
-				break;
-			default:
-				pr_err("invalid format\n");
-				break;
-			}
-			snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_RX_I2S_CTL,
-					    0x03, (rx_fs_rate >> 0x05));
-		} else {
-			tomtom_set_rxsb_port_format(params, dai);
-			tomtom->dai[dai->id].rate   = params_rate(params);
-		}
-		break;
-	default:
-		pr_err("%s: Invalid stream type %d\n", __func__,
-			substream->stream);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static struct snd_soc_dai_ops tomtom_dai_ops = {
-	.startup = tomtom_startup,
-	.shutdown = tomtom_shutdown,
-	.hw_params = tomtom_hw_params,
-	.set_sysclk = tomtom_set_dai_sysclk,
-	.set_fmt = tomtom_set_dai_fmt,
-	.set_channel_map = tomtom_set_channel_map,
-	.get_channel_map = tomtom_get_channel_map,
-};
-
-static struct snd_soc_dai_driver tomtom_dai[] = {
-	{
-		.name = "tomtom_rx1",
-		.id = AIF1_PB,
-		.playback = {
-			.stream_name = "AIF1 Playback",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS_S16_S24_LE,
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 2,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_tx1",
-		.id = AIF1_CAP,
-		.capture = {
-			.stream_name = "AIF1 Capture",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS,
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 4,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_rx2",
-		.id = AIF2_PB,
-		.playback = {
-			.stream_name = "AIF2 Playback",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS_S16_S24_LE,
-			.rate_min = 8000,
-			.rate_max = 192000,
-			.channels_min = 1,
-			.channels_max = 2,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_tx2",
-		.id = AIF2_CAP,
-		.capture = {
-			.stream_name = "AIF2 Capture",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS,
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 8,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_rx3",
-		.id = AIF3_PB,
-		.playback = {
-			.stream_name = "AIF3 Playback",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS_S16_S24_LE,
-			.rate_min = 8000,
-			.rate_max = 192000,
-			.channels_min = 1,
-			.channels_max = 2,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_tx3",
-		.id = AIF3_CAP,
-		.capture = {
-			.stream_name = "AIF3 Capture",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS,
-			.rate_max = 48000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 2,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_vifeedback",
-		.id = AIF4_VIFEED,
-		.capture = {
-			.stream_name = "VIfeed",
-			.rates = SNDRV_PCM_RATE_48000,
-			.formats = TOMTOM_FORMATS,
-			.rate_max = 48000,
-			.rate_min = 48000,
-			.channels_min = 2,
-			.channels_max = 2,
-	 },
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_mad1",
-		.id = AIF4_MAD_TX,
-		.capture = {
-			.stream_name = "AIF4 MAD TX",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = TOMTOM_FORMATS_S16_S24_LE,
-			.rate_min = 16000,
-			.rate_max = 16000,
-			.channels_min = 1,
-			.channels_max = 1,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-};
-
-static struct snd_soc_dai_driver tomtom_i2s_dai[] = {
-	{
-		.name = "tomtom_i2s_rx1",
-		.id = AIF1_PB,
-		.playback = {
-			.stream_name = "AIF1 Playback",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS,
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 4,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_i2s_tx1",
-		.id = AIF1_CAP,
-		.capture = {
-			.stream_name = "AIF1 Capture",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS,
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 4,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_i2s_rx2",
-		.id = AIF1_PB,
-		.playback = {
-			.stream_name = "AIF2 Playback",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS,
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 4,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-	{
-		.name = "tomtom_i2s_tx2",
-		.id = AIF1_CAP,
-		.capture = {
-			.stream_name = "AIF2 Capture",
-			.rates = WCD9330_RATES,
-			.formats = TOMTOM_FORMATS,
-			.rate_max = 192000,
-			.rate_min = 8000,
-			.channels_min = 1,
-			.channels_max = 4,
-		},
-		.ops = &tomtom_dai_ops,
-	},
-};
-
-static int tomtom_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai,
-					  bool up)
-{
-	int ret = 0;
-	struct wcd9xxx_ch *ch;
-
-	if (up) {
-		list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
-			ret = wcd9xxx_get_slave_port(ch->ch_num);
-			if (ret < 0) {
-				pr_err("%s: Invalid slave port ID: %d\n",
-				       __func__, ret);
-				ret = -EINVAL;
-			} else {
-				set_bit(ret, &dai->ch_mask);
-			}
-		}
-	} else {
-		ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
-					 msecs_to_jiffies(
-						TOMTOM_SLIM_CLOSE_TIMEOUT));
-		if (!ret) {
-			pr_err("%s: Slim close tx/rx wait timeout\n", __func__);
-			ret = -ETIMEDOUT;
-		} else {
-			ret = 0;
-		}
-	}
-	return ret;
-}
-
-static void tomtom_codec_enable_int_port(struct wcd9xxx_codec_dai_data *dai,
-					  struct snd_soc_codec *codec)
-{
-	struct wcd9xxx_ch *ch;
-	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
-	int port_num = 0;
-	unsigned short reg = 0;
-	u8 val = 0;
-
-	if (!dai || !codec) {
-		pr_err("%s: Invalid params\n", __func__);
-		return;
-	}
-	list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
-		if (ch->port >= TOMTOM_RX_PORT_START_NUMBER) {
-			port_num = ch->port - TOMTOM_RX_PORT_START_NUMBER;
-			reg = TOMTOM_SLIM_PGD_PORT_INT_EN0 + (port_num / 8);
-			val = wcd9xxx_interface_reg_read(wcd9xxx,
-				reg);
-			if (!(val & (1 << (port_num % 8)))) {
-				val |= (1 << (port_num % 8));
-				wcd9xxx_interface_reg_write(
-					wcd9xxx, reg, val);
-				val = wcd9xxx_interface_reg_read(
-					wcd9xxx, reg);
-			}
-		} else {
-			port_num = ch->port;
-			reg = TOMTOM_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8);
-			val = wcd9xxx_interface_reg_read(wcd9xxx,
-				reg);
-			if (!(val & (1 << (port_num % 8)))) {
-				val |= (1 << (port_num % 8));
-				wcd9xxx_interface_reg_write(wcd9xxx,
-					reg, val);
-				val = wcd9xxx_interface_reg_read(
-					wcd9xxx, reg);
-			}
-		}
-	}
-}
-
-static int tomtom_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
-				     struct snd_kcontrol *kcontrol,
-				     int event)
-{
-	struct wcd9xxx *core;
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-	int ret = 0;
-	struct wcd9xxx_codec_dai_data *dai;
-
-	core = dev_get_drvdata(codec->dev->parent);
-
-	pr_debug("%s: event called! codec name %s num_dai %d\n"
-		"stream name %s event %d\n",
-		__func__, codec->component.name,
-		codec->component.num_dai, w->sname, event);
-
-	/* Execute the callback only if interface type is slimbus */
-	if (tomtom_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
-		return 0;
-
-	dai = &tomtom_p->dai[w->shift];
-	pr_debug("%s: w->name %s w->shift %d event %d\n",
-		 __func__, w->name, w->shift, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		dai->bus_down_in_recovery = false;
-		tomtom_codec_enable_int_port(dai, codec);
-		(void) tomtom_codec_enable_slim_chmask(dai, true);
-		ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
-					      dai->rate, dai->bit_width,
-					      &dai->grph);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
-						dai->grph);
-		if (!dai->bus_down_in_recovery)
-			ret = tomtom_codec_enable_slim_chmask(dai, false);
-		else
-			pr_debug("%s: bus in recovery skip enable slim_chmask",
-				__func__);
-		if (ret < 0) {
-			ret = wcd9xxx_disconnect_port(core,
-						      &dai->wcd9xxx_ch_list,
-						      dai->grph);
-			pr_debug("%s: Disconnect RX port, ret = %d\n",
-				 __func__, ret);
-		}
-		break;
-	}
-	return ret;
-}
-
-static int tomtom_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w,
-				struct snd_kcontrol *kcontrol,
-				int event)
-{
-	struct wcd9xxx *core = NULL;
-	struct snd_soc_codec *codec = NULL;
-	struct tomtom_priv *tomtom_p = NULL;
-	u32 ret = 0;
-	struct wcd9xxx_codec_dai_data *dai = NULL;
-
-	if (!w) {
-		pr_err("%s invalid params\n", __func__);
-		return -EINVAL;
-	}
-	codec = snd_soc_dapm_to_codec(w->dapm);
-	tomtom_p = snd_soc_codec_get_drvdata(codec);
-	core = dev_get_drvdata(codec->dev->parent);
-
-	pr_debug("%s: event called! codec name %s num_dai %d stream name %s\n",
-		__func__, codec->component.name,
-		codec->component.num_dai, w->sname);
-
-	/* Execute the callback only if interface type is slimbus */
-	if (tomtom_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
-		pr_err("%s Interface is not correct", __func__);
-		return 0;
-	}
-
-	pr_debug("%s(): w->name %s event %d w->shift %d\n",
-		__func__, w->name, event, w->shift);
-	if (w->shift != AIF4_VIFEED) {
-		pr_err("%s Error in enabling the tx path\n", __func__);
-		ret = -EINVAL;
-		goto out_vi;
-	}
-	dai = &tomtom_p->dai[w->shift];
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		/*Enable V&I sensing*/
-		snd_soc_update_bits(codec, TOMTOM_A_SPKR1_PROT_EN,
-				0x88, 0x88);
-		/*Enable spkr VI clocks*/
-		snd_soc_update_bits(codec,
-		TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0xC, 0xC);
-		dai->bus_down_in_recovery = false;
-		tomtom_codec_enable_int_port(dai, codec);
-		(void) tomtom_codec_enable_slim_chmask(dai, true);
-		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
-					dai->rate, dai->bit_width,
-					&dai->grph);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
-						dai->grph);
-		if (ret)
-			pr_err("%s error in close_slim_sch_tx %d\n",
-				__func__, ret);
-		if (!dai->bus_down_in_recovery)
-			ret = tomtom_codec_enable_slim_chmask(dai, false);
-		if (ret < 0) {
-			ret = wcd9xxx_disconnect_port(core,
-				&dai->wcd9xxx_ch_list,
-				dai->grph);
-			pr_debug("%s: Disconnect TX port, ret = %d\n",
-				__func__, ret);
-		}
-
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL,
-				0xC, 0x0);
-		/*Disable V&I sensing*/
-		snd_soc_update_bits(codec, TOMTOM_A_SPKR1_PROT_EN,
-				0x88, 0x00);
-		break;
-	}
-out_vi:
-	return ret;
-}
-
-/* __tomtom_codec_enable_slimtx: Enable the slimbus slave port
- *				 for TX path
- * @codec: Handle to the codec for which the slave port is to be
- *	   enabled.
- * @dai_data: The dai specific data for dai which is enabled.
- */
-static int __tomtom_codec_enable_slimtx(struct snd_soc_codec *codec,
-		int event, struct wcd9xxx_codec_dai_data *dai_data)
-{
-	struct wcd9xxx *core;
-	int ret = 0;
-
-	core = dev_get_drvdata(codec->dev->parent);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		dai_data->bus_down_in_recovery = false;
-		tomtom_codec_enable_int_port(dai_data, codec);
-		(void) tomtom_codec_enable_slim_chmask(dai_data, true);
-		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai_data->wcd9xxx_ch_list,
-					      dai_data->rate,
-					      dai_data->bit_width,
-					      &dai_data->grph);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		ret = wcd9xxx_close_slim_sch_tx(core,
-						&dai_data->wcd9xxx_ch_list,
-						dai_data->grph);
-		if (!dai_data->bus_down_in_recovery)
-			ret = tomtom_codec_enable_slim_chmask(dai_data, false);
-		if (ret < 0) {
-			ret = wcd9xxx_disconnect_port(core,
-					&dai_data->wcd9xxx_ch_list,
-					dai_data->grph);
-			dev_dbg(codec->dev,
-				"%s: Disconnect TX port, ret = %d\n",
-				 __func__, ret);
-		}
-		break;
-	}
-
-	return ret;
-}
-
-/*
- * tomtom_codec_enable_slimtx_mad: Callback function that will be invoked
- *	to setup the slave port for MAD.
- * @codec: Handle to the codec
- * @event: Indicates whether to enable or disable the slave port
- */
-static int tomtom_codec_enable_slimtx_mad(struct snd_soc_codec *codec,
-					  u8 event)
-{
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx_codec_dai_data *dai;
-	int dapm_event = SND_SOC_DAPM_POST_PMU;
-
-	dai = &tomtom_p->dai[AIF4_MAD_TX];
-
-	if (event == 0)
-		dapm_event = SND_SOC_DAPM_POST_PMD;
-
-	dev_dbg(codec->dev,
-		"%s: mad_channel, event = 0x%x\n",
-		 __func__, event);
-	return __tomtom_codec_enable_slimtx(codec, dapm_event, dai);
-}
-
-/*
- * tomtom_codec_enable_slimtx: DAPM widget allback for TX widgets
- * @w: widget for which this callback is invoked
- * @kcontrol: kcontrol associated with this widget
- * @event: DAPM supplied event indicating enable/disable
- */
-static int tomtom_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
-				     struct snd_kcontrol *kcontrol,
-				     int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx_codec_dai_data *dai;
-
-	dev_dbg(codec->dev, "%s: event called! codec name %s num_dai %d stream name %s\n",
-		__func__, codec->component.name,
-		codec->component.num_dai, w->sname);
-
-	/* Execute the callback only if interface type is slimbus */
-	if (tomtom_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
-		return 0;
-
-	dev_dbg(codec->dev,
-		"%s(): w->name %s event %d w->shift %d\n",
-		__func__, w->name, event, w->shift);
-
-	dai = &tomtom_p->dai[w->shift];
-	return __tomtom_codec_enable_slimtx(codec, event, dai);
-}
-
-static int tomtom_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		wcd9xxx_clsh_fsm(codec, &tomtom_p->clsh_d,
-						 WCD9XXX_CLSH_STATE_EAR,
-						 WCD9XXX_CLSH_REQ_ENABLE,
-						 WCD9XXX_CLSH_EVENT_POST_PA);
-
-		usleep_range(5000, 5100);
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct tomtom_priv *tomtom_p = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		wcd9xxx_clsh_fsm(codec, &tomtom_p->clsh_d,
-						 WCD9XXX_CLSH_STATE_EAR,
-						 WCD9XXX_CLSH_REQ_ENABLE,
-						 WCD9XXX_CLSH_EVENT_PRE_DAC);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		wcd9xxx_clsh_fsm(codec, &tomtom_p->clsh_d,
-						 WCD9XXX_CLSH_STATE_EAR,
-						 WCD9XXX_CLSH_REQ_DISABLE,
-						 WCD9XXX_CLSH_EVENT_POST_PA);
-		usleep_range(5000, 5100);
-		break;
-	default:
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_set_iir_gain(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-	pr_debug("%s: event = %d\n", __func__, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU: /* fall through */
-	case SND_SOC_DAPM_PRE_PMD:
-		if (strnstr(w->name, "IIR1", sizeof("IIR1"))) {
-			snd_soc_write(codec, TOMTOM_A_CDC_IIR1_GAIN_B1_CTL,
-				      snd_soc_read(codec,
-					      TOMTOM_A_CDC_IIR1_GAIN_B1_CTL));
-			snd_soc_write(codec, TOMTOM_A_CDC_IIR1_GAIN_B2_CTL,
-				      snd_soc_read(codec,
-					      TOMTOM_A_CDC_IIR1_GAIN_B2_CTL));
-			snd_soc_write(codec, TOMTOM_A_CDC_IIR1_GAIN_B3_CTL,
-				      snd_soc_read(codec,
-					      TOMTOM_A_CDC_IIR1_GAIN_B3_CTL));
-			snd_soc_write(codec, TOMTOM_A_CDC_IIR1_GAIN_B4_CTL,
-				      snd_soc_read(codec,
-					      TOMTOM_A_CDC_IIR1_GAIN_B4_CTL));
-		} else {
-			snd_soc_write(codec, TOMTOM_A_CDC_IIR2_GAIN_B1_CTL,
-				      snd_soc_read(codec,
-					      TOMTOM_A_CDC_IIR2_GAIN_B1_CTL));
-			snd_soc_write(codec, TOMTOM_A_CDC_IIR2_GAIN_B2_CTL,
-				      snd_soc_read(codec,
-					      TOMTOM_A_CDC_IIR2_GAIN_B2_CTL));
-			snd_soc_write(codec, TOMTOM_A_CDC_IIR2_GAIN_B3_CTL,
-				      snd_soc_read(codec,
-					      TOMTOM_A_CDC_IIR2_GAIN_B3_CTL));
-			snd_soc_write(codec, TOMTOM_A_CDC_IIR2_GAIN_B4_CTL,
-				      snd_soc_read(codec,
-					      TOMTOM_A_CDC_IIR2_GAIN_B4_CTL));
-		}
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	u8 reg_val, zoh_mux_val = 0x00;
-
-	pr_debug("%s: event = %d\n", __func__, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		reg_val = snd_soc_read(codec, TOMTOM_A_CDC_CONN_CLSH_CTL);
-
-		if ((reg_val & 0x30) == 0x10)
-			zoh_mux_val = 0x04;
-		else if ((reg_val & 0x30) == 0x20)
-			zoh_mux_val = 0x08;
-
-		if (zoh_mux_val != 0x00)
-			snd_soc_update_bits(codec,
-					TOMTOM_A_CDC_CONN_CLSH_CTL,
-					0x0C, zoh_mux_val);
-		break;
-
-	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, TOMTOM_A_CDC_CONN_CLSH_CTL,
-							0x0C, 0x00);
-		break;
-	}
-	return 0;
-}
-
-static int tomtom_codec_enable_anc_ear(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	int ret = 0;
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		ret = tomtom_codec_enable_anc(w, kcontrol, event);
-		msleep(50);
-		snd_soc_update_bits(codec, TOMTOM_A_RX_EAR_EN, 0x10, 0x10);
-		break;
-	case SND_SOC_DAPM_POST_PMU:
-		ret = tomtom_codec_enable_ear_pa(w, kcontrol, event);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, TOMTOM_A_RX_EAR_EN, 0x10, 0x00);
-		msleep(40);
-		ret |= tomtom_codec_enable_anc(w, kcontrol, event);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		ret = tomtom_codec_enable_ear_pa(w, kcontrol, event);
-		break;
-	}
-	return ret;
-}
-
-/* Todo: Have separate dapm widgets for I2S and Slimbus.
- * Might Need to have callbacks registered only for slimbus
- */
-static const struct snd_soc_dapm_widget tomtom_dapm_widgets[] = {
-	/*RX stuff */
-	SND_SOC_DAPM_OUTPUT("EAR"),
-
-	SND_SOC_DAPM_PGA_E("EAR PA", TOMTOM_A_RX_EAR_EN, 4, 0, NULL, 0,
-			tomtom_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_MIXER_E("DAC1", TOMTOM_A_RX_EAR_EN, 6, 0, dac1_switch,
-		ARRAY_SIZE(dac1_switch), tomtom_codec_ear_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
-				AIF1_PB, 0, tomtom_codec_enable_slimrx,
-				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
-				AIF2_PB, 0, tomtom_codec_enable_slimrx,
-				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
-				AIF3_PB, 0, tomtom_codec_enable_slimrx,
-				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TOMTOM_RX1, 0,
-				&slim_rx_mux[TOMTOM_RX1]),
-	SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TOMTOM_RX2, 0,
-				&slim_rx_mux[TOMTOM_RX2]),
-	SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TOMTOM_RX3, 0,
-				&slim_rx_mux[TOMTOM_RX3]),
-	SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TOMTOM_RX4, 0,
-				&slim_rx_mux[TOMTOM_RX4]),
-	SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TOMTOM_RX5, 0,
-				&slim_rx_mux[TOMTOM_RX5]),
-	SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, TOMTOM_RX6, 0,
-				&slim_rx_mux[TOMTOM_RX6]),
-	SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, TOMTOM_RX7, 0,
-				&slim_rx_mux[TOMTOM_RX7]),
-	SND_SOC_DAPM_MUX("SLIM RX8 MUX", SND_SOC_NOPM, TOMTOM_RX8, 0,
-				&slim_rx_mux[TOMTOM_RX8]),
-
-	SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("SLIM RX8", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-	/* Headphone */
-	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
-	SND_SOC_DAPM_PGA_E("HPHL", TOMTOM_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
-		tomtom_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER_E("HPHL DAC", TOMTOM_A_RX_HPH_L_DAC_CTL, 7, 0,
-		hphl_switch, ARRAY_SIZE(hphl_switch), tomtom_hphl_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_PGA_E("HPHR", TOMTOM_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
-		tomtom_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TOMTOM_A_RX_HPH_R_DAC_CTL, 7, 0,
-		tomtom_hphr_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	/* Speaker */
-	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
-	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
-	SND_SOC_DAPM_OUTPUT("LINEOUT3"),
-	SND_SOC_DAPM_OUTPUT("LINEOUT4"),
-	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
-
-	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TOMTOM_A_RX_LINE_CNP_EN, 0, 0, NULL,
-			0, tomtom_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TOMTOM_A_RX_LINE_CNP_EN, 1, 0, NULL,
-			0, tomtom_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TOMTOM_A_RX_LINE_CNP_EN, 2, 0, NULL,
-			0, tomtom_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TOMTOM_A_RX_LINE_CNP_EN, 3, 0, NULL,
-			0, tomtom_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0, NULL,
-			   0, tomtom_codec_enable_spk_pa,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("SPK2 PA", SND_SOC_NOPM, 0, 0, NULL,
-			   0, tomtom_codec_enable_spk_pa,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TOMTOM_A_RX_LINE_1_DAC_CTL, 7,
-		0, tomtom_lineout_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TOMTOM_A_RX_LINE_2_DAC_CTL, 7,
-		0, tomtom_lineout_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TOMTOM_A_RX_LINE_3_DAC_CTL, 7,
-		0, tomtom_lineout_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
-				&lineout3_ground_switch),
-	SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TOMTOM_A_RX_LINE_4_DAC_CTL, 7,
-		0, tomtom_lineout_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
-				&lineout4_ground_switch),
-
-	SND_SOC_DAPM_DAC_E("SPK DAC", NULL, TOMTOM_A_CDC_BOOST_TRGR_EN, 0, 0,
-			   tomtom_spk_dac_event,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_DAC_E("SPK2 DAC", NULL, TOMTOM_A_CDC_BOOST_TRGR_EN, 1, 0,
-			   tomtom_spk_dac_event,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
-			    tomtom_codec_enable_vdd_spkr,
-			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("VDD_SPKDRV2", SND_SOC_NOPM, 0, 0,
-			    tomtom_codec_enable_vdd_spkr2,
-			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("RX7 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-	SND_SOC_DAPM_MIXER("RX1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("RX2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-	SND_SOC_DAPM_MIXER_E("RX3 MIX1", TOMTOM_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
-		0, tomtom_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX4 MIX1", TOMTOM_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
-		0, tomtom_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX5 MIX1", TOMTOM_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
-		0, tomtom_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX6 MIX1", TOMTOM_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
-		0, tomtom_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX7 MIX2", TOMTOM_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
-		0, tomtom_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX8 MIX1", TOMTOM_A_CDC_CLK_RX_B1_CTL, 7, 0, NULL,
-		0, tomtom_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_MUX_E("RX1 INTERP", TOMTOM_A_CDC_CLK_RX_B1_CTL, 0, 0,
-			&rx1_interp_mux, tomtom_codec_enable_interpolator,
-			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MUX_E("RX2 INTERP", TOMTOM_A_CDC_CLK_RX_B1_CTL, 1, 0,
-			&rx2_interp_mux, tomtom_codec_enable_interpolator,
-			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
-
-
-	SND_SOC_DAPM_MIXER("RX1 CHAIN", TOMTOM_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("RX2 CHAIN", TOMTOM_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
-
-	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-		&rx_mix1_inp3_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx2_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx2_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx3_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx3_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx5_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx5_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx6_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx6_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx7_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx7_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX8 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx8_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX8 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx8_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-		&rx1_mix2_inp1_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
-		&rx1_mix2_inp2_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-		&rx2_mix2_inp1_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
-		&rx2_mix2_inp2_mux),
-	SND_SOC_DAPM_MUX("RX7 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-		&rx7_mix2_inp1_mux),
-	SND_SOC_DAPM_MUX("RX7 MIX2 INP2", SND_SOC_NOPM, 0, 0,
-		&rx7_mix2_inp2_mux),
-
-	SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
-		&rx_dac5_mux),
-	SND_SOC_DAPM_MUX("RDAC7 MUX", SND_SOC_NOPM, 0, 0,
-		&rx_dac7_mux),
-
-	SND_SOC_DAPM_MUX("MAD_SEL MUX", SND_SOC_NOPM, 0, 0,
-		&mad_sel_mux),
-
-	SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
-		&class_h_dsm_mux, tomtom_codec_dsm_mux_event,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
-		tomtom_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("CDC_I2S_RX_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 5, 0,
-			    NULL, 0),
-
-	/* TX */
-
-	SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
-		0),
-
-	SND_SOC_DAPM_SUPPLY("LDO_H", SND_SOC_NOPM, 7, 0,
-			    tomtom_codec_enable_ldo_h,
-			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	/*
-	 * DAPM 'LDO_H Standalone' is to be powered by mbhc driver after
-	 * acquring codec_resource lock.
-	 * So call __tomtom_codec_enable_ldo_h instead and avoid deadlock.
-	 */
-	SND_SOC_DAPM_SUPPLY("LDO_H Standalone", SND_SOC_NOPM, 7, 0,
-			    __tomtom_codec_enable_ldo_h,
-			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
-		tomtom_config_compander, SND_SOC_DAPM_PRE_PMU |
-			SND_SOC_DAPM_PRE_PMD),
-	SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
-		tomtom_config_compander, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-	SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
-		tomtom_config_compander, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-
-
-	SND_SOC_DAPM_INPUT("AMIC1"),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_INPUT("AMIC3"),
-
-	SND_SOC_DAPM_INPUT("AMIC4"),
-
-	SND_SOC_DAPM_INPUT("AMIC5"),
-
-	SND_SOC_DAPM_INPUT("AMIC6"),
-
-	SND_SOC_DAPM_MUX_E("DEC1 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
-		&dec1_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC2 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
-		&dec2_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC3 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
-		&dec3_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC4 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
-		&dec4_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC5 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
-		&dec5_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC6 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
-		&dec6_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC7 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
-		&dec7_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC8 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
-		&dec8_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC9 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
-		&dec9_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC10 MUX", TOMTOM_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
-		&dec10_mux, tomtom_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
-	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
-
-	SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
-	SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 5, 0, NULL, 0,
-		tomtom_codec_enable_anc_hph,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 4, 0, NULL, 0,
-		tomtom_codec_enable_anc_hph, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_OUTPUT("ANC EAR"),
-	SND_SOC_DAPM_PGA_E("ANC EAR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
-		tomtom_codec_enable_anc_ear,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
-
-	SND_SOC_DAPM_INPUT("AMIC2"),
-	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS2_EXTERNAL_STANDALONE, SND_SOC_NOPM,
-			       7, 0, tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU |
-			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU |
-			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", SND_SOC_NOPM, 7, 0,
-			       tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU |
-			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", SND_SOC_NOPM, 7,
-			       0, tomtom_codec_enable_micbias,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			       SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
-		AIF1_CAP, 0, tomtom_codec_enable_slimtx,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
-		AIF2_CAP, 0, tomtom_codec_enable_slimtx,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
-		AIF3_CAP, 0, tomtom_codec_enable_slimtx,
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM,
-		AIF4_VIFEED, 0, tomtom_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,
-			       tomtom_codec_enable_mad,
-			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_SWITCH("MADONOFF", SND_SOC_NOPM, 0, 0,
-			    &aif4_mad_switch),
-	SND_SOC_DAPM_INPUT("MADINPUT"),
-	SND_SOC_DAPM_INPUT("MAD_CPE_INPUT"),
-
-	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
-		aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)),
-
-	SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
-		aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)),
-
-	SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
-		aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)),
-
-	SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TOMTOM_TX1, 0,
-		&sb_tx1_mux),
-	SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TOMTOM_TX2, 0,
-		&sb_tx2_mux),
-	SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TOMTOM_TX3, 0,
-		&sb_tx3_mux),
-	SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TOMTOM_TX4, 0,
-		&sb_tx4_mux),
-	SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TOMTOM_TX5, 0,
-		&sb_tx5_mux),
-	SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, TOMTOM_TX6, 0,
-		&sb_tx6_mux),
-	SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, TOMTOM_TX7, 0,
-		&sb_tx7_mux),
-	SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, TOMTOM_TX8, 0,
-		&sb_tx8_mux),
-	SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, TOMTOM_TX9, 0,
-		&sb_tx9_mux),
-	SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, TOMTOM_TX10, 0,
-		&sb_tx10_mux),
-
-	/* Digital Mic Inputs */
-	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
-		tomtom_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
-		tomtom_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
-		tomtom_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
-		tomtom_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
-		tomtom_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
-		tomtom_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	/* Sidetone */
-	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
-
-	SND_SOC_DAPM_MUX("IIR1 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp2_mux),
-
-	SND_SOC_DAPM_MUX("IIR1 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp3_mux),
-
-	SND_SOC_DAPM_MUX("IIR1 INP4 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp4_mux),
-
-	SND_SOC_DAPM_MIXER_E("IIR1", TOMTOM_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0,
-		tomtom_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-
-	SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
-
-	SND_SOC_DAPM_MUX("IIR2 INP2 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp2_mux),
-
-	SND_SOC_DAPM_MUX("IIR2 INP3 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp3_mux),
-
-	SND_SOC_DAPM_MUX("IIR2 INP4 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp4_mux),
-
-	SND_SOC_DAPM_MIXER_E("IIR2", TOMTOM_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0,
-		tomtom_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-
-	/* AUX PGA */
-	SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TOMTOM_A_RX_AUX_SW_CTL, 7, 0,
-		tomtom_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TOMTOM_A_RX_AUX_SW_CTL, 6, 0,
-		tomtom_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	/* Lineout, ear and HPH PA Mixers */
-
-	SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
-		ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
-
-	SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
-		hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
-
-	SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
-		hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
-
-	SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
-		lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
-
-	SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
-		lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
-
-	SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
-		lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
-
-	SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
-		lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
-
-	SND_SOC_DAPM_SWITCH("VIONOFF", SND_SOC_NOPM, 0, 0,
-			    &aif4_vi_switch),
-
-	SND_SOC_DAPM_INPUT("VIINPUT"),
-};
-
-static irqreturn_t tomtom_slimbus_irq(int irq, void *data)
-{
-	struct tomtom_priv *priv = data;
-	struct snd_soc_codec *codec = priv->codec;
-	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
-	unsigned long status = 0;
-	int i, j, port_id, k;
-	u32 bit;
-	u8 val, int_val = 0;
-	bool tx, cleared;
-	unsigned short reg = 0;
-
-	for (i = TOMTOM_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
-	     i <= TOMTOM_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
-		val = wcd9xxx_interface_reg_read(wcd9xxx, i);
-		status |= ((u32)val << (8 * j));
-	}
-
-	for_each_set_bit(j, &status, 32) {
-		tx = (j >= 16 ? true : false);
-		port_id = (tx ? j - 16 : j);
-		val = wcd9xxx_interface_reg_read(wcd9xxx,
-				TOMTOM_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
-		if (val) {
-			if (!tx)
-				reg = TOMTOM_SLIM_PGD_PORT_INT_EN0 +
-					(port_id / 8);
-			else
-				reg = TOMTOM_SLIM_PGD_PORT_INT_TX_EN0 +
-					(port_id / 8);
-			int_val = wcd9xxx_interface_reg_read(
-				wcd9xxx, reg);
-			/*
-			 * Ignore interrupts for ports for which the
-			 * interrupts are not specifically enabled.
-			 */
-			if (!(int_val & (1 << (port_id % 8))))
-				continue;
-		}
-		if (val & TOMTOM_SLIM_IRQ_OVERFLOW)
-			pr_err_ratelimited(
-			   "%s: overflow error on %s port %d, value %x\n",
-			   __func__, (tx ? "TX" : "RX"), port_id, val);
-		if (val & TOMTOM_SLIM_IRQ_UNDERFLOW)
-			pr_err_ratelimited(
-			   "%s: underflow error on %s port %d, value %x\n",
-			   __func__, (tx ? "TX" : "RX"), port_id, val);
-		if ((val & TOMTOM_SLIM_IRQ_OVERFLOW) ||
-			(val & TOMTOM_SLIM_IRQ_UNDERFLOW)) {
-			if (!tx)
-				reg = TOMTOM_SLIM_PGD_PORT_INT_EN0 +
-					(port_id / 8);
-			else
-				reg = TOMTOM_SLIM_PGD_PORT_INT_TX_EN0 +
-					(port_id / 8);
-			int_val = wcd9xxx_interface_reg_read(wcd9xxx, reg);
-			if (int_val & (1 << (port_id % 8))) {
-				int_val = int_val ^ (1 << (port_id % 8));
-				wcd9xxx_interface_reg_write(wcd9xxx, reg,
-							    int_val);
-			}
-		}
-		if (val & TOMTOM_SLIM_IRQ_PORT_CLOSED) {
-			/*
-			 * INT SOURCE register starts from RX to TX
-			 * but port number in the ch_mask is in opposite way
-			 */
-			bit = (tx ? j - 16 : j + 16);
-			pr_debug("%s: %s port %d closed value %x, bit %u\n",
-				 __func__, (tx ? "TX" : "RX"), port_id, val,
-				 bit);
-			for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
-				pr_debug("%s: priv->dai[%d].ch_mask = 0x%lx\n",
-					 __func__, k, priv->dai[k].ch_mask);
-				if (test_and_clear_bit(bit,
-						       &priv->dai[k].ch_mask)) {
-					cleared = true;
-					if (!priv->dai[k].ch_mask)
-						wake_up(&priv->dai[k].dai_wait);
-					/*
-					 * There are cases when multiple DAIs
-					 * might be using the same slimbus
-					 * channel. Hence don't break here.
-					 */
-				}
-			}
-			WARN(!cleared,
-			     "Couldn't find slimbus %s port %d for closing\n",
-			     (tx ? "TX" : "RX"), port_id);
-		}
-		wcd9xxx_interface_reg_write(wcd9xxx,
-					    TOMTOM_SLIM_PGD_PORT_INT_CLR_RX_0 +
-					    (j / 8),
-					    1 << (j % 8));
-	}
-
-	return IRQ_HANDLED;
-}
-
-static int tomtom_handle_pdata(struct tomtom_priv *tomtom)
-{
-	struct snd_soc_codec *codec = tomtom->codec;
-	struct wcd9xxx_pdata *pdata = tomtom->resmgr.pdata;
-	int k1, k2, k3, dec, rc = 0;
-	u8 leg_mode, txfe_bypass, txfe_buff, flag;
-	u8 i = 0, j = 0;
-	u8 val_txfe = 0, value = 0;
-	u8 dmic_ctl_val, mad_dmic_ctl_val;
-	u8 anc_ctl_value = 0;
-	u32 def_dmic_rate;
-	u16 tx_dmic_ctl_reg;
-
-	if (!pdata) {
-		pr_err("%s: NULL pdata\n", __func__);
-		rc = -ENODEV;
-		goto done;
-	}
-
-	leg_mode = pdata->amic_settings.legacy_mode;
-	txfe_bypass = pdata->amic_settings.txfe_enable;
-	txfe_buff = pdata->amic_settings.txfe_buff;
-	flag = pdata->amic_settings.use_pdata;
-
-	/* Make sure settings are correct */
-	if ((pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V) ||
-	    (pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
-	    (pdata->micbias.bias2_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
-	    (pdata->micbias.bias3_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
-	    (pdata->micbias.bias4_cfilt_sel > WCD9XXX_CFILT3_SEL)) {
-		rc = -EINVAL;
-		goto done;
-	}
-	/* figure out k value */
-	k1 = wcd9xxx_resmgr_get_k_val(&tomtom->resmgr,
-				      pdata->micbias.cfilt1_mv);
-	k2 = wcd9xxx_resmgr_get_k_val(&tomtom->resmgr,
-				      pdata->micbias.cfilt2_mv);
-	k3 = wcd9xxx_resmgr_get_k_val(&tomtom->resmgr,
-				      pdata->micbias.cfilt3_mv);
-	if (k1 < 0 || k2 < 0 || k3 < 0) {
-		rc = -EINVAL;
-		goto done;
-	}
-	/* Set voltage level and always use LDO */
-	snd_soc_update_bits(codec, TOMTOM_A_LDO_H_MODE_1, 0x0C,
-			    (pdata->micbias.ldoh_v << 2));
-
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_CFILT_1_VAL, 0xFC, (k1 << 2));
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_CFILT_2_VAL, 0xFC, (k2 << 2));
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_CFILT_3_VAL, 0xFC, (k3 << 2));
-
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_1_CTL, 0x60,
-			    (pdata->micbias.bias1_cfilt_sel << 5));
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_2_CTL, 0x60,
-			    (pdata->micbias.bias2_cfilt_sel << 5));
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_3_CTL, 0x60,
-			    (pdata->micbias.bias3_cfilt_sel << 5));
-	snd_soc_update_bits(codec, tomtom->resmgr.reg_addr->micb_4_ctl, 0x60,
-			    (pdata->micbias.bias4_cfilt_sel << 5));
-
-	for (i = 0; i < 6; j++, i += 2) {
-		if (flag & (0x01 << i)) {
-			val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
-			val_txfe = val_txfe |
-				((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
-			snd_soc_update_bits(codec,
-				TOMTOM_A_TX_1_2_TEST_EN + j * 10,
-				0x30, val_txfe);
-		}
-		if (flag & (0x01 << (i + 1))) {
-			val_txfe = (txfe_bypass &
-					(0x01 << (i + 1))) ? 0x02 : 0x00;
-			val_txfe |= (txfe_buff &
-					(0x01 << (i + 1))) ? 0x01 : 0x00;
-			snd_soc_update_bits(codec,
-				TOMTOM_A_TX_1_2_TEST_EN + j * 10,
-				0x03, val_txfe);
-		}
-	}
-	if (flag & 0x40) {
-		value = (leg_mode & 0x40) ? 0x10 : 0x00;
-		value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
-		value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
-		snd_soc_update_bits(codec, TOMTOM_A_TX_7_MBHC_EN,
-			0x13, value);
-	}
-
-	if (pdata->ocp.use_pdata) {
-		/* not defined in CODEC specification */
-		if (pdata->ocp.hph_ocp_limit == 1 ||
-			pdata->ocp.hph_ocp_limit == 5) {
-			rc = -EINVAL;
-			goto done;
-		}
-		snd_soc_update_bits(codec, TOMTOM_A_RX_COM_OCP_CTL,
-			0x0F, pdata->ocp.num_attempts);
-		snd_soc_write(codec, TOMTOM_A_RX_COM_OCP_COUNT,
-			((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
-		snd_soc_update_bits(codec, TOMTOM_A_RX_HPH_OCP_CTL,
-			0xE0, (pdata->ocp.hph_ocp_limit << 5));
-	}
-
-	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
-		if (pdata->regulator[i].name &&
-		    !strcmp(pdata->regulator[i].name, "CDC_VDDA_RX")) {
-			if (pdata->regulator[i].min_uV == 1800000 &&
-			    pdata->regulator[i].max_uV == 1800000) {
-				snd_soc_write(codec, TOMTOM_A_BIAS_REF_CTL,
-					      0x1C);
-			} else if (pdata->regulator[i].min_uV == 2200000 &&
-				   pdata->regulator[i].max_uV == 2200000) {
-				snd_soc_write(codec, TOMTOM_A_BIAS_REF_CTL,
-					      0x1E);
-			} else {
-				pr_err("%s: unsupported CDC_VDDA_RX voltage\n"
-				       "min %d, max %d\n", __func__,
-				       pdata->regulator[i].min_uV,
-				       pdata->regulator[i].max_uV);
-				rc = -EINVAL;
-			}
-			break;
-		}
-	}
-
-	/* Set micbias capless mode with tail current */
-	value = (pdata->micbias.bias1_cap_mode == MICBIAS_EXT_BYP_CAP ?
-		 0x00 : 0x16);
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_1_CTL, 0x1E, value);
-	value = (pdata->micbias.bias2_cap_mode == MICBIAS_EXT_BYP_CAP ?
-		 0x00 : 0x16);
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_2_CTL, 0x1E, value);
-	value = (pdata->micbias.bias3_cap_mode == MICBIAS_EXT_BYP_CAP ?
-		 0x00 : 0x16);
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_3_CTL, 0x1E, value);
-	value = (pdata->micbias.bias4_cap_mode == MICBIAS_EXT_BYP_CAP ?
-		 0x00 : 0x16);
-	snd_soc_update_bits(codec, TOMTOM_A_MICB_4_CTL, 0x1E, value);
-
-	/* Set the DMIC sample rate */
-	switch (pdata->mclk_rate) {
-	case TOMTOM_MCLK_CLK_9P6MHZ:
-		def_dmic_rate =
-			WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
-		break;
-	case TOMTOM_MCLK_CLK_12P288MHZ:
-		def_dmic_rate =
-			WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ;
-		break;
-	default:
-		/* should never happen */
-		pr_err("%s: Invalid mclk_rate %d\n",
-			__func__, pdata->mclk_rate);
-		rc = -EINVAL;
-		goto done;
-	}
-
-	if (pdata->dmic_sample_rate ==
-	    WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) {
-		pr_info("%s: dmic_rate invalid default = %d\n",
-			__func__, def_dmic_rate);
-		pdata->dmic_sample_rate = def_dmic_rate;
-	}
-
-	if (pdata->mad_dmic_sample_rate ==
-	    WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) {
-		pr_info("%s: mad_dmic_rate invalid default = %d\n",
-			__func__, def_dmic_rate);
-		/*
-		 * use dmic_sample_rate as the default for MAD
-		 * if mad dmic sample rate is undefined
-		 */
-		pdata->mad_dmic_sample_rate = pdata->dmic_sample_rate;
-	}
-
-	/*
-	 * Default the DMIC clk rates to mad_dmic_sample_rate,
-	 * whereas, the anc/txfe dmic rates to dmic_sample_rate
-	 * since the anc/txfe are independent of mad block.
-	 */
-	mad_dmic_ctl_val = tomtom_get_dmic_clk_val(tomtom->codec,
-				pdata->mclk_rate,
-				pdata->mad_dmic_sample_rate);
-	snd_soc_update_bits(codec, TOMTOM_A_DMIC_B1_CTL,
-		0xE0, mad_dmic_ctl_val << 5);
-	snd_soc_update_bits(codec, TOMTOM_A_DMIC_B2_CTL,
-		0x70, mad_dmic_ctl_val << 4);
-	snd_soc_update_bits(codec, TOMTOM_A_DMIC_B2_CTL,
-		0x0E, mad_dmic_ctl_val << 1);
-
-	dmic_ctl_val = tomtom_get_dmic_clk_val(tomtom->codec,
-				pdata->mclk_rate,
-				pdata->dmic_sample_rate);
-
-	if (dmic_ctl_val == WCD9330_DMIC_CLK_DIV_2)
-		anc_ctl_value = WCD9XXX_ANC_DMIC_X2_ON;
-	else
-		anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
-
-	for (dec = 0; dec < NUM_DECIMATORS; dec++) {
-		tx_dmic_ctl_reg =
-			TOMTOM_A_CDC_TX1_DMIC_CTL + (8 * dec);
-		snd_soc_update_bits(codec, tx_dmic_ctl_reg,
-				    0x07, dmic_ctl_val);
-	}
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_ANC1_B2_CTL,
-		0x1, anc_ctl_value);
-	snd_soc_update_bits(codec, TOMTOM_A_CDC_ANC2_B2_CTL,
-		0x1, anc_ctl_value);
-done:
-	return rc;
-}
-
-static const struct wcd9xxx_reg_mask_val tomtom_reg_defaults[] = {
-
-	/* set MCLk to 9.6 */
-	TOMTOM_REG_VAL(TOMTOM_A_CHIP_CTL, 0x02),
-
-	/* EAR PA deafults  */
-	TOMTOM_REG_VAL(TOMTOM_A_RX_EAR_CMBUFF, 0x05),
-
-	/* RX deafults */
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX1_B5_CTL, 0x79),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX2_B5_CTL, 0x79),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX3_B5_CTL, 0x79),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX4_B5_CTL, 0x79),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX5_B5_CTL, 0x79),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX6_B5_CTL, 0x79),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX7_B5_CTL, 0x79),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX8_B5_CTL, 0x79),
-
-	/* RX1 and RX2 defaults */
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX1_B6_CTL, 0xA0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX2_B6_CTL, 0xA0),
-
-	/* RX3 to RX7 defaults */
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX3_B6_CTL, 0x80),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX4_B6_CTL, 0x80),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX5_B6_CTL, 0x80),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX6_B6_CTL, 0x80),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX7_B6_CTL, 0x80),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX8_B6_CTL, 0x80),
-
-	/* MAD registers */
-	TOMTOM_REG_VAL(TOMTOM_A_MAD_ANA_CTRL, 0xF1),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_MAIN_CTL_1, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_MAIN_CTL_2, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_CTL_1, 0x00),
-	/* Set SAMPLE_TX_EN bit */
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_CTL_2, 0x03),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_CTL_3, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_CTL_4, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_CTL_5, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_CTL_6, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_CTL_7, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_CTL_8, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_PTR, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_AUDIO_IIR_CTL_VAL, 0x40),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_DEBUG_B7_CTL, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_CLK_OTHR_RESET_B1_CTL, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_CLK_OTHR_CTL, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_INP_SEL, 0x01),
-
-	/* Set HPH Path to low power mode */
-	TOMTOM_REG_VAL(TOMTOM_A_RX_HPH_BIAS_PA, 0x57),
-
-	/* BUCK default */
-	TOMTOM_REG_VAL(TOMTOM_A_BUCK_CTRL_CCL_4, 0x51),
-	TOMTOM_REG_VAL(TOMTOM_A_BUCK_CTRL_CCL_1, 0x5B),
-};
-
-/*
- * Don't update TOMTOM_A_CHIP_CTL, TOMTOM_A_BUCK_CTRL_CCL_1 and
- * TOMTOM_A_RX_EAR_CMBUFF as those are updated in tomtom_reg_defaults
- */
-static const struct wcd9xxx_reg_mask_val tomtom_1_0_reg_defaults[] = {
-	TOMTOM_REG_VAL(TOMTOM_A_TX_1_GAIN, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_TX_2_GAIN, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_TX_1_2_ADC_IB, 0x44),
-	TOMTOM_REG_VAL(TOMTOM_A_TX_3_GAIN, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_TX_4_GAIN, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_TX_3_4_ADC_IB, 0x44),
-	TOMTOM_REG_VAL(TOMTOM_A_TX_5_GAIN, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_TX_6_GAIN, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_TX_5_6_ADC_IB, 0x44),
-	TOMTOM_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
-	TOMTOM_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x8),
-	TOMTOM_REG_VAL(TOMTOM_A_BUCK_CTRL_CCL_4, 0x51),
-	TOMTOM_REG_VAL(TOMTOM_A_NCP_DTEST, 0x10),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_HPH_CHOP_CTL, 0xA4),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_HPH_OCP_CTL, 0x69),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_HPH_CNP_WG_CTL, 0xDA),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_HPH_CNP_WG_TIME, 0x15),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_EAR_BIAS_PA, 0x76),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_EAR_CNP, 0xC0),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_LINE_BIAS_PA, 0x78),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_LINE_1_TEST, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_LINE_2_TEST, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_LINE_3_TEST, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_LINE_4_TEST, 0x2),
-	TOMTOM_REG_VAL(TOMTOM_A_SPKR_DRV1_OCP_CTL, 0x97),
-	TOMTOM_REG_VAL(TOMTOM_A_SPKR_DRV1_CLIP_DET, 0x1),
-	TOMTOM_REG_VAL(TOMTOM_A_SPKR_DRV1_IEC, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_SPKR_DRV2_OCP_CTL, 0x97),
-	TOMTOM_REG_VAL(TOMTOM_A_SPKR_DRV2_CLIP_DET, 0x1),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX1_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX2_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX3_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX4_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX5_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX6_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX7_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX8_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX9_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX10_MUX_CTL, 0x4A),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX1_B4_CTL, 0xB),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX2_B4_CTL, 0xB),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX3_B4_CTL, 0xB),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX4_B4_CTL, 0xB),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX5_B4_CTL, 0xB),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX6_B4_CTL, 0xB),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX7_B4_CTL, 0xB),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX8_B4_CTL, 0xB),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_VBAT_GAIN_UPD_MON, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_PA_RAMP_B1_CTL, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_PA_RAMP_B2_CTL, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_PA_RAMP_B3_CTL, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_PA_RAMP_B4_CTL, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_SPKR_CLIPDET_B1_CTL, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_SPKR2_CLIPDET_B1_CTL, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_COMP0_B4_CTL, 0x37),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_COMP0_B5_CTL, 0x7f),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_COMP0_B5_CTL, 0x7f),
-};
-
-static const struct wcd9xxx_reg_mask_val tomtom_2_0_reg_defaults[] = {
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_MAD_MAIN_CTL_2, 0x32),
-	TOMTOM_REG_VAL(TOMTOM_A_RCO_CTRL, 0x10),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_HPH_L_TEST, 0x0A),
-	TOMTOM_REG_VAL(TOMTOM_A_RX_HPH_R_TEST, 0x0A),
-	TOMTOM_REG_VAL(TOMTOM_A_PIN_CTL_OE0, 0xC3),
-	TOMTOM_REG_VAL(TOMTOM_A_PIN_CTL_DATA0, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX_I2S_SCK_MODE, 0x04),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX_I2S_WS_MODE, 0x04),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX_I2S_SCK_MODE, 0x04),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX_I2S_WS_MODE, 0x04),
-	TOMTOM_REG_VAL(TOMTOM_A_PIN_CTL_OE1, 0xE0),
-	TOMTOM_REG_VAL(TOMTOM_A_PIN_CTL_OE2, 0x03),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_JTCK_MODE, 0x04),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_JTDI_MODE, 0x04),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_JTMS_MODE, 0x04),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_JTDO_MODE, 0x04),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_JTRST_MODE, 0x04),
-};
-
-static const struct wcd9xxx_reg_mask_val tomtom_2_0_reg_i2c_defaults[] = {
-	TOMTOM_REG_VAL(TOMTOM_A_PIN_CTL_OE0, 0x00),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX_I2S_SCK_MODE, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_TX_I2S_WS_MODE, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX_I2S_SCK_MODE, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_CDC_RX_I2S_WS_MODE, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_PIN_CTL_OE1, 0x0),
-	TOMTOM_REG_VAL(TOMTOM_A_PIN_CTL_OE2, 0x0),
-};
-
-static void tomtom_update_reg_defaults(struct snd_soc_codec *codec)
-{
-	u32 i;
-	struct wcd9xxx *tomtom_core = dev_get_drvdata(codec->dev->parent);
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	for (i = 0; i < ARRAY_SIZE(tomtom_reg_defaults); i++)
-		snd_soc_write(codec, tomtom_reg_defaults[i].reg,
-			      tomtom_reg_defaults[i].val);
-
-	for (i = 0; i < ARRAY_SIZE(tomtom_1_0_reg_defaults); i++)
-		snd_soc_write(codec, tomtom_1_0_reg_defaults[i].reg,
-				tomtom_1_0_reg_defaults[i].val);
-
-	if (!TOMTOM_IS_1_0(tomtom_core->version)) {
-		for (i = 0; i < ARRAY_SIZE(tomtom_2_0_reg_defaults); i++)
-			snd_soc_write(codec, tomtom_2_0_reg_defaults[i].reg,
-				      tomtom_2_0_reg_defaults[i].val);
-
-		if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
-			for (i = 0; i < ARRAY_SIZE(tomtom_2_0_reg_i2c_defaults);
-			     i++)
-				snd_soc_write(codec,
-					tomtom_2_0_reg_i2c_defaults[i].reg,
-					tomtom_2_0_reg_i2c_defaults[i].val);
-		}
-	}
-}
-
-static const struct wcd9xxx_reg_mask_val tomtom_codec_reg_init_val[] = {
-	/* Initialize current threshold to 350MA
-	 * number of wait and run cycles to 4096
-	 */
-	{TOMTOM_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
-	{TOMTOM_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
-	{TOMTOM_A_RX_HPH_L_TEST, 0x01, 0x01},
-	{TOMTOM_A_RX_HPH_R_TEST, 0x01, 0x01},
-
-	/* Initialize gain registers to use register gain */
-	{TOMTOM_A_RX_HPH_L_GAIN, 0x20, 0x20},
-	{TOMTOM_A_RX_HPH_R_GAIN, 0x20, 0x20},
-	{TOMTOM_A_RX_LINE_1_GAIN, 0x20, 0x20},
-	{TOMTOM_A_RX_LINE_2_GAIN, 0x20, 0x20},
-	{TOMTOM_A_RX_LINE_3_GAIN, 0x20, 0x20},
-	{TOMTOM_A_RX_LINE_4_GAIN, 0x20, 0x20},
-	{TOMTOM_A_SPKR_DRV1_GAIN, 0x04, 0x04},
-	{TOMTOM_A_SPKR_DRV2_GAIN, 0x04, 0x04},
-
-	/* Use 16 bit sample size for TX1 to TX6 */
-	{TOMTOM_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
-	{TOMTOM_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
-	{TOMTOM_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
-	{TOMTOM_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
-	{TOMTOM_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
-	{TOMTOM_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
-
-	/* Use 16 bit sample size for TX7 to TX10 */
-	{TOMTOM_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
-	{TOMTOM_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
-	{TOMTOM_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
-	{TOMTOM_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
-
-	/*enable HPF filter for TX paths */
-	{TOMTOM_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
-	{TOMTOM_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
-	{TOMTOM_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
-	{TOMTOM_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
-	{TOMTOM_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
-	{TOMTOM_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
-	{TOMTOM_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
-	{TOMTOM_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
-	{TOMTOM_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
-	{TOMTOM_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
-
-	/* Compander zone selection */
-	{TOMTOM_A_CDC_COMP0_B4_CTL, 0x3F, 0x37},
-	{TOMTOM_A_CDC_COMP1_B4_CTL, 0x3F, 0x37},
-	{TOMTOM_A_CDC_COMP2_B4_CTL, 0x3F, 0x37},
-	{TOMTOM_A_CDC_COMP0_B5_CTL, 0x7F, 0x7F},
-	{TOMTOM_A_CDC_COMP1_B5_CTL, 0x7F, 0x7F},
-	{TOMTOM_A_CDC_COMP2_B5_CTL, 0x7F, 0x7F},
-
-	/*
-	 * Setup wavegen timer to 20msec and disable chopper
-	 * as default. This corresponds to Compander OFF
-	 */
-	{TOMTOM_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDB},
-	{TOMTOM_A_RX_HPH_CNP_WG_TIME, 0xFF, 0x58},
-	{TOMTOM_A_RX_HPH_BIAS_WG_OCP, 0xFF, 0x1A},
-	{TOMTOM_A_RX_HPH_CHOP_CTL, 0xFF, 0x24},
-
-	/* Choose max non-overlap time for NCP */
-	{TOMTOM_A_NCP_CLK, 0xFF, 0xFC},
-
-	/* Program the 0.85 volt VBG_REFERENCE */
-	{TOMTOM_A_BIAS_CURR_CTL_2, 0xFF, 0x04},
-
-	/* set MAD input MIC to DMIC1 */
-	{TOMTOM_A_CDC_MAD_INP_SEL, 0x0F, 0x08},
-
-	{TOMTOM_A_INTR_MODE, 0x04, 0x04},
-};
-
-static const struct wcd9xxx_reg_mask_val tomtom_codec_2_0_reg_init_val[] = {
-	{TOMTOM_A_RX_HPH_L_TEST, 0x08, 0x00},
-	{TOMTOM_A_RX_HPH_R_TEST, 0x08, 0x00},
-	{TOMTOM_A_CDC_CLIP_ADJ_SPKR_MIN_CLIP_THRESHOLD, 0xFF, 0x00},
-	{TOMTOM_A_CDC_CLIP_ADJ_SPKR2_MIN_CLIP_THRESHOLD, 0xFF, 0x00},
-	{TOMTOM_A_CDC_CLIP_ADJ_SPKR_BOOST_GATING, 0x01, 0x01},
-	{TOMTOM_A_CDC_CLIP_ADJ_SPKR2_BOOST_GATING, 0x01, 0x01},
-	{TOMTOM_A_CDC_CLIP_ADJ_SPKR_B1_CTL, 0x01, 0x00},
-	{TOMTOM_A_CDC_CLIP_ADJ_SPKR2_B1_CTL, 0x01, 0x00},
-};
-
-static void tomtom_codec_init_reg(struct snd_soc_codec *codec)
-{
-	u32 i;
-	struct wcd9xxx *tomtom_core = dev_get_drvdata(codec->dev->parent);
-
-	for (i = 0; i < ARRAY_SIZE(tomtom_codec_reg_init_val); i++)
-		snd_soc_update_bits(codec, tomtom_codec_reg_init_val[i].reg,
-				tomtom_codec_reg_init_val[i].mask,
-				tomtom_codec_reg_init_val[i].val);
-
-	if (!TOMTOM_IS_1_0(tomtom_core->version)) {
-		for (i = 0; i < ARRAY_SIZE(tomtom_codec_2_0_reg_init_val); i++)
-			snd_soc_update_bits(codec,
-				tomtom_codec_2_0_reg_init_val[i].reg,
-				tomtom_codec_2_0_reg_init_val[i].mask,
-				tomtom_codec_2_0_reg_init_val[i].val);
-	}
-
-}
-
-static void tomtom_slim_interface_init_reg(struct snd_soc_codec *codec)
-{
-	int i;
-	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
-
-	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
-		wcd9xxx_interface_reg_write(wcd9xxx,
-					    TOMTOM_SLIM_PGD_PORT_INT_EN0 + i,
-					    0xFF);
-}
-
-static int tomtom_setup_irqs(struct tomtom_priv *tomtom)
-{
-	int ret = 0;
-	struct snd_soc_codec *codec = tomtom->codec;
-	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
-	struct wcd9xxx_core_resource *core_res =
-				&wcd9xxx->core_res;
-
-	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
-				  tomtom_slimbus_irq, "SLIMBUS Slave", tomtom);
-	if (ret)
-		pr_err("%s: Failed to request irq %d\n", __func__,
-		       WCD9XXX_IRQ_SLIMBUS);
-	else
-		tomtom_slim_interface_init_reg(codec);
-
-	return ret;
-}
-
-static void tomtom_cleanup_irqs(struct tomtom_priv *tomtom)
-{
-	struct snd_soc_codec *codec = tomtom->codec;
-	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
-	struct wcd9xxx_core_resource *core_res =
-				&wcd9xxx->core_res;
-
-	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tomtom);
-}
-
-static
-struct firmware_cal *tomtom_get_hwdep_fw_cal(struct snd_soc_codec *codec,
-			enum wcd_cal_type type)
-{
-	struct tomtom_priv *tomtom;
-	struct firmware_cal *hwdep_cal;
-
-	if (!codec) {
-		pr_err("%s: NULL codec pointer\n", __func__);
-		return NULL;
-	}
-	tomtom = snd_soc_codec_get_drvdata(codec);
-	hwdep_cal = wcdcal_get_fw_cal(tomtom->fw_data, type);
-	if (!hwdep_cal) {
-		dev_err(codec->dev, "%s: cal not sent by %d\n",
-				__func__, type);
-		return NULL;
-	} else {
-		return hwdep_cal;
-	}
-}
-
-int tomtom_hs_detect(struct snd_soc_codec *codec,
-		    struct wcd9xxx_mbhc_config *mbhc_cfg)
-{
-	int rc;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	if (mbhc_cfg->insert_detect) {
-		rc = wcd9xxx_mbhc_start(&tomtom->mbhc, mbhc_cfg);
-		if (!rc)
-			tomtom->mbhc_started = true;
-	} else {
-		/* MBHC is disabled, so disable Auto pulldown */
-		snd_soc_update_bits(codec, TOMTOM_A_MBHC_INSERT_DETECT2, 0xC0,
-				    0x00);
-		snd_soc_update_bits(codec, TOMTOM_A_MICB_CFILT_2_CTL, 0x01,
-				    0x00);
-		tomtom->mbhc.mbhc_cfg = NULL;
-		rc = 0;
-	}
-	return rc;
-}
-EXPORT_SYMBOL(tomtom_hs_detect);
-
-void tomtom_hs_detect_exit(struct snd_soc_codec *codec)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	wcd9xxx_mbhc_stop(&tomtom->mbhc);
-	tomtom->mbhc_started = false;
-}
-EXPORT_SYMBOL(tomtom_hs_detect_exit);
-
-void tomtom_event_register(
-	int (*machine_event_cb)(struct snd_soc_codec *codec,
-				enum wcd9xxx_codec_event),
-	struct snd_soc_codec *codec)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	tomtom->machine_codec_event_cb = machine_event_cb;
-}
-EXPORT_SYMBOL(tomtom_event_register);
-
-void tomtom_register_ext_clk_cb(
-	int (*codec_ext_clk_en)(struct snd_soc_codec *codec,
-				int enable, bool dapm),
-	int (*get_ext_clk_cnt)(void),
-	struct snd_soc_codec *codec)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-	tomtom->codec_ext_clk_en_cb =  codec_ext_clk_en;
-	tomtom->codec_get_ext_clk_cnt = get_ext_clk_cnt;
-}
-EXPORT_SYMBOL(tomtom_register_ext_clk_cb);
-
-static void tomtom_init_slim_slave_cfg(struct snd_soc_codec *codec)
-{
-	struct tomtom_priv *priv = snd_soc_codec_get_drvdata(codec);
-	struct afe_param_cdc_slimbus_slave_cfg *cfg;
-	struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
-	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 tomtom_device_down(struct wcd9xxx *wcd9xxx)
-{
-	int count;
-	struct snd_soc_codec *codec;
-	struct tomtom_priv *priv;
-
-	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
-	priv = snd_soc_codec_get_drvdata(codec);
-	wcd_cpe_ssr_event(priv->cpe_core, WCD_CPE_BUS_DOWN_EVENT);
-	snd_soc_card_change_online_state(codec->component.card, 0);
-	set_bit(BUS_DOWN, &priv->status_mask);
-
-	for (count = 0; count < NUM_CODEC_DAIS; count++)
-		priv->dai[count].bus_down_in_recovery = true;
-	return 0;
-}
-
-static int wcd9xxx_prepare_static_pa(struct wcd9xxx_mbhc *mbhc,
-				     struct list_head *lh)
-{
-	int i;
-	struct snd_soc_codec *codec = mbhc->codec;
-	u32 delay;
-
-	const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
-		{TOMTOM_A_TX_COM_BIAS, 0xff, 0xF0},
-		{WCD9XXX_A_CDC_RX1_B6_CTL, 0xff, 0x81},
-		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x01, 0x01},
-		{WCD9XXX_A_BUCK_MODE_2, 0xff, 0xEF},
-		{WCD9XXX_A_BUCK_MODE_2, 0xff, 0xEE},
-		{TOMTOM_A_NCP_DTEST, 0xff, 0x20},
-		{WCD9XXX_A_CDC_CLK_OTHR_CTL, 0xff, 0x21},
-		{WCD9XXX_A_CDC_RX2_B6_CTL, 0xff, 0x81},
-		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x02, 0x02},
-
-		{WCD9XXX_A_BUCK_MODE_2, 0xff, 0xAE},
-		{WCD9XXX_A_BUCK_MODE_2, 0xff, 0xAA},
-		{WCD9XXX_A_NCP_CLK, 0xff, 0x9C},
-		{WCD9XXX_A_NCP_CLK, 0xff, 0xFC},
-		{WCD9XXX_A_RX_COM_BIAS, 0xff, 0xA0},
-		{WCD9XXX_A_BUCK_MODE_3, 0xff, 0xC6},
-		{WCD9XXX_A_BUCK_MODE_4, 0xff, 0xE6},
-		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x02},
-		{WCD9XXX_A_BUCK_MODE_1, 0xff, 0xA1},
-		/* Add a delay of 1ms after this reg write */
-
-		{WCD9XXX_A_NCP_STATIC, 0xff, 0x28},
-		{WCD9XXX_A_NCP_EN, 0xff, 0xFF},
-		/* Add a delay of 1ms after this reg write */
-
-		/* set HPHL */
-		{WCD9XXX_A_RX_HPH_L_TEST, 0xff, 0x00},
-		{TOMTOM_A_RX_HPH_L_PA_CTL, 0xff, 0x42},
-		{TOMTOM_A_RX_HPH_BIAS_LDO, 0xff, 0x8C},
-		{TOMTOM_A_RX_HPH_CHOP_CTL, 0xff, 0xA4},
-		{WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0xE0},
-		{WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0xEC},
-
-		/* set HPHR */
-		{WCD9XXX_A_RX_HPH_R_TEST, 0xff, 0x00},
-		{TOMTOM_A_RX_HPH_R_PA_CTL, 0xff, 0x42},
-		{WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x20},
-		{WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x2C},
-
-		/* set HPH PAs */
-		{WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xff, 0x2A},
-		{WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xff, 0xDA},
-		{WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xff, 0x15},
-		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0xff, 0xE6},
-		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xff, 0x40},
-		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xff, 0xC0},
-		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xff, 0x40},
-		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xff, 0xC0},
-
-		{TOMTOM_A_RX_HPH_L_ATEST, 0xff, 0x00},
-		{TOMTOM_A_RX_HPH_R_ATEST, 0xff, 0x00},
-	};
-
-	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++) {
-		/*
-		 * Some of the codec registers like BUCK_MODE_1
-		 * and NCP_EN requires 1ms wait time for them
-		 * to take effect. Other register writes for
-		 * PA configuration do not require any wait time.
-		 */
-		if (reg_set_paon[i].reg == WCD9XXX_A_BUCK_MODE_1 ||
-		    reg_set_paon[i].reg == WCD9XXX_A_NCP_EN)
-			delay = 1000;
-		else
-			delay = 0;
-		wcd9xxx_soc_update_bits_push(codec, lh,
-					     reg_set_paon[i].reg,
-					     reg_set_paon[i].mask,
-					     reg_set_paon[i].val, delay);
-	}
-	pr_debug("%s: PAs are prepared\n", __func__);
-
-	return 0;
-}
-
-static int wcd9xxx_enable_static_pa(struct wcd9xxx_mbhc *mbhc, bool enable,
-				    u8 hph_pa)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	const int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
-			    TOMTOM_WG_TIME_FACTOR_US;
-	u8 mask = (hph_pa << 4);
-	u8 pa_en = enable ? mask : ~mask;
-
-	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, mask, pa_en);
-	/* Wait for wave gen time to avoid pop noise */
-	usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-	pr_debug("%s: PAs are %s as static mode (wg_time %d)\n", __func__,
-		 enable ? "enabled" : "disabled", wg_time);
-	return 0;
-}
-
-static int tomtom_setup_zdet(struct wcd9xxx_mbhc *mbhc,
-			    enum mbhc_impedance_detect_stages stage)
-{
-	int ret = 0;
-	struct snd_soc_codec *codec = mbhc->codec;
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-
-#define __wr(reg, mask, value)						  \
-	do {								  \
-		ret = wcd9xxx_soc_update_bits_push(codec,		  \
-						   &tomtom->reg_save_restore, \
-						   reg, mask, value, 0);  \
-		if (ret < 0)						  \
-			return ret;					  \
-	} while (0)
-
-	switch (stage) {
-
-	case MBHC_ZDET_PRE_MEASURE:
-		INIT_LIST_HEAD(&tomtom->reg_save_restore);
-		wcd9xxx_prepare_static_pa(mbhc, &tomtom->reg_save_restore);
-		/* Set HPH_MBHC for zdet */
-		__wr(WCD9XXX_A_MBHC_HPH, 0xff, 0xC4);
-		usleep_range(10, 10 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		wcd9xxx_enable_static_pa(mbhc, HPH_PA_ENABLE, HPH_PA_L_R);
-
-		/* save old value of registers and write the new value */
-		__wr(WCD9XXX_A_RX_HPH_OCP_CTL, 0xff, 0x69);
-		__wr(WCD9XXX_A_CDC_RX1_B6_CTL, 0xff, 0x80);
-		__wr(WCD9XXX_A_CDC_RX2_B6_CTL, 0xff, 0x80);
-		/* Enable MBHC MUX, Set MUX current to 37.5uA and ADC7 */
-		__wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0xff, 0xC0);
-		__wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xff, 0xF0);
-		__wr(TOMTOM_A_TX_7_TXFE_CLKDIV, 0xff, 0x8B);
-		__wr(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xff, 0x78);
-		__wr(WCD9XXX_A_TX_7_MBHC_EN, 0xff, 0x8C);
-		__wr(WCD9XXX_A_CDC_MBHC_B1_CTL, 0xff, 0xDC);
-		/* Reset MBHC and set it up for STA */
-		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xff, 0x0A);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x00);
-		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xff, 0x02);
-		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xff, 0x80);
-		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0xff, 0x25);
-		/* Wait for ~50us to let MBHC hardware settle down */
-		usleep_range(50, 50 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		break;
-	case MBHC_ZDET_POST_MEASURE:
-		/* 0x69 for 105 number of samples for PA RAMP */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0x69);
-		/* Program the PA Ramp to FS_16K, L shift 1 */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL,
-			      0x1 << 4 | 0x6);
-		/* Reset the PA Ramp */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1C);
-		/*
-		 * Connect the PA Ramp to PA chain and release reset with
-		 * keep it connected.
-		 */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1F);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
-
-		/* Start the PA ramp on HPH L and R */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x05);
-		/* Ramp generator takes ~30ms */
-		usleep_range(TOMTOM_HPH_PA_RAMP_DELAY,
-			     TOMTOM_HPH_PA_RAMP_DELAY +
-			     WCD9XXX_USLEEP_RANGE_MARGIN_US);
-
-		/*
-		 * Set the multiplication factor for zdet calculation
-		 * based on the Ramp voltage and Gain used
-		 */
-		tomtom->zdet_gain_mul_fact = TOMTOM_ZDET_MUL_FACTOR_1X;
-		break;
-	case MBHC_ZDET_GAIN_0:
-		/* Set Gain at 1x */
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_ATEST, 0x00);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_R_ATEST, 0x00);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_PA_CTL, 0x42);
-		/* Allow 100us for gain registers to settle */
-		usleep_range(100,
-			     100 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		break;
-	case MBHC_ZDET_GAIN_UPDATE_1X:
-		/*
-		 * Set the multiplication factor for zdet calculation
-		 * based on the Gain value used
-		 */
-		tomtom->zdet_gain_mul_fact = TOMTOM_ZDET_MUL_FACTOR_1X;
-		break;
-	case MBHC_ZDET_GAIN_1:
-		/* Set Gain at 10x */
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_ATEST, 0x10);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_R_ATEST, 0x00);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_PA_CTL, 0x42);
-		/* Allow 100us for gain registers to settle */
-		usleep_range(100,
-			     100 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-
-		/*
-		 * Set the multiplication factor for zdet calculation
-		 * based on the Gain value used
-		 */
-		tomtom->zdet_gain_mul_fact = TOMTOM_ZDET_MUL_FACTOR_10X;
-		break;
-	case MBHC_ZDET_GAIN_2:
-		/* Set Gain at 100x */
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_ATEST, 0x00);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_R_ATEST, 0x10);
-		snd_soc_write(codec, TOMTOM_A_RX_HPH_L_PA_CTL, 0x43);
-		/* Allow 100us for gain registers to settle */
-		usleep_range(100,
-			     100 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-
-		/*
-		 * Set the multiplication factor for zdet calculation
-		 * based on the Gain value used
-		 */
-		tomtom->zdet_gain_mul_fact = TOMTOM_ZDET_MUL_FACTOR_100X;
-		break;
-	case MBHC_ZDET_RAMP_DISABLE:
-		/* Ramp HPH L & R back to Zero */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
-		/* 0x69 for 105 number of samples for PA RAMP */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0x69);
-		/* Program the PA Ramp to FS_16K, L shift 1 */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL,
-			      0x1 << 4 | 0x6);
-		/* Reset the PA Ramp */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x17);
-		/*
-		 * Connect the PA Ramp to PA chain and release reset with
-		 * keep it connected.
-		 */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
-		/* Start the PA ramp on HPH L and R */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x0A);
-		/* Ramp generator takes ~30ms to settle down */
-		usleep_range(TOMTOM_HPH_PA_RAMP_DELAY,
-			     TOMTOM_HPH_PA_RAMP_DELAY +
-			     WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		break;
-	case MBHC_ZDET_HPHR_RAMP_DISABLE:
-		/* Ramp HPHR back to Zero */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0x69);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL,
-			      0x1 << 4 | 0x6);
-		/* Reset the PA Ramp */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x17);
-		/*
-		 * Connect the PA Ramp to PA chain and release reset with
-		 * keep it connected.
-		 */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x08);
-		/* Ramp generator takes ~30ms to settle down */
-		usleep_range(TOMTOM_HPH_PA_RAMP_DELAY,
-			     TOMTOM_HPH_PA_RAMP_DELAY +
-			     WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		break;
-	case MBHC_ZDET_HPHL_RAMP_DISABLE:
-		/* Ramp back to Zero */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0x69);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL,
-			      0x1 << 4 | 0x6);
-		/* Reset the PA Ramp */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x17);
-		/*
-		 * Connect the PA Ramp to PA chain and release reset with
-		 * keep it connected.
-		 */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x02);
-		/* Ramp generator takes ~30ms to settle down */
-		usleep_range(TOMTOM_HPH_PA_RAMP_DELAY,
-			     TOMTOM_HPH_PA_RAMP_DELAY +
-			     WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		break;
-	case MBHC_ZDET_HPHR_PA_DISABLE:
-		/* Disable PA */
-		wcd9xxx_enable_static_pa(mbhc, HPH_PA_DISABLE, HPH_PA_R);
-		break;
-	case MBHC_ZDET_PA_DISABLE:
-		/* Disable PA */
-		if (!mbhc->hph_pa_dac_state &&
-			(!(test_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state) ||
-			test_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state))))
-			wcd9xxx_enable_static_pa(mbhc, HPH_PA_DISABLE,
-						 HPH_PA_L_R);
-		else if (!(snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_EN) & 0x10))
-			wcd9xxx_enable_static_pa(mbhc, HPH_PA_ENABLE, HPH_PA_R);
-
-		/* Turn off PA ramp generator */
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x00);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL, 0x00);
-		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0x00);
-
-		/* Restore registers */
-		wcd9xxx_restore_registers(codec, &tomtom->reg_save_restore);
-		break;
-	}
-#undef __wr
-
-	return ret;
-}
-
-/* Calculate final impedance values for HPH left and right based on formulae */
-static void tomtom_compute_impedance(struct wcd9xxx_mbhc *mbhc, s16 *l, s16 *r,
-				     uint32_t *zl, uint32_t *zr)
-{
-	s64 zln, zrn;
-	int zld, zrd;
-	s64 rl = 0, rr = 0;
-	struct snd_soc_codec *codec;
-	struct tomtom_priv *tomtom;
-
-	if (!mbhc) {
-		pr_err("%s: Invalid parameters mbhc = %pK\n",
-			__func__,  mbhc);
-		return;
-	}
-	codec = mbhc->codec;
-	tomtom = snd_soc_codec_get_drvdata(codec);
-
-	if (l && zl) {
-		zln = (s64) (l[1] - l[0]) * tomtom->zdet_gain_mul_fact;
-		zld = (l[2] - l[0]);
-		if (zld)
-			rl = div_s64(zln, zld);
-		else
-			/* If L0 and L2 are same, Z has to be on Zone 3.
-			 * Assign a default value so that atleast the value
-			 * is read again with Ramp-up
-			 */
-			rl = TOMTOM_ZDET_ZONE_3_DEFAULT_VAL;
-
-		/* 32-bit LSBs are enough to hold Impedance values */
-		*zl = (u32) rl;
-	}
-	if (r && zr) {
-		zrn = (s64) (r[1] - r[0]) * tomtom->zdet_gain_mul_fact;
-		zrd = (r[2] - r[0]);
-		if (zrd)
-			rr = div_s64(zrn, zrd);
-		else
-			/* If R0 and R2 are same, Z has to be on Zone 3.
-			 * Assign a default value so that atleast the value
-			 * is read again with Ramp-up
-			 */
-			rr = TOMTOM_ZDET_ZONE_3_DEFAULT_VAL;
-
-		/* 32-bit LSBs are enough to hold Impedance values */
-		*zr = (u32) rr;
-	}
-}
-
-/*
- * Calculate error approximation of impedance values for HPH left
- * and HPH right based on QFuse values
- */
-static void tomtom_zdet_error_approx(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
-				     uint32_t *zr)
-{
-	struct snd_soc_codec *codec;
-	struct tomtom_priv *tomtom;
-	s8 q1_t, q2_t;
-	s8 q1_m, q2_m;
-	s8 q1, q2;
-	u8 div_shift;
-	int rl_alpha = 0, rr_alpha = 0;
-	int rl_beta = 0, rr_beta = 0;
-	u64 rl = 0, rr = 0;
-	const int mult_factor = TOMTOM_ZDET_ERROR_APPROX_MUL_FACTOR;
-	const int shift = TOMTOM_ZDET_ERROR_APPROX_SHIFT;
-
-	if (!zl || !zr || !mbhc) {
-		pr_err("%s: Invalid parameters zl = %pK zr = %pK, mbhc = %pK\n",
-			__func__, zl, zr, mbhc);
-		return;
-	}
-	codec = mbhc->codec;
-	tomtom = snd_soc_codec_get_drvdata(codec);
-
-	if ((tomtom->zdet_gain_mul_fact == TOMTOM_ZDET_MUL_FACTOR_1X) ||
-	    (tomtom->zdet_gain_mul_fact == TOMTOM_ZDET_MUL_FACTOR_10X)) {
-		q1_t = ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT0) &
-			0x3) << 0x5);
-		q1_t |= ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT1) &
-			0xF8) >> 0x3);
-		q2_t = ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT1) &
-			0x7) << 0x4);
-		q2_t |= ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT2) &
-			0xF0) >> 0x4);
-		/* Take out the numeric part of the Qfuse value */
-		q1_m = q1_t & 0x3F;
-		q2_m = q2_t & 0x3F;
-		/* Check the sign part of the Qfuse and adjust value */
-		q1 = (q1_t & 0x40) ? -q1_m : q1_m;
-		q2 = (q2_t & 0x40) ? -q2_m : q2_m;
-		div_shift = 1;
-	} else {
-		q1_t = ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT2) &
-			0xF) << 0x2);
-		q1_t |= ((snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT3) &
-			0xC0) >> 0x6);
-		q2_t = (snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT3) & 0x3F);
-		/* Take out the numeric part of the Qfuse value */
-		q1_m = q1_t & 0x1F;
-		q2_m = q2_t & 0x1F;
-		/* Check the sign part of the Qfuse and adjust value */
-		q1 = (q1_t & 0x20) ? -q1_m : q1_m;
-		q2 = (q2_t & 0x20) ? -q2_m : q2_m;
-		div_shift = 0;
-	}
-
-	dev_dbg(codec->dev, "%s: qfuse1 = %d, qfuse2 = %d\n",
-		__func__, q1, q2);
-	if (!q1 && !q2) {
-		dev_dbg(codec->dev, "%s: qfuse1 and qfuse2 are 0. Exiting\n",
-			__func__);
-		return;
-	}
-
-	/*
-	 * Use multiplication and shift to avoid floating point math
-	 * The Z value is calculated with the below formulae using
-	 * the Qfuse value-
-	 * zl = zl * [1 - {(Q1 / div) / 100}] (Include sign for Q1)
-	 * zr = zr * [1 - {(Q2 / div) / 100}] (Include sign for Q2)
-	 * We multiply by 65536 and shift 16 times to get the approx result
-	 * div = 4 for 1x gain, div = 2 for 10x/100x gain
-	 */
-	/* Q1/4 */
-	rl_alpha = q1 >> div_shift;
-	rl_alpha = 100 - rl_alpha;
-	/* {rl_alpha/100} * 65536 */
-	rl_beta = rl_alpha * mult_factor;
-	rl = (u64) *zl * rl_beta;
-	/* rl/65536 */
-	rl = (u64) rl >> shift;
-
-	rr_alpha = q2 >> div_shift;
-	rr_alpha = 100 - rr_alpha;
-	rr_beta = rr_alpha * mult_factor;
-	rr = (u64) *zr * rr_beta;
-	rr = (u64) rr >> shift;
-
-	dev_dbg(codec->dev, "%s: rl = 0x%llx (%lld) \t rr = 0x%llx (%lld)\n",
-		__func__, rl, rl, rr, rr);
-
-	*zl = (u32) rl;
-	*zr = (u32) rr;
-}
-
-static enum wcd9xxx_cdc_type tomtom_get_cdc_type(void)
-{
-	return WCD9XXX_CDC_TYPE_TOMTOM;
-}
-
-static bool tomtom_mbhc_ins_rem_status(struct snd_soc_codec *codec)
-{
-	return !(snd_soc_read(codec, WCD9XXX_A_MBHC_INSERT_DET_STATUS) &
-			    (1 << 4));
-}
-
-static void tomtom_mbhc_micb_pulldown_ctrl(struct wcd9xxx_mbhc *mbhc,
-					   bool enable)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	if (!enable) {
-		/* Remove automatic pulldown on micbias */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
-				    0x01, 0x00);
-	} else {
-		/* Enable automatic pulldown on micbias */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
-				    0x01, 0x01);
-	}
-}
-
-static void tomtom_codec_hph_auto_pull_down(struct snd_soc_codec *codec,
-					    bool enable)
-{
-	struct wcd9xxx *tomtom_core = dev_get_drvdata(codec->dev->parent);
-
-	if (TOMTOM_IS_1_0(tomtom_core->version))
-		return;
-
-	dev_dbg(codec->dev, "%s: %s auto pull down\n", __func__,
-			enable ? "enable" : "disable");
-	if (enable) {
-		snd_soc_update_bits(codec, TOMTOM_A_RX_HPH_L_TEST, 0x08, 0x08);
-		snd_soc_update_bits(codec, TOMTOM_A_RX_HPH_R_TEST, 0x08, 0x08);
-	} else {
-		snd_soc_update_bits(codec, TOMTOM_A_RX_HPH_L_TEST, 0x08, 0x00);
-		snd_soc_update_bits(codec, TOMTOM_A_RX_HPH_R_TEST, 0x08, 0x00);
-	}
-}
-
-static const struct wcd9xxx_mbhc_cb mbhc_cb = {
-	.get_cdc_type = tomtom_get_cdc_type,
-	.setup_zdet = tomtom_setup_zdet,
-	.compute_impedance = tomtom_compute_impedance,
-	.zdet_error_approx = tomtom_zdet_error_approx,
-	.insert_rem_status = tomtom_mbhc_ins_rem_status,
-	.micbias_pulldown_ctrl = tomtom_mbhc_micb_pulldown_ctrl,
-	.codec_rco_ctrl = tomtom_codec_internal_rco_ctrl,
-	.hph_auto_pulldown_ctrl = tomtom_codec_hph_auto_pull_down,
-	.get_hwdep_fw_cal = tomtom_get_hwdep_fw_cal,
-};
-
-static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
-	.poll_plug_rem = WCD9XXX_IRQ_MBHC_REMOVAL,
-	.shortavg_complete = WCD9XXX_IRQ_MBHC_SHORT_TERM,
-	.potential_button_press = WCD9XXX_IRQ_MBHC_PRESS,
-	.button_release = WCD9XXX_IRQ_MBHC_RELEASE,
-	.dce_est_complete = WCD9XXX_IRQ_MBHC_POTENTIAL,
-	.insertion = WCD9XXX_IRQ_MBHC_INSERTION,
-	.hph_left_ocp = WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
-	.hph_right_ocp = WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
-	.hs_jack_switch = WCD9330_IRQ_MBHC_JACK_SWITCH,
-};
-
-static int tomtom_post_reset_cb(struct wcd9xxx *wcd9xxx)
-{
-	int ret = 0;
-	struct snd_soc_codec *codec;
-	struct tomtom_priv *tomtom;
-	int rco_clk_rate;
-
-	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
-	tomtom = snd_soc_codec_get_drvdata(codec);
-
-	snd_soc_card_change_online_state(codec->component.card, 1);
-	clear_bit(BUS_DOWN, &tomtom->status_mask);
-
-	mutex_lock(&tomtom->codec_mutex);
-
-	tomtom_update_reg_defaults(codec);
-	if (wcd9xxx->mclk_rate == TOMTOM_MCLK_CLK_12P288MHZ)
-		snd_soc_update_bits(codec, TOMTOM_A_CHIP_CTL, 0x06, 0x0);
-	else if (wcd9xxx->mclk_rate == TOMTOM_MCLK_CLK_9P6MHZ)
-		snd_soc_update_bits(codec, TOMTOM_A_CHIP_CTL, 0x06, 0x2);
-	tomtom_codec_init_reg(codec);
-
-	snd_soc_cache_sync(codec);
-
-	ret = tomtom_handle_pdata(tomtom);
-	if (ret < 0)
-		pr_err("%s: bad pdata\n", __func__);
-
-	tomtom_init_slim_slave_cfg(codec);
-	tomtom_slim_interface_init_reg(codec);
-	wcd_cpe_ssr_event(tomtom->cpe_core, WCD_CPE_BUS_UP_EVENT);
-	wcd9xxx_resmgr_post_ssr(&tomtom->resmgr);
-
-	if (tomtom->mbhc_started) {
-		wcd9xxx_mbhc_deinit(&tomtom->mbhc);
-		tomtom->mbhc_started = false;
-
-		if (wcd9xxx->mclk_rate == TOMTOM_MCLK_CLK_12P288MHZ)
-			rco_clk_rate = TOMTOM_MCLK_CLK_12P288MHZ;
-		else
-			rco_clk_rate = TOMTOM_MCLK_CLK_9P6MHZ;
-
-		ret = wcd9xxx_mbhc_init(&tomtom->mbhc, &tomtom->resmgr, codec,
-					tomtom_enable_mbhc_micbias,
-					&mbhc_cb, &cdc_intr_ids,
-					rco_clk_rate, TOMTOM_ZDET_SUPPORTED);
-		if (ret)
-			pr_err("%s: mbhc init failed %d\n", __func__, ret);
-		else
-			tomtom_hs_detect(codec, tomtom->mbhc.mbhc_cfg);
-	}
-
-	if (tomtom->machine_codec_event_cb)
-		tomtom->machine_codec_event_cb(codec,
-				       WCD9XXX_CODEC_EVENT_CODEC_UP);
-
-	tomtom_cleanup_irqs(tomtom);
-	ret = tomtom_setup_irqs(tomtom);
-	if (ret)
-		pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
-
-	/*
-	 * After SSR, the qfuse sensing is lost.
-	 * Perform qfuse sensing again after SSR
-	 * handling is finished.
-	 */
-	tomtom_enable_qfuse_sensing(codec);
-	mutex_unlock(&tomtom->codec_mutex);
-	return ret;
-}
-
-void *tomtom_get_afe_config(struct snd_soc_codec *codec,
-			   enum afe_config_type config_type)
-{
-	struct tomtom_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 &tomtom_audio_reg_cfg;
-	case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
-		return &tomtom_slimbus_slave_port_cfg;
-	case AFE_AANC_VERSION:
-		return &tomtom_cdc_aanc_version;
-	case AFE_CLIP_BANK_SEL:
-		return &clip_bank_sel;
-	case AFE_CDC_CLIP_REGISTERS_CONFIG:
-		return &tomtom_clip_reg_cfg;
-	default:
-		pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
-		return NULL;
-	}
-}
-
-static struct wcd9xxx_reg_address tomtom_reg_address = {
-	.micb_4_mbhc = TOMTOM_A_MICB_4_MBHC,
-	.micb_4_int_rbias = TOMTOM_A_MICB_4_INT_RBIAS,
-	.micb_4_ctl = TOMTOM_A_MICB_4_CTL,
-};
-
-static int wcd9xxx_ssr_register(struct wcd9xxx *control,
-				int (*device_down_cb)(struct wcd9xxx *wcd9xxx),
-				int (*device_up_cb)(struct wcd9xxx *wcd9xxx),
-				void *priv)
-{
-	control->dev_down = device_down_cb;
-	control->post_reset = device_up_cb;
-	control->ssr_priv = priv;
-	return 0;
-}
-
-static const struct snd_soc_dapm_widget tomtom_1_dapm_widgets[] = {
-	SND_SOC_DAPM_ADC_E("ADC1", NULL, TOMTOM_A_TX_1_GAIN, 7, 0,
-			   tomtom_codec_enable_adc,
-			   SND_SOC_DAPM_PRE_PMU |
-			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC2", NULL, TOMTOM_A_TX_2_GAIN, 7, 0,
-			   tomtom_codec_enable_adc,
-			   SND_SOC_DAPM_PRE_PMU |
-			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC3", NULL, TOMTOM_A_TX_3_GAIN, 7, 0,
-			   tomtom_codec_enable_adc,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			   SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC4", NULL, TOMTOM_A_TX_4_GAIN, 7, 0,
-			   tomtom_codec_enable_adc,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			   SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC5", NULL, TOMTOM_A_TX_5_GAIN, 7, 0,
-			   tomtom_codec_enable_adc,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			   SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC6", NULL, TOMTOM_A_TX_6_GAIN, 7, 0,
-			   tomtom_codec_enable_adc,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-			   SND_SOC_DAPM_POST_PMD),
-};
-
-static struct regulator *tomtom_codec_find_regulator(struct snd_soc_codec *cdc,
-						    const char *name)
-{
-	int i;
-	struct wcd9xxx *core = dev_get_drvdata(cdc->dev->parent);
-
-	for (i = 0; i < core->num_of_supplies; i++) {
-		if (core->supplies[i].supply &&
-		    !strcmp(core->supplies[i].supply, name))
-			return core->supplies[i].consumer;
-	}
-
-	return NULL;
-}
-
-static struct wcd_cpe_core *tomtom_codec_get_cpe_core(
-		struct snd_soc_codec *codec)
-{
-	struct tomtom_priv *priv = snd_soc_codec_get_drvdata(codec);
-
-	return priv->cpe_core;
-}
-
-static int tomtom_codec_fll_enable(struct snd_soc_codec *codec,
-				   bool enable)
-{
-	struct wcd9xxx *wcd9xxx;
-
-	if (!codec || !codec->control_data) {
-		pr_err("%s: Invalid codec handle, %pK\n",
-		       __func__, codec);
-		return -EINVAL;
-	}
-
-	wcd9xxx = codec->control_data;
-
-	dev_dbg(codec->dev, "%s: %s, mclk_rate = %d\n",
-		__func__, (enable ? "enable" : "disable"),
-		wcd9xxx->mclk_rate);
-
-	switch (wcd9xxx->mclk_rate) {
-	case TOMTOM_MCLK_CLK_9P6MHZ:
-		snd_soc_update_bits(codec, TOMTOM_A_FLL_NREF,
-				    0x1F, 0x15);
-		snd_soc_update_bits(codec, TOMTOM_A_FLL_KDCO_TUNE,
-				    0x07, 0x06);
-		snd_soc_write(codec, TOMTOM_A_FLL_LOCK_THRESH, 0xD1);
-		snd_soc_write(codec, TOMTOM_A_FLL_LOCK_DET_COUNT,
-			      0x40);
-		break;
-	case TOMTOM_MCLK_CLK_12P288MHZ:
-		snd_soc_update_bits(codec, TOMTOM_A_FLL_NREF,
-				    0x1F, 0x11);
-		snd_soc_update_bits(codec, TOMTOM_A_FLL_KDCO_TUNE,
-				    0x07, 0x05);
-		snd_soc_write(codec, TOMTOM_A_FLL_LOCK_THRESH, 0xB1);
-		snd_soc_write(codec, TOMTOM_A_FLL_LOCK_DET_COUNT,
-			      0x40);
-		break;
-	}
-
-	return 0;
-}
-
-static int tomtom_codec_slim_reserve_bw(struct snd_soc_codec *codec,
-		u32 bw_ops, bool commit)
-{
-	struct wcd9xxx *wcd9xxx;
-
-	if (!codec) {
-		pr_err("%s: Invalid handle to codec\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	wcd9xxx = dev_get_drvdata(codec->dev->parent);
-
-	if (!wcd9xxx) {
-		dev_err(codec->dev, "%s: Invalid parent drv_data\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	return wcd9xxx_slim_reserve_bw(wcd9xxx, bw_ops, commit);
-}
-
-static int tomtom_codec_vote_max_bw(struct snd_soc_codec *codec,
-			bool vote)
-{
-	u32 bw_ops;
-
-	if (vote)
-		bw_ops = SLIM_BW_CLK_GEAR_9;
-	else
-		bw_ops = SLIM_BW_UNVOTE;
-
-	return tomtom_codec_slim_reserve_bw(codec,
-			bw_ops, true);
-}
-
-static const struct wcd9xxx_resmgr_cb resmgr_cb = {
-	.cdc_rco_ctrl = tomtom_codec_internal_rco_ctrl,
-};
-
-static int tomtom_cpe_err_irq_control(struct snd_soc_codec *codec,
-	enum cpe_err_irq_cntl_type cntl_type, u8 *status)
-{
-	switch (cntl_type) {
-	case CPE_ERR_IRQ_MASK:
-		snd_soc_update_bits(codec,
-				    TOMTOM_A_SVASS_INT_MASK,
-				    0x3F, 0x3F);
-		break;
-	case CPE_ERR_IRQ_UNMASK:
-		snd_soc_update_bits(codec,
-				    TOMTOM_A_SVASS_INT_MASK,
-				    0x3F, 0x0C);
-		break;
-	case CPE_ERR_IRQ_CLEAR:
-		snd_soc_update_bits(codec,
-				    TOMTOM_A_SVASS_INT_CLR,
-				    0x3F, 0x3F);
-		break;
-	case CPE_ERR_IRQ_STATUS:
-		if (!status)
-			return -EINVAL;
-		*status = snd_soc_read(codec,
-				       TOMTOM_A_SVASS_INT_STATUS);
-		break;
-	}
-
-	return 0;
-}
-
-static const struct wcd_cpe_cdc_cb cpe_cb = {
-	.cdc_clk_en = tomtom_codec_internal_rco_ctrl,
-	.cpe_clk_en = tomtom_codec_fll_enable,
-	.lab_cdc_ch_ctl = tomtom_codec_enable_slimtx_mad,
-	.cdc_ext_clk = tomtom_codec_ext_clk_en,
-	.bus_vote_bw = tomtom_codec_vote_max_bw,
-	.cpe_err_irq_control = tomtom_cpe_err_irq_control,
-};
-
-static struct cpe_svc_init_param cpe_svc_params = {
-	.version = 0,
-	.query_freq_plans_cb = NULL,
-	.change_freq_plan_cb = NULL,
-};
-
-static int tomtom_cpe_initialize(struct snd_soc_codec *codec)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	struct wcd_cpe_params cpe_params;
-
-	memset(&cpe_params, 0,
-	       sizeof(struct wcd_cpe_params));
-	cpe_params.codec = codec;
-	cpe_params.get_cpe_core = tomtom_codec_get_cpe_core;
-	cpe_params.cdc_cb = &cpe_cb;
-	cpe_params.dbg_mode = cpe_debug_mode;
-	cpe_params.cdc_major_ver = CPE_SVC_CODEC_TOMTOM;
-	cpe_params.cdc_minor_ver = CPE_SVC_CODEC_V1P0;
-	cpe_params.cdc_id = CPE_SVC_CODEC_TOMTOM;
-
-	cpe_params.cdc_irq_info.cpe_engine_irq =
-			WCD9330_IRQ_SVASS_ENGINE;
-	cpe_params.cdc_irq_info.cpe_err_irq =
-			WCD9330_IRQ_SVASS_ERR_EXCEPTION;
-	cpe_params.cdc_irq_info.cpe_fatal_irqs =
-			TOMTOM_CPE_FATAL_IRQS;
-
-	cpe_svc_params.context = codec;
-	cpe_params.cpe_svc_params = &cpe_svc_params;
-
-	tomtom->cpe_core = wcd_cpe_init("cpe", codec,
-					&cpe_params);
-	if (IS_ERR_OR_NULL(tomtom->cpe_core)) {
-		dev_err(codec->dev,
-			"%s: Failed to enable CPE\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int tomtom_codec_probe(struct snd_soc_codec *codec)
-{
-	struct wcd9xxx *control;
-	struct tomtom_priv *tomtom;
-	struct wcd9xxx_pdata *pdata;
-	struct wcd9xxx *wcd9xxx;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	int ret = 0;
-	int i, rco_clk_rate;
-	void *ptr = NULL;
-	struct wcd9xxx_core_resource *core_res;
-	struct clk *wcd_ext_clk = NULL;
-
-	dev_info(codec->dev, "%s()\n", __func__);
-
-	control = dev_get_drvdata(codec->dev->parent);
-
-	tomtom = snd_soc_codec_get_drvdata(codec);
-
-	wcd9xxx_ssr_register(control, tomtom_device_down,
-			     tomtom_post_reset_cb, (void *)codec);
-
-	for (i = 0; i < NUM_DECIMATORS; i++) {
-		tx_hpf_work[i].tomtom = tomtom;
-		tx_hpf_work[i].decimator = i + 1;
-		tx_hpf_work[i].tx_hpf_bypass = false;
-		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
-			tx_hpf_corner_freq_callback);
-	}
-
-	wcd9xxx = control;
-	if (!of_find_property(wcd9xxx->dev->of_node, "clock-names", NULL)) {
-		dev_dbg(wcd9xxx->dev, "%s: codec not using audio-ext-clk driver\n",
-			__func__);
-	} else {
-		wcd_ext_clk = clk_get(wcd9xxx->dev, "wcd_clk");
-		if (IS_ERR(wcd_ext_clk)) {
-			dev_err(codec->dev, "%s: clk get %s failed\n",
-					__func__, "wcd_ext_clk");
-			goto err_nomem_slimch;
-		}
-	}
-	tomtom->wcd_ext_clk = wcd_ext_clk;
-	core_res = &wcd9xxx->core_res;
-	pdata = dev_get_platdata(codec->dev->parent);
-	/* codec resmgr module init */
-	ret = wcd9xxx_resmgr_init(&tomtom->resmgr, codec, core_res, pdata,
-				  &pdata->micbias, &tomtom_reg_address,
-				  &resmgr_cb, WCD9XXX_CDC_TYPE_TOMTOM);
-	if (ret) {
-		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
-		goto err_nomem_slimch;
-	}
-
-	tomtom->clsh_d.buck_mv = tomtom_codec_get_buck_mv(codec);
-	/* TomTom does not support dynamic switching of vdd_cp */
-	tomtom->clsh_d.is_dynamic_vdd_cp = false;
-	wcd9xxx_clsh_init(&tomtom->clsh_d, &tomtom->resmgr);
-
-	if (wcd9xxx->mclk_rate == TOMTOM_MCLK_CLK_12P288MHZ)
-		rco_clk_rate = TOMTOM_MCLK_CLK_12P288MHZ;
-	else
-		rco_clk_rate = TOMTOM_MCLK_CLK_9P6MHZ;
-
-	tomtom->fw_data = kzalloc(sizeof(*(tomtom->fw_data)), GFP_KERNEL);
-	if (!tomtom->fw_data)
-		goto err_nomem_slimch;
-	set_bit(WCD9XXX_ANC_CAL, tomtom->fw_data->cal_bit);
-	set_bit(WCD9XXX_MAD_CAL, tomtom->fw_data->cal_bit);
-	set_bit(WCD9XXX_MBHC_CAL, tomtom->fw_data->cal_bit);
-	ret = wcd_cal_create_hwdep(tomtom->fw_data,
-				WCD9XXX_CODEC_HWDEP_NODE, codec);
-	if (ret < 0) {
-		dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
-		goto err_hwdep;
-	}
-
-	/* init and start mbhc */
-	ret = wcd9xxx_mbhc_init(&tomtom->mbhc, &tomtom->resmgr, codec,
-				tomtom_enable_mbhc_micbias,
-				&mbhc_cb, &cdc_intr_ids,
-				rco_clk_rate, TOMTOM_ZDET_SUPPORTED);
-	if (ret) {
-		pr_err("%s: mbhc init failed %d\n", __func__, ret);
-		goto err_hwdep;
-	}
-
-	tomtom->codec = codec;
-	for (i = 0; i < COMPANDER_MAX; i++) {
-		tomtom->comp_enabled[i] = 0;
-		tomtom->comp_fs[i] = COMPANDER_FS_48KHZ;
-	}
-	tomtom->intf_type = wcd9xxx_get_intf_type();
-	tomtom->aux_pga_cnt = 0;
-	tomtom->aux_l_gain = 0x1F;
-	tomtom->aux_r_gain = 0x1F;
-	tomtom->ldo_h_users = 0;
-	tomtom->micb_2_users = 0;
-	tomtom_update_reg_defaults(codec);
-	pr_debug("%s: MCLK Rate = %x\n", __func__, wcd9xxx->mclk_rate);
-	if (wcd9xxx->mclk_rate == TOMTOM_MCLK_CLK_12P288MHZ)
-		snd_soc_update_bits(codec, TOMTOM_A_CHIP_CTL, 0x06, 0x0);
-	else if (wcd9xxx->mclk_rate == TOMTOM_MCLK_CLK_9P6MHZ)
-		snd_soc_update_bits(codec, TOMTOM_A_CHIP_CTL, 0x06, 0x2);
-	tomtom_codec_init_reg(codec);
-
-	ret = tomtom_handle_pdata(tomtom);
-	if (ret < 0) {
-		pr_err("%s: bad pdata\n", __func__);
-		goto err_hwdep;
-	}
-
-	tomtom->spkdrv_reg = tomtom_codec_find_regulator(codec,
-					       WCD9XXX_VDD_SPKDRV_NAME);
-	tomtom->spkdrv2_reg = tomtom_codec_find_regulator(codec,
-					       WCD9XXX_VDD_SPKDRV2_NAME);
-
-	ptr = kmalloc((sizeof(tomtom_rx_chs) +
-		       sizeof(tomtom_tx_chs)), GFP_KERNEL);
-	if (!ptr) {
-		ret = -ENOMEM;
-		goto err_hwdep;
-	}
-
-	if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
-		snd_soc_dapm_new_controls(dapm, tomtom_dapm_i2s_widgets,
-			ARRAY_SIZE(tomtom_dapm_i2s_widgets));
-		snd_soc_dapm_add_routes(dapm, audio_i2s_map,
-			ARRAY_SIZE(audio_i2s_map));
-		for (i = 0; i < ARRAY_SIZE(tomtom_i2s_dai); i++)
-			INIT_LIST_HEAD(&tomtom->dai[i].wcd9xxx_ch_list);
-	} else if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
-		for (i = 0; i < NUM_CODEC_DAIS; i++) {
-			INIT_LIST_HEAD(&tomtom->dai[i].wcd9xxx_ch_list);
-			init_waitqueue_head(&tomtom->dai[i].dai_wait);
-		}
-		tomtom_slimbus_slave_port_cfg.slave_dev_intfdev_la =
-		    control->slim_slave->laddr;
-		tomtom_slimbus_slave_port_cfg.slave_dev_pgd_la =
-		    control->slim->laddr;
-		tomtom_slimbus_slave_port_cfg.slave_port_mapping[0] =
-		    TOMTOM_MAD_SLIMBUS_TX_PORT;
-
-		tomtom_init_slim_slave_cfg(codec);
-	}
-
-	snd_soc_dapm_new_controls(dapm, tomtom_1_dapm_widgets,
-			ARRAY_SIZE(tomtom_1_dapm_widgets));
-	snd_soc_add_codec_controls(codec,
-			tomtom_1_x_analog_gain_controls,
-			ARRAY_SIZE(tomtom_1_x_analog_gain_controls));
-
-	snd_soc_add_codec_controls(codec, impedance_detect_controls,
-				   ARRAY_SIZE(impedance_detect_controls));
-	snd_soc_add_codec_controls(codec, hph_type_detect_controls,
-				   ARRAY_SIZE(hph_type_detect_controls));
-
-	control->num_rx_port = TOMTOM_RX_MAX;
-	control->rx_chs = ptr;
-	memcpy(control->rx_chs, tomtom_rx_chs, sizeof(tomtom_rx_chs));
-	control->num_tx_port = TOMTOM_TX_MAX;
-	control->tx_chs = ptr + sizeof(tomtom_rx_chs);
-	memcpy(control->tx_chs, tomtom_tx_chs, sizeof(tomtom_tx_chs));
-
-	snd_soc_dapm_sync(dapm);
-
-	ret = tomtom_setup_irqs(tomtom);
-	if (ret) {
-		pr_err("%s: tomtom irq setup failed %d\n", __func__, ret);
-		goto err_pdata;
-	}
-
-	atomic_set(&kp_tomtom_priv, (unsigned long)tomtom);
-	mutex_lock(&tomtom->codec_mutex);
-	snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
-	snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
-	snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
-	snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
-	snd_soc_dapm_disable_pin(dapm, "ANC EAR");
-	mutex_unlock(&tomtom->codec_mutex);
-	snd_soc_dapm_sync(dapm);
-
-	codec->component.ignore_pmdown_time = 1;
-	ret = tomtom_cpe_initialize(codec);
-	if (ret) {
-		dev_info(codec->dev,
-			"%s: cpe initialization failed, ret = %d\n",
-			__func__, ret);
-		/* Do not fail probe if CPE failed */
-		ret = 0;
-	}
-	return ret;
-
-err_pdata:
-	kfree(ptr);
-	control->rx_chs = NULL;
-	control->tx_chs = NULL;
-err_hwdep:
-	kfree(tomtom->fw_data);
-	tomtom->fw_data = NULL;
-err_nomem_slimch:
-	devm_kfree(codec->dev, tomtom);
-	return ret;
-}
-static int tomtom_codec_remove(struct snd_soc_codec *codec)
-{
-	struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
-	struct wcd9xxx *control;
-
-	WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr);
-	atomic_set(&kp_tomtom_priv, 0);
-
-	WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr);
-
-	control = dev_get_drvdata(codec->dev->parent);
-	control->rx_chs = NULL;
-	control->tx_chs = NULL;
-
-	if (tomtom->wcd_ext_clk)
-		clk_put(tomtom->wcd_ext_clk);
-	tomtom_cleanup_irqs(tomtom);
-
-	/* cleanup MBHC */
-	wcd9xxx_mbhc_deinit(&tomtom->mbhc);
-	/* cleanup resmgr */
-	wcd9xxx_resmgr_deinit(&tomtom->resmgr);
-
-	tomtom->spkdrv_reg = NULL;
-	tomtom->spkdrv2_reg = NULL;
-
-	devm_kfree(codec->dev, tomtom);
-	return 0;
-}
-
-static struct regmap *tomtom_get_regmap(struct device *dev)
-{
-	struct wcd9xxx *control = dev_get_drvdata(dev->parent);
-
-	return control->regmap;
-}
-
-static struct snd_soc_codec_driver soc_codec_dev_tomtom = {
-	.probe = tomtom_codec_probe,
-	.remove = tomtom_codec_remove,
-	.get_regmap = tomtom_get_regmap,
-	.component_driver = {
-		.controls = tomtom_snd_controls,
-		.num_controls = ARRAY_SIZE(tomtom_snd_controls),
-		.dapm_widgets = tomtom_dapm_widgets,
-		.num_dapm_widgets = ARRAY_SIZE(tomtom_dapm_widgets),
-		.dapm_routes = audio_map,
-		.num_dapm_routes = ARRAY_SIZE(audio_map),
-	},
-};
-
-#ifdef CONFIG_PM
-static int tomtom_suspend(struct device *dev)
-{
-	dev_dbg(dev, "%s: system suspend\n", __func__);
-	return 0;
-}
-
-static int tomtom_resume(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct tomtom_priv *tomtom = platform_get_drvdata(pdev);
-
-	if (!tomtom) {
-		dev_err(dev, "%s: tomtom private data is NULL\n", __func__);
-		return -EINVAL;
-	}
-	dev_dbg(dev, "%s: system resume\n", __func__);
-	/* Notify */
-	wcd9xxx_resmgr_notifier_call(&tomtom->resmgr,
-				     WCD9XXX_EVENT_POST_RESUME);
-	return 0;
-}
-
-static const struct dev_pm_ops tomtom_pm_ops = {
-	.suspend	= tomtom_suspend,
-	.resume		= tomtom_resume,
-};
-#endif
-
-static int tomtom_probe(struct platform_device *pdev)
-{
-	int ret = 0;
-	struct tomtom_priv *tomtom;
-
-	tomtom = devm_kzalloc(&pdev->dev, sizeof(struct tomtom_priv),
-			      GFP_KERNEL);
-	if (!tomtom)
-		return -ENOMEM;
-
-	platform_set_drvdata(pdev, tomtom);
-
-	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
-		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tomtom,
-			tomtom_dai, ARRAY_SIZE(tomtom_dai));
-	else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tomtom,
-			tomtom_i2s_dai, ARRAY_SIZE(tomtom_i2s_dai));
-	mutex_init(&tomtom->codec_mutex);
-	return ret;
-}
-static int tomtom_remove(struct platform_device *pdev)
-{
-	struct tomtom_priv *tomtom = platform_get_drvdata(pdev);
-
-	mutex_destroy(&tomtom->codec_mutex);
-	snd_soc_unregister_codec(&pdev->dev);
-	return 0;
-}
-static struct platform_driver tomtom_codec_driver = {
-	.probe = tomtom_probe,
-	.remove = tomtom_remove,
-	.driver = {
-		.name = "tomtom_codec",
-		.owner = THIS_MODULE,
-#ifdef CONFIG_PM
-		.pm = &tomtom_pm_ops,
-#endif
-	},
-};
-
-static int __init tomtom_codec_init(void)
-{
-	return platform_driver_register(&tomtom_codec_driver);
-}
-
-static void __exit tomtom_codec_exit(void)
-{
-	platform_driver_unregister(&tomtom_codec_driver);
-}
-
-module_init(tomtom_codec_init);
-module_exit(tomtom_codec_exit);
-
-MODULE_DESCRIPTION("TomTom codec driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9330.h b/sound/soc/codecs/wcd9330.h
deleted file mode 100644
index 8679d01..0000000
--- a/sound/soc/codecs/wcd9330.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef WCD9330_H
-#define WCD9330_H
-
-#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"
-#include "wcd9xxx-common.h"
-
-#define TOMTOM_NUM_REGISTERS 0x400
-#define TOMTOM_MAX_REGISTER (TOMTOM_NUM_REGISTERS-1)
-#define TOMTOM_CACHE_SIZE TOMTOM_NUM_REGISTERS
-
-#define TOMTOM_REG_VAL(reg, val)		{reg, 0, val}
-#define TOMTOM_MCLK_ID 0
-
-#define TOMTOM_REGISTER_START_OFFSET 0x800
-#define TOMTOM_SB_PGD_PORT_RX_BASE   0x40
-#define TOMTOM_SB_PGD_PORT_TX_BASE   0x50
-
-#define WCD9330_DMIC_CLK_DIV_2 0x00
-#define WCD9330_DMIC_CLK_DIV_3 0x01
-#define WCD9330_DMIC_CLK_DIV_4 0x02
-#define WCD9330_DMIC_CLK_DIV_6 0x03
-#define WCD9330_DMIC_CLK_DIV_16 0x04
-
-#define TOMTOM_ZDET_SUPPORTED true
-
-extern const u8 tomtom_reset_reg_defaults[TOMTOM_CACHE_SIZE];
-struct tomtom_codec_dai_data {
-	u32 rate;
-	u32 *ch_num;
-	u32 ch_act;
-	u32 ch_tot;
-};
-
-enum tomtom_pid_current {
-	TOMTOM_PID_MIC_2P5_UA,
-	TOMTOM_PID_MIC_5_UA,
-	TOMTOM_PID_MIC_10_UA,
-	TOMTOM_PID_MIC_20_UA,
-};
-
-enum tomtom_mbhc_analog_pwr_cfg {
-	TOMTOM_ANALOG_PWR_COLLAPSED = 0,
-	TOMTOM_ANALOG_PWR_ON,
-	TOMTOM_NUM_ANALOG_PWR_CONFIGS,
-};
-
-enum {
-	HPH_PA_NONE = 0,
-	HPH_PA_R,
-	HPH_PA_L,
-	HPH_PA_L_R,
-};
-
-/* Number of input and output Slimbus port */
-enum {
-	TOMTOM_RX1 = 0,
-	TOMTOM_RX2,
-	TOMTOM_RX3,
-	TOMTOM_RX4,
-	TOMTOM_RX5,
-	TOMTOM_RX6,
-	TOMTOM_RX7,
-	TOMTOM_RX8,
-	TOMTOM_RX9,
-	TOMTOM_RX10,
-	TOMTOM_RX11,
-	TOMTOM_RX12,
-	TOMTOM_RX13,
-	TOMTOM_RX_MAX,
-};
-
-enum {
-	TOMTOM_TX1 = 0,
-	TOMTOM_TX2,
-	TOMTOM_TX3,
-	TOMTOM_TX4,
-	TOMTOM_TX5,
-	TOMTOM_TX6,
-	TOMTOM_TX7,
-	TOMTOM_TX8,
-	TOMTOM_TX9,
-	TOMTOM_TX10,
-	TOMTOM_TX11,
-	TOMTOM_TX12,
-	TOMTOM_TX13,
-	TOMTOM_TX14,
-	TOMTOM_TX15,
-	TOMTOM_TX16,
-	TOMTOM_TX_MAX,
-};
-
-extern int tomtom_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
-			     bool dapm);
-extern int tomtom_codec_mclk_enable(struct snd_soc_codec *codec,
-				    int mclk_enable, bool dapm);
-extern int tomtom_hs_detect(struct snd_soc_codec *codec,
-			   struct wcd9xxx_mbhc_config *mbhc_cfg);
-extern void tomtom_hs_detect_exit(struct snd_soc_codec *codec);
-extern void *tomtom_get_afe_config(struct snd_soc_codec *codec,
-				  enum afe_config_type config_type);
-
-extern void tomtom_event_register(
-	int (*machine_event_cb)(struct snd_soc_codec *codec,
-				enum wcd9xxx_codec_event),
-	struct snd_soc_codec *codec);
-extern void tomtom_register_ext_clk_cb(
-	int (*codec_ext_clk_en)(struct snd_soc_codec *codec,
-				int enable, bool dapm),
-	int (*get_ext_clk_cnt)(void),
-	struct snd_soc_codec *codec);
-extern int tomtom_enable_qfuse_sensing(struct snd_soc_codec *codec);
-#endif
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index eb556f8..329aa7a 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -26,6 +26,7 @@
 #include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9335/registers.h>
+#include <linux/mfd/wcd9335/irq.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
 #include <linux/regulator/consumer.h>
 #include <linux/clk.h>
@@ -188,7 +189,7 @@
 MODULE_PARM_DESC(sido_buck_svs_voltage,
 			"setting for SVS voltage for SIDO BUCK");
 
-#define TASHA_TX_UNMUTE_DELAY_MS	25
+#define TASHA_TX_UNMUTE_DELAY_MS	40
 
 static int tx_unmute_delay = TASHA_TX_UNMUTE_DELAY_MS;
 module_param(tx_unmute_delay, int, 0664);
@@ -546,38 +547,6 @@
 	SPLINE_SRC_MAX,
 };
 
-/* wcd9335 interrupt table  */
-static const struct intr_data wcd9335_intr_table[] = {
-	{WCD9XXX_IRQ_SLIMBUS, false},
-	{WCD9335_IRQ_MBHC_SW_DET, true},
-	{WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, true},
-	{WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, true},
-	{WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, true},
-	{WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
-	{WCD9335_IRQ_FLL_LOCK_LOSS, false},
-	{WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, false},
-	{WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, false},
-	{WCD9335_IRQ_EAR_PA_CNP_COMPLETE, false},
-	{WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, false},
-	{WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, false},
-	{WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, false},
-	{WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, false},
-	{WCD9335_IRQ_HPH_PA_OCPL_FAULT, false},
-	{WCD9335_IRQ_HPH_PA_OCPR_FAULT, false},
-	{WCD9335_IRQ_EAR_PA_OCP_FAULT, false},
-	{WCD9335_IRQ_SOUNDWIRE, false},
-	{WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, false},
-	{WCD9335_IRQ_RCO_ERROR, false},
-	{WCD9335_IRQ_SVA_ERROR, false},
-	{WCD9335_IRQ_MAD_AUDIO, false},
-	{WCD9335_IRQ_MAD_BEACON, false},
-	{WCD9335_IRQ_SVA_OUTBOX1, true},
-	{WCD9335_IRQ_SVA_OUTBOX2, true},
-	{WCD9335_IRQ_MAD_ULTRASOUND, false},
-	{WCD9335_IRQ_VBAT_ATTACK, false},
-	{WCD9335_IRQ_VBAT_RESTORE, false},
-};
-
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -875,176 +844,6 @@
 	{WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44},
 };
 
-/*
- * wcd9335_get_codec_info: Get codec specific information
- *
- * @wcd9xxx: pointer to wcd9xxx structure
- * @wcd_type: pointer to wcd9xxx_codec_type structure
- *
- * Returns 0 for success or negative error code for failure
- */
-int wcd9335_get_codec_info(struct wcd9xxx *wcd9xxx,
-			   struct wcd9xxx_codec_type *wcd_type)
-{
-	u16 id_minor, id_major;
-	struct regmap *wcd_regmap;
-	int rc, val, version = 0;
-
-	if (!wcd9xxx || !wcd_type)
-		return -EINVAL;
-
-	if (!wcd9xxx->regmap) {
-		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
-			__func__);
-		return -EINVAL;
-	}
-	wcd_regmap = wcd9xxx->regmap;
-
-	rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
-			(u8 *)&id_minor, sizeof(u16));
-	if (rc)
-		return -EINVAL;
-
-	rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
-			      (u8 *)&id_major, sizeof(u16));
-	if (rc)
-		return -EINVAL;
-
-	dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
-		 __func__, id_major, id_minor);
-
-	/* Version detection */
-	if (id_major == TASHA_MAJOR) {
-		regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0,
-			    &val);
-		version = ((u8)val & 0x80) >> 7;
-	} else if (id_major == TASHA2P0_MAJOR)
-		version = 2;
-	else
-		dev_err(wcd9xxx->dev, "%s: wcd9335 version unknown (major 0x%x, minor 0x%x)\n",
-			__func__, id_major, id_minor);
-
-	/* Fill codec type info */
-	wcd_type->id_major = id_major;
-	wcd_type->id_minor = id_minor;
-	wcd_type->num_irqs = WCD9335_NUM_IRQS;
-	wcd_type->version = version;
-	wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
-	wcd_type->i2c_chip_status = 0x01;
-	wcd_type->intr_tbl = wcd9335_intr_table;
-	wcd_type->intr_tbl_size = ARRAY_SIZE(wcd9335_intr_table);
-
-	wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
-						WCD9335_INTR_PIN1_STATUS0;
-	wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
-						WCD9335_INTR_PIN1_CLEAR0;
-	wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
-						WCD9335_INTR_PIN1_MASK0;
-	wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
-						WCD9335_INTR_LEVEL0;
-	wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
-						WCD9335_INTR_CLR_COMMIT;
-
-	return rc;
-}
-EXPORT_SYMBOL(wcd9335_get_codec_info);
-
-/*
- * wcd9335_bringdown: Bringdown WCD Codec
- *
- * @wcd9xxx: Pointer to wcd9xxx structure
- *
- * Returns 0 for success or negative error code for failure
- */
-int wcd9335_bringdown(struct wcd9xxx *wcd9xxx)
-{
-	if (!wcd9xxx || !wcd9xxx->regmap)
-		return -EINVAL;
-
-	regmap_write(wcd9xxx->regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-		     0x04);
-
-	return 0;
-}
-EXPORT_SYMBOL(wcd9335_bringdown);
-
-/*
- * wcd9335_bringup: Bringup WCD Codec
- *
- * @wcd9xxx: Pointer to the wcd9xxx structure
- *
- * Returns 0 for success or negative error code for failure
- */
-int wcd9335_bringup(struct wcd9xxx *wcd9xxx)
-{
-	int ret = 0;
-	int val, byte0;
-	struct regmap *wcd_regmap;
-
-	if (!wcd9xxx)
-		return -EINVAL;
-
-	if (!wcd9xxx->regmap) {
-		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
-			__func__);
-		return -EINVAL;
-	}
-	wcd_regmap = wcd9xxx->regmap;
-
-	regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val);
-	regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0);
-
-	if ((val < 0) || (byte0 < 0)) {
-		dev_err(wcd9xxx->dev, "%s: tasha codec version detection fail!\n",
-			__func__);
-		return -EINVAL;
-	}
-	if ((val & 0x80) && (byte0 == 0x0)) {
-		dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.1\n",
-			 __func__);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
-		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
-		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			     0x5);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			     0x7);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			     0x3);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
-	} else if (byte0 == 0x1) {
-		dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v2.0\n",
-			 __func__);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
-		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_TEST_2, 0x00);
-		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
-		regmap_write(wcd_regmap, WCD9335_BIAS_VBG_FINE_ADJ, 0x65);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			     0x5);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			     0x7);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			     0x3);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
-	} else if ((byte0 == 0) && (!(val & 0x80))) {
-		dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.0\n",
-			 __func__);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
-		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
-		regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-			     0x3);
-		regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
-	} else {
-		dev_err(wcd9xxx->dev, "%s: tasha codec version unknown\n",
-			__func__);
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL(wcd9335_bringup);
-
 /**
  * tasha_set_spkr_gain_offset - offset the speaker path
  * gain with the given offset value.
@@ -4941,7 +4740,7 @@
 					 int src_num,
 					 int event)
 {
-	u16 src_paired_reg;
+	u16 src_paired_reg = 0;
 	struct tasha_priv *tasha;
 	u16 rx_path_cfg_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
 	u16 rx_path_ctl_reg = WCD9335_CDC_RX1_RX_PATH_CTL;
diff --git a/sound/soc/codecs/wcd9335.h b/sound/soc/codecs/wcd9335.h
index d27bb96..c76461e 100644
--- a/sound/soc/codecs/wcd9335.h
+++ b/sound/soc/codecs/wcd9335.h
@@ -83,44 +83,6 @@
 	TASHA_TX_MAX,
 };
 
-enum {
-	/* INTR_REG 0 */
-	WCD9335_IRQ_FLL_LOCK_LOSS = 1,
-	WCD9335_IRQ_HPH_PA_OCPL_FAULT,
-	WCD9335_IRQ_HPH_PA_OCPR_FAULT,
-	WCD9335_IRQ_EAR_PA_OCP_FAULT,
-	WCD9335_IRQ_HPH_PA_CNPL_COMPLETE,
-	WCD9335_IRQ_HPH_PA_CNPR_COMPLETE,
-	WCD9335_IRQ_EAR_PA_CNP_COMPLETE,
-	/* INTR_REG 1 */
-	WCD9335_IRQ_MBHC_SW_DET,
-	WCD9335_IRQ_MBHC_ELECT_INS_REM_DET,
-	WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
-	WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
-	WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
-	WCD9335_IRQ_RESERVED_0,
-	WCD9335_IRQ_RESERVED_1,
-	WCD9335_IRQ_RESERVED_2,
-	/* INTR_REG 2 */
-	WCD9335_IRQ_LINE_PA1_CNP_COMPLETE,
-	WCD9335_IRQ_LINE_PA2_CNP_COMPLETE,
-	WCD9335_IRQ_LINE_PA3_CNP_COMPLETE,
-	WCD9335_IRQ_LINE_PA4_CNP_COMPLETE,
-	WCD9335_IRQ_SOUNDWIRE,
-	WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE,
-	WCD9335_IRQ_RCO_ERROR,
-	WCD9335_IRQ_SVA_ERROR,
-	/* INTR_REG 3 */
-	WCD9335_IRQ_MAD_AUDIO,
-	WCD9335_IRQ_MAD_BEACON,
-	WCD9335_IRQ_MAD_ULTRASOUND,
-	WCD9335_IRQ_VBAT_ATTACK,
-	WCD9335_IRQ_VBAT_RESTORE,
-	WCD9335_IRQ_SVA_OUTBOX1,
-	WCD9335_IRQ_SVA_OUTBOX2,
-	WCD9335_NUM_IRQS,
-};
-
 enum wcd9335_codec_event {
 	WCD9335_CODEC_EVENT_CODEC_UP = 0,
 };
diff --git a/sound/soc/codecs/wcd934x/Makefile b/sound/soc/codecs/wcd934x/Makefile
index 2843fa1..12781f6 100644
--- a/sound/soc/codecs/wcd934x/Makefile
+++ b/sound/soc/codecs/wcd934x/Makefile
@@ -1,9 +1,6 @@
 #
 # Makefile for wcd934x codec driver.
 #
-snd-soc-wcd934x-objs := wcd934x.o wcd934x-dsp-cntl.o
+snd-soc-wcd934x-objs := wcd934x.o wcd934x-dsp-cntl.o \
+			wcd934x-mbhc.o wcd934x-dsd.o
 obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o
-snd-soc-wcd934x-mbhc-objs := wcd934x-mbhc.o
-obj-$(CONFIG_SND_SOC_WCD934X_MBHC) += snd-soc-wcd934x-mbhc.o
-snd-soc-wcd934x-dsd-objs := wcd934x-dsd.o
-obj-$(CONFIG_SND_SOC_WCD934X_DSD) += snd-soc-wcd934x-dsd.o
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsd.h b/sound/soc/codecs/wcd934x/wcd934x-dsd.h
index 4982883..834b96c 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsd.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -43,7 +43,7 @@
 	int version;
 };
 
-#ifdef CONFIG_SND_SOC_WCD934X_DSD
+#if IS_ENABLED(CONFIG_SND_SOC_WCD934X_DSD)
 int tavil_dsd_set_mixer_value(struct tavil_dsd_config *dsd_conf,
 			      int interp_num, int sw_value);
 int tavil_dsd_get_current_mixer_value(struct tavil_dsd_config *dsd_conf,
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
index 578c347..a1a5e2d 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
@@ -24,6 +24,7 @@
 #include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd934x/registers.h>
+#include <linux/mfd/wcd934x/irq.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
index d40546a..53c886d 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
@@ -35,7 +35,7 @@
 	bool is_hph_recover;
 };
 
-#ifdef CONFIG_SND_SOC_WCD934X_MBHC
+#if IS_ENABLED(CONFIG_SND_SOC_WCD934X_MBHC)
 extern int tavil_mbhc_init(struct wcd934x_mbhc **mbhc,
 			   struct snd_soc_codec *codec,
 			   struct fw_info *fw_data);
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 3c026e64..ca16ed8 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -31,6 +31,7 @@
 #include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd934x/registers.h>
+#include <linux/mfd/wcd934x/irq.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
 #include <linux/regulator/consumer.h>
 #include <linux/soundwire/swr-wcd.h>
@@ -123,6 +124,7 @@
 #define WCD934X_DEC_PWR_LVL_DF 0x00
 #define WCD934X_STRING_LEN 100
 
+#define WCD934X_CDC_SIDETONE_IIR_COEFF_MAX 5
 #define WCD934X_DIG_CORE_REG_MIN  WCD934X_CDC_ANC0_CLK_RESET_CTL
 #define WCD934X_DIG_CORE_REG_MAX  0xFFF
 
@@ -232,37 +234,6 @@
 	u8 hph_idle_detect_en;
 };
 
-static const struct intr_data wcd934x_intr_table[] = {
-	{WCD9XXX_IRQ_SLIMBUS, false},
-	{WCD934X_IRQ_MBHC_SW_DET, true},
-	{WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, true},
-	{WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, true},
-	{WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, true},
-	{WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
-	{WCD934X_IRQ_MISC, false},
-	{WCD934X_IRQ_HPH_PA_CNPL_COMPLETE, false},
-	{WCD934X_IRQ_HPH_PA_CNPR_COMPLETE, false},
-	{WCD934X_IRQ_EAR_PA_CNP_COMPLETE, false},
-	{WCD934X_IRQ_LINE_PA1_CNP_COMPLETE, false},
-	{WCD934X_IRQ_LINE_PA2_CNP_COMPLETE, false},
-	{WCD934X_IRQ_SLNQ_ANALOG_ERROR, false},
-	{WCD934X_IRQ_RESERVED_3, false},
-	{WCD934X_IRQ_HPH_PA_OCPL_FAULT, false},
-	{WCD934X_IRQ_HPH_PA_OCPR_FAULT, false},
-	{WCD934X_IRQ_EAR_PA_OCP_FAULT, false},
-	{WCD934X_IRQ_SOUNDWIRE, false},
-	{WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE, false},
-	{WCD934X_IRQ_RCO_ERROR, false},
-	{WCD934X_IRQ_CPE_ERROR, false},
-	{WCD934X_IRQ_MAD_AUDIO, false},
-	{WCD934X_IRQ_MAD_BEACON, false},
-	{WCD934X_IRQ_CPE1_INTR, true},
-	{WCD934X_IRQ_RESERVED_4, false},
-	{WCD934X_IRQ_MAD_ULTRASOUND, false},
-	{WCD934X_IRQ_VBAT_ATTACK, false},
-	{WCD934X_IRQ_VBAT_RESTORE, false},
-};
-
 struct tavil_cpr_reg_defaults {
 	int wr_data;
 	int wr_addr;
@@ -505,7 +476,7 @@
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
 
-#define WCD934X_TX_UNMUTE_DELAY_MS 25
+#define WCD934X_TX_UNMUTE_DELAY_MS 40
 
 static int tx_unmute_delay = WCD934X_TX_UNMUTE_DELAY_MS;
 module_param(tx_unmute_delay, int, 0664);
@@ -651,6 +622,8 @@
 	struct tavil_idle_detect_config idle_det_cfg;
 
 	int power_active_ref;
+	int sidetone_coeff_array[IIR_MAX][BAND_MAX]
+		[WCD934X_CDC_SIDETONE_IIR_COEFF_MAX];
 };
 
 static const struct tavil_reg_mask_val tavil_spkr_default[] = {
@@ -673,140 +646,6 @@
 
 static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil);
 
-/*
- * wcd934x_get_codec_info: Get codec specific information
- *
- * @wcd9xxx: pointer to wcd9xxx structure
- * @wcd_type: pointer to wcd9xxx_codec_type structure
- *
- * Returns 0 for success or negative error code for failure
- */
-int wcd934x_get_codec_info(struct wcd9xxx *wcd9xxx,
-			   struct wcd9xxx_codec_type *wcd_type)
-{
-	u16 id_minor, id_major;
-	struct regmap *wcd_regmap;
-	int rc, version = -1;
-
-	if (!wcd9xxx || !wcd_type)
-		return -EINVAL;
-
-	if (!wcd9xxx->regmap) {
-		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null\n", __func__);
-		return -EINVAL;
-	}
-	wcd_regmap = wcd9xxx->regmap;
-
-	rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
-			      (u8 *)&id_minor, sizeof(u16));
-	if (rc)
-		return -EINVAL;
-
-	rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
-			      (u8 *)&id_major, sizeof(u16));
-	if (rc)
-		return -EINVAL;
-
-	dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
-		 __func__, id_major, id_minor);
-
-	if (id_major != TAVIL_MAJOR)
-		goto version_unknown;
-
-	/*
-	 * As fine version info cannot be retrieved before tavil probe.
-	 * Assign coarse versions for possible future use before tavil probe.
-	 */
-	if (id_minor == cpu_to_le16(0))
-		version = TAVIL_VERSION_1_0;
-	else if (id_minor == cpu_to_le16(0x01))
-		version = TAVIL_VERSION_1_1;
-
-version_unknown:
-	if (version < 0)
-		dev_err(wcd9xxx->dev, "%s: wcd934x version unknown\n",
-			__func__);
-
-	/* Fill codec type info */
-	wcd_type->id_major = id_major;
-	wcd_type->id_minor = id_minor;
-	wcd_type->num_irqs = WCD934X_NUM_IRQS;
-	wcd_type->version = version;
-	wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
-	wcd_type->i2c_chip_status = 0x01;
-	wcd_type->intr_tbl = wcd934x_intr_table;
-	wcd_type->intr_tbl_size = ARRAY_SIZE(wcd934x_intr_table);
-
-	wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
-						WCD934X_INTR_PIN1_STATUS0;
-	wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
-						WCD934X_INTR_PIN1_CLEAR0;
-	wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
-						WCD934X_INTR_PIN1_MASK0;
-	wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
-						WCD934X_INTR_LEVEL0;
-	wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
-						WCD934X_INTR_CLR_COMMIT;
-
-	return rc;
-}
-EXPORT_SYMBOL(wcd934x_get_codec_info);
-
-/*
- * wcd934x_bringdown: Bringdown WCD Codec
- *
- * @wcd9xxx: Pointer to wcd9xxx structure
- *
- * Returns 0 for success or negative error code for failure
- */
-int wcd934x_bringdown(struct wcd9xxx *wcd9xxx)
-{
-	if (!wcd9xxx || !wcd9xxx->regmap)
-		return -EINVAL;
-
-	regmap_write(wcd9xxx->regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
-		     0x04);
-
-	return 0;
-}
-EXPORT_SYMBOL(wcd934x_bringdown);
-
-/*
- * wcd934x_bringup: Bringup WCD Codec
- *
- * @wcd9xxx: Pointer to the wcd9xxx structure
- *
- * Returns 0 for success or negative error code for failure
- */
-int wcd934x_bringup(struct wcd9xxx *wcd9xxx)
-{
-	struct regmap *wcd_regmap;
-
-	if (!wcd9xxx)
-		return -EINVAL;
-
-	if (!wcd9xxx->regmap) {
-		dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
-			__func__);
-		return -EINVAL;
-	}
-	wcd_regmap = wcd9xxx->regmap;
-
-	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
-	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
-	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
-	/* Add 1msec delay for VOUT to settle */
-	usleep_range(1000, 1100);
-	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
-	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
-	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
-	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
-	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
-
-	return 0;
-}
-EXPORT_SYMBOL(wcd934x_bringup);
-
 /**
  * tavil_set_spkr_gain_offset - offset the speaker path
  * gain with the given offset value.
@@ -5159,10 +4998,12 @@
 					struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
 	int iir_idx = ((struct soc_multi_mixer_control *)
 					kcontrol->private_value)->reg;
 	int band_idx = ((struct soc_multi_mixer_control *)
 					kcontrol->private_value)->shift;
+	int coeff_idx;
 
 	/*
 	 * Mask top bit it is reserved
@@ -5172,16 +5013,15 @@
 		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
 		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
 
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[0]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[1]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[2]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[3]);
-	set_iir_band_coeff(codec, iir_idx, band_idx,
-				ucontrol->value.integer.value[4]);
+	/* Store the coefficients in sidetone coeff array */
+	for (coeff_idx = 0; coeff_idx < WCD934X_CDC_SIDETONE_IIR_COEFF_MAX;
+		coeff_idx++) {
+		tavil->sidetone_coeff_array[iir_idx][band_idx][coeff_idx] =
+			ucontrol->value.integer.value[coeff_idx];
+		set_iir_band_coeff(codec, iir_idx, band_idx,
+			tavil->sidetone_coeff_array[iir_idx][band_idx]
+							[coeff_idx]);
+	}
 
 	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
 		"%s: IIR #%d band #%d b1 = 0x%x\n"
@@ -5201,6 +5041,26 @@
 	return 0;
 }
 
+static void tavil_restore_iir_coeff(struct tavil_priv *tavil, int iir_idx)
+{
+	int band_idx = 0, coeff_idx = 0;
+	struct snd_soc_codec *codec = tavil->codec;
+
+	for (band_idx = 0; band_idx < BAND_MAX; band_idx++) {
+		snd_soc_write(codec,
+		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+		for (coeff_idx = 0;
+			coeff_idx < WCD934X_CDC_SIDETONE_IIR_COEFF_MAX;
+			coeff_idx++) {
+			set_iir_band_coeff(codec, iir_idx, band_idx,
+				tavil->sidetone_coeff_array[iir_idx][band_idx]
+								[coeff_idx]);
+		}
+	}
+}
+
 static int tavil_compander_get(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
@@ -5473,7 +5333,7 @@
 	u32 adc, i, mic_bias_found = 0;
 	int ret = 0;
 	char *mad_input;
-	bool is_adc2_input = false;
+	bool is_adc_input = false;
 
 	tavil_mad_input = ucontrol->value.integer.value[0];
 
@@ -5521,8 +5381,7 @@
 		snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc);
 
 		mad_input_widget = mad_amic_input_widget;
-		if (adc == 2)
-			is_adc2_input = true;
+		is_adc_input = true;
 	} else {
 		/* DMIC type input widget*/
 		mad_input_widget = tavil_conn_mad_text[tavil_mad_input];
@@ -5530,7 +5389,7 @@
 
 	dev_dbg(codec->dev,
 		"%s: tavil input widget = %s, adc_input = %s\n", __func__,
-		mad_input_widget, is_adc2_input ? "true" : "false");
+		mad_input_widget, is_adc_input ? "true" : "false");
 
 	for (i = 0; i < card->num_of_dapm_routes; i++) {
 		if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) {
@@ -5575,8 +5434,8 @@
 			    0x0F, tavil_mad_input);
 	snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
 			    0x07, mic_bias_found);
-	/* for adc2 input, mad should be in micbias mode with BG enabled */
-	if (is_adc2_input)
+	/* for all adc inputs, mad should be in micbias mode with BG enabled */
+	if (is_adc_input)
 		snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
 				    0x88, 0x88);
 	else
@@ -8154,6 +8013,8 @@
 			     WCD934X_DIG_CORE_REG_MIN,
 			     WCD934X_DIG_CORE_REG_MAX);
 
+	tavil_restore_iir_coeff(tavil, IIR0);
+	tavil_restore_iir_coeff(tavil, IIR1);
 	return 0;
 }
 
@@ -8578,6 +8439,7 @@
 	{WCD934X_TLMM_DMIC3_CLK_PINCFG, 0xFF, 0x0a},
 	{WCD934X_TLMM_DMIC3_DATA_PINCFG, 0xFF, 0x0a},
 	{WCD934X_CPE_SS_SVA_CFG, 0x60, 0x00},
+	{WCD934X_CPE_SS_CPAR_CFG, 0x10, 0x10},
 };
 
 static void tavil_codec_init_reg(struct tavil_priv *priv)
@@ -9072,8 +8934,9 @@
 
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	priv = snd_soc_codec_get_drvdata(codec);
-	swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev,
-			SWR_DEVICE_DOWN, NULL);
+	if (priv->swr.ctrl_data)
+		swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev,
+				SWR_DEVICE_DOWN, NULL);
 	tavil_dsd_reset(priv->dsd_config);
 	snd_soc_card_change_online_state(codec->component.card, 0);
 	for (count = 0; count < NUM_CODEC_DAIS; count++)
diff --git a/sound/soc/codecs/wcd934x/wcd934x.h b/sound/soc/codecs/wcd934x/wcd934x.h
index ae70175..c3bf50a 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.h
+++ b/sound/soc/codecs/wcd934x/wcd934x.h
@@ -95,45 +95,6 @@
 	INTERP_MAX,
 };
 
-enum {
-	/* INTR_REG 0 */
-	WCD934X_IRQ_MISC = 1,
-	WCD934X_IRQ_HPH_PA_OCPL_FAULT,
-	WCD934X_IRQ_HPH_PA_OCPR_FAULT,
-	WCD934X_IRQ_EAR_PA_OCP_FAULT,
-	WCD934X_IRQ_HPH_PA_CNPL_COMPLETE,
-	WCD934X_IRQ_HPH_PA_CNPR_COMPLETE,
-	WCD934X_IRQ_EAR_PA_CNP_COMPLETE,
-	/* INTR_REG 1 */
-	WCD934X_IRQ_MBHC_SW_DET,
-	WCD934X_IRQ_MBHC_ELECT_INS_REM_DET,
-	WCD934X_IRQ_MBHC_BUTTON_PRESS_DET,
-	WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET,
-	WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
-	WCD934X_IRQ_RESERVED_0,
-	WCD934X_IRQ_RESERVED_1,
-	WCD934X_IRQ_RESERVED_2,
-	/* INTR_REG 2 */
-	WCD934X_IRQ_LINE_PA1_CNP_COMPLETE,
-	WCD934X_IRQ_LINE_PA2_CNP_COMPLETE,
-	WCD934X_IRQ_SLNQ_ANALOG_ERROR,
-	WCD934X_IRQ_RESERVED_3,
-	WCD934X_IRQ_SOUNDWIRE,
-	WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE,
-	WCD934X_IRQ_RCO_ERROR,
-	WCD934X_IRQ_CPE_ERROR,
-	/* INTR_REG 3 */
-	WCD934X_IRQ_MAD_AUDIO,
-	WCD934X_IRQ_MAD_BEACON,
-	WCD934X_IRQ_MAD_ULTRASOUND,
-	WCD934X_IRQ_VBAT_ATTACK,
-	WCD934X_IRQ_VBAT_RESTORE,
-	WCD934X_IRQ_CPE1_INTR,
-	WCD934X_IRQ_RESERVED_4,
-	WCD934X_IRQ_SLNQ_DIGITAL,
-	WCD934X_NUM_IRQS,
-};
-
 /*
  * Selects compander and smart boost settings
  * for a given speaker mode
diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c
index 9ac38c2..6216657 100644
--- a/sound/soc/codecs/wcd9xxx-common-v2.c
+++ b/sound/soc/codecs/wcd9xxx-common-v2.c
@@ -1316,6 +1316,7 @@
 		break;
 	};
 }
+EXPORT_SYMBOL(wcd_clsh_fsm);
 
 int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh)
 {
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
deleted file mode 100644
index 7b2e68a..0000000
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ /dev/null
@@ -1,1480 +0,0 @@
-/* Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <sound/soc.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
-#include "wcd9xxx-common.h"
-
-#define CLSH_COMPUTE_EAR 0x01
-#define CLSH_COMPUTE_HPH_L 0x02
-#define CLSH_COMPUTE_HPH_R 0x03
-
-#define BUCK_VREF_0P494V 0x3F
-#define BUCK_VREF_2V 0xFF
-#define BUCK_VREF_0P494V 0x3F
-#define BUCK_VREF_1P8V 0xE6
-
-#define BUCK_SETTLE_TIME_US 50
-#define NCP_SETTLE_TIME_US 50
-
-#define MAX_IMPED_PARAMS 13
-
-#define USLEEP_RANGE_MARGIN_US 100
-
-struct wcd9xxx_imped_val {
-	u32 imped_val;
-	u8 index;
-};
-
-static const struct wcd9xxx_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = {
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x46},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9B},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x15},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x04},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0C},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x47},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9B},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x15},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x05},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0C},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x49},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x12},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x35},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x4E},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x06},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0E},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x49},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x16},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x17},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x5F},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xCF},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x06},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0F},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x59},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x15},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xCE},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xBD},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x07},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x10},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x66},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9A},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xBD},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA6},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x07},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x11},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x79},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA6},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAD},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x08},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x12},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x76},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x4E},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAD},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x09},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x12},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x78},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x12},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xD0},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0A},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x13},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x7A},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xB7},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0B},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x14},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x60},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x09},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA4},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1F},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0C},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x14},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x79},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x17},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1F},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0D},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x15},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x78},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x16},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0E},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x89},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x40},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x10},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xD0},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x12},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x17},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8A},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xB7},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x10},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x13},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x17},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8A},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA4},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x15},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x18},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x9A},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x08},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x27},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x18},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8B},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x18},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x20},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1A},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x9A},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x17},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2D},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1D},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x1A},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xA9},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2D},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1F},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xB9},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x10},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x23},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x18},
-	},
-	{
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xA9},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x27},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x35},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x26},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
-	},
-};
-
-static const struct wcd9xxx_imped_val imped_index[] = {
-	{4000, 0},
-	{4500, 1},
-	{5000, 2},
-	{5500, 3},
-	{6000, 4},
-	{6500, 5},
-	{7000, 6},
-	{7700, 7},
-	{8470, 8},
-	{9317, 9},
-	{10248, 10},
-	{11273, 11},
-	{12400, 12},
-	{13641, 13},
-	{15005, 14},
-	{16505, 15},
-	{18156, 16},
-	{19971, 17},
-	{21969, 18},
-	{24165, 19},
-	{26582, 20},
-	{29240, 21},
-	{32164, 22},
-};
-
-static inline void
-wcd9xxx_enable_clsh_block(struct snd_soc_codec *codec,
-			  struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
-{
-	if ((enable && ++clsh_d->clsh_users == 1) ||
-	    (!enable && --clsh_d->clsh_users == 0))
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
-				    0x01, enable ? 0x01 : 0x00);
-	dev_dbg(codec->dev, "%s: clsh_users %d, enable %d", __func__,
-		clsh_d->clsh_users, enable);
-}
-
-static inline void wcd9xxx_enable_anc_delay(
-	struct snd_soc_codec *codec,
-	bool on)
-{
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
-		0x02, on ? 0x02 : 0x00);
-}
-
-static inline void
-wcd9xxx_enable_buck(struct snd_soc_codec *codec,
-		    struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
-{
-	if ((enable && ++clsh_d->buck_users == 1) ||
-	    (!enable && --clsh_d->buck_users == 0))
-		snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
-				    0x80, enable ? 0x80 : 0x00);
-	dev_dbg(codec->dev, "%s: buck_users %d, enable %d", __func__,
-		clsh_d->buck_users, enable);
-}
-
-static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_codec *,
-					      struct wcd9xxx_clsh_cdc_data *,
-					      u8 req_state, bool req_type);
-
-static const char *state_to_str(u8 state, char *buf, size_t buflen)
-{
-	int i;
-	int cnt = 0;
-	/*
-	 * This array of strings should match with enum wcd9xxx_clsh_state_bit.
-	 */
-	static const char *const states[] = {
-		"STATE_EAR",
-		"STATE_HPH_L",
-		"STATE_HPH_R",
-		"STATE_LO",
-	};
-
-	if (state == WCD9XXX_CLSH_STATE_IDLE) {
-		snprintf(buf, buflen, "[STATE_IDLE]");
-		goto done;
-	}
-
-	buf[0] = '\0';
-	for (i = 0; i < ARRAY_SIZE(states); i++) {
-		if (!(state & (1 << i)))
-			continue;
-		cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf,
-			       buf[0] == '\0' ? "[" : "|",
-			       states[i]);
-	}
-	if (cnt > 0)
-		strlcat(buf + cnt, "]", buflen);
-
-done:
-	if (buf[0] == '\0')
-		snprintf(buf, buflen, "[STATE_UNKNOWN]");
-	return buf;
-}
-
-static void wcd9xxx_cfg_clsh_param_common(
-		struct snd_soc_codec *codec)
-{
-	int i;
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 0, 0},
-		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 2, 1 << 2},
-		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, (0x1 << 4), 0},
-		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 0), 0x01},
-		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 2), (0x01 << 2)},
-		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0xf << 4), (0x03 << 4)},
-		{WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 4), (0x03 << 4)},
-		{WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 0), (0x0B)},
-		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 5), (0x01 << 5)},
-		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 1), (0x01 << 1)},
-	};
-
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
-						    reg_set[i].val);
-
-	dev_dbg(codec->dev, "%s: Programmed class H controller common parameters",
-			 __func__);
-}
-
-static void wcd9xxx_chargepump_request(struct snd_soc_codec *codec, bool on)
-{
-	static int cp_count;
-
-	if (on && (++cp_count == 1)) {
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
-				    0x01, 0x01);
-		dev_dbg(codec->dev, "%s: Charge Pump enabled, count = %d\n",
-			__func__, cp_count);
-	} else if (!on) {
-		if (--cp_count < 0) {
-			dev_dbg(codec->dev,
-				"%s: Unbalanced disable for charge pump\n",
-				__func__);
-			if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL) &
-			    0x01) {
-				dev_dbg(codec->dev,
-					"%s: Actual chargepump is ON\n",
-					__func__);
-			}
-			cp_count = 0;
-			WARN_ON(1);
-		}
-
-		if (cp_count == 0) {
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
-					    0x01, 0x00);
-			dev_dbg(codec->dev,
-				"%s: Charge pump disabled, count = %d\n",
-				__func__, cp_count);
-		}
-	}
-}
-
-void wcd9xxx_enable_high_perf_mode(struct snd_soc_codec *codec,
-				struct wcd9xxx_clsh_cdc_data *clsh_d,
-				u8 uhqa_mode, u8 req_state, bool req_type)
-{
-	dev_dbg(codec->dev, "%s: users fclk8 %d, fclk5 %d", __func__,
-			clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
-			clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
-
-	if (req_type == WCD9XXX_CLSAB_REQ_ENABLE) {
-		clsh_d->ncp_users[NCP_FCLK_LEVEL_8]++;
-		snd_soc_write(codec, WCD9XXX_A_RX_HPH_BIAS_PA,
-					WCD9XXX_A_RX_HPH_BIAS_PA__POR);
-		snd_soc_write(codec, WCD9XXX_A_RX_HPH_L_PA_CTL, 0x48);
-		snd_soc_write(codec, WCD9XXX_A_RX_HPH_R_PA_CTL, 0x48);
-		if (uhqa_mode)
-			snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CHOP_CTL,
-						0x20, 0x00);
-		wcd9xxx_chargepump_request(codec, true);
-		wcd9xxx_enable_anc_delay(codec, true);
-		wcd9xxx_enable_buck(codec, clsh_d, false);
-		if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] > 0)
-			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
-						0x0F, 0x08);
-		snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x30, 0x30);
-
-		/* Enable NCP and wait until settles down */
-		if (snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x01))
-			usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US+10);
-	} else {
-		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CHOP_CTL,
-					0x20, 0x20);
-		snd_soc_write(codec, WCD9XXX_A_RX_HPH_L_PA_CTL,
-					WCD9XXX_A_RX_HPH_L_PA_CTL__POR);
-		snd_soc_write(codec, WCD9XXX_A_RX_HPH_R_PA_CTL,
-					WCD9XXX_A_RX_HPH_R_PA_CTL__POR);
-		snd_soc_write(codec, WCD9XXX_A_RX_HPH_BIAS_PA, 0x57);
-		wcd9xxx_enable_buck(codec, clsh_d, true);
-		wcd9xxx_chargepump_request(codec, false);
-		wcd9xxx_enable_anc_delay(codec, false);
-		clsh_d->ncp_users[NCP_FCLK_LEVEL_8]--;
-		if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0 &&
-		    clsh_d->ncp_users[NCP_FCLK_LEVEL_5] == 0)
-			snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
-						0x01, 0x00);
-		else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0)
-			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
-						0x0F, 0x05);
-	}
-	dev_dbg(codec->dev, "%s: leave\n", __func__);
-}
-EXPORT_SYMBOL(wcd9xxx_enable_high_perf_mode);
-
-static int get_impedance_index(u32 imped)
-{
-	int i = 0;
-
-	if (imped < imped_index[i].imped_val) {
-		pr_debug("%s, detected impedance is less than 4 Ohm\n",
-				__func__);
-		goto ret;
-	}
-	if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) {
-		pr_debug("%s, detected impedance is greater than 32164 Ohm\n",
-				__func__);
-		i = ARRAY_SIZE(imped_index) - 1;
-		goto ret;
-	}
-	for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) {
-		if (imped >= imped_index[i].imped_val &&
-			imped < imped_index[i + 1].imped_val)
-			break;
-	}
-ret:
-	pr_debug("%s: selected impedance index = %d\n",
-			__func__, imped_index[i].index);
-	return imped_index[i].index;
-}
-
-void wcd9xxx_clsh_imped_config(struct snd_soc_codec *codec,
-				  int imped)
-{
-	int i  = 0;
-	int index = 0;
-
-	index = get_impedance_index(imped);
-	if (index >= ARRAY_SIZE(imped_index)) {
-		pr_err("%s, invalid imped = %d\n", __func__, imped);
-		return;
-	}
-	for (i = 0; i < MAX_IMPED_PARAMS; i++)
-		snd_soc_write(codec, imped_table[index][i].reg,
-					imped_table[index][i].val);
-}
-
-static void wcd9xxx_clsh_comp_req(struct snd_soc_codec *codec,
-				  struct wcd9xxx_clsh_cdc_data *clsh_d,
-				  int compute_pa, bool on)
-{
-	u8 shift;
-
-	if (compute_pa == CLSH_COMPUTE_EAR) {
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10,
-				    (on ? 0x10 : 0));
-	} else {
-		if (compute_pa == CLSH_COMPUTE_HPH_L) {
-			shift = 3;
-		} else if (compute_pa == CLSH_COMPUTE_HPH_R) {
-			shift = 2;
-		} else {
-			dev_dbg(codec->dev,
-				"%s: classh computation request is incorrect\n",
-				__func__);
-			return;
-		}
-
-		if (on)
-			wcd9xxx_resmgr_add_cond_update_bits(clsh_d->resmgr,
-						  WCD9XXX_COND_HPH,
-						  WCD9XXX_A_CDC_CLSH_B1_CTL,
-						  shift, false);
-		else
-			wcd9xxx_resmgr_rm_cond_update_bits(clsh_d->resmgr,
-						  WCD9XXX_COND_HPH,
-						  WCD9XXX_A_CDC_CLSH_B1_CTL,
-						  shift, false);
-	}
-}
-
-int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
-					struct list_head *list,
-					uint16_t reg, uint8_t mask,
-					uint8_t value, int delay)
-{
-	int rc;
-	struct wcd9xxx_register_save_node *node;
-
-	node = kmalloc(sizeof(*node), GFP_KERNEL);
-	if (unlikely(!node)) {
-		pr_err("%s: Not enough memory\n", __func__);
-		return -ENOMEM;
-	}
-	node->reg = reg;
-	node->value = snd_soc_read(codec, reg);
-	list_add(&node->lh, list);
-	if (mask == 0xFF)
-		rc = snd_soc_write(codec, reg, value);
-	else
-		rc = snd_soc_update_bits(codec, reg, mask, value);
-	if (delay)
-		usleep_range(delay, delay + USLEEP_RANGE_MARGIN_US);
-	return rc;
-}
-EXPORT_SYMBOL(wcd9xxx_soc_update_bits_push);
-
-void wcd9xxx_restore_registers(struct snd_soc_codec *codec,
-			       struct list_head *lh)
-{
-	struct wcd9xxx_register_save_node *node, *nodetmp;
-
-	list_for_each_entry_safe(node, nodetmp, lh, lh) {
-		snd_soc_write(codec, node->reg, node->value);
-		list_del(&node->lh);
-		kfree(node);
-	}
-}
-EXPORT_SYMBOL(wcd9xxx_restore_registers);
-
-static void wcd9xxx_dynamic_bypass_buck_ctrl_lo(struct snd_soc_codec *cdc,
-						bool enable)
-{
-	int i;
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_BUCK_MODE_3, (0x1 << 3), (enable << 3)},
-		{WCD9XXX_A_BUCK_MODE_5, enable ? 0xFF : 0x02, 0x02},
-		{WCD9XXX_A_BUCK_MODE_5, 0x1, 0x01}
-	};
-
-	if (!enable) {
-		snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_1,
-					(0x1 << 3), 0x00);
-		snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_4,
-					0xFF, BUCK_VREF_2V);
-	}
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(cdc, reg_set[i].reg, reg_set[i].mask,
-							reg_set[i].val);
-
-	/* 50us sleep is reqd. as per the class H HW design sequence */
-	usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
-}
-
-static void wcd9xxx_dynamic_bypass_buck_ctrl(struct snd_soc_codec *cdc,
-						bool enable)
-{
-	int i;
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_BUCK_MODE_3, (0x1 << 3), (enable << 3)},
-		{WCD9XXX_A_BUCK_MODE_5, (0x1 << 1), ((!enable) << 1)},
-		{WCD9XXX_A_BUCK_MODE_5, 0x1, !enable}
-	};
-	if (!enable) {
-		snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_1,
-					(0x1 << 3), 0x00);
-		snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_4,
-					0xFF, BUCK_VREF_2V);
-	}
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(cdc, reg_set[i].reg, reg_set[i].mask,
-							reg_set[i].val);
-
-	/* 50us sleep is reqd. as per the class H HW design sequence */
-	usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
-}
-
-static void wcd9xxx_set_buck_mode(struct snd_soc_codec *codec, u8 buck_vref)
-{
-	int i;
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x02},
-		{WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
-		{WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
-		{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
-		{WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
-	};
-
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(codec, reg_set[i].reg,
-					reg_set[i].mask, reg_set[i].val);
-
-	dev_dbg(codec->dev, "%s: Done\n", __func__);
-	usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US + 10);
-}
-
-
-/* This will be called for all states except Lineout */
-static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec,
-	struct wcd9xxx_clsh_cdc_data *cdc_clsh_d)
-{
-	int i;
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
-		{WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
-		{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
-	};
-
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(codec, reg_set[i].reg,
-					reg_set[i].mask, reg_set[i].val);
-
-	if (!cdc_clsh_d->is_dynamic_vdd_cp)
-		snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_3,
-							0x08, 0x08);
-
-	dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
-		   __func__);
-
-}
-
-static void wcd9xxx_set_fclk_get_ncp(struct snd_soc_codec *codec,
-				     struct wcd9xxx_clsh_cdc_data *clsh_d,
-				     enum ncp_fclk_level fclk_level)
-{
-	clsh_d->ncp_users[fclk_level]++;
-
-	pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
-		 fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
-		 clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x10, 0x00);
-	/* fclk level 8 dominates level 5 */
-	if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] > 0)
-		snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x08);
-	else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_5] > 0)
-		snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
-	else
-		WARN_ONCE(1, "Unexpected users %d,%d\n",
-			  clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
-			  clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
-	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x20, 0x20);
-
-	/* enable NCP and wait until settles down */
-	if (snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x01))
-		usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US + 50);
-	pr_debug("%s: leave\n", __func__);
-}
-
-static void wcd9xxx_set_fclk_put_ncp(struct snd_soc_codec *codec,
-				     struct wcd9xxx_clsh_cdc_data *clsh_d,
-				     enum ncp_fclk_level fclk_level)
-{
-	clsh_d->ncp_users[fclk_level]--;
-
-	pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
-		 fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
-		 clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
-
-	if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0 &&
-	    clsh_d->ncp_users[NCP_FCLK_LEVEL_5] == 0)
-		snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x00);
-	else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0)
-		/* if dominating level 8 has gone, switch to 5 */
-		snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
-	pr_debug("%s: leave\n", __func__);
-}
-
-static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
-{
-	int i;
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 7), 0},
-		{WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR, (0x3f << 0), 0x0D},
-		{WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR, (0x3f << 0), 0x3A},
-
-		/* Under assumption that EAR load is 10.7ohm */
-		{WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD, (0x3f << 0), 0x26},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD, (0x3f << 0), 0x2C},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xff, 0xA9},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U, 0xff, 0x07},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, (0xf << 0), 0x08},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1b},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2d},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x36},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-	};
-
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(codec, reg_set[i].reg,
-					reg_set[i].mask, reg_set[i].val);
-
-	dev_dbg(codec->dev, "%s: Programmed Class H controller EAR specific params\n",
-			 __func__);
-}
-
-static void wcd9xxx_cfg_clsh_param_hph(struct snd_soc_codec *codec)
-{
-	int i;
-	const struct wcd9xxx_reg_mask_val reg_set[] = {
-		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 6), 0},
-		{WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH, 0x3f, 0x0D},
-		{WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH, 0x3f, 0x1D},
-
-		/* Under assumption that HPH load is 16ohm per channel */
-		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0x3f, 0x13},
-		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x1f, 0x19},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
-		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
-		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0x0f, 0},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
-		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
-	};
-
-	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
-		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
-							reg_set[i].val);
-	dev_dbg(codec->dev, "%s: Programmed Class H controller HPH specific params\n",
-			 __func__);
-}
-
-static void wcd9xxx_ncp_bypass_enable(struct snd_soc_codec *cdc, bool enable)
-{
-	snd_soc_update_bits(cdc, WCD9XXX_A_NCP_STATIC, 0x10, (enable << 4));
-	/* 50us sleep is reqd. as per the class H HW design sequence */
-	usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
-}
-
-static void wcd9xxx_clsh_set_Iest(struct snd_soc_codec *codec,
-		u8 value)
-{
-	snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
-				    0x01, (0x01 & 0x03));
-	snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
-				    0xFC, (value << 2));
-}
-
-static void wcd9xxx_clsh_state_hph_ear(struct snd_soc_codec *codec,
-			struct wcd9xxx_clsh_cdc_data *clsh_d,
-			u8 req_state, bool is_enable)
-{
-	int compute_pa = 0;
-
-	dev_dbg(codec->dev, "%s: enter %s\n", __func__,
-			is_enable ? "enable" : "disable");
-
-	if (is_enable) {
-		/*
-		 * The below check condition is required to make sure
-		 * functions inside if condition will execute only once.
-		 */
-		if ((clsh_d->state == WCD9XXX_CLSH_STATE_EAR) ||
-			(req_state == WCD9XXX_CLSH_STATE_EAR)) {
-			wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
-			wcd9xxx_ncp_bypass_enable(codec, true);
-		}
-		switch (req_state) {
-		case WCD9XXX_CLSH_STATE_HPHL:
-			compute_pa = CLSH_COMPUTE_HPH_L;
-			break;
-		case WCD9XXX_CLSH_STATE_HPHR:
-			compute_pa = CLSH_COMPUTE_HPH_R;
-			break;
-		case WCD9XXX_CLSH_STATE_EAR:
-			compute_pa = CLSH_COMPUTE_EAR;
-			break;
-		default:
-			dev_dbg(codec->dev,
-				"%s:Invalid state:0x%x,enable:0x%x\n",
-				__func__, req_state, is_enable);
-			break;
-		}
-		wcd9xxx_clsh_comp_req(codec, clsh_d, compute_pa, true);
-
-		dev_dbg(codec->dev, "%s: Enabled hph+ear mode clsh\n",
-				__func__);
-	} else {
-		switch (req_state) {
-		case WCD9XXX_CLSH_STATE_HPHL:
-			compute_pa = CLSH_COMPUTE_HPH_L;
-			break;
-		case WCD9XXX_CLSH_STATE_HPHR:
-			compute_pa = CLSH_COMPUTE_HPH_R;
-			break;
-		case WCD9XXX_CLSH_STATE_EAR:
-			compute_pa = CLSH_COMPUTE_EAR;
-			break;
-		default:
-			dev_dbg(codec->dev,
-				"%s:Invalid state:0x%x,enable:0x%x\n",
-				__func__, req_state, is_enable);
-			break;
-		}
-		wcd9xxx_clsh_comp_req(codec, clsh_d, compute_pa, false);
-
-		if (((clsh_d->state & (~req_state)) ==
-				WCD9XXX_CLSH_STATE_EAR) ||
-			(req_state == WCD9XXX_CLSH_STATE_EAR)) {
-			wcd9xxx_ncp_bypass_enable(codec, false);
-			wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
-		}
-	}
-}
-
-static void wcd9xxx_clsh_state_hph_lo(struct snd_soc_codec *codec,
-			struct wcd9xxx_clsh_cdc_data *clsh_d,
-			u8 req_state, bool is_enable)
-{
-
-	dev_dbg(codec->dev, "%s: enter %s\n", __func__,
-			is_enable ? "enable" : "disable");
-	if (is_enable) {
-		if ((clsh_d->state == WCD9XXX_CLSH_STATE_LO) ||
-			(req_state == WCD9XXX_CLSH_STATE_LO)) {
-			wcd9xxx_dynamic_bypass_buck_ctrl_lo(codec, false);
-			wcd9xxx_enable_buck(codec, clsh_d, true);
-			wcd9xxx_ncp_bypass_enable(codec, true);
-			if (req_state & WCD9XXX_CLSH_STATE_HPH_ST) {
-				wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
-							NCP_FCLK_LEVEL_8);
-				wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
-							NCP_FCLK_LEVEL_5);
-				wcd9xxx_enable_clsh_block(codec, clsh_d, true);
-				wcd9xxx_chargepump_request(codec, true);
-				wcd9xxx_enable_anc_delay(codec, true);
-			}
-		}
-		if (req_state == WCD9XXX_CLSH_STATE_HPHL)
-			wcd9xxx_clsh_comp_req(codec, clsh_d,
-						CLSH_COMPUTE_HPH_L, true);
-		if (req_state == WCD9XXX_CLSH_STATE_HPHR)
-			wcd9xxx_clsh_comp_req(codec, clsh_d,
-						CLSH_COMPUTE_HPH_R, true);
-	} else {
-		switch (req_state) {
-		case WCD9XXX_CLSH_STATE_LO:
-			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
-						0x20, 0x00);
-			wcd9xxx_dynamic_bypass_buck_ctrl_lo(codec, true);
-			break;
-		case WCD9XXX_CLSH_STATE_HPHL:
-			wcd9xxx_clsh_comp_req(codec, clsh_d,
-						CLSH_COMPUTE_HPH_L, false);
-			break;
-		case WCD9XXX_CLSH_STATE_HPHR:
-			wcd9xxx_clsh_comp_req(codec, clsh_d,
-						CLSH_COMPUTE_HPH_R, false);
-			break;
-		default:
-			dev_dbg(codec->dev,
-				 "%s:Invalid state:0x%x,enable:0x%x\n",
-				__func__, req_state, is_enable);
-			break;
-		}
-		if ((req_state == WCD9XXX_CLSH_STATE_LO) ||
-		((clsh_d->state & (~req_state)) == WCD9XXX_CLSH_STATE_LO)) {
-			wcd9xxx_ncp_bypass_enable(codec, false);
-
-			if ((clsh_d->state & (~req_state)) ==
-						WCD9XXX_CLSH_STATE_LO) {
-				wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
-							NCP_FCLK_LEVEL_5);
-				wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
-							NCP_FCLK_LEVEL_8);
-			}
-
-			if (req_state & WCD9XXX_CLSH_STATE_HPH_ST) {
-				usleep_range(BUCK_SETTLE_TIME_US,
-						BUCK_SETTLE_TIME_US + 10);
-				if (clsh_d->buck_mv ==
-						WCD9XXX_CDC_BUCK_MV_1P8) {
-					wcd9xxx_enable_buck(codec, clsh_d,
-								false);
-					wcd9xxx_ncp_bypass_enable(codec, true);
-				} else {
-					/*
-					 *NCP settle time recommended by codec
-					 *specification
-					 */
-					usleep_range(NCP_SETTLE_TIME_US,
-						NCP_SETTLE_TIME_US + 10);
-					wcd9xxx_clsh_set_Iest(codec, 0x02);
-				}
-				snd_soc_update_bits(codec,
-						WCD9XXX_A_BUCK_MODE_1,
-						0x04, 0x00);
-				snd_soc_update_bits(codec,
-						 WCD9XXX_A_BUCK_MODE_4,
-						0xFF, BUCK_VREF_1P8V);
-			}
-		}
-	}
-}
-
-static void wcd9xxx_clsh_state_ear_lo(struct snd_soc_codec *codec,
-			struct wcd9xxx_clsh_cdc_data *clsh_d,
-			u8 req_state, bool is_enable)
-{
-
-	dev_dbg(codec->dev, "%s: enter %s\n", __func__,
-			is_enable ? "enable" : "disable");
-	if (is_enable) {
-		wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
-		wcd9xxx_enable_buck(codec, clsh_d, true);
-		wcd9xxx_ncp_bypass_enable(codec, true);
-		if (req_state & WCD9XXX_CLSH_STATE_EAR) {
-			wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
-						NCP_FCLK_LEVEL_8);
-			wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
-						NCP_FCLK_LEVEL_5);
-			wcd9xxx_enable_clsh_block(codec, clsh_d, true);
-			wcd9xxx_chargepump_request(codec, true);
-			wcd9xxx_enable_anc_delay(codec, true);
-			wcd9xxx_clsh_comp_req(codec, clsh_d,
-						CLSH_COMPUTE_EAR, true);
-		}
-	} else {
-		wcd9xxx_ncp_bypass_enable(codec, false);
-
-		if ((clsh_d->state & (~req_state)) == WCD9XXX_CLSH_STATE_LO) {
-			wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
-						NCP_FCLK_LEVEL_5);
-			wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
-						NCP_FCLK_LEVEL_8);
-		}
-
-		if (req_state & WCD9XXX_CLSH_STATE_LO) {
-			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
-						0x20, 0x00);
-			wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
-		} else if (req_state & WCD9XXX_CLSH_STATE_EAR) {
-			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR,
-						false);
-			/*sleep 5ms*/
-			if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
-				wcd9xxx_enable_buck(codec, clsh_d, false);
-				wcd9xxx_ncp_bypass_enable(codec, true);
-			} else {
-				/* NCP settle time recommended by codec	spec */
-				usleep_range(NCP_SETTLE_TIME_US,
-					     NCP_SETTLE_TIME_US + 10);
-				wcd9xxx_clsh_set_Iest(codec, 0x02);
-			}
-			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
-						0x04, 0x00);
-			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_4,
-						0xFF, BUCK_VREF_1P8V);
-		}
-	}
-}
-
-static void wcd9xxx_clsh_state_hph_ear_lo(struct snd_soc_codec *codec,
-			struct wcd9xxx_clsh_cdc_data *clsh_d,
-			u8 req_state, bool is_enable)
-{
-	dev_dbg(codec->dev, "%s: enter %s\n", __func__,
-			is_enable ? "enable" : "disable");
-
-	if (req_state & WCD9XXX_CLSH_STATE_HPHL)
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
-					is_enable);
-
-	if (req_state & WCD9XXX_CLSH_STATE_HPHR)
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
-					is_enable);
-
-	if (req_state & WCD9XXX_CLSH_STATE_EAR)
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR,
-					is_enable);
-}
-
-static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
-			struct wcd9xxx_clsh_cdc_data *clsh_d,
-			u8 req_state, bool is_enable)
-{
-	pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
-	if (is_enable) {
-		wcd9xxx_cfg_clsh_param_common(codec);
-		wcd9xxx_cfg_clsh_param_ear(codec);
-		wcd9xxx_enable_clsh_block(codec, clsh_d, true);
-		wcd9xxx_chargepump_request(codec, true);
-		wcd9xxx_enable_anc_delay(codec, true);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
-		wcd9xxx_set_buck_mode(codec, BUCK_VREF_2V);
-		wcd9xxx_enable_buck(codec, clsh_d, true);
-		wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
-
-		dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
-	} else {
-		dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
-		wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
-		wcd9xxx_enable_buck(codec, clsh_d, false);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, false);
-		wcd9xxx_chargepump_request(codec, false);
-		wcd9xxx_enable_clsh_block(codec, clsh_d, false);
-	}
-}
-
-static void wcd9xxx_clsh_state_hph_l(struct snd_soc_codec *codec,
-		struct wcd9xxx_clsh_cdc_data *clsh_d,
-		u8 req_state, bool is_enable)
-{
-	pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
-
-	if (is_enable) {
-		wcd9xxx_cfg_clsh_param_common(codec);
-		wcd9xxx_cfg_clsh_param_hph(codec);
-		wcd9xxx_enable_clsh_block(codec, clsh_d, true);
-		wcd9xxx_chargepump_request(codec, true);
-		wcd9xxx_enable_anc_delay(codec, true);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
-		wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
-		wcd9xxx_enable_buck(codec, clsh_d, true);
-		wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
-
-		dev_dbg(codec->dev, "%s: Done\n", __func__);
-	} else {
-		wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
-		wcd9xxx_enable_buck(codec, clsh_d, false);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, false);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, false);
-		wcd9xxx_enable_clsh_block(codec, clsh_d, false);
-		wcd9xxx_chargepump_request(codec, false);
-	}
-}
-
-static void wcd9xxx_clsh_state_hph_r(struct snd_soc_codec *codec,
-		struct wcd9xxx_clsh_cdc_data *clsh_d,
-		u8 req_state, bool is_enable)
-{
-	pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
-
-	if (is_enable) {
-		wcd9xxx_cfg_clsh_param_common(codec);
-		wcd9xxx_cfg_clsh_param_hph(codec);
-		wcd9xxx_enable_clsh_block(codec, clsh_d, true);
-		wcd9xxx_chargepump_request(codec, true);
-		wcd9xxx_enable_anc_delay(codec, true);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
-		wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
-		wcd9xxx_enable_buck(codec, clsh_d, true);
-		wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
-
-		dev_dbg(codec->dev, "%s: Done\n", __func__);
-	} else {
-		wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
-		wcd9xxx_enable_buck(codec, clsh_d, false);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, false);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, false);
-		wcd9xxx_enable_clsh_block(codec, clsh_d, false);
-		wcd9xxx_chargepump_request(codec, false);
-	}
-}
-
-static void wcd9xxx_clsh_state_hph_st(struct snd_soc_codec *codec,
-		struct wcd9xxx_clsh_cdc_data *clsh_d,
-		u8 req_state, bool is_enable)
-{
-	pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
-
-	if (is_enable)
-		dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
-	else
-		dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
-}
-
-static void wcd9xxx_clsh_state_lo(struct snd_soc_codec *codec,
-		struct wcd9xxx_clsh_cdc_data *clsh_d,
-		u8 req_state, bool is_enable)
-{
-	pr_debug("%s: enter %s, buck_mv %d\n", __func__,
-		 is_enable ? "enable" : "disable", clsh_d->buck_mv);
-
-	if (is_enable) {
-		wcd9xxx_set_buck_mode(codec, BUCK_VREF_1P8V);
-		wcd9xxx_enable_buck(codec, clsh_d, true);
-		wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
-
-		if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
-			wcd9xxx_enable_buck(codec, clsh_d, false);
-			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
-					    1 << 4, 1 << 4);
-			/* NCP settle time recommended by codec specification */
-			usleep_range(NCP_SETTLE_TIME_US,
-				     NCP_SETTLE_TIME_US + 10);
-		} else {
-			/* NCP settle time recommended by codec specification */
-			usleep_range(NCP_SETTLE_TIME_US,
-				     NCP_SETTLE_TIME_US + 10);
-			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
-					    0x01, (0x01 & 0x03));
-			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
-					    0xFC, (0xFC & 0xB));
-		}
-		snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1, 0x04, 0x00);
-	} else {
-		dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
-		wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
-		if (clsh_d->buck_mv != WCD9XXX_CDC_BUCK_MV_1P8)
-			wcd9xxx_enable_buck(codec, clsh_d, false);
-	}
-}
-
-static void wcd9xxx_clsh_state_err(struct snd_soc_codec *codec,
-		struct wcd9xxx_clsh_cdc_data *clsh_d,
-		u8 req_state, bool is_enable)
-{
-	char msg[128];
-
-	dev_dbg(codec->dev,
-		"%s Wrong request for class H state machine requested to %s %s",
-		__func__, is_enable ? "enable" : "disable",
-		state_to_str(req_state, msg, sizeof(msg)));
-	WARN_ON(1);
-}
-
-/*
- * Function: wcd9xxx_clsh_is_state_valid
- * Params: state
- * Description:
- * Provides information on valid states of Class H configuration
- */
-static int wcd9xxx_clsh_is_state_valid(u8 state)
-{
-	switch (state) {
-	case WCD9XXX_CLSH_STATE_IDLE:
-	case WCD9XXX_CLSH_STATE_EAR:
-	case WCD9XXX_CLSH_STATE_HPHL:
-	case WCD9XXX_CLSH_STATE_HPHR:
-	case WCD9XXX_CLSH_STATE_HPH_ST:
-	case WCD9XXX_CLSH_STATE_LO:
-	case WCD9XXX_CLSH_STATE_HPHL_EAR:
-	case WCD9XXX_CLSH_STATE_HPHR_EAR:
-	case WCD9XXX_CLSH_STATE_HPH_ST_EAR:
-	case WCD9XXX_CLSH_STATE_HPHL_LO:
-	case WCD9XXX_CLSH_STATE_HPHR_LO:
-	case WCD9XXX_CLSH_STATE_HPH_ST_LO:
-	case WCD9XXX_CLSH_STATE_EAR_LO:
-	case WCD9XXX_CLSH_STATE_HPHL_EAR_LO:
-	case WCD9XXX_CLSH_STATE_HPHR_EAR_LO:
-	case WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO:
-		return 1;
-	default:
-		break;
-	}
-	return 0;
-}
-
-/*
- * Function: wcd9xxx_clsh_fsm
- * Params: codec, cdc_clsh_d, req_state, req_type, clsh_event
- * Description:
- * This function handles PRE DAC and POST DAC conditions of different devices
- * and updates class H configuration of different combination of devices
- * based on validity of their states. cdc_clsh_d will contain current
- * class h state information
- */
-void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
-		struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
-		u8 req_state, bool req_type, u8 clsh_event)
-{
-	u8 old_state, new_state;
-	char msg0[128], msg1[128];
-
-	switch (clsh_event) {
-	case WCD9XXX_CLSH_EVENT_PRE_DAC:
-		/* PRE_DAC event should be used only for Enable */
-		BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
-
-		old_state = cdc_clsh_d->state;
-		new_state = old_state | req_state;
-
-		if (!wcd9xxx_clsh_is_state_valid(new_state)) {
-			dev_dbg(codec->dev,
-				"%s: classH not a valid new state: %s\n",
-				__func__,
-				state_to_str(new_state, msg0, sizeof(msg0)));
-			return;
-		}
-		if (new_state == old_state) {
-			dev_dbg(codec->dev,
-				"%s: classH already in requested state: %s\n",
-				__func__,
-				state_to_str(new_state, msg0, sizeof(msg0)));
-			return;
-		}
-		(*clsh_state_fp[new_state]) (codec, cdc_clsh_d, req_state,
-					     req_type);
-		cdc_clsh_d->state = new_state;
-		dev_dbg(codec->dev,
-			"%s: ClassH state transition from %s to %s\n",
-			__func__, state_to_str(old_state, msg0, sizeof(msg0)),
-			state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
-
-		break;
-	case WCD9XXX_CLSH_EVENT_POST_PA:
-		if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
-			old_state = cdc_clsh_d->state;
-			new_state = old_state & (~req_state);
-
-			if (new_state < NUM_CLSH_STATES) {
-				if (!wcd9xxx_clsh_is_state_valid(old_state)) {
-					dev_dbg(codec->dev,
-						"%s:Invalid old state:%s\n",
-						__func__,
-						state_to_str(old_state, msg0,
-						sizeof(msg0)));
-					return;
-				}
-				if (new_state == old_state) {
-					dev_dbg(codec->dev,
-					"%s: clsH already in old state: %s\n",
-					__func__,
-					state_to_str(new_state, msg0,
-					sizeof(msg0)));
-					return;
-				}
-				(*clsh_state_fp[old_state]) (codec, cdc_clsh_d,
-							     req_state,
-							     req_type);
-				cdc_clsh_d->state = new_state;
-				dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
-					__func__, state_to_str(old_state, msg0,
-							       sizeof(msg0)),
-					state_to_str(cdc_clsh_d->state, msg1,
-						     sizeof(msg1)));
-
-			} else {
-				dev_dbg(codec->dev, "%s:wrong new state=0x%x\n",
-						__func__, new_state);
-			}
-		} else if (!(cdc_clsh_d->state & WCD9XXX_CLSH_STATE_LO)) {
-			wcd9xxx_clsh_enable_post_pa(codec, cdc_clsh_d);
-		}
-
-		break;
-	}
-
-}
-EXPORT_SYMBOL(wcd9xxx_clsh_fsm);
-
-void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
-		       struct wcd9xxx_resmgr *resmgr)
-{
-	int i;
-
-	clsh->state = WCD9XXX_CLSH_STATE_IDLE;
-	clsh->resmgr = resmgr;
-
-	for (i = 0; i < NUM_CLSH_STATES; i++)
-		clsh_state_fp[i] = wcd9xxx_clsh_state_err;
-
-	clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
-						wcd9xxx_clsh_state_hph_l;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR] =
-						wcd9xxx_clsh_state_hph_r;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
-						wcd9xxx_clsh_state_hph_st;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_EAR] =
-						wcd9xxx_clsh_state_hph_ear;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_EAR] =
-						wcd9xxx_clsh_state_hph_ear;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_EAR] =
-						wcd9xxx_clsh_state_hph_ear;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_LO] = wcd9xxx_clsh_state_hph_lo;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_LO] = wcd9xxx_clsh_state_hph_lo;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_LO] =
-						wcd9xxx_clsh_state_hph_lo;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_EAR_LO] = wcd9xxx_clsh_state_ear_lo;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_EAR_LO] =
-						wcd9xxx_clsh_state_hph_ear_lo;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_EAR_LO] =
-						wcd9xxx_clsh_state_hph_ear_lo;
-	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO] =
-						wcd9xxx_clsh_state_hph_ear_lo;
-
-}
-EXPORT_SYMBOL(wcd9xxx_clsh_init);
-
-MODULE_DESCRIPTION("WCD9XXX Common");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
deleted file mode 100644
index 5c0c4a9..0000000
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef WCD9XXX_CODEC_COMMON
-
-#define WCD9XXX_CODEC_COMMON
-
-#include "wcd9xxx-resmgr.h"
-
-#define WCD9XXX_CLSH_REQ_ENABLE true
-#define WCD9XXX_CLSH_REQ_DISABLE false
-
-#define WCD9XXX_CLSH_EVENT_PRE_DAC 0x01
-#define WCD9XXX_CLSH_EVENT_POST_PA 0x02
-
-/* Basic states for Class H state machine.
- * represented as a bit mask within a u8 data type
- * bit 0: EAR mode
- * bit 1: HPH Left mode
- * bit 2: HPH Right mode
- * bit 3: Lineout mode
- * bit 4: Ultrasound mode
- */
-#define	WCD9XXX_CLSH_STATE_IDLE 0x00
-#define	WCD9XXX_CLSH_STATE_EAR (0x01 << 0)
-#define	WCD9XXX_CLSH_STATE_HPHL (0x01 << 1)
-#define	WCD9XXX_CLSH_STATE_HPHR (0x01 << 2)
-#define	WCD9XXX_CLSH_STATE_LO (0x01 << 3)
-#define NUM_CLSH_STATES (0x01 << 4)
-
-#define	WCD9XXX_CLSAB_STATE_IDLE  0x00
-#define WCD9XXX_CLSAB_STATE_HPHL (0x01 << 1)
-#define WCD9XXX_CLSAB_STATE_HPHR (0x01 << 2)
-
-#define WCD9XXX_CLSAB_REQ_ENABLE  true
-#define WCD9XXX_CLSAB_REQ_DISABLE false
-
-#define WCD9XXX_NON_UHQA_MODE	0
-
-#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_2    0x0
-#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_3    0x1
-#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_4    0x2
-
-#define WCD9XXX_DMIC_B1_CTL_DIV_2 0x00
-#define WCD9XXX_DMIC_B1_CTL_DIV_3 0x22
-#define WCD9XXX_DMIC_B1_CTL_DIV_4 0x44
-
-#define WCD9XXX_DMIC_B2_CTL_DIV_2 0x00
-#define WCD9XXX_DMIC_B2_CTL_DIV_3 0x02
-#define WCD9XXX_DMIC_B2_CTL_DIV_4 0x04
-
-#define WCD9XXX_ANC_DMIC_X2_ON    0x1
-#define WCD9XXX_ANC_DMIC_X2_OFF   0x0
-
-/* Derived State: Bits 1 and 2 should be set for Headphone stereo */
-#define WCD9XXX_CLSH_STATE_HPH_ST (WCD9XXX_CLSH_STATE_HPHL | \
-						WCD9XXX_CLSH_STATE_HPHR)
-
-#define WCD9XXX_CLSH_STATE_HPHL_EAR (WCD9XXX_CLSH_STATE_HPHL | \
-						WCD9XXX_CLSH_STATE_EAR)
-#define WCD9XXX_CLSH_STATE_HPHR_EAR (WCD9XXX_CLSH_STATE_HPHR | \
-						WCD9XXX_CLSH_STATE_EAR)
-
-#define WCD9XXX_CLSH_STATE_HPH_ST_EAR (WCD9XXX_CLSH_STATE_HPH_ST | \
-						WCD9XXX_CLSH_STATE_EAR)
-
-#define WCD9XXX_CLSH_STATE_HPHL_LO (WCD9XXX_CLSH_STATE_HPHL | \
-						WCD9XXX_CLSH_STATE_LO)
-#define WCD9XXX_CLSH_STATE_HPHR_LO (WCD9XXX_CLSH_STATE_HPHR | \
-						WCD9XXX_CLSH_STATE_LO)
-
-#define WCD9XXX_CLSH_STATE_HPH_ST_LO (WCD9XXX_CLSH_STATE_HPH_ST | \
-						WCD9XXX_CLSH_STATE_LO)
-
-#define WCD9XXX_CLSH_STATE_EAR_LO (WCD9XXX_CLSH_STATE_EAR | \
-						WCD9XXX_CLSH_STATE_LO)
-
-#define WCD9XXX_CLSH_STATE_HPHL_EAR_LO (WCD9XXX_CLSH_STATE_HPHL | \
-						WCD9XXX_CLSH_STATE_EAR | \
-						WCD9XXX_CLSH_STATE_LO)
-#define WCD9XXX_CLSH_STATE_HPHR_EAR_LO (WCD9XXX_CLSH_STATE_HPHR | \
-						WCD9XXX_CLSH_STATE_EAR | \
-						WCD9XXX_CLSH_STATE_LO)
-#define WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO (WCD9XXX_CLSH_STATE_HPH_ST | \
-						WCD9XXX_CLSH_STATE_EAR | \
-						WCD9XXX_CLSH_STATE_LO)
-
-struct wcd9xxx_reg_mask_val {
-	u16	reg;
-	u8	mask;
-	u8	val;
-};
-
-enum ncp_fclk_level {
-	NCP_FCLK_LEVEL_8,
-	NCP_FCLK_LEVEL_5,
-	NCP_FCLK_LEVEL_MAX,
-};
-
-/* Class H data that the codec driver will maintain */
-struct wcd9xxx_clsh_cdc_data {
-	u8 state;
-	int buck_mv;
-	bool is_dynamic_vdd_cp;
-	int clsh_users;
-	int buck_users;
-	int ncp_users[NCP_FCLK_LEVEL_MAX];
-	struct wcd9xxx_resmgr *resmgr;
-};
-
-struct wcd9xxx_anc_header {
-	u32 reserved[3];
-	u32 num_anc_slots;
-};
-
-enum wcd9xxx_buck_volt {
-	WCD9XXX_CDC_BUCK_UNSUPPORTED = 0,
-	WCD9XXX_CDC_BUCK_MV_1P8 = 1800000,
-	WCD9XXX_CDC_BUCK_MV_2P15 = 2150000,
-};
-
-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 void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
-		struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
-		u8 req_state, bool req_type, u8 clsh_event);
-
-extern void wcd9xxx_enable_high_perf_mode(struct snd_soc_codec *codec,
-				struct wcd9xxx_clsh_cdc_data *clsh_d,
-				u8 uhqa_mode, u8 req_state, bool req_type);
-
-extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
-			      struct wcd9xxx_resmgr *resmgr);
-
-extern void wcd9xxx_clsh_imped_config(struct snd_soc_codec *codec,
-				  int imped);
-
-enum wcd9xxx_codec_event {
-	WCD9XXX_CODEC_EVENT_CODEC_UP = 0,
-};
-
-struct wcd9xxx_register_save_node {
-	struct list_head lh;
-	u16 reg;
-	u16 value;
-};
-
-extern int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
-					struct list_head *lh,
-					uint16_t reg, uint8_t mask,
-					uint8_t value, int delay);
-extern void wcd9xxx_restore_registers(struct snd_soc_codec *codec,
-				      struct list_head *lh);
-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,
-	SB_PGD_TX_PORTn_MULTI_CHNL_0,
-	SB_PGD_TX_PORTn_MULTI_CHNL_1,
-	SB_PGD_RX_PORTn_MULTI_CHNL_0,
-	SB_PGD_RX_PORTn_MULTI_CHNL_1,
-	AANC_FF_GAIN_ADAPTIVE,
-	AANC_FFGAIN_ADAPTIVE_EN,
-	AANC_GAIN_CONTROL,
-	SPKR_CLIP_PIPE_BANK_SEL,
-	SPKR_CLIPDET_VAL0,
-	SPKR_CLIPDET_VAL1,
-	SPKR_CLIPDET_VAL2,
-	SPKR_CLIPDET_VAL3,
-	SPKR_CLIPDET_VAL4,
-	SPKR_CLIPDET_VAL5,
-	SPKR_CLIPDET_VAL6,
-	SPKR_CLIPDET_VAL7,
-	VBAT_RELEASE_INT_DEST_SELECT_REG,
-	VBAT_RELEASE_INT_MASK_REG,
-	VBAT_RELEASE_INT_STATUS_REG,
-	VBAT_RELEASE_INT_CLEAR_REG,
-	MAD2_CLIP_INT_DEST_SELECT_REG,
-	MAD2_CLIP_INT_MASK_REG,
-	MAD2_CLIP_INT_STATUS_REG,
-	MAD2_CLIP_INT_CLEAR_REG,
-	SPKR2_CLIP_PIPE_BANK_SEL,
-	SPKR2_CLIPDET_VAL0,
-	SPKR2_CLIPDET_VAL1,
-	SPKR2_CLIPDET_VAL2,
-	SPKR2_CLIPDET_VAL3,
-	SPKR2_CLIPDET_VAL4,
-	SPKR2_CLIPDET_VAL5,
-	SPKR2_CLIPDET_VAL6,
-	SPKR2_CLIPDET_VAL7,
-	MAX_CFG_REGISTERS,
-};
-
-#endif
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
deleted file mode 100644
index 3754b57..0000000
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ /dev/null
@@ -1,5671 +0,0 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/printk.h>
-#include <linux/ratelimit.h>
-#include <linux/debugfs.h>
-#include <linux/list.h>
-#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
-#include <linux/mfd/wcd9xxx/wcd9320_registers.h>
-#include <linux/mfd/wcd9xxx/pdata.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/jack.h>
-#include <sound/tlv.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/input.h>
-#include "wcd9xxx-mbhc.h"
-#include "wcdcal-hwdep.h"
-#include "wcd9xxx-resmgr.h"
-#include "wcd9xxx-common.h"
-
-#define WCD9XXX_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
-			   SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
-			   SND_JACK_UNSUPPORTED | SND_JACK_MICROPHONE2 | \
-			   SND_JACK_MECHANICAL)
-#define WCD9XXX_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
-				  SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
-				  SND_JACK_BTN_4 | SND_JACK_BTN_5)
-
-#define NUM_DCE_PLUG_DETECT 3
-#define NUM_DCE_PLUG_INS_DETECT 5
-#define NUM_ATTEMPTS_INSERT_DETECT 25
-#define NUM_ATTEMPTS_TO_REPORT 5
-
-#define FAKE_INS_LOW 10
-#define FAKE_INS_HIGH 80
-#define FAKE_INS_HIGH_NO_SWCH 150
-#define FAKE_REMOVAL_MIN_PERIOD_MS 50
-#define FAKE_INS_DELTA_SCALED_MV 300
-
-#define BUTTON_MIN 0x8000
-#define STATUS_REL_DETECTION 0x0C
-
-#define HS_DETECT_PLUG_TIME_MS (5 * 1000)
-#define ANC_HPH_DETECT_PLUG_TIME_MS (5 * 1000)
-#define HS_DETECT_PLUG_INERVAL_MS 100
-#define SWCH_REL_DEBOUNCE_TIME_MS 50
-#define SWCH_IRQ_DEBOUNCE_TIME_US 5000
-#define BTN_RELEASE_DEBOUNCE_TIME_MS 25
-
-#define GND_MIC_SWAP_THRESHOLD 2
-#define OCP_ATTEMPT 1
-
-#define FW_READ_ATTEMPTS 15
-#define FW_READ_TIMEOUT 4000000
-
-#define BUTTON_POLLING_SUPPORTED true
-
-#define MCLK_RATE_12288KHZ 12288000
-#define MCLK_RATE_9600KHZ 9600000
-
-#define DEFAULT_DCE_STA_WAIT 55
-#define DEFAULT_DCE_WAIT 60000
-#define DEFAULT_STA_WAIT 5000
-
-#define VDDIO_MICBIAS_MV 1800
-
-#define WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US 5000
-
-#define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
-#define WCD9XXX_MUX_SWITCH_READY_WAIT_MS 50
-#define WCD9XXX_MEAS_DELTA_MAX_MV 120
-#define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
-#define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
-
-/* Threshold in milliohm used for mono/stereo
- * plug classification
- */
-#define WCD9XXX_MONO_HS_DIFF_THR 20000000
-#define WCD9XXX_MONO_HS_MIN_THR 2000
-
-/*
- * Invalid voltage range for the detection
- * of plug type with current source
- */
-#define WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV 160
-#define WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV 265
-
-/*
- * Threshold used to detect euro headset
- * with current source
- */
-#define WCD9XXX_CS_GM_SWAP_THRES_MIN_MV 10
-#define WCD9XXX_CS_GM_SWAP_THRES_MAX_MV 40
-
-#define WCD9XXX_MBHC_NSC_CS 9
-#define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
-#define WCD9XXX_GM_SWAP_THRES_MAX_MV 650
-#define WCD9XXX_THRESHOLD_MIC_THRESHOLD 200
-
-#define WCD9XXX_USLEEP_RANGE_MARGIN_US 100
-
-/* RX_HPH_CNP_WG_TIME increases by 0.24ms */
-#define WCD9XXX_WG_TIME_FACTOR_US	240
-
-#define WCD9XXX_V_CS_HS_MAX 500
-#define WCD9XXX_V_CS_NO_MIC 5
-#define WCD9XXX_MB_MEAS_DELTA_MAX_MV 80
-#define WCD9XXX_CS_MEAS_DELTA_MAX_MV 12
-
-#define WCD9XXX_ZDET_ZONE_1 80000
-#define WCD9XXX_ZDET_ZONE_2 800000
-
-#define WCD9XXX_IS_IN_ZDET_ZONE_1(x) (x < WCD9XXX_ZDET_ZONE_1 ? 1 : 0)
-#define WCD9XXX_IS_IN_ZDET_ZONE_2(x) ((x > WCD9XXX_ZDET_ZONE_1 && \
-				x < WCD9XXX_ZDET_ZONE_2) ? 1 : 0)
-#define WCD9XXX_IS_IN_ZDET_ZONE_3(x) (x > WCD9XXX_ZDET_ZONE_2 ? 1 : 0)
-#define WCD9XXX_BOX_CAR_AVRG_MIN 1
-#define WCD9XXX_BOX_CAR_AVRG_MAX 10
-
-/*
- * Need to report LINEIN if H/L impedance
- * is larger than 5K ohm
- */
-#define WCD9XXX_LINEIN_THRESHOLD 5000000
-
-static int impedance_detect_en;
-module_param(impedance_detect_en, int, 0664);
-MODULE_PARM_DESC(impedance_detect_en, "enable/disable impedance detect");
-static unsigned int z_det_box_car_avg = 1;
-module_param(z_det_box_car_avg, int, 0664);
-MODULE_PARM_DESC(z_det_box_car_avg,
-		 "Number of samples for impedance detection");
-
-static bool detect_use_vddio_switch;
-
-struct wcd9xxx_mbhc_detect {
-	u16 dce;
-	u16 sta;
-	u16 hphl_status;
-	bool swap_gnd;
-	bool vddio;
-	bool hwvalue;
-	bool mic_bias;
-	/* internal purpose from here */
-	bool _above_no_mic;
-	bool _below_v_hs_max;
-	s16 _vdces;
-	enum wcd9xxx_mbhc_plug_type _type;
-};
-
-enum meas_type {
-	STA = 0,
-	DCE,
-};
-
-enum {
-	MBHC_USE_HPHL_TRIGGER = 1,
-	MBHC_USE_MB_TRIGGER = 2
-};
-
-/*
- * Flags to track of PA and DAC state.
- * PA and DAC should be tracked separately as AUXPGA loopback requires
- * only PA to be turned on without DAC being on.
- */
-enum pa_dac_ack_flags {
-	WCD9XXX_HPHL_PA_OFF_ACK = 0,
-	WCD9XXX_HPHR_PA_OFF_ACK,
-	WCD9XXX_HPHL_DAC_OFF_ACK,
-	WCD9XXX_HPHR_DAC_OFF_ACK
-};
-
-enum wcd9xxx_current_v_idx {
-	WCD9XXX_CURRENT_V_INS_H,
-	WCD9XXX_CURRENT_V_INS_HU,
-	WCD9XXX_CURRENT_V_B1_H,
-	WCD9XXX_CURRENT_V_B1_HU,
-	WCD9XXX_CURRENT_V_BR_H,
-};
-
-static int wcd9xxx_detect_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
-				    uint32_t *zr);
-static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
-				 const enum wcd9xxx_current_v_idx idx);
-static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z,
-			  struct mbhc_micbias_regs *micb_regs,
-			  bool norel);
-
-static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc);
-
-static u16 wcd9xxx_codec_v_sta_dce(struct wcd9xxx_mbhc *mbhc,
-				   enum meas_type dce, s16 vin_mv,
-				   bool cs_enable);
-
-static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
-{
-	return snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_EN_CTL) & 0x1;
-}
-
-static void wcd9xxx_turn_onoff_override(struct wcd9xxx_mbhc *mbhc, bool on)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-			    0x04, on ? 0x04 : 0x00);
-}
-
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_pause_hs_polling(struct wcd9xxx_mbhc *mbhc)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	pr_debug("%s: enter\n", __func__);
-	if (!mbhc->polling_active) {
-		pr_debug("polling not active, nothing to pause\n");
-		return;
-	}
-
-	/* Soft reset MBHC block */
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
-	pr_debug("%s: leave\n", __func__);
-}
-
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_start_hs_polling(struct wcd9xxx_mbhc *mbhc)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	int mbhc_state = mbhc->mbhc_state;
-
-	pr_debug("%s: enter\n", __func__);
-	if (!mbhc->polling_active) {
-		pr_debug("Polling is not active, do not start polling\n");
-		return;
-	}
-
-	/*
-	 * setup internal micbias if codec uses internal micbias for
-	 * headset detection
-	 */
-	if (mbhc->mbhc_cfg->use_int_rbias) {
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
-			mbhc->mbhc_cb->setup_int_rbias(codec, true);
-		else
-			pr_err("%s: internal bias requested but codec did not provide callback\n",
-				__func__);
-	}
-
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
-		mbhc->mbhc_cb->enable_mux_bias_block(codec);
-	else
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				    0x80, 0x80);
-
-	if (!mbhc->no_mic_headset_override &&
-	    mbhc_state == MBHC_STATE_POTENTIAL) {
-		pr_debug("%s recovering MBHC state machine\n", __func__);
-		mbhc->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
-		/* set to max button press threshold */
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL, 0x7F);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, 0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL, 0x7F);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, 0xFF);
-		/* set to max */
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
-	}
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
-	pr_debug("%s: leave\n", __func__);
-}
-
-static int __wcd9xxx_resmgr_get_k_val(struct wcd9xxx_mbhc *mbhc,
-		unsigned int cfilt_mv)
-{
-	return wcd9xxx_resmgr_get_k_val(mbhc->resmgr, cfilt_mv);
-}
-
-/*
- * called under codec_resource_lock acquisition
- * return old status
- */
-static bool __wcd9xxx_switch_micbias(struct wcd9xxx_mbhc *mbhc,
-				     int vddio_switch, bool restartpolling,
-				     bool checkpolling)
-{
-	bool ret;
-	int cfilt_k_val;
-	bool override;
-	struct snd_soc_codec *codec;
-	struct mbhc_internal_cal_data *d = &mbhc->mbhc_data;
-
-	codec = mbhc->codec;
-
-	if (mbhc->micbias_enable) {
-		pr_debug("%s: micbias is already on\n", __func__);
-		ret = mbhc->mbhc_micbias_switched;
-		return ret;
-	}
-
-	ret = mbhc->mbhc_micbias_switched;
-	if (vddio_switch && !mbhc->mbhc_micbias_switched &&
-	    (!checkpolling || mbhc->polling_active)) {
-		if (restartpolling)
-			wcd9xxx_pause_hs_polling(mbhc);
-		override = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
-			   0x04;
-		if (!override)
-			wcd9xxx_turn_onoff_override(mbhc, true);
-
-		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL,
-				    0x10, 0x00);
-		snd_soc_update_bits(codec, WCD9XXX_A_LDO_H_MODE_1,
-				    0x20, 0x00);
-		/* Adjust threshold if Mic Bias voltage changes */
-		if (d->micb_mv != VDDIO_MICBIAS_MV) {
-			cfilt_k_val = __wcd9xxx_resmgr_get_k_val(mbhc,
-							      VDDIO_MICBIAS_MV);
-			usleep_range(10000, 10100);
-			snd_soc_update_bits(codec,
-					mbhc->mbhc_bias_regs.cfilt_val,
-					0xFC, (cfilt_k_val << 2));
-			usleep_range(10000, 10100);
-			/* Threshods for insertion/removal */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
-				      d->v_ins_hu[MBHC_V_IDX_VDDIO] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
-				      (d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
-				      0xFF);
-
-			if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
-				/* Threshods for button press */
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
-					d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-					(d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
-					0xFF);
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
-					d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-					(d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
-					0xFF);
-				/* Threshods for button release */
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
-					d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-					(d->v_brh[MBHC_V_IDX_VDDIO] >> 8) &
-					0xFF);
-			}
-			pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
-				 __func__);
-		}
-
-		/* Enable MIC BIAS Switch to VDDIO */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
-				    0x80, 0x80);
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
-				    0x10, 0x00);
-		if (!override)
-			wcd9xxx_turn_onoff_override(mbhc, false);
-		if (restartpolling)
-			wcd9xxx_start_hs_polling(mbhc);
-
-		mbhc->mbhc_micbias_switched = true;
-		pr_debug("%s: VDDIO switch enabled\n", __func__);
-	} else if (!vddio_switch && mbhc->mbhc_micbias_switched) {
-		if ((!checkpolling || mbhc->polling_active) &&
-		    restartpolling)
-			wcd9xxx_pause_hs_polling(mbhc);
-
-			snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL,
-					    0x10, 0x10);
-			snd_soc_update_bits(codec, WCD9XXX_A_LDO_H_MODE_1,
-					    0x20, 0x20);
-		/* Reprogram thresholds */
-		if (d->micb_mv != VDDIO_MICBIAS_MV) {
-			cfilt_k_val =
-			    __wcd9xxx_resmgr_get_k_val(mbhc,
-						     d->micb_mv);
-			snd_soc_update_bits(codec,
-					mbhc->mbhc_bias_regs.cfilt_val,
-					0xFC, (cfilt_k_val << 2));
-			usleep_range(10000, 10100);
-			/* Revert threshods for insertion/removal */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
-					d->v_ins_hu[MBHC_V_IDX_CFILT] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
-					(d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
-					0xFF);
-			if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
-				/* Revert threshods for button press */
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
-					d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-					(d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
-					0xFF);
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
-					d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-					(d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
-					0xFF);
-				/* Revert threshods for button release */
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
-					d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
-				snd_soc_write(codec,
-					WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-					(d->v_brh[MBHC_V_IDX_CFILT] >> 8) &
-					0xFF);
-			}
-			pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
-					__func__);
-		}
-
-		/* Disable MIC BIAS Switch to VDDIO */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x80,
-				    0x00);
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x10,
-				    0x00);
-
-		if ((!checkpolling || mbhc->polling_active) && restartpolling)
-			wcd9xxx_start_hs_polling(mbhc);
-
-		mbhc->mbhc_micbias_switched = false;
-		pr_debug("%s: VDDIO switch disabled\n", __func__);
-	}
-
-	return ret;
-}
-
-static void wcd9xxx_switch_micbias(struct wcd9xxx_mbhc *mbhc, int vddio_switch)
-{
-	__wcd9xxx_switch_micbias(mbhc, vddio_switch, true, true);
-}
-
-static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
-				 const enum wcd9xxx_current_v_idx idx)
-{
-	enum mbhc_v_index vidx;
-	s16 ret = -EINVAL;
-
-	if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
-	    mbhc->mbhc_micbias_switched)
-		vidx = MBHC_V_IDX_VDDIO;
-	else
-		vidx = MBHC_V_IDX_CFILT;
-
-	switch (idx) {
-	case WCD9XXX_CURRENT_V_INS_H:
-		ret = (s16)mbhc->mbhc_data.v_ins_h[vidx];
-		break;
-	case WCD9XXX_CURRENT_V_INS_HU:
-		ret = (s16)mbhc->mbhc_data.v_ins_hu[vidx];
-		break;
-	case WCD9XXX_CURRENT_V_B1_H:
-		ret = (s16)mbhc->mbhc_data.v_b1_h[vidx];
-		break;
-	case WCD9XXX_CURRENT_V_B1_HU:
-		ret = (s16)mbhc->mbhc_data.v_b1_hu[vidx];
-		break;
-	case WCD9XXX_CURRENT_V_BR_H:
-		ret = (s16)mbhc->mbhc_data.v_brh[vidx];
-		break;
-	}
-
-	return ret;
-}
-
-void *wcd9xxx_mbhc_cal_btn_det_mp(
-			    const struct wcd9xxx_mbhc_btn_detect_cfg *btn_det,
-			    const enum wcd9xxx_mbhc_btn_det_mem mem)
-{
-	void *ret = (void *)&btn_det->_v_btn_low;
-
-	switch (mem) {
-	case MBHC_BTN_DET_GAIN:
-		ret += sizeof(btn_det->_n_cic);
-		/* fallthrough */
-	case MBHC_BTN_DET_N_CIC:
-		ret += sizeof(btn_det->_n_ready);
-		/* fallthrough */
-	case MBHC_BTN_DET_N_READY:
-		ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
-		/* fallthrough */
-	case MBHC_BTN_DET_V_BTN_HIGH:
-		ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
-		/* fallthrough */
-	case MBHC_BTN_DET_V_BTN_LOW:
-		/* do nothing */
-		break;
-	default:
-		ret = NULL;
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL(wcd9xxx_mbhc_cal_btn_det_mp);
-
-static void wcd9xxx_calibrate_hs_polling(struct wcd9xxx_mbhc *mbhc)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	const s16 v_ins_hu = wcd9xxx_get_current_v(mbhc,
-						   WCD9XXX_CURRENT_V_INS_HU);
-	const s16 v_b1_hu = wcd9xxx_get_current_v(mbhc,
-						  WCD9XXX_CURRENT_V_B1_HU);
-	const s16 v_b1_h = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
-	const s16 v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
-		      (v_ins_hu >> 8) & 0xFF);
-
-	if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
-				0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-				(v_b1_hu >> 8) & 0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h &
-				0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-				(v_b1_h >> 8) & 0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
-				0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-				(v_brh >> 8) & 0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
-				mbhc->mbhc_data.v_brl & 0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
-				(mbhc->mbhc_data.v_brl >> 8) & 0xFF);
-	}
-}
-
-static void wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
-					    bool fast)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	struct wcd9xxx_cfilt_mode cfilt_mode;
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->switch_cfilt_mode) {
-		cfilt_mode = mbhc->mbhc_cb->switch_cfilt_mode(mbhc, fast);
-	} else {
-		if (fast)
-			cfilt_mode.reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
-		else
-			cfilt_mode.reg_mode_val = WCD9XXX_CFILT_SLOW_MODE;
-
-		cfilt_mode.reg_mask = 0x40;
-		cfilt_mode.cur_mode_val =
-		    snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x40;
-	}
-
-	if (cfilt_mode.cur_mode_val
-			!= cfilt_mode.reg_mode_val) {
-		if (mbhc->polling_active && wcd9xxx_mbhc_polling(mbhc))
-			wcd9xxx_pause_hs_polling(mbhc);
-		snd_soc_update_bits(codec,
-				    mbhc->mbhc_bias_regs.cfilt_ctl,
-					cfilt_mode.reg_mask,
-					cfilt_mode.reg_mode_val);
-		if (mbhc->polling_active && wcd9xxx_mbhc_polling(mbhc))
-			wcd9xxx_start_hs_polling(mbhc);
-		pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
-			cfilt_mode.cur_mode_val,
-			cfilt_mode.reg_mode_val);
-	} else {
-		pr_debug("%s: CFILT Value is already %x\n",
-			 __func__, cfilt_mode.cur_mode_val);
-	}
-}
-
-static void wcd9xxx_jack_report(struct wcd9xxx_mbhc *mbhc,
-				struct snd_soc_jack *jack, int status, int mask)
-{
-	if (jack == &mbhc->headset_jack) {
-		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
-						WCD9XXX_COND_HPH_MIC,
-						status & SND_JACK_MICROPHONE);
-		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
-						WCD9XXX_COND_HPH,
-						status & SND_JACK_HEADPHONE);
-	}
-
-	snd_soc_jack_report(jack, status, mask);
-}
-
-static void __hphocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status,
-				int irq)
-{
-	struct snd_soc_codec *codec;
-
-	pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
-	codec = mbhc->codec;
-	if (mbhc->hph_status & jack_status) {
-		mbhc->hph_status &= ~jack_status;
-		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
-				    mbhc->hph_status, WCD9XXX_JACK_MASK);
-		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
-				    0x00);
-		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
-				    0x10);
-		/*
-		 * reset retry counter as PA is turned off signifying
-		 * start of new OCP detection session
-		 */
-		if (mbhc->intr_ids->hph_left_ocp)
-			mbhc->hphlocp_cnt = 0;
-		else
-			mbhc->hphrocp_cnt = 0;
-		wcd9xxx_enable_irq(mbhc->resmgr->core_res, irq);
-	}
-}
-
-static void hphrocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status)
-{
-	__hphocp_off_report(mbhc, SND_JACK_OC_HPHR,
-			    mbhc->intr_ids->hph_right_ocp);
-}
-
-static void hphlocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status)
-{
-	__hphocp_off_report(mbhc, SND_JACK_OC_HPHL,
-			    mbhc->intr_ids->hph_left_ocp);
-}
-
-static void wcd9xxx_get_mbhc_micbias_regs(struct wcd9xxx_mbhc *mbhc,
-				enum wcd9xxx_mbhc_micbias_type mb_type)
-{
-	unsigned int cfilt;
-	struct wcd9xxx_micbias_setting *micbias_pdata =
-		mbhc->resmgr->micbias_pdata;
-	struct mbhc_micbias_regs *micbias_regs;
-	enum wcd9xxx_micbias_num mb_num;
-
-	if (mb_type == MBHC_ANC_MIC_MB) {
-		micbias_regs = &mbhc->mbhc_anc_bias_regs;
-		mb_num = mbhc->mbhc_cfg->anc_micbias;
-	} else {
-		micbias_regs = &mbhc->mbhc_bias_regs;
-		mb_num = mbhc->mbhc_cfg->micbias;
-	}
-
-	switch (mb_num) {
-	case MBHC_MICBIAS1:
-		cfilt = micbias_pdata->bias1_cfilt_sel;
-		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
-		micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
-		micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
-		break;
-	case MBHC_MICBIAS2:
-		cfilt = micbias_pdata->bias2_cfilt_sel;
-		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_2_MBHC;
-		micbias_regs->int_rbias = WCD9XXX_A_MICB_2_INT_RBIAS;
-		micbias_regs->ctl_reg = WCD9XXX_A_MICB_2_CTL;
-		break;
-	case MBHC_MICBIAS3:
-		cfilt = micbias_pdata->bias3_cfilt_sel;
-		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_3_MBHC;
-		micbias_regs->int_rbias = WCD9XXX_A_MICB_3_INT_RBIAS;
-		micbias_regs->ctl_reg = WCD9XXX_A_MICB_3_CTL;
-		break;
-	case MBHC_MICBIAS4:
-		cfilt = micbias_pdata->bias4_cfilt_sel;
-		micbias_regs->mbhc_reg = mbhc->resmgr->reg_addr->micb_4_mbhc;
-		micbias_regs->int_rbias =
-		    mbhc->resmgr->reg_addr->micb_4_int_rbias;
-		micbias_regs->ctl_reg = mbhc->resmgr->reg_addr->micb_4_ctl;
-		break;
-	default:
-		/* Should never reach here */
-		pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
-		return;
-	}
-
-	micbias_regs->cfilt_sel = cfilt;
-
-	switch (cfilt) {
-	case WCD9XXX_CFILT1_SEL:
-		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
-		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
-		break;
-	case WCD9XXX_CFILT2_SEL:
-		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_2_VAL;
-		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_2_CTL;
-		break;
-	case WCD9XXX_CFILT3_SEL:
-		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_3_VAL;
-		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_3_CTL;
-		break;
-	}
-
-	if (mb_type == MBHC_PRIMARY_MIC_MB) {
-		switch (cfilt) {
-		case WCD9XXX_CFILT1_SEL:
-			mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt1_mv;
-			break;
-		case WCD9XXX_CFILT2_SEL:
-			mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt2_mv;
-			break;
-		case WCD9XXX_CFILT3_SEL:
-			mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt3_mv;
-			break;
-		}
-	}
-
-}
-
-static void wcd9xxx_clr_and_turnon_hph_padac(struct wcd9xxx_mbhc *mbhc)
-{
-	bool pa_turned_on = false;
-	struct snd_soc_codec *codec = mbhc->codec;
-	u8 wg_time;
-
-	wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME);
-	wg_time += 1;
-
-	if (test_and_clear_bit(WCD9XXX_HPHR_DAC_OFF_ACK,
-			       &mbhc->hph_pa_dac_state)) {
-		pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
-		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_DAC_CTL,
-				    0xC0, 0xC0);
-	}
-	if (test_and_clear_bit(WCD9XXX_HPHL_DAC_OFF_ACK,
-				&mbhc->hph_pa_dac_state)) {
-		pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
-		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL,
-				    0x80, 0x80);
-	}
-
-	if (test_and_clear_bit(WCD9XXX_HPHR_PA_OFF_ACK,
-			       &mbhc->hph_pa_dac_state)) {
-		pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
-		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x10,
-				    1 << 4);
-		pa_turned_on = true;
-	}
-	if (test_and_clear_bit(WCD9XXX_HPHL_PA_OFF_ACK,
-			       &mbhc->hph_pa_dac_state)) {
-		pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
-		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x20, 1
-				    << 5);
-		pa_turned_on = true;
-	}
-
-	if (pa_turned_on) {
-		pr_debug("%s: PA was turned on by MBHC and not by DAPM\n",
-			 __func__);
-		usleep_range(wg_time * 1000, wg_time * 1000 + 50);
-	}
-}
-
-static int wcd9xxx_cancel_btn_work(struct wcd9xxx_mbhc *mbhc)
-{
-	int r;
-
-	r = cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
-	if (r)
-		/* if scheduled mbhc.mbhc_btn_dwork is canceled from here,
-		 * we have to unlock from here instead btn_work
-		 */
-		wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
-	return r;
-}
-
-static bool wcd9xxx_is_hph_dac_on(struct snd_soc_codec *codec, int left)
-{
-	u8 hph_reg_val = 0;
-
-	if (left)
-		hph_reg_val = snd_soc_read(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL);
-	else
-		hph_reg_val = snd_soc_read(codec, WCD9XXX_A_RX_HPH_R_DAC_CTL);
-
-	return (hph_reg_val & 0xC0) ? true : false;
-}
-
-static bool wcd9xxx_is_hph_pa_on(struct snd_soc_codec *codec)
-{
-	u8 hph_reg_val = 0;
-
-	hph_reg_val = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_EN);
-
-	return (hph_reg_val & 0x30) ? true : false;
-}
-
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_set_and_turnoff_hph_padac(struct wcd9xxx_mbhc *mbhc)
-{
-	u8 wg_time;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME);
-	wg_time += 1;
-
-	/* If headphone PA is on, check if userspace receives
-	 * removal event to sync-up PA's state
-	 */
-	if (wcd9xxx_is_hph_pa_on(codec)) {
-		pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
-		set_bit(WCD9XXX_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
-		set_bit(WCD9XXX_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
-	} else {
-		pr_debug("%s PA is off\n", __func__);
-	}
-
-	if (wcd9xxx_is_hph_dac_on(codec, 1))
-		set_bit(WCD9XXX_HPHL_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
-	if (wcd9xxx_is_hph_dac_on(codec, 0))
-		set_bit(WCD9XXX_HPHR_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30, 0x00);
-	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL, 0x80, 0x00);
-	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xC0, 0x00);
-	usleep_range(wg_time * 1000, wg_time * 1000 + 50);
-}
-
-static void wcd9xxx_insert_detect_setup(struct wcd9xxx_mbhc *mbhc, bool ins)
-{
-	if (!mbhc->mbhc_cfg->insert_detect)
-		return;
-	pr_debug("%s: Setting up %s detection\n", __func__,
-		 ins ? "insert" : "removal");
-	/* Disable detection to avoid glitch */
-	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 0);
-	if (mbhc->mbhc_cfg->gpio_level_insert)
-		snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
-			      (0x68 | (ins ? (1 << 1) : 0)));
-	else
-		snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
-			      (0x6C | (ins ? (1 << 1) : 0)));
-	/* Re-enable detection */
-	snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 1);
-}
-
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_report_plug(struct wcd9xxx_mbhc *mbhc, int insertion,
-				enum snd_jack_types jack_type)
-{
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	pr_debug("%s: enter insertion %d hph_status %x\n",
-		 __func__, insertion, mbhc->hph_status);
-	if (!insertion) {
-		/* Report removal */
-		mbhc->hph_status &= ~jack_type;
-		/*
-		 * cancel possibly scheduled btn work and
-		 * report release if we reported button press
-		 */
-		if (wcd9xxx_cancel_btn_work(mbhc))
-			pr_debug("%s: button press is canceled\n", __func__);
-		else if (mbhc->buttons_pressed) {
-			pr_debug("%s: release of button press%d\n",
-				 __func__, jack_type);
-			wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
-					    mbhc->buttons_pressed);
-			mbhc->buttons_pressed &=
-				~WCD9XXX_JACK_BUTTON_MASK;
-		}
-
-		if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
-			pr_debug("%s: Disabling micbias\n", __func__);
-			mbhc->micbias_enable = false;
-			mbhc->micbias_enable_cb(mbhc->codec, false,
-						mbhc->mbhc_cfg->micbias);
-		}
-		mbhc->zl = mbhc->zr = 0;
-		mbhc->hph_type = MBHC_HPH_NONE;
-		pr_debug("%s: Reporting removal %d(%x)\n", __func__,
-			 jack_type, mbhc->hph_status);
-		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
-				    WCD9XXX_JACK_MASK);
-		wcd9xxx_set_and_turnoff_hph_padac(mbhc);
-		hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
-		hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
-		mbhc->current_plug = PLUG_TYPE_NONE;
-		mbhc->polling_active = false;
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->hph_auto_pulldown_ctrl)
-			mbhc->mbhc_cb->hph_auto_pulldown_ctrl(mbhc->codec,
-								false);
-	} else {
-		/*
-		 * Report removal of current jack type.
-		 * Headphone to headset shouldn't report headphone
-		 * removal.
-		 */
-		if (mbhc->mbhc_cfg->detect_extn_cable &&
-		    !(mbhc->current_plug == PLUG_TYPE_HEADPHONE &&
-		      jack_type == SND_JACK_HEADSET) &&
-		    (mbhc->hph_status && mbhc->hph_status != jack_type)) {
-			if (mbhc->micbias_enable && mbhc->micbias_enable_cb &&
-			    mbhc->hph_status == SND_JACK_HEADSET) {
-				pr_debug("%s: Disabling micbias\n", __func__);
-				mbhc->micbias_enable = false;
-				mbhc->micbias_enable_cb(mbhc->codec, false,
-						mbhc->mbhc_cfg->micbias);
-			}
-
-			pr_debug("%s: Reporting removal (%x)\n",
-				 __func__, mbhc->hph_status);
-			mbhc->zl = mbhc->zr = 0;
-			wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
-					    0, WCD9XXX_JACK_MASK);
-			mbhc->hph_status &= ~(SND_JACK_HEADSET |
-						SND_JACK_LINEOUT |
-						SND_JACK_ANC_HEADPHONE |
-						SND_JACK_UNSUPPORTED);
-			if (mbhc->mbhc_cb &&
-				 mbhc->mbhc_cb->hph_auto_pulldown_ctrl)
-				mbhc->mbhc_cb->hph_auto_pulldown_ctrl(
-								mbhc->codec,
-								false);
-		}
-
-		/* Report insertion */
-		if (jack_type == SND_JACK_HEADPHONE) {
-			mbhc->current_plug = PLUG_TYPE_HEADPHONE;
-		} else if (jack_type == SND_JACK_UNSUPPORTED) {
-			mbhc->current_plug = PLUG_TYPE_GND_MIC_SWAP;
-		} else if (jack_type == SND_JACK_HEADSET) {
-			mbhc->polling_active = BUTTON_POLLING_SUPPORTED;
-			mbhc->current_plug = PLUG_TYPE_HEADSET;
-			mbhc->update_z = true;
-		} else if (jack_type == SND_JACK_LINEOUT) {
-			mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
-		} else if (jack_type == SND_JACK_ANC_HEADPHONE) {
-			mbhc->polling_active = BUTTON_POLLING_SUPPORTED;
-			mbhc->current_plug = PLUG_TYPE_ANC_HEADPHONE;
-		}
-
-		if (mbhc->impedance_detect && impedance_detect_en) {
-			wcd9xxx_detect_impedance(mbhc,
-					&mbhc->zl, &mbhc->zr);
-			if ((mbhc->zl > WCD9XXX_LINEIN_THRESHOLD) &&
-				(mbhc->zr > WCD9XXX_LINEIN_THRESHOLD)) {
-				jack_type = SND_JACK_LINEOUT;
-				mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
-				pr_debug("%s: Replace with SND_JACK_LINEOUT\n",
-				__func__);
-			}
-		}
-
-		mbhc->hph_status |= jack_type;
-
-		if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
-			pr_debug("%s: Enabling micbias\n", __func__);
-			mbhc->micbias_enable_cb(mbhc->codec, true,
-						mbhc->mbhc_cfg->micbias);
-		}
-
-		pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
-			 jack_type, mbhc->hph_status);
-		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
-				    (mbhc->hph_status | SND_JACK_MECHANICAL),
-				    WCD9XXX_JACK_MASK);
-		/*
-		 * if PA is already on, switch micbias
-		 * source to VDDIO
-		 */
-		if (((mbhc->current_plug == PLUG_TYPE_HEADSET) ||
-		     (mbhc->current_plug == PLUG_TYPE_ANC_HEADPHONE)) &&
-		    ((mbhc->event_state & (1 << MBHC_EVENT_PA_HPHL |
-			1 << MBHC_EVENT_PA_HPHR))))
-			__wcd9xxx_switch_micbias(mbhc, 1, false,
-						 false);
-		wcd9xxx_clr_and_turnon_hph_padac(mbhc);
-	}
-	/* Setup insert detect */
-	wcd9xxx_insert_detect_setup(mbhc, !insertion);
-
-	pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status);
-}
-
-/* should be called under interrupt context that hold suspend */
-static void wcd9xxx_schedule_hs_detect_plug(struct wcd9xxx_mbhc *mbhc,
-					    struct work_struct *work)
-{
-	pr_debug("%s: scheduling wcd9xxx_correct_swch_plug\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-	mbhc->hs_detect_work_stop = false;
-	wcd9xxx_lock_sleep(mbhc->resmgr->core_res);
-	schedule_work(work);
-}
-
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_cancel_hs_detect_plug(struct wcd9xxx_mbhc *mbhc,
-					 struct work_struct *work)
-{
-	pr_debug("%s: Canceling correct_plug_swch\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-	mbhc->hs_detect_work_stop = true;
-
-	/* Make sure mbhc state update complete before unlocking. */
-	wmb();
-	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	if (cancel_work_sync(work)) {
-		pr_debug("%s: correct_plug_swch is canceled\n",
-			 __func__);
-		wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
-	}
-	WCD9XXX_BCL_LOCK(mbhc->resmgr);
-}
-
-static s16 scale_v_micb_vddio(struct wcd9xxx_mbhc *mbhc, int v, bool tovddio)
-{
-	int r;
-	int vddio_k, mb_k;
-
-	vddio_k = __wcd9xxx_resmgr_get_k_val(mbhc, VDDIO_MICBIAS_MV);
-	mb_k = __wcd9xxx_resmgr_get_k_val(mbhc, mbhc->mbhc_data.micb_mv);
-	if (tovddio)
-		r = v * (vddio_k + 4) / (mb_k + 4);
-	else
-		r = v * (mb_k + 4) / (vddio_k + 4);
-	return r;
-}
-
-static s16 wcd9xxx_get_current_v_hs_max(struct wcd9xxx_mbhc *mbhc)
-{
-	s16 v_hs_max;
-	struct wcd9xxx_mbhc_plug_type_cfg *plug_type;
-
-	plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
-	if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
-	    mbhc->mbhc_micbias_switched)
-		v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max, true);
-	else
-		v_hs_max = plug_type->v_hs_max;
-	return v_hs_max;
-}
-
-static short wcd9xxx_read_sta_result(struct snd_soc_codec *codec)
-{
-	u8 bias_msb, bias_lsb;
-	short bias_value;
-
-	bias_msb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B3_STATUS);
-	bias_lsb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B2_STATUS);
-	bias_value = (bias_msb << 8) | bias_lsb;
-	return bias_value;
-}
-
-static short wcd9xxx_read_dce_result(struct snd_soc_codec *codec)
-{
-	u8 bias_msb, bias_lsb;
-	short bias_value;
-
-	bias_msb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B5_STATUS);
-	bias_lsb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B4_STATUS);
-	bias_value = (bias_msb << 8) | bias_lsb;
-	return bias_value;
-}
-
-static void wcd9xxx_turn_onoff_rel_detection(struct snd_soc_codec *codec,
-					     bool on)
-{
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
-}
-
-static short __wcd9xxx_codec_sta_dce(struct wcd9xxx_mbhc *mbhc, int dce,
-				     bool override_bypass, bool noreldetection)
-{
-	short bias_value;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	wcd9xxx_disable_irq(mbhc->resmgr->core_res,
-			    mbhc->intr_ids->dce_est_complete);
-	if (noreldetection)
-		wcd9xxx_turn_onoff_rel_detection(codec, false);
-
-	if (mbhc->mbhc_cfg->do_recalibration)
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
-				    0x0);
-	/* Turn on the override */
-	if (!override_bypass)
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
-	if (dce) {
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
-				    0x8);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
-				    0x0);
-		if (mbhc->mbhc_cfg->do_recalibration)
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
-					    0x2, 0x2);
-		usleep_range(mbhc->mbhc_data.t_sta_dce,
-			     mbhc->mbhc_data.t_sta_dce + 50);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
-		usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce + 50);
-		bias_value = wcd9xxx_read_dce_result(codec);
-	} else {
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
-				    0x8);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
-				    0x0);
-		if (mbhc->mbhc_cfg->do_recalibration)
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
-					    0x2, 0x2);
-		usleep_range(mbhc->mbhc_data.t_sta_dce,
-			     mbhc->mbhc_data.t_sta_dce + 50);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
-		usleep_range(mbhc->mbhc_data.t_sta,
-			     mbhc->mbhc_data.t_sta + 50);
-		bias_value = wcd9xxx_read_sta_result(codec);
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
-				    0x8);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x0);
-	}
-	/* Turn off the override after measuring mic voltage */
-	if (!override_bypass)
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04,
-				    0x00);
-
-	if (noreldetection)
-		wcd9xxx_turn_onoff_rel_detection(codec, true);
-	wcd9xxx_enable_irq(mbhc->resmgr->core_res,
-			   mbhc->intr_ids->dce_est_complete);
-
-	return bias_value;
-}
-
-static short wcd9xxx_codec_sta_dce(struct wcd9xxx_mbhc *mbhc, int dce,
-				   bool norel)
-{
-	bool override_bypass;
-
-	/* Bypass override if it is already enabled */
-	override_bypass = (snd_soc_read(mbhc->codec,
-					WCD9XXX_A_CDC_MBHC_B1_CTL) &
-			   0x04) ? true : false;
-
-	return __wcd9xxx_codec_sta_dce(mbhc, dce, override_bypass, norel);
-}
-
-static s32 __wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
-				     u16 bias_value, s16 z, u32 micb_mv)
-{
-	s16 value, mb;
-	s32 mv = 0;
-
-	value = bias_value;
-	if (dce) {
-		mb = (mbhc->mbhc_data.dce_mb);
-		if (mb - z)
-			mv = (value - z) * (s32)micb_mv / (mb - z);
-	} else {
-		mb = (mbhc->mbhc_data.sta_mb);
-		if (mb - z)
-			mv = (value - z) * (s32)micb_mv / (mb - z);
-	}
-
-	return mv;
-}
-
-static s32 wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
-				   u16 bias_value)
-{
-	s16 z;
-
-	z = dce ? (s16)mbhc->mbhc_data.dce_z : (s16)mbhc->mbhc_data.sta_z;
-	return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z,
-					 mbhc->mbhc_data.micb_mv);
-}
-
-/* To enable/disable bandgap and RC oscillator */
-static void wcd9xxx_mbhc_ctrl_clk_bandgap(struct wcd9xxx_mbhc *mbhc,
-		bool enable)
-{
-	if (enable) {
-		WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-		wcd9xxx_resmgr_get_bandgap(mbhc->resmgr,
-				WCD9XXX_BANDGAP_AUDIO_MODE);
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->codec_rco_ctrl) {
-			WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
-			mbhc->mbhc_cb->codec_rco_ctrl(mbhc->codec, true);
-		} else {
-			wcd9xxx_resmgr_get_clk_block(mbhc->resmgr,
-					WCD9XXX_CLK_RCO);
-			WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
-		}
-	} else {
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->codec_rco_ctrl) {
-			mbhc->mbhc_cb->codec_rco_ctrl(mbhc->codec, false);
-			WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-		} else {
-			WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-			wcd9xxx_resmgr_put_clk_block(mbhc->resmgr,
-					WCD9XXX_CLK_RCO);
-		}
-		wcd9xxx_resmgr_put_bandgap(mbhc->resmgr,
-				WCD9XXX_BANDGAP_AUDIO_MODE);
-		WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
-	}
-}
-
-/* called only from interrupt which is under codec_resource_lock acquisition */
-static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc,
-				struct mbhc_micbias_regs *mbhc_micb_regs,
-				bool is_cs_enable)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	short bias_value;
-	u8 cfilt_mode;
-
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	pr_debug("%s: enter\n", __func__);
-	if (!mbhc->mbhc_cfg->calibration) {
-		pr_err("%s: Error, no calibration exists\n", __func__);
-		return -ENODEV;
-	}
-
-	/* Enable external voltage source to micbias if present */
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
-		mbhc->mbhc_cb->enable_mb_source(codec, true, true);
-
-	/*
-	 * setup internal micbias if codec uses internal micbias for
-	 * headset detection
-	 */
-	if (mbhc->mbhc_cfg->use_int_rbias) {
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
-			mbhc->mbhc_cb->setup_int_rbias(codec, true);
-	else
-		pr_err("%s: internal bias requested but codec did not provide callback\n",
-			__func__);
-	}
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x01);
-
-	/* Make sure CFILT is in fast mode, save current mode */
-	cfilt_mode = snd_soc_read(codec, mbhc_micb_regs->cfilt_ctl);
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
-		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
-	else
-		snd_soc_update_bits(codec, mbhc_micb_regs->cfilt_ctl,
-				    0x70, 0x00);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-		      mbhc->scaling_mux_in);
-	pr_debug("%s:  scaling_mux_input: %d\n", __func__,
-						 mbhc->scaling_mux_in);
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
-		mbhc->mbhc_cb->enable_mux_bias_block(codec);
-	else
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				    0x80, 0x80);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x80, 0x80);
-	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x1F, 0x1C);
-	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x80, 0x00);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
-
-	if (!mbhc->mbhc_cfg->do_recalibration) {
-		if (!is_cs_enable)
-			wcd9xxx_calibrate_hs_polling(mbhc);
-	}
-
-	/* don't flip override */
-	bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
-	snd_soc_write(codec, mbhc_micb_regs->cfilt_ctl, cfilt_mode);
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
-
-	return bias_value;
-}
-
-static void wcd9xxx_recalibrate(struct wcd9xxx_mbhc *mbhc,
-				struct mbhc_micbias_regs *mbhc_micb_regs,
-				bool is_cs_enable)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	s16 reg;
-	int change;
-	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
-	s16 sta_z = 0, dce_z = 0;
-
-	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
-
-	if (mbhc->mbhc_cfg->do_recalibration) {
-		/* recalibrate dce_z and sta_z */
-		reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
-		change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-					     0x78, btn_det->mbhc_nsc << 3);
-		wcd9xxx_get_z(mbhc, &dce_z, &sta_z, mbhc_micb_regs, true);
-		if (change)
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
-		if (dce_z && sta_z) {
-			pr_debug("%s: sta_z 0x%x -> 0x%x, dce_z 0x%x -> 0x%x\n",
-				 __func__,
-				 mbhc->mbhc_data.sta_z, sta_z & 0xffff,
-				 mbhc->mbhc_data.dce_z, dce_z & 0xffff);
-			mbhc->mbhc_data.dce_z = dce_z;
-			mbhc->mbhc_data.sta_z = sta_z;
-			wcd9xxx_mbhc_calc_thres(mbhc);
-			wcd9xxx_calibrate_hs_polling(mbhc);
-		} else {
-			pr_warn("%s: failed get new dce_z/sta_z 0x%x/0x%x\n",
-				__func__, dce_z, sta_z);
-		}
-
-		if (is_cs_enable) {
-			/* recalibrate dce_nsc_cs_z */
-			reg = snd_soc_read(mbhc->codec,
-					   WCD9XXX_A_CDC_MBHC_B1_CTL);
-			snd_soc_update_bits(mbhc->codec,
-					    WCD9XXX_A_CDC_MBHC_B1_CTL,
-					    0x78, WCD9XXX_MBHC_NSC_CS << 3);
-			wcd9xxx_get_z(mbhc, &dce_z, NULL, mbhc_micb_regs,
-				      true);
-			snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-				      reg);
-			if (dce_z) {
-				mbhc->mbhc_data.dce_nsc_cs_z = dce_z;
-				/* update v_cs_ins_h with new dce_nsc_cs_z */
-				mbhc->mbhc_data.v_cs_ins_h =
-						wcd9xxx_codec_v_sta_dce(
-							mbhc, DCE,
-							WCD9XXX_V_CS_HS_MAX,
-							is_cs_enable);
-				pr_debug("%s: dce_nsc_cs_z 0x%x -> 0x%x, v_cs_ins_h 0x%x\n",
-					  __func__,
-					  mbhc->mbhc_data.dce_nsc_cs_z,
-					  dce_z & 0xffff,
-					  mbhc->mbhc_data.v_cs_ins_h);
-			} else {
-				pr_debug("%s: failed get new dce_nsc_cs_z\n",
-					 __func__);
-			}
-		}
-	}
-}
-
-static void wcd9xxx_shutdown_hs_removal_detect(struct wcd9xxx_mbhc *mbhc)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	const struct wcd9xxx_mbhc_general_cfg *generic =
-	    WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
-
-	/* Need MBHC clock */
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->codec_rco_ctrl)
-		mbhc->mbhc_cb->codec_rco_ctrl(mbhc->codec, true);
-	else {
-		WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-		wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
-		WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
-	}
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
-	__wcd9xxx_switch_micbias(mbhc, 0, false, false);
-
-	usleep_range(generic->t_shutdown_plug_rem,
-		     generic->t_shutdown_plug_rem + 50);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->codec_rco_ctrl)
-		mbhc->mbhc_cb->codec_rco_ctrl(mbhc->codec, false);
-	else {
-		WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-		/* Put requested CLK back */
-		wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
-		WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
-	}
-
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x00);
-}
-
-static void wcd9xxx_cleanup_hs_polling(struct wcd9xxx_mbhc *mbhc)
-{
-
-	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	wcd9xxx_shutdown_hs_removal_detect(mbhc);
-
-
-	/* Disable external voltage source to micbias if present */
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
-		mbhc->mbhc_cb->enable_mb_source(mbhc->codec, false, true);
-
-	mbhc->polling_active = false;
-	mbhc->mbhc_state = MBHC_STATE_NONE;
-	pr_debug("%s: leave\n", __func__);
-}
-
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
-{
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01, on);
-	if (on)
-		usleep_range(5000, 5100);
-}
-
-static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
-{
-	pr_debug("%s: vddio %d\n", __func__, on);
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->pull_mb_to_vddio) {
-		mbhc->mbhc_cb->pull_mb_to_vddio(mbhc->codec, on);
-		goto exit;
-	}
-
-	if (on) {
-		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
-				    1 << 7, 1 << 7);
-		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
-				    1 << 4, 0);
-	} else {
-		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
-				    1 << 4, 1 << 4);
-		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
-				    1 << 7, 0);
-	}
-
-exit:
-	/*
-	 * Wait for the micbias to settle down to vddio
-	 * when the micbias to vddio switch is enabled.
-	 */
-	if (on)
-		usleep_range(10000, 10100);
-}
-
-static int wcd9xxx_hphl_status(struct wcd9xxx_mbhc *mbhc)
-{
-	u16 hph, status;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-	hph = snd_soc_read(codec, WCD9XXX_A_MBHC_HPH);
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x12, 0x02);
-	usleep_range(WCD9XXX_HPHL_STATUS_READY_WAIT_US,
-		     WCD9XXX_HPHL_STATUS_READY_WAIT_US +
-		     WCD9XXX_USLEEP_RANGE_MARGIN_US);
-	status = snd_soc_read(codec, WCD9XXX_A_RX_HPH_L_STATUS);
-	snd_soc_write(codec, WCD9XXX_A_MBHC_HPH, hph);
-	return status;
-}
-
-static enum wcd9xxx_mbhc_plug_type
-wcd9xxx_cs_find_plug_type(struct wcd9xxx_mbhc *mbhc,
-			  struct wcd9xxx_mbhc_detect *dt, const int size,
-			  bool highhph,
-			  unsigned long event_state)
-{
-	int i;
-	int vdce, mb_mv;
-	int ch, sz, delta_thr;
-	int minv = 0, maxv = INT_MIN;
-	struct wcd9xxx_mbhc_detect *d = dt;
-	struct wcd9xxx_mbhc_detect *dprev = d, *dmicbias = NULL, *dgnd = NULL;
-	enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
-
-	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
-	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
-	s16 hs_max, no_mic, dce_z;
-	int highhph_cnt = 0;
-
-	pr_debug("%s: enter\n", __func__);
-	pr_debug("%s: event_state 0x%lx\n", __func__, event_state);
-
-	sz = size - 1;
-	for (i = 0, d = dt, ch = 0; i < sz; i++, d++) {
-		if (d->mic_bias) {
-			dce_z = mbhc->mbhc_data.dce_z;
-			mb_mv = mbhc->mbhc_data.micb_mv;
-			hs_max = plug_type->v_hs_max;
-			no_mic = plug_type->v_no_mic;
-		} else {
-			dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
-			mb_mv = VDDIO_MICBIAS_MV;
-			hs_max = WCD9XXX_V_CS_HS_MAX;
-			no_mic = WCD9XXX_V_CS_NO_MIC;
-		}
-
-		vdce = __wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce,
-						 dce_z, (u32)mb_mv);
-		d->_vdces = vdce;
-		if (d->_vdces < no_mic)
-			d->_type = PLUG_TYPE_HEADPHONE;
-		else if (d->_vdces >= hs_max) {
-			d->_type = PLUG_TYPE_HIGH_HPH;
-			highhph_cnt++;
-		} else
-			d->_type = PLUG_TYPE_HEADSET;
-
-		pr_debug("%s: DCE #%d, %04x, V %04d(%04d), HPHL %d TYPE %d\n",
-			 __func__, i, d->dce, vdce, d->_vdces,
-			 d->hphl_status & 0x01,
-			 d->_type);
-
-		ch += d->hphl_status & 0x01;
-		if (!d->swap_gnd && !d->mic_bias) {
-			if (maxv < d->_vdces)
-				maxv = d->_vdces;
-			if (!minv || minv > d->_vdces)
-				minv = d->_vdces;
-		}
-		if ((!d->mic_bias &&
-		    (d->_vdces >= WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV &&
-		     d->_vdces <= WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV)) ||
-		    (d->mic_bias &&
-		    (d->_vdces >= WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
-		     d->_vdces <= WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV))) {
-			pr_debug("%s: within invalid range\n", __func__);
-			type = PLUG_TYPE_INVALID;
-			goto exit;
-		}
-	}
-
-	delta_thr = ((highhph_cnt == sz) || highhph) ?
-			      WCD9XXX_MB_MEAS_DELTA_MAX_MV :
-			      WCD9XXX_CS_MEAS_DELTA_MAX_MV;
-
-	for (i = 0, d = dt; i < sz; i++, d++) {
-		if ((i > 0) && !d->mic_bias && !d->swap_gnd &&
-		    (d->_type != dprev->_type)) {
-			pr_debug("%s: Invalid, inconsistent types\n", __func__);
-			type = PLUG_TYPE_INVALID;
-			goto exit;
-		}
-
-		if (!d->swap_gnd && !d->mic_bias &&
-		    (abs(minv - d->_vdces) > delta_thr ||
-		     abs(maxv - d->_vdces) > delta_thr)) {
-			pr_debug("%s: Invalid, delta %dmv, %dmv and %dmv\n",
-				 __func__, d->_vdces, minv, maxv);
-			type = PLUG_TYPE_INVALID;
-			goto exit;
-		} else if (d->swap_gnd) {
-			dgnd = d;
-		}
-
-		if (!d->mic_bias && !d->swap_gnd)
-			dprev = d;
-		else if (d->mic_bias)
-			dmicbias = d;
-	}
-	if (dgnd && dt->_type != PLUG_TYPE_HEADSET &&
-	    dt->_type != dgnd->_type) {
-		pr_debug("%s: Invalid, inconsistent types\n", __func__);
-		type = PLUG_TYPE_INVALID;
-		goto exit;
-	}
-
-	type = dt->_type;
-	if (dmicbias) {
-		if (dmicbias->_type == PLUG_TYPE_HEADSET &&
-		    (dt->_type == PLUG_TYPE_HIGH_HPH ||
-		     dt->_type == PLUG_TYPE_HEADSET)) {
-			type = PLUG_TYPE_HEADSET;
-			if (dt->_type == PLUG_TYPE_HIGH_HPH) {
-				pr_debug("%s: Headset with threshold on MIC detected\n",
-					 __func__);
-				if (mbhc->mbhc_cfg->micbias_enable_flags &
-				 (1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET))
-					mbhc->micbias_enable = true;
-			}
-		}
-	}
-
-	if (type == PLUG_TYPE_HEADSET && dgnd && !dgnd->mic_bias) {
-		/* if plug type is Headphone report as GND_MIC_SWAP */
-		if (dgnd->_type == PLUG_TYPE_HEADPHONE) {
-			pr_debug("%s: GND_MIC_SWAP\n", __func__);
-			type = PLUG_TYPE_GND_MIC_SWAP;
-			/*
-			 * if type is GND_MIC_SWAP we should not check
-			 * HPHL status hence goto exit
-			 */
-			goto exit;
-		} else if (dgnd->_type != PLUG_TYPE_HEADSET && !dmicbias) {
-			pr_debug("%s: Invalid, inconsistent types\n", __func__);
-			type = PLUG_TYPE_INVALID;
-		}
-	}
-
-	if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
-		pr_debug("%s: HPHL PA was ON\n", __func__);
-	} else if (ch != sz && ch > 0) {
-		pr_debug("%s: Invalid, inconsistent HPHL..\n", __func__);
-		type = PLUG_TYPE_INVALID;
-		goto exit;
-	}
-
-	if (!(event_state & (1UL << MBHC_EVENT_PA_HPHL))) {
-		if (((type == PLUG_TYPE_HEADSET ||
-		      type == PLUG_TYPE_HEADPHONE) && ch != sz)) {
-			pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
-				 __func__, type);
-			type = PLUG_TYPE_INVALID;
-		}
-	}
-
-	if (type == PLUG_TYPE_HEADSET &&
-	    (mbhc->mbhc_cfg->micbias_enable_flags &
-	    (1 << MBHC_MICBIAS_ENABLE_REGULAR_HEADSET)))
-		mbhc->micbias_enable = true;
-
-exit:
-	pr_debug("%s: Plug type %d detected\n", __func__, type);
-	return type;
-}
-
-/*
- * wcd9xxx_find_plug_type : Find out and return the best plug type with given
- *			    list of wcd9xxx_mbhc_detect structure.
- * param mbhc wcd9xxx_mbhc structure
- * param dt collected measurements
- * param size array size of dt
- * param event_state mbhc->event_state when dt is collected
- */
-static enum wcd9xxx_mbhc_plug_type
-wcd9xxx_find_plug_type(struct wcd9xxx_mbhc *mbhc,
-		       struct wcd9xxx_mbhc_detect *dt, const int size,
-		       unsigned long event_state)
-{
-	int i;
-	int ch;
-	enum wcd9xxx_mbhc_plug_type type;
-	int vdce;
-	struct wcd9xxx_mbhc_detect *d, *dprev, *dgnd = NULL, *dvddio = NULL;
-	int maxv = 0, minv = 0;
-	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
-	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
-	const s16 hs_max = plug_type->v_hs_max;
-	const s16 no_mic = plug_type->v_no_mic;
-
-	pr_debug("%s: event_state 0x%lx\n", __func__, event_state);
-
-	for (i = 0, d = dt, ch = 0; i < size; i++, d++) {
-		vdce = wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce);
-		if (d->vddio)
-			d->_vdces = scale_v_micb_vddio(mbhc, vdce, false);
-		else
-			d->_vdces = vdce;
-
-		if (d->_vdces >= no_mic && d->_vdces < hs_max)
-			d->_type = PLUG_TYPE_HEADSET;
-		else if (d->_vdces < no_mic)
-			d->_type = PLUG_TYPE_HEADPHONE;
-		else
-			d->_type = PLUG_TYPE_HIGH_HPH;
-
-		ch += d->hphl_status & 0x01;
-		if (!d->swap_gnd && !d->hwvalue && !d->vddio) {
-			if (maxv < d->_vdces)
-				maxv = d->_vdces;
-			if (!minv || minv > d->_vdces)
-				minv = d->_vdces;
-		}
-
-		pr_debug("%s: DCE #%d, %04x, V %04d(%04d), GND %d, VDDIO %d, HPHL %d TYPE %d\n",
-			 __func__, i, d->dce, vdce, d->_vdces,
-			 d->swap_gnd, d->vddio, d->hphl_status & 0x01,
-			 d->_type);
-
-
-		/*
-		 * If GND and MIC prongs are aligned to HPHR and GND of
-		 * headphone, codec measures the voltage based on
-		 * impedance between HPHR and GND which results in ~80mv.
-		 * Avoid this.
-		 */
-		if (d->_vdces >= WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
-		    d->_vdces <= WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV) {
-			pr_debug("%s: within invalid range\n", __func__);
-			type = PLUG_TYPE_INVALID;
-			goto exit;
-		}
-	}
-
-	if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
-		pr_debug("%s: HPHL PA was ON\n", __func__);
-	} else if (ch != size && ch > 0) {
-		pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
-		type = PLUG_TYPE_INVALID;
-		goto exit;
-	}
-
-	for (i = 0, dprev = NULL, d = dt; i < size; i++, d++) {
-		if (d->vddio) {
-			dvddio = d;
-			continue;
-		}
-
-		if ((i > 0) && (dprev != NULL) && (d->_type != dprev->_type)) {
-			pr_debug("%s: Invalid, inconsistent types\n", __func__);
-			type = PLUG_TYPE_INVALID;
-			goto exit;
-		}
-
-		if (!d->swap_gnd && !d->hwvalue &&
-		    (abs(minv - d->_vdces) > WCD9XXX_MEAS_DELTA_MAX_MV ||
-		     abs(maxv - d->_vdces) > WCD9XXX_MEAS_DELTA_MAX_MV)) {
-			pr_debug("%s: Invalid, delta %dmv, %dmv and %dmv\n",
-				 __func__, d->_vdces, minv, maxv);
-			type = PLUG_TYPE_INVALID;
-			goto exit;
-		} else if (d->swap_gnd) {
-			dgnd = d;
-		}
-		dprev = d;
-	}
-
-	WARN_ON(i != size);
-	type = dt->_type;
-	if (type == PLUG_TYPE_HEADSET && dgnd) {
-		if ((dgnd->_vdces + WCD9XXX_GM_SWAP_THRES_MIN_MV <
-		     minv) &&
-		    (dgnd->_vdces + WCD9XXX_GM_SWAP_THRES_MAX_MV >
-		     maxv))
-			type = PLUG_TYPE_GND_MIC_SWAP;
-	}
-
-	/* if HPHL PA was on, we cannot use hphl status */
-	if (!(event_state & (1UL << MBHC_EVENT_PA_HPHL))) {
-		if (((type == PLUG_TYPE_HEADSET ||
-		      type == PLUG_TYPE_HEADPHONE) && ch != size) ||
-		    (type == PLUG_TYPE_GND_MIC_SWAP && ch)) {
-			pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
-				 __func__, type);
-			type = PLUG_TYPE_INVALID;
-		}
-	}
-
-	if (type == PLUG_TYPE_HEADSET) {
-		if (dvddio && ((dvddio->_vdces > hs_max) ||
-		   (dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD))) {
-			pr_debug("%s: Headset with threshold on MIC detected\n",
-				 __func__);
-			if (mbhc->mbhc_cfg->micbias_enable_flags &
-			    (1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET))
-				mbhc->micbias_enable = true;
-		} else {
-			pr_debug("%s: Headset with regular MIC detected\n",
-				 __func__);
-			if (mbhc->mbhc_cfg->micbias_enable_flags &
-			    (1 << MBHC_MICBIAS_ENABLE_REGULAR_HEADSET))
-				mbhc->micbias_enable = true;
-		}
-	}
-exit:
-	pr_debug("%s: Plug type %d detected, micbias_enable %d\n", __func__,
-		 type, mbhc->micbias_enable);
-	return type;
-}
-
-/*
- * Pull down MBHC micbias for provided duration in microsecond.
- */
-static int wcd9xxx_pull_down_micbias(struct wcd9xxx_mbhc *mbhc, int us)
-{
-	bool micbiasconn = false;
-	struct snd_soc_codec *codec = mbhc->codec;
-	const u16 ctlreg = mbhc->mbhc_bias_regs.ctl_reg;
-
-	/*
-	 * Disable MBHC to micbias connection to pull down
-	 * micbias and pull down micbias for a moment.
-	 */
-	if ((snd_soc_read(mbhc->codec, ctlreg) & 0x01)) {
-		WARN_ONCE(1, "MBHC micbias is already pulled down unexpectedly\n");
-		return -EFAULT;
-	}
-
-	if ((snd_soc_read(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL) & 1 << 4)) {
-		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
-				    1 << 4, 0);
-		micbiasconn = true;
-	}
-
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
-
-	/*
-	 * Pull down for 1ms to discharge bias. Give small margin (10us) to be
-	 * able to get consistent result across DCEs.
-	 */
-	usleep_range(1000, 1000 + 10);
-
-	if (micbiasconn)
-		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
-				    1 << 4, 1 << 4);
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
-	usleep_range(us, us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-
-	return 0;
-}
-
-/* Called under codec resource lock acquisition */
-void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc,
-				       struct mbhc_micbias_regs *mbhc_micb_regs,
-				       bool on, bool highhph)
-{
-	struct snd_soc_codec *codec;
-	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
-	const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
-	    WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
-
-	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
-	codec = mbhc->codec;
-
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	if ((on && mbhc->is_cs_enabled) ||
-	    (!on && !mbhc->is_cs_enabled)) {
-		pr_debug("%s: Current source is already %s\n",
-			__func__, on ? "ON" : "OFF");
-		return;
-	}
-
-	if (on) {
-		pr_debug("%s: enabling current source\n", __func__);
-		/* Nsc to 9 */
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-				    0x78, 0x48);
-		/* pull down diode bit to 0 */
-		snd_soc_update_bits(codec, mbhc_micb_regs->mbhc_reg,
-				    0x01, 0x00);
-		/*
-		 * Keep the low power insertion/removal
-		 * detection (reg 0x3DD) disabled
-		 */
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL,
-				    0x01, 0x00);
-		/*
-		 * Enable the Mic Bias current source
-		 * Write bits[6:5] of register MICB_2_MBHC to 0x3 (V_20_UA)
-		 * Write bit[7] of register MICB_2_MBHC to 1
-		 * (INS_DET_ISRC_EN__ENABLE)
-		 * MICB_2_MBHC__SCHT_TRIG_EN to 1
-		 */
-		snd_soc_update_bits(codec, mbhc_micb_regs->mbhc_reg,
-				    0xF0, 0xF0);
-		/* Disconnect MBHC Override from MicBias and LDOH */
-		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x00);
-		mbhc->is_cs_enabled = true;
-	} else {
-		pr_debug("%s: disabling current source\n", __func__);
-		/* Connect MBHC Override from MicBias and LDOH */
-		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x10);
-		/* INS_DET_ISRC_CTL to acdb value */
-		snd_soc_update_bits(codec, mbhc_micb_regs->mbhc_reg,
-				    0x60, plug_det->mic_current << 5);
-		if (!highhph) {
-			/* INS_DET_ISRC_EN__ENABLE to 0 */
-			snd_soc_update_bits(codec,
-					    mbhc_micb_regs->mbhc_reg,
-					    0x80, 0x00);
-			/* MICB_2_MBHC__SCHT_TRIG_EN  to 0 */
-			snd_soc_update_bits(codec,
-					    mbhc_micb_regs->mbhc_reg,
-					    0x10, 0x00);
-		}
-		/* Nsc to acdb value */
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
-				    btn_det->mbhc_nsc << 3);
-		mbhc->is_cs_enabled = false;
-	}
-}
-
-static enum wcd9xxx_mbhc_plug_type
-wcd9xxx_codec_cs_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT];
-	enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
-	int i;
-
-	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	BUG_ON(NUM_DCE_PLUG_INS_DETECT < 4);
-
-	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
-	rt[0].swap_gnd = false;
-	rt[0].vddio = false;
-	rt[0].hwvalue = true;
-	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
-	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, &mbhc->mbhc_bias_regs,
-						  true);
-	rt[0].mic_bias = false;
-
-	for (i = 1; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) {
-		rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 3);
-		rt[i].mic_bias = ((i == NUM_DCE_PLUG_INS_DETECT - 4) &&
-				   highhph);
-		rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
-		if (rt[i].swap_gnd)
-			wcd9xxx_codec_hphr_gnd_switch(codec, true);
-
-		if (rt[i].mic_bias)
-			wcd9xxx_turn_onoff_current_source(mbhc,
-							  &mbhc->mbhc_bias_regs,
-							  false, false);
-
-		rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, !highhph, true);
-		if (rt[i].mic_bias)
-			wcd9xxx_turn_onoff_current_source(mbhc,
-							  &mbhc->mbhc_bias_regs,
-							  true, false);
-		if (rt[i].swap_gnd)
-			wcd9xxx_codec_hphr_gnd_switch(codec, false);
-	}
-
-	/* recalibrate DCE/STA GND voltages */
-	wcd9xxx_recalibrate(mbhc, &mbhc->mbhc_bias_regs, true);
-
-	type = wcd9xxx_cs_find_plug_type(mbhc, rt, ARRAY_SIZE(rt), highhph,
-					 mbhc->event_state);
-
-	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
-	pr_debug("%s: plug_type:%d\n", __func__, type);
-
-	return type;
-}
-
-static enum wcd9xxx_mbhc_plug_type
-wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
-{
-	int i;
-	bool vddioon;
-	struct wcd9xxx_mbhc_plug_type_cfg *plug_type_ptr;
-	struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT];
-	enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	/* make sure override is on */
-	WARN_ON(!(snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x04));
-
-	/* GND and MIC swap detection requires at least 2 rounds of DCE */
-	BUG_ON(NUM_DCE_PLUG_INS_DETECT < 2);
-	detect_use_vddio_switch = mbhc->mbhc_cfg->use_vddio_meas;
-
-	/*
-	 * There are chances vddio switch is on and cfilt voltage is adjusted
-	 * to vddio voltage even after plug type removal reported.
-	 */
-	vddioon = __wcd9xxx_switch_micbias(mbhc, 0, false, false);
-	pr_debug("%s: vddio switch was %s\n", __func__, vddioon ? "on" : "off");
-
-	plug_type_ptr =
-	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
-
-	/*
-	 * cfilter in fast mode requires 1ms to charge up and down micbias
-	 * fully.
-	 */
-	(void) wcd9xxx_pull_down_micbias(mbhc,
-					 WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
-
-	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
-	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
-	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, &mbhc->mbhc_bias_regs,
-						  false);
-	rt[0].swap_gnd = false;
-	rt[0].vddio = false;
-	rt[0].hwvalue = true;
-	for (i = 1; i < NUM_DCE_PLUG_INS_DETECT; i++) {
-		rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 2);
-		if (detect_use_vddio_switch)
-			rt[i].vddio = (i == 1);
-		else
-			rt[i].vddio = false;
-		rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
-		rt[i].hwvalue = false;
-		if (rt[i].swap_gnd)
-			wcd9xxx_codec_hphr_gnd_switch(codec, true);
-		if (rt[i].vddio)
-			wcd9xxx_onoff_vddio_switch(mbhc, true);
-		/*
-		 * Pull down micbias to detect headset with mic which has
-		 * threshold and to have more consistent voltage measurements.
-		 *
-		 * cfilter in fast mode requires 1ms to charge up and down
-		 * micbias fully.
-		 */
-		(void) wcd9xxx_pull_down_micbias(mbhc,
-					    WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
-		rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
-		if (rt[i].vddio)
-			wcd9xxx_onoff_vddio_switch(mbhc, false);
-		if (rt[i].swap_gnd)
-			wcd9xxx_codec_hphr_gnd_switch(codec, false);
-	}
-	/* recalibrate DCE/STA GND voltages */
-	wcd9xxx_recalibrate(mbhc, &mbhc->mbhc_bias_regs, false);
-
-	if (vddioon)
-		__wcd9xxx_switch_micbias(mbhc, 1, false, false);
-
-	type = wcd9xxx_find_plug_type(mbhc, rt, ARRAY_SIZE(rt),
-				      mbhc->event_state);
-
-	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
-	pr_debug("%s: leave\n", __func__);
-	return type;
-}
-
-static bool wcd9xxx_swch_level_remove(struct wcd9xxx_mbhc *mbhc)
-{
-	if (mbhc->mbhc_cfg->gpio)
-		return (gpio_get_value_cansleep(mbhc->mbhc_cfg->gpio) !=
-			mbhc->mbhc_cfg->gpio_level_insert);
-	else if (mbhc->mbhc_cfg->insert_detect) {
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->insert_rem_status)
-			return mbhc->mbhc_cb->insert_rem_status(mbhc->codec);
-		else
-			return snd_soc_read(mbhc->codec,
-				    WCD9XXX_A_MBHC_INSERT_DET_STATUS) &
-				    (1 << 2);
-	} else
-		WARN(1, "Invalid jack detection configuration\n");
-
-	return true;
-}
-
-static bool is_clk_active(struct snd_soc_codec *codec)
-{
-	return !!(snd_soc_read(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL) & 0x05);
-}
-
-static int wcd9xxx_enable_hs_detect(struct wcd9xxx_mbhc *mbhc,
-				    int insertion, int trigger, bool padac_off)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	int central_bias_enabled = 0;
-	const struct wcd9xxx_mbhc_general_cfg *generic =
-	    WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
-	const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
-	    WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
-
-	pr_debug("%s: enter insertion(%d) trigger(0x%x)\n",
-		 __func__, insertion, trigger);
-
-	if (!mbhc->mbhc_cfg->calibration) {
-		pr_err("Error, no wcd9xxx calibration\n");
-		return -EINVAL;
-	}
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0);
-
-	/*
-	 * Make sure mic bias and Mic line schmitt trigger
-	 * are turned OFF
-	 */
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
-
-	if (insertion) {
-		wcd9xxx_switch_micbias(mbhc, 0);
-
-		/* DAPM can manipulate PA/DAC bits concurrently */
-		if (padac_off == true)
-			wcd9xxx_set_and_turnoff_hph_padac(mbhc);
-
-		if (trigger & MBHC_USE_HPHL_TRIGGER) {
-			/* Enable HPH Schmitt Trigger */
-			snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x11,
-					0x11);
-			snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x0C,
-					plug_det->hph_current << 2);
-			snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x02,
-					0x02);
-		}
-		if (trigger & MBHC_USE_MB_TRIGGER) {
-			/* enable the mic line schmitt trigger */
-			snd_soc_update_bits(codec,
-					mbhc->mbhc_bias_regs.mbhc_reg,
-					0x60, plug_det->mic_current << 5);
-			snd_soc_update_bits(codec,
-					mbhc->mbhc_bias_regs.mbhc_reg,
-					0x80, 0x80);
-			usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid +
-						WCD9XXX_USLEEP_RANGE_MARGIN_US);
-			snd_soc_update_bits(codec,
-					mbhc->mbhc_bias_regs.ctl_reg, 0x01,
-					0x00);
-			snd_soc_update_bits(codec,
-					mbhc->mbhc_bias_regs.mbhc_reg,
-					0x10, 0x10);
-		}
-
-		/* setup for insetion detection */
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x2, 0);
-	} else {
-		pr_debug("setup for removal detection\n");
-		/* Make sure the HPH schmitt trigger is OFF */
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x12, 0x00);
-
-		/* enable the mic line schmitt trigger */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg,
-				    0x01, 0x00);
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x60,
-				    plug_det->mic_current << 5);
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
-				    0x80, 0x80);
-		usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid +
-					WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
-				    0x10, 0x10);
-
-		/* Setup for low power removal detection */
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x2,
-				    0x2);
-	}
-
-	if (snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x4) {
-		/* called by interrupt */
-		if (!is_clk_active(codec)) {
-			wcd9xxx_resmgr_enable_config_mode(mbhc->resmgr, 1);
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-					0x06, 0);
-			usleep_range(generic->t_shutdown_plug_rem,
-					generic->t_shutdown_plug_rem +
-					WCD9XXX_USLEEP_RANGE_MARGIN_US);
-			wcd9xxx_resmgr_enable_config_mode(mbhc->resmgr, 0);
-		} else
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-					0x06, 0);
-	}
-
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.int_rbias, 0x80, 0);
-
-	/* If central bandgap disabled */
-	if (!(snd_soc_read(codec, WCD9XXX_A_PIN_CTL_OE1) & 1)) {
-		snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE1, 0x3, 0x3);
-		usleep_range(generic->t_bg_fast_settle,
-			     generic->t_bg_fast_settle +
-			     WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		central_bias_enabled = 1;
-	}
-
-	/* If LDO_H disabled */
-	if (snd_soc_read(codec, WCD9XXX_A_PIN_CTL_OE0) & 0x80) {
-		snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE0, 0x10, 0);
-		snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE0, 0x80, 0x80);
-		usleep_range(generic->t_ldoh, generic->t_ldoh +
-					      WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE0, 0x80, 0);
-
-		if (central_bias_enabled)
-			snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE1, 0x1,
-					    0);
-	}
-
-	if (mbhc->resmgr->reg_addr && mbhc->resmgr->reg_addr->micb_4_mbhc)
-		snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
-				    0x3, mbhc->mbhc_cfg->micbias);
-
-	wcd9xxx_enable_irq(mbhc->resmgr->core_res, mbhc->intr_ids->insertion);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
-	pr_debug("%s: leave\n", __func__);
-
-	return 0;
-}
-
-/*
- * Function to determine whether anc microphone is preset or not.
- * Return true if anc microphone is detected or false if not detected.
- */
-static bool wcd9xxx_detect_anc_plug_type(struct wcd9xxx_mbhc *mbhc)
-{
-	struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT - 1];
-	bool anc_mic_found = true;
-	int i, mb_mv;
-	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
-	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
-	s16 hs_max, dce_z;
-	s16 no_mic;
-	bool override_en;
-	bool timedout;
-	unsigned long timeout, retry = 0;
-	enum wcd9xxx_mbhc_plug_type type;
-	bool cs_enable;
-
-	if (mbhc->mbhc_cfg->anc_micbias != MBHC_MICBIAS3 &&
-	    mbhc->mbhc_cfg->anc_micbias != MBHC_MICBIAS2)
-		return false;
-
-	pr_debug("%s: enter\n", __func__);
-
-	override_en = (snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
-		       0x04) ? true : false;
-	cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
-		    (1 << MBHC_CS_ENABLE_DET_ANC)) != 0) &&
-		    (!(snd_soc_read(mbhc->codec,
-		       mbhc->mbhc_anc_bias_regs.ctl_reg) & 0x80)) &&
-		     (mbhc->mbhc_cfg->micbias != mbhc->mbhc_cfg->anc_micbias);
-
-	if (cs_enable) {
-		wcd9xxx_turn_onoff_current_source(mbhc,
-						  &mbhc->mbhc_anc_bias_regs,
-						  true, false);
-	} else {
-		if (mbhc->mbhc_cfg->anc_micbias == MBHC_MICBIAS3) {
-			if (mbhc->micbias_enable_cb)
-				mbhc->micbias_enable_cb(mbhc->codec, true,
-						mbhc->mbhc_cfg->anc_micbias);
-			else
-				return false;
-		} else {
-			/* Enable override */
-			if (!override_en)
-				wcd9xxx_turn_onoff_override(mbhc, true);
-		}
-	}
-
-	if (!cs_enable) {
-		hs_max = plug_type->v_hs_max;
-		no_mic = plug_type->v_no_mic;
-		dce_z = mbhc->mbhc_data.dce_z;
-		mb_mv = mbhc->mbhc_data.micb_mv;
-	} else {
-		hs_max = WCD9XXX_V_CS_HS_MAX;
-		no_mic = WCD9XXX_V_CS_NO_MIC;
-		mb_mv = VDDIO_MICBIAS_MV;
-		dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
-	}
-
-	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
-
-	timeout = jiffies + msecs_to_jiffies(ANC_HPH_DETECT_PLUG_TIME_MS);
-	anc_mic_found = true;
-
-	while (!(timedout = time_after(jiffies, timeout))) {
-		retry++;
-
-		if (wcd9xxx_swch_level_remove(mbhc)) {
-			pr_debug("%s: Switch level is low\n", __func__);
-			anc_mic_found = false;
-			break;
-		}
-
-		pr_debug("%s: Retry attempt %lu", __func__, retry - 1);
-
-		rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
-		rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc,
-						  &mbhc->mbhc_anc_bias_regs,
-						  cs_enable);
-		rt[0]._vdces = __wcd9xxx_codec_sta_dce_v(mbhc, true, rt[0].dce,
-							 dce_z, (u32)mb_mv);
-
-		if (rt[0]._vdces >= no_mic && rt[0]._vdces < hs_max)
-			rt[0]._type = PLUG_TYPE_HEADSET;
-		else if (rt[0]._vdces < no_mic)
-			rt[0]._type = PLUG_TYPE_HEADPHONE;
-		else
-			rt[0]._type = PLUG_TYPE_HIGH_HPH;
-
-		pr_debug("%s: DCE #%d, V %04d, HPHL %d TYPE %d\n",
-				__func__, 0, rt[0]._vdces,
-				rt[0].hphl_status & 0x01,
-				rt[0]._type);
-
-		for (i = 1; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) {
-			rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1,
-							    true, true);
-			rt[i]._vdces = __wcd9xxx_codec_sta_dce_v(mbhc, true,
-							 rt[i].dce, dce_z,
-							 (u32) mb_mv);
-
-			if (rt[i]._vdces >= no_mic && rt[i]._vdces < hs_max)
-				rt[i]._type = PLUG_TYPE_HEADSET;
-			else if (rt[i]._vdces < no_mic)
-				rt[i]._type = PLUG_TYPE_HEADPHONE;
-			else
-				rt[i]._type = PLUG_TYPE_HIGH_HPH;
-
-			rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
-
-			pr_debug("%s: DCE #%d, V %04d, HPHL %d TYPE %d\n",
-					__func__, i, rt[i]._vdces,
-					rt[i].hphl_status & 0x01,
-					rt[i]._type);
-		}
-
-		/*
-		 * Check for the "type" of all the 4 measurements
-		 * If all 4 measurements have the Type as PLUG_TYPE_HEADSET
-		 * then it is proper mic and declare that the plug has two mics
-		 */
-		for (i = 0; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) {
-			if (i > 0 && (rt[i - 1]._type != rt[i]._type)) {
-				type = PLUG_TYPE_INVALID;
-				break;
-			} else {
-				type = rt[0]._type;
-			}
-		}
-
-		pr_debug("%s: Plug type found in ANC detection :%d",
-			__func__, type);
-
-		if (type != PLUG_TYPE_HEADSET)
-			anc_mic_found = false;
-		if (anc_mic_found || (type == PLUG_TYPE_HEADPHONE &&
-		    mbhc->mbhc_cfg->hw_jack_type == FIVE_POLE_JACK) ||
-		    (type == PLUG_TYPE_HIGH_HPH &&
-		    mbhc->mbhc_cfg->hw_jack_type == SIX_POLE_JACK))
-			break;
-	}
-
-	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
-	if (cs_enable) {
-		wcd9xxx_turn_onoff_current_source(mbhc,
-						  &mbhc->mbhc_anc_bias_regs,
-						  false, false);
-	} else {
-		if (mbhc->mbhc_cfg->anc_micbias == MBHC_MICBIAS3) {
-			if (mbhc->micbias_enable_cb)
-				mbhc->micbias_enable_cb(mbhc->codec, false,
-						mbhc->mbhc_cfg->anc_micbias);
-		} else {
-			/* Disable override */
-			if (!override_en)
-				wcd9xxx_turn_onoff_override(mbhc, false);
-		}
-	}
-	pr_debug("%s: leave\n", __func__);
-	return anc_mic_found;
-}
-
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_find_plug_and_report(struct wcd9xxx_mbhc *mbhc,
-					 enum wcd9xxx_mbhc_plug_type plug_type)
-{
-	bool anc_mic_found = false;
-
-	pr_debug("%s: enter current_plug(%d) new_plug(%d)\n",
-		 __func__, mbhc->current_plug, plug_type);
-
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	if (plug_type == PLUG_TYPE_HEADPHONE &&
-	    mbhc->current_plug == PLUG_TYPE_NONE) {
-		/*
-		 * Nothing was reported previously
-		 * report a headphone or unsupported
-		 */
-		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
-		wcd9xxx_cleanup_hs_polling(mbhc);
-	} else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
-		if (!mbhc->mbhc_cfg->detect_extn_cable) {
-			if (mbhc->current_plug == PLUG_TYPE_HEADSET)
-				wcd9xxx_report_plug(mbhc, 0,
-							 SND_JACK_HEADSET);
-			else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE)
-				wcd9xxx_report_plug(mbhc, 0,
-							 SND_JACK_HEADPHONE);
-		}
-		wcd9xxx_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED);
-		wcd9xxx_cleanup_hs_polling(mbhc);
-	} else if (plug_type == PLUG_TYPE_HEADSET) {
-
-		if (mbhc->mbhc_cfg->enable_anc_mic_detect) {
-			/*
-			 * Do not report Headset, because at this point
-			 * it could be a ANC headphone having two mics.
-			 * So, proceed further to detect if there is a
-			 * second mic.
-			 */
-			mbhc->scaling_mux_in = 0x08;
-			anc_mic_found = wcd9xxx_detect_anc_plug_type(mbhc);
-		}
-
-		if (anc_mic_found) {
-			/* Report ANC headphone */
-			wcd9xxx_report_plug(mbhc, 1, SND_JACK_ANC_HEADPHONE);
-		} else {
-			/*
-			 * If Headphone was reported previously, this will
-			 * only report the mic line
-			 */
-			wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
-		}
-		/* Button detection required RC oscillator */
-		wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
-		/*
-		 * sleep so that audio path completely tears down
-		 * before report plug insertion to the user space
-		 */
-		msleep(100);
-
-		wcd9xxx_start_hs_polling(mbhc);
-	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
-		if (mbhc->mbhc_cfg->detect_extn_cable) {
-			/* High impedance device found. Report as LINEOUT*/
-			if (mbhc->current_plug == PLUG_TYPE_NONE)
-				wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
-			wcd9xxx_cleanup_hs_polling(mbhc);
-			pr_debug("%s: setup mic trigger for further detection\n",
-				 __func__);
-			mbhc->lpi_enabled = true;
-			/*
-			 * Do not enable HPHL trigger. If playback is active,
-			 * it might lead to continuous false HPHL triggers
-			 */
-			wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER,
-						 false);
-		} else {
-			if (mbhc->current_plug == PLUG_TYPE_NONE)
-				wcd9xxx_report_plug(mbhc, 1,
-							 SND_JACK_HEADPHONE);
-			wcd9xxx_cleanup_hs_polling(mbhc);
-			pr_debug("setup mic trigger for further detection\n");
-			mbhc->lpi_enabled = true;
-			wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER |
-							  MBHC_USE_HPHL_TRIGGER,
-						 false);
-		}
-	} else {
-		WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
-		     mbhc->current_plug, plug_type);
-	}
-	pr_debug("%s: leave\n", __func__);
-}
-
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc)
-{
-	enum wcd9xxx_mbhc_plug_type plug_type;
-	bool current_source_enable;
-
-	pr_debug("%s: enter\n", __func__);
-
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	current_source_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
-		      (1 << MBHC_CS_ENABLE_INSERTION)) != 0) &&
-		     (!(snd_soc_read(mbhc->codec,
-				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
-
-	mbhc->scaling_mux_in = 0x04;
-
-	if (current_source_enable) {
-		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
-						  true, false);
-		plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false);
-		/*
-		 * For other plug types, the current source disable
-		 * will be done from wcd9xxx_correct_swch_plug
-		 */
-		if (plug_type == PLUG_TYPE_HEADSET)
-			wcd9xxx_turn_onoff_current_source(mbhc,
-						&mbhc->mbhc_bias_regs,
-						false, false);
-	} else {
-		wcd9xxx_turn_onoff_override(mbhc, true);
-		plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
-		wcd9xxx_turn_onoff_override(mbhc, false);
-	}
-
-	if (wcd9xxx_swch_level_remove(mbhc)) {
-		if (current_source_enable && mbhc->is_cs_enabled) {
-			wcd9xxx_turn_onoff_current_source(mbhc,
-					&mbhc->mbhc_bias_regs,
-					false, false);
-		}
-		pr_debug("%s: Switch level is low when determining plug\n",
-			 __func__);
-		return;
-	}
-
-	if (plug_type == PLUG_TYPE_INVALID ||
-	    plug_type == PLUG_TYPE_GND_MIC_SWAP) {
-		wcd9xxx_cleanup_hs_polling(mbhc);
-		wcd9xxx_schedule_hs_detect_plug(mbhc,
-						&mbhc->correct_plug_swch);
-	} else if (plug_type == PLUG_TYPE_HEADPHONE) {
-		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
-		wcd9xxx_cleanup_hs_polling(mbhc);
-		wcd9xxx_schedule_hs_detect_plug(mbhc,
-						&mbhc->correct_plug_swch);
-	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
-		wcd9xxx_cleanup_hs_polling(mbhc);
-		wcd9xxx_schedule_hs_detect_plug(mbhc,
-						&mbhc->correct_plug_swch);
-	} else {
-		pr_debug("%s: Valid plug found, determine plug type %d\n",
-			 __func__, plug_type);
-		wcd9xxx_find_plug_and_report(mbhc, plug_type);
-	}
-	pr_debug("%s: leave\n", __func__);
-}
-
-/* called under codec_resource_lock acquisition */
-static void wcd9xxx_mbhc_detect_plug_type(struct wcd9xxx_mbhc *mbhc)
-{
-	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	if (wcd9xxx_swch_level_remove(mbhc))
-		pr_debug("%s: Switch level low when determining plug\n",
-			 __func__);
-	else
-		wcd9xxx_mbhc_decide_swch_plug(mbhc);
-	pr_debug("%s: leave\n", __func__);
-}
-
-/* called only from interrupt which is under codec_resource_lock acquisition */
-static void wcd9xxx_hs_insert_irq_swch(struct wcd9xxx_mbhc *mbhc,
-				       bool is_removal)
-{
-	if (!is_removal) {
-		pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
-
-		/* Make sure memory read is completed before reading
-		 * lpi_enabled.
-		 */
-		rmb();
-		if (mbhc->lpi_enabled)
-			msleep(100);
-
-		/* Make sure memory read is completed before reading
-		 * lpi_enabled.
-		 */
-		rmb();
-		if (!mbhc->lpi_enabled) {
-			pr_debug("%s: lpi is disabled\n", __func__);
-		} else if (!wcd9xxx_swch_level_remove(mbhc)) {
-			pr_debug("%s: Valid insertion, detect plug type\n",
-				 __func__);
-			wcd9xxx_mbhc_decide_swch_plug(mbhc);
-		} else {
-			pr_debug("%s: Invalid insertion stop plug detection\n",
-				 __func__);
-		}
-	} else if (mbhc->mbhc_cfg->detect_extn_cable) {
-		pr_debug("%s: Removal\n", __func__);
-		if (!wcd9xxx_swch_level_remove(mbhc)) {
-			/*
-			 * Switch indicates, something is still inserted.
-			 * This could be extension cable i.e. headset is
-			 * removed from extension cable.
-			 */
-			/* cancel detect plug */
-			wcd9xxx_cancel_hs_detect_plug(mbhc,
-						      &mbhc->correct_plug_swch);
-			wcd9xxx_mbhc_decide_swch_plug(mbhc);
-		}
-	} else {
-		pr_err("%s: Switch IRQ used, invalid MBHC Removal\n", __func__);
-	}
-}
-
-static bool is_valid_mic_voltage(struct wcd9xxx_mbhc *mbhc, s32 mic_mv,
-				 bool cs_enable)
-{
-	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
-	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
-	const s16 v_hs_max = wcd9xxx_get_current_v_hs_max(mbhc);
-
-	if (cs_enable)
-		return ((mic_mv > WCD9XXX_V_CS_NO_MIC) &&
-			 (mic_mv < WCD9XXX_V_CS_HS_MAX)) ? true : false;
-	else
-		return (!(mic_mv > WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
-			  mic_mv < WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV) &&
-			(mic_mv > plug_type->v_no_mic) &&
-			(mic_mv < v_hs_max)) ? true : false;
-}
-
-/*
- * called under codec_resource_lock acquisition
- * returns true if mic voltage range is back to normal insertion
- * returns false either if timedout or removed
- */
-static bool wcd9xxx_hs_remove_settle(struct wcd9xxx_mbhc *mbhc)
-{
-	int i;
-	bool timedout, settled = false;
-	s32 mic_mv[NUM_DCE_PLUG_DETECT];
-	short mb_v[NUM_DCE_PLUG_DETECT];
-	unsigned long retry = 0, timeout;
-	bool cs_enable;
-
-	cs_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
-		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0) &&
-		     (!(snd_soc_read(mbhc->codec,
-				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
-	if (cs_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
-						  true, false);
-
-	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
-	while (!(timedout = time_after(jiffies, timeout))) {
-		retry++;
-		if (wcd9xxx_swch_level_remove(mbhc)) {
-			pr_debug("%s: Switch indicates removal\n", __func__);
-			break;
-		}
-
-		if (retry > 1)
-			msleep(250);
-		else
-			msleep(50);
-
-		if (wcd9xxx_swch_level_remove(mbhc)) {
-			pr_debug("%s: Switch indicates removal\n", __func__);
-			break;
-		}
-
-		if (cs_enable) {
-			for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
-				mb_v[i] = __wcd9xxx_codec_sta_dce(mbhc, 1,
-								  true, true);
-				mic_mv[i] = __wcd9xxx_codec_sta_dce_v(mbhc,
-								      true,
-								      mb_v[i],
-						mbhc->mbhc_data.dce_nsc_cs_z,
-						(u32)VDDIO_MICBIAS_MV);
-				pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
-					 __func__, retry, mic_mv[i], mb_v[i]);
-			}
-		} else {
-			for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
-				mb_v[i] = wcd9xxx_codec_sta_dce(mbhc, 1,
-								true);
-				mic_mv[i] = wcd9xxx_codec_sta_dce_v(mbhc, 1,
-								mb_v[i]);
-				pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
-					 __func__, retry, mic_mv[i],
-								mb_v[i]);
-			}
-		}
-
-		if (wcd9xxx_swch_level_remove(mbhc)) {
-			pr_debug("%s: Switcn indicates removal\n", __func__);
-			break;
-		}
-
-		if (mbhc->current_plug == PLUG_TYPE_NONE) {
-			pr_debug("%s : headset/headphone is removed\n",
-				 __func__);
-			break;
-		}
-
-		for (i = 0; i < NUM_DCE_PLUG_DETECT; i++)
-			if (!is_valid_mic_voltage(mbhc, mic_mv[i], cs_enable))
-				break;
-
-		if (i == NUM_DCE_PLUG_DETECT) {
-			pr_debug("%s: MIC voltage settled\n", __func__);
-			settled = true;
-			msleep(200);
-			break;
-		}
-	}
-
-	if (cs_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
-						  false, false);
-
-	if (timedout)
-		pr_debug("%s: Microphone did not settle in %d seconds\n",
-			 __func__, HS_DETECT_PLUG_TIME_MS);
-	return settled;
-}
-
-/* called only from interrupt which is under codec_resource_lock acquisition */
-static void wcd9xxx_hs_remove_irq_swch(struct wcd9xxx_mbhc *mbhc)
-{
-	pr_debug("%s: enter\n", __func__);
-	if (wcd9xxx_hs_remove_settle(mbhc))
-		wcd9xxx_start_hs_polling(mbhc);
-	pr_debug("%s: leave\n", __func__);
-}
-
-/* called only from interrupt which is under codec_resource_lock acquisition */
-static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc)
-{
-	s16 dce, dcez;
-	unsigned long timeout;
-	bool removed = true;
-	struct snd_soc_codec *codec = mbhc->codec;
-	const struct wcd9xxx_mbhc_general_cfg *generic =
-		WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
-	bool cs_enable;
-	s16 cur_v_ins_h;
-	u32 mb_mv;
-
-	pr_debug("%s: enter\n", __func__);
-	if (mbhc->current_plug != PLUG_TYPE_HEADSET &&
-		mbhc->current_plug != PLUG_TYPE_ANC_HEADPHONE) {
-		pr_debug("%s(): Headset is not inserted, ignore removal\n",
-			 __func__);
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
-				0x08, 0x08);
-		return;
-	}
-
-	usleep_range(generic->t_shutdown_plug_rem,
-		     generic->t_shutdown_plug_rem +
-		     WCD9XXX_USLEEP_RANGE_MARGIN_US);
-
-	/* If micbias is enabled, don't enable current source */
-	cs_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
-		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0) &&
-		     (!(snd_soc_read(codec,
-				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
-	if (cs_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
-						  true, false);
-
-	timeout = jiffies + msecs_to_jiffies(FAKE_REMOVAL_MIN_PERIOD_MS);
-	do {
-		if (cs_enable) {
-			dce = __wcd9xxx_codec_sta_dce(mbhc, 1,  true, true);
-			dcez = mbhc->mbhc_data.dce_nsc_cs_z;
-			mb_mv = VDDIO_MICBIAS_MV;
-		} else {
-			dce = wcd9xxx_codec_sta_dce(mbhc, 1,  true);
-			dcez = mbhc->mbhc_data.dce_z;
-			mb_mv = mbhc->mbhc_data.micb_mv;
-		}
-
-		pr_debug("%s: DCE 0x%x,%d\n", __func__, dce,
-			  __wcd9xxx_codec_sta_dce_v(mbhc, true, dce,
-						    dcez, mb_mv));
-
-		cur_v_ins_h = cs_enable ? (s16) mbhc->mbhc_data.v_cs_ins_h :
-					  (wcd9xxx_get_current_v(mbhc,
-					   WCD9XXX_CURRENT_V_INS_H));
-
-		if (dce < cur_v_ins_h) {
-			removed = false;
-			break;
-		}
-	} while (!time_after(jiffies, timeout));
-	pr_debug("%s: headset %sactually removed\n", __func__,
-		  removed ? "" : "not ");
-
-	if (cs_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
-						  false, false);
-
-	if (removed) {
-		if (mbhc->mbhc_cfg->detect_extn_cable) {
-			if (!wcd9xxx_swch_level_remove(mbhc)) {
-				/*
-				 * extension cable is still plugged in
-				 * report it as LINEOUT device
-				 */
-				if (mbhc->hph_status == SND_JACK_HEADSET)
-					wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc,
-							false);
-				wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
-				wcd9xxx_cleanup_hs_polling(mbhc);
-				wcd9xxx_enable_hs_detect(mbhc, 1,
-							 MBHC_USE_MB_TRIGGER,
-							 false);
-			}
-		} else {
-			/* Cancel possibly running hs_detect_work */
-			wcd9xxx_cancel_hs_detect_plug(mbhc,
-						    &mbhc->correct_plug_noswch);
-			/*
-			 * If this removal is not false, first check the micbias
-			 * switch status and switch it to LDOH if it is already
-			 * switched to VDDIO.
-			 */
-			wcd9xxx_switch_micbias(mbhc, 0);
-
-			wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
-			wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
-			wcd9xxx_cleanup_hs_polling(mbhc);
-			wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER |
-							  MBHC_USE_HPHL_TRIGGER,
-						 true);
-		}
-	} else {
-		wcd9xxx_start_hs_polling(mbhc);
-	}
-	pr_debug("%s: leave\n", __func__);
-}
-
-/* called only from interrupt which is under codec_resource_lock acquisition */
-static void wcd9xxx_hs_insert_irq_extn(struct wcd9xxx_mbhc *mbhc,
-				       bool is_mb_trigger)
-{
-	/* Cancel possibly running hs_detect_work */
-	wcd9xxx_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
-
-	if (is_mb_trigger) {
-		pr_debug("%s: Waiting for Headphone left trigger\n", __func__);
-		wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_HPHL_TRIGGER, false);
-	} else  {
-		pr_debug("%s: HPHL trigger received, detecting plug type\n",
-			 __func__);
-		wcd9xxx_mbhc_detect_plug_type(mbhc);
-	}
-}
-
-static irqreturn_t wcd9xxx_hs_remove_irq(int irq, void *data)
-{
-	struct wcd9xxx_mbhc *mbhc = data;
-
-	pr_debug("%s: enter, removal interrupt\n", __func__);
-	WCD9XXX_BCL_LOCK(mbhc->resmgr);
-	/*
-	 * While we don't know whether MIC is there or not, let the resmgr know
-	 * so micbias can be disabled temporarily
-	 */
-	if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
-		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
-						WCD9XXX_COND_HPH_MIC, false);
-		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
-						WCD9XXX_COND_HPH, false);
-	} else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
-		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
-						WCD9XXX_COND_HPH, false);
-	}
-
-	if (mbhc->mbhc_cfg->detect_extn_cable &&
-	    !wcd9xxx_swch_level_remove(mbhc))
-		wcd9xxx_hs_remove_irq_noswch(mbhc);
-	else
-		wcd9xxx_hs_remove_irq_swch(mbhc);
-
-	if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
-		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
-						WCD9XXX_COND_HPH, true);
-		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
-						WCD9XXX_COND_HPH_MIC, true);
-	} else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
-		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
-						WCD9XXX_COND_HPH, true);
-	}
-	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t wcd9xxx_hs_insert_irq(int irq, void *data)
-{
-	bool is_mb_trigger, is_removal;
-	struct wcd9xxx_mbhc *mbhc = data;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_LOCK(mbhc->resmgr);
-	wcd9xxx_disable_irq(mbhc->resmgr->core_res, mbhc->intr_ids->insertion);
-
-	is_mb_trigger = !!(snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg) &
-			   0x10);
-	is_removal = !!(snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_INT_CTL) & 0x02);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
-
-	/* Turn off both HPH and MIC line schmitt triggers */
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
-
-	if (mbhc->mbhc_cfg->detect_extn_cable &&
-	    mbhc->current_plug == PLUG_TYPE_HIGH_HPH)
-		wcd9xxx_hs_insert_irq_extn(mbhc, is_mb_trigger);
-	else
-		wcd9xxx_hs_insert_irq_swch(mbhc, is_removal);
-
-	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	return IRQ_HANDLED;
-}
-
-static void wcd9xxx_btn_lpress_fn(struct work_struct *work)
-{
-	struct delayed_work *dwork;
-	short bias_value;
-	int dce_mv, sta_mv;
-	struct wcd9xxx_mbhc *mbhc;
-
-	pr_debug("%s:\n", __func__);
-
-	dwork = to_delayed_work(work);
-	mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_btn_dwork);
-
-	bias_value = wcd9xxx_read_sta_result(mbhc->codec);
-	sta_mv = wcd9xxx_codec_sta_dce_v(mbhc, 0, bias_value);
-
-	bias_value = wcd9xxx_read_dce_result(mbhc->codec);
-	dce_mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, bias_value);
-	pr_debug("%s: STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
-
-	pr_debug("%s: Reporting long button press event\n", __func__);
-	wcd9xxx_jack_report(mbhc, &mbhc->button_jack, mbhc->buttons_pressed,
-			    mbhc->buttons_pressed);
-
-	pr_debug("%s: leave\n", __func__);
-	wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
-}
-
-static void wcd9xxx_mbhc_insert_work(struct work_struct *work)
-{
-	struct delayed_work *dwork;
-	struct wcd9xxx_mbhc *mbhc;
-	struct snd_soc_codec *codec;
-	struct wcd9xxx_core_resource *core_res;
-
-	dwork = to_delayed_work(work);
-	mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_insert_dwork);
-	codec = mbhc->codec;
-	core_res = mbhc->resmgr->core_res;
-
-	pr_debug("%s:\n", __func__);
-
-	/* Turn off both HPH and MIC line schmitt triggers */
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
-	wcd9xxx_disable_irq_sync(core_res, mbhc->intr_ids->insertion);
-	wcd9xxx_mbhc_detect_plug_type(mbhc);
-	wcd9xxx_unlock_sleep(core_res);
-}
-
-static bool wcd9xxx_mbhc_fw_validate(const void *data, size_t size)
-{
-	u32 cfg_offset;
-	struct wcd9xxx_mbhc_imped_detect_cfg *imped_cfg;
-	struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
-	struct firmware_cal fw;
-
-	fw.data = (void *)data;
-	fw.size = size;
-
-	if (fw.size < WCD9XXX_MBHC_CAL_MIN_SIZE)
-		return false;
-
-	/*
-	 * Previous check guarantees that there is enough fw data up
-	 * to num_btn
-	 */
-	btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(fw.data);
-	cfg_offset = (u32) ((void *) btn_cfg - (void *) fw.data);
-	if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_BTN_SZ(btn_cfg)))
-		return false;
-
-	/*
-	 * Previous check guarantees that there is enough fw data up
-	 * to start of impedance detection configuration
-	 */
-	imped_cfg = WCD9XXX_MBHC_CAL_IMPED_DET_PTR(fw.data);
-	cfg_offset = (u32) ((void *) imped_cfg - (void *) fw.data);
-
-	if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_MIN_SZ))
-		return false;
-
-	if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_SZ(imped_cfg)))
-		return false;
-
-	return true;
-}
-
-static u16 wcd9xxx_codec_v_sta_dce(struct wcd9xxx_mbhc *mbhc,
-				   enum meas_type dce, s16 vin_mv,
-				   bool cs_enable)
-{
-	s16 diff, zero;
-	u32 mb_mv, in;
-	u16 value;
-	s16 dce_z;
-
-	mb_mv = mbhc->mbhc_data.micb_mv;
-	dce_z = mbhc->mbhc_data.dce_z;
-
-	if (mb_mv == 0) {
-		pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
-		return -EINVAL;
-	}
-	if (cs_enable) {
-		mb_mv = VDDIO_MICBIAS_MV;
-		dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
-	}
-
-	if (dce) {
-		diff = (mbhc->mbhc_data.dce_mb) - (dce_z);
-		zero = (dce_z);
-	} else {
-		diff = (mbhc->mbhc_data.sta_mb) - (mbhc->mbhc_data.sta_z);
-		zero = (mbhc->mbhc_data.sta_z);
-	}
-	in = (u32) diff * vin_mv;
-
-	value = (u16) (in / mb_mv) + zero;
-	return value;
-}
-
-static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc)
-{
-	struct snd_soc_codec *codec;
-	s16 adj_v_hs_max;
-	s16 btn_mv = 0, btn_mv_sta[MBHC_V_IDX_NUM], btn_mv_dce[MBHC_V_IDX_NUM];
-	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
-	struct wcd9xxx_mbhc_plug_type_cfg *plug_type;
-	u16 *btn_high;
-	int i;
-
-	pr_debug("%s: enter\n", __func__);
-	codec = mbhc->codec;
-	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
-	plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
-
-	mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max, false);
-	mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max, false);
-
-	mbhc->mbhc_data.v_inval_ins_low = FAKE_INS_LOW;
-	mbhc->mbhc_data.v_inval_ins_high = FAKE_INS_HIGH;
-
-	if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
-		adj_v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max,
-						  true);
-		mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_VDDIO] =
-		    wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max, false);
-		mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_VDDIO] =
-		    wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max, false);
-		mbhc->mbhc_data.v_inval_ins_low =
-		    scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_low,
-				       false);
-		mbhc->mbhc_data.v_inval_ins_high =
-		    scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_high,
-				       false);
-	}
-	mbhc->mbhc_data.v_cs_ins_h = wcd9xxx_codec_v_sta_dce(mbhc, DCE,
-							WCD9XXX_V_CS_HS_MAX,
-							true);
-	pr_debug("%s: v_ins_h for current source: 0x%x\n", __func__,
-		  mbhc->mbhc_data.v_cs_ins_h);
-
-	btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
-					       MBHC_BTN_DET_V_BTN_HIGH);
-	for (i = 0; i < btn_det->num_btn; i++)
-		btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
-
-	btn_mv_sta[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_sta;
-	btn_mv_dce[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_cic;
-	btn_mv_sta[MBHC_V_IDX_VDDIO] =
-	    scale_v_micb_vddio(mbhc, btn_mv_sta[MBHC_V_IDX_CFILT], true);
-	btn_mv_dce[MBHC_V_IDX_VDDIO] =
-	    scale_v_micb_vddio(mbhc, btn_mv_dce[MBHC_V_IDX_CFILT], true);
-
-	mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT],
-				    false);
-	mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT],
-				    false);
-	mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_VDDIO] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO],
-				    false);
-	mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO],
-				    false);
-
-	mbhc->mbhc_data.v_brh[MBHC_V_IDX_CFILT] =
-	    mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT];
-	mbhc->mbhc_data.v_brh[MBHC_V_IDX_VDDIO] =
-	    mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO];
-
-	mbhc->mbhc_data.v_brl = BUTTON_MIN;
-
-	mbhc->mbhc_data.v_no_mic =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_no_mic, false);
-	pr_debug("%s: leave\n", __func__);
-}
-
-static void wcd9xxx_onoff_ext_mclk(struct wcd9xxx_mbhc *mbhc, bool on)
-{
-	/*
-	 * XXX: {codec}_mclk_enable holds WCD9XXX_BCL_LOCK,
-	 * therefore wcd9xxx_onoff_ext_mclk caller SHOULDN'T hold
-	 * WCD9XXX_BCL_LOCK when it calls wcd9xxx_onoff_ext_mclk()
-	 */
-	if (mbhc && mbhc->mbhc_cfg && mbhc->mbhc_cfg->mclk_cb_fn)
-		mbhc->mbhc_cfg->mclk_cb_fn(mbhc->codec, on, false);
-}
-
-/*
- * Mic Bias Enable Decision
- * Return true if high_hph_cnt is a power of 2 (!= 2)
- * otherwise return false
- */
-static bool wcd9xxx_mbhc_enable_mb_decision(int high_hph_cnt)
-{
-	return (high_hph_cnt > 2) && !(high_hph_cnt & (high_hph_cnt - 1));
-}
-
-static inline void wcd9xxx_handle_gnd_mic_swap(struct wcd9xxx_mbhc *mbhc,
-					int pt_gnd_mic_swap_cnt,
-					enum wcd9xxx_mbhc_plug_type plug_type)
-{
-	if (mbhc->mbhc_cfg->swap_gnd_mic &&
-	    (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD)) {
-		/*
-		 * if switch is toggled, check again,
-		 * otherwise report unsupported plug
-		 */
-		mbhc->mbhc_cfg->swap_gnd_mic(mbhc->codec);
-	} else if (pt_gnd_mic_swap_cnt >= GND_MIC_SWAP_THRESHOLD) {
-		/* Report UNSUPPORTED plug
-		 * and continue polling
-		 */
-		WCD9XXX_BCL_LOCK(mbhc->resmgr);
-		if (!mbhc->mbhc_cfg->detect_extn_cable) {
-			if (mbhc->current_plug == PLUG_TYPE_HEADPHONE)
-				wcd9xxx_report_plug(mbhc, 0,
-						    SND_JACK_HEADPHONE);
-			else if (mbhc->current_plug == PLUG_TYPE_HEADSET)
-				wcd9xxx_report_plug(mbhc, 0,
-						    SND_JACK_HEADSET);
-		}
-		if (mbhc->current_plug != plug_type)
-			wcd9xxx_report_plug(mbhc, 1,
-					SND_JACK_UNSUPPORTED);
-		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	}
-}
-
-static void wcd9xxx_correct_swch_plug(struct work_struct *work)
-{
-	struct wcd9xxx_mbhc *mbhc;
-	struct snd_soc_codec *codec;
-	enum wcd9xxx_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
-	unsigned long timeout;
-	int retry = 0, pt_gnd_mic_swap_cnt = 0;
-	int highhph_cnt = 0;
-	bool correction = false;
-	bool current_source_enable;
-	bool wrk_complete = true, highhph = false;
-
-	pr_debug("%s: enter\n", __func__);
-
-	mbhc = container_of(work, struct wcd9xxx_mbhc, correct_plug_swch);
-	codec = mbhc->codec;
-
-	current_source_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
-		      (1 << MBHC_CS_ENABLE_POLLING)) != 0) &&
-		     (!(snd_soc_read(codec,
-				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
-
-	wcd9xxx_onoff_ext_mclk(mbhc, true);
-
-	/*
-	 * Keep override on during entire plug type correction work.
-	 *
-	 * This is okay under the assumption that any switch irqs which use
-	 * MBHC block cancel and sync this work so override is off again
-	 * prior to switch interrupt handler's MBHC block usage.
-	 * Also while this correction work is running, we can guarantee
-	 * DAPM doesn't use any MBHC block as this work only runs with
-	 * headphone detection.
-	 */
-	if (current_source_enable) {
-		WCD9XXX_BCL_LOCK(mbhc->resmgr);
-		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
-						  true, false);
-		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	} else {
-		wcd9xxx_turn_onoff_override(mbhc, true);
-	}
-
-	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
-	while (!time_after(jiffies, timeout)) {
-		++retry;
-
-		/* Make sure any pending memory read is completed, before
-		 * hs_detect_work_stop value is read.
-		 */
-		rmb();
-		if (mbhc->hs_detect_work_stop) {
-			wrk_complete = false;
-			pr_debug("%s: stop requested\n", __func__);
-			break;
-		}
-
-		msleep(HS_DETECT_PLUG_INERVAL_MS);
-		if (wcd9xxx_swch_level_remove(mbhc)) {
-			wrk_complete = false;
-			pr_debug("%s: Switch level is low\n", __func__);
-			break;
-		}
-
-		/* can race with removal interrupt */
-		WCD9XXX_BCL_LOCK(mbhc->resmgr);
-		if (current_source_enable)
-			plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc,
-								   highhph);
-		else
-			plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
-		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-
-		pr_debug("%s: attempt(%d) current_plug(%d) new_plug(%d)\n",
-			 __func__, retry, mbhc->current_plug, plug_type);
-
-		highhph_cnt = (plug_type == PLUG_TYPE_HIGH_HPH) ?
-					(highhph_cnt + 1) :
-					0;
-		highhph = wcd9xxx_mbhc_enable_mb_decision(highhph_cnt);
-		if (plug_type == PLUG_TYPE_INVALID) {
-			pr_debug("Invalid plug in attempt # %d\n", retry);
-			if (!mbhc->mbhc_cfg->detect_extn_cable &&
-			    retry == NUM_ATTEMPTS_TO_REPORT &&
-			    mbhc->current_plug == PLUG_TYPE_NONE) {
-				WCD9XXX_BCL_LOCK(mbhc->resmgr);
-				wcd9xxx_report_plug(mbhc, 1,
-						    SND_JACK_HEADPHONE);
-				WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-			}
-		} else if (plug_type == PLUG_TYPE_HEADPHONE) {
-			pr_debug("Good headphone detected, continue polling\n");
-			WCD9XXX_BCL_LOCK(mbhc->resmgr);
-			if (mbhc->mbhc_cfg->detect_extn_cable) {
-				if (mbhc->current_plug != plug_type)
-					wcd9xxx_report_plug(mbhc, 1,
-							    SND_JACK_HEADPHONE);
-			} else if (mbhc->current_plug == PLUG_TYPE_NONE) {
-				wcd9xxx_report_plug(mbhc, 1,
-						    SND_JACK_HEADPHONE);
-			}
-			WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-		} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
-			pr_debug("%s: High HPH detected, continue polling\n",
-				  __func__);
-			WCD9XXX_BCL_LOCK(mbhc->resmgr);
-			if (mbhc->mbhc_cfg->detect_extn_cable) {
-				if (mbhc->current_plug != plug_type)
-					wcd9xxx_report_plug(mbhc, 1,
-							    SND_JACK_LINEOUT);
-			} else if (mbhc->current_plug == PLUG_TYPE_NONE) {
-				wcd9xxx_report_plug(mbhc, 1,
-						    SND_JACK_HEADPHONE);
-			}
-			WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-		} else {
-			if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
-				pt_gnd_mic_swap_cnt++;
-				if (pt_gnd_mic_swap_cnt >=
-						GND_MIC_SWAP_THRESHOLD)
-					wcd9xxx_handle_gnd_mic_swap(mbhc,
-							pt_gnd_mic_swap_cnt,
-							plug_type);
-				pr_debug("%s: unsupported HS detected, continue polling\n",
-					 __func__);
-				continue;
-			} else {
-				pt_gnd_mic_swap_cnt = 0;
-
-				WCD9XXX_BCL_LOCK(mbhc->resmgr);
-				/* Turn off override/current source */
-				if (current_source_enable)
-					wcd9xxx_turn_onoff_current_source(mbhc,
-							&mbhc->mbhc_bias_regs,
-							false, false);
-				else
-					wcd9xxx_turn_onoff_override(mbhc,
-								    false);
-				/*
-				 * The valid plug also includes
-				 * PLUG_TYPE_GND_MIC_SWAP
-				 */
-				wcd9xxx_find_plug_and_report(mbhc, plug_type);
-				WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-				pr_debug("Attempt %d found correct plug %d\n",
-						retry,
-						plug_type);
-				correction = true;
-			}
-			break;
-		}
-	}
-
-	highhph = false;
-	if (wrk_complete && plug_type == PLUG_TYPE_HIGH_HPH) {
-		pr_debug("%s: polling is done, still HPH, so enabling MIC trigger\n",
-			 __func__);
-		WCD9XXX_BCL_LOCK(mbhc->resmgr);
-		wcd9xxx_find_plug_and_report(mbhc, plug_type);
-		highhph = true;
-		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	}
-
-	if (plug_type == PLUG_TYPE_HEADPHONE) {
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->hph_auto_pulldown_ctrl)
-			mbhc->mbhc_cb->hph_auto_pulldown_ctrl(codec, true);
-	}
-
-	if (!correction && current_source_enable) {
-		WCD9XXX_BCL_LOCK(mbhc->resmgr);
-		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
-						  false, highhph);
-		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	} else if (!correction) {
-		wcd9xxx_turn_onoff_override(mbhc, false);
-	}
-
-	wcd9xxx_onoff_ext_mclk(mbhc, false);
-
-	if (mbhc->mbhc_cfg->detect_extn_cable) {
-		WCD9XXX_BCL_LOCK(mbhc->resmgr);
-		if ((mbhc->current_plug == PLUG_TYPE_HEADPHONE &&
-		    wrk_complete) ||
-		    mbhc->current_plug == PLUG_TYPE_GND_MIC_SWAP ||
-		    mbhc->current_plug == PLUG_TYPE_INVALID ||
-		    (plug_type == PLUG_TYPE_INVALID && wrk_complete)) {
-			/* Enable removal detection */
-			wcd9xxx_cleanup_hs_polling(mbhc);
-			wcd9xxx_enable_hs_detect(mbhc, 0, 0, false);
-		}
-		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	}
-	pr_debug("%s: leave current_plug(%d)\n", __func__, mbhc->current_plug);
-	/* unlock sleep */
-	wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
-}
-
-static void wcd9xxx_swch_irq_handler(struct wcd9xxx_mbhc *mbhc)
-{
-	bool insert;
-	bool is_removed = false;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	pr_debug("%s: enter\n", __func__);
-
-	mbhc->in_swch_irq_handler = true;
-	/* Wait here for debounce time */
-	usleep_range(SWCH_IRQ_DEBOUNCE_TIME_US, SWCH_IRQ_DEBOUNCE_TIME_US +
-					WCD9XXX_USLEEP_RANGE_MARGIN_US);
-
-	WCD9XXX_BCL_LOCK(mbhc->resmgr);
-
-	/* cancel pending button press */
-	if (wcd9xxx_cancel_btn_work(mbhc))
-		pr_debug("%s: button press is canceled\n", __func__);
-
-	insert = !wcd9xxx_swch_level_remove(mbhc);
-	pr_debug("%s: Current plug type %d, insert %d\n", __func__,
-		 mbhc->current_plug, insert);
-	if ((mbhc->current_plug == PLUG_TYPE_NONE) && insert) {
-
-		mbhc->lpi_enabled = false;
-
-		/* Make sure mbhc state update complete before cancel detect
-		 * plug.
-		 */
-		wmb();
-		/* cancel detect plug */
-		wcd9xxx_cancel_hs_detect_plug(mbhc,
-				      &mbhc->correct_plug_swch);
-
-		if ((mbhc->current_plug != PLUG_TYPE_NONE) &&
-		    (mbhc->current_plug != PLUG_TYPE_HIGH_HPH) &&
-		    !(snd_soc_read(codec, WCD9XXX_A_MBHC_INSERT_DETECT) &
-				   (1 << 1))) {
-			pr_debug("%s: current plug: %d\n", __func__,
-				mbhc->current_plug);
-			goto exit;
-		}
-
-		/* Disable Mic Bias pull down and HPH Switch to GND */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01,
-				    0x00);
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01, 0x00);
-		wcd9xxx_mbhc_detect_plug_type(mbhc);
-	} else if ((mbhc->current_plug != PLUG_TYPE_NONE) && !insert) {
-		mbhc->lpi_enabled = false;
-
-		/* Make sure mbhc state update complete before cancel detect
-		 * plug.
-		 */
-		wmb();
-		/* cancel detect plug */
-		wcd9xxx_cancel_hs_detect_plug(mbhc,
-				      &mbhc->correct_plug_swch);
-
-		if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
-			wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
-			is_removed = true;
-		} else if (mbhc->current_plug == PLUG_TYPE_GND_MIC_SWAP) {
-			wcd9xxx_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED);
-			is_removed = true;
-		} else if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
-			wcd9xxx_pause_hs_polling(mbhc);
-			wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
-			wcd9xxx_cleanup_hs_polling(mbhc);
-			wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
-			is_removed = true;
-		} else if (mbhc->current_plug == PLUG_TYPE_HIGH_HPH) {
-			wcd9xxx_report_plug(mbhc, 0, SND_JACK_LINEOUT);
-			is_removed = true;
-		} else if (mbhc->current_plug == PLUG_TYPE_ANC_HEADPHONE) {
-			wcd9xxx_pause_hs_polling(mbhc);
-			wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
-			wcd9xxx_cleanup_hs_polling(mbhc);
-			wcd9xxx_report_plug(mbhc, 0, SND_JACK_ANC_HEADPHONE);
-			is_removed = true;
-		}
-
-		if (is_removed) {
-			snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				      0x00);
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-					    0x02, 0x00);
-
-			/* Enable Mic Bias pull down and HPH Switch to GND */
-			snd_soc_update_bits(codec,
-					mbhc->mbhc_bias_regs.ctl_reg, 0x01,
-					0x01);
-			snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01,
-					0x01);
-			/* Make sure mic trigger is turned off */
-			snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg,
-					    0x01, 0x01);
-			snd_soc_update_bits(codec,
-					    mbhc->mbhc_bias_regs.mbhc_reg,
-					    0x90, 0x00);
-			/* Reset MBHC State Machine */
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
-					    0x08, 0x08);
-			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
-					    0x08, 0x00);
-			/* Turn off override */
-			wcd9xxx_turn_onoff_override(mbhc, false);
-		}
-	}
-exit:
-	mbhc->in_swch_irq_handler = false;
-	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	pr_debug("%s: leave\n", __func__);
-}
-
-static irqreturn_t wcd9xxx_mech_plug_detect_irq(int irq, void *data)
-{
-	int r = IRQ_HANDLED;
-	struct wcd9xxx_mbhc *mbhc = data;
-
-	pr_debug("%s: enter\n", __func__);
-	if (unlikely(wcd9xxx_lock_sleep(mbhc->resmgr->core_res) == false)) {
-		pr_warn("%s: failed to hold suspend\n", __func__);
-		r = IRQ_NONE;
-	} else {
-		/* Call handler */
-		wcd9xxx_swch_irq_handler(mbhc);
-		wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
-	}
-
-	pr_debug("%s: leave %d\n", __func__, r);
-	return r;
-}
-
-static int wcd9xxx_is_false_press(struct wcd9xxx_mbhc *mbhc)
-{
-	s16 mb_v;
-	int i = 0;
-	int r = 0;
-	const s16 v_ins_hu =
-	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
-	const s16 v_ins_h =
-	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
-	const s16 v_b1_hu =
-	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
-	const s16 v_b1_h =
-	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
-	const unsigned long timeout =
-	    jiffies + msecs_to_jiffies(BTN_RELEASE_DEBOUNCE_TIME_MS);
-
-	while (time_before(jiffies, timeout)) {
-		/*
-		 * This function needs to run measurements just few times during
-		 * release debounce time.  Make 1ms interval to avoid
-		 * unnecessary excessive measurements.
-		 */
-		usleep_range(1000, 1000 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		if (i == 0) {
-			mb_v = wcd9xxx_codec_sta_dce(mbhc, 0, true);
-			pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
-				 wcd9xxx_codec_sta_dce_v(mbhc, 0, mb_v));
-			if (mb_v < v_b1_hu || mb_v > v_ins_hu) {
-				r = 1;
-				break;
-			}
-		} else {
-			mb_v = wcd9xxx_codec_sta_dce(mbhc, 1, true);
-			pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
-				 wcd9xxx_codec_sta_dce_v(mbhc, 1, mb_v));
-			if (mb_v < v_b1_h || mb_v > v_ins_h) {
-				r = 1;
-				break;
-			}
-		}
-		i++;
-	}
-
-	return r;
-}
-
-/* called under codec_resource_lock acquisition */
-static int wcd9xxx_determine_button(const struct wcd9xxx_mbhc *mbhc,
-				  const s32 micmv)
-{
-	s16 *v_btn_low, *v_btn_high;
-	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
-	int i, btn = -1;
-
-	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
-	v_btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
-						MBHC_BTN_DET_V_BTN_LOW);
-	v_btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
-						 MBHC_BTN_DET_V_BTN_HIGH);
-
-	for (i = 0; i < btn_det->num_btn; i++) {
-		if ((v_btn_low[i] <= micmv) && (v_btn_high[i] >= micmv)) {
-			btn = i;
-			break;
-		}
-	}
-
-	if (btn == -1)
-		pr_debug("%s: couldn't find button number for mic mv %d\n",
-			 __func__, micmv);
-
-	return btn;
-}
-
-static int wcd9xxx_get_button_mask(const int btn)
-{
-	int mask = 0;
-
-	switch (btn) {
-	case 0:
-		mask = SND_JACK_BTN_0;
-		break;
-	case 1:
-		mask = SND_JACK_BTN_1;
-		break;
-	case 2:
-		mask = SND_JACK_BTN_2;
-		break;
-	case 3:
-		mask = SND_JACK_BTN_3;
-		break;
-	case 4:
-		mask = SND_JACK_BTN_4;
-		break;
-	case 5:
-		mask = SND_JACK_BTN_5;
-		break;
-	}
-	return mask;
-}
-
-static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z,
-			  struct mbhc_micbias_regs *micb_regs,
-			  bool norel_detection)
-{
-	s16 reg0, reg1;
-	int change;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-	/* Pull down micbias to ground and disconnect vddio switch */
-	reg0 = snd_soc_read(codec, micb_regs->ctl_reg);
-	snd_soc_update_bits(codec, micb_regs->ctl_reg, 0x81, 0x1);
-	reg1 = snd_soc_read(codec, micb_regs->mbhc_reg);
-	snd_soc_update_bits(codec, micb_regs->mbhc_reg, 1 << 7, 0);
-
-	/* Disconnect override from micbias */
-	change = snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4,
-				     1 << 0);
-	usleep_range(1000, 1000 + 1000);
-	if (sta_z) {
-		*sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, norel_detection);
-		pr_debug("%s: sta_z 0x%x\n", __func__, *sta_z & 0xFFFF);
-	}
-	if (dce_z) {
-		*dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, norel_detection);
-		pr_debug("%s: dce_z 0x%x\n", __func__, *dce_z & 0xFFFF);
-	}
-
-	/* Connect override from micbias */
-	if (change)
-		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4,
-				    1 << 4);
-	/* Disable pull down micbias to ground */
-	snd_soc_write(codec, micb_regs->mbhc_reg, reg1);
-	snd_soc_write(codec, micb_regs->ctl_reg, reg0);
-}
-
-/*
- * This function recalibrates dce_z and sta_z parameters.
- * No release detection will be false when this function is
- * used.
- */
-void wcd9xxx_update_z(struct wcd9xxx_mbhc *mbhc)
-{
-	const u16 sta_z = mbhc->mbhc_data.sta_z;
-	const u16 dce_z = mbhc->mbhc_data.dce_z;
-
-	wcd9xxx_get_z(mbhc, &mbhc->mbhc_data.dce_z, &mbhc->mbhc_data.sta_z,
-		      &mbhc->mbhc_bias_regs, false);
-	pr_debug("%s: sta_z 0x%x,dce_z 0x%x -> sta_z 0x%x,dce_z 0x%x\n",
-		 __func__, sta_z & 0xFFFF, dce_z & 0xFFFF,
-		 mbhc->mbhc_data.sta_z & 0xFFFF,
-		 mbhc->mbhc_data.dce_z & 0xFFFF);
-
-	wcd9xxx_mbhc_calc_thres(mbhc);
-	wcd9xxx_calibrate_hs_polling(mbhc);
-}
-
-/*
- * wcd9xxx_update_rel_threshold : update mbhc release upper bound threshold
- *				  to ceilmv + buffer
- */
-static int wcd9xxx_update_rel_threshold(struct wcd9xxx_mbhc *mbhc, int ceilmv,
-					bool vddio)
-{
-	u16 v_brh, v_b1_hu;
-	int mv;
-	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
-	void *calibration = mbhc->mbhc_cfg->calibration;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration);
-	mv = ceilmv + btn_det->v_btn_press_delta_cic;
-	if (vddio)
-		mv = scale_v_micb_vddio(mbhc, mv, true);
-	pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
-
-	if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
-		/*
-		 * update LSB first so mbhc hardware block
-		 * doesn't see too low value.
-		 */
-		v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
-				0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-				(v_b1_hu >> 8) & 0xFF);
-		v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
-				0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-				(v_brh >> 8) & 0xFF);
-	}
-	return 0;
-}
-
-irqreturn_t wcd9xxx_dce_handler(int irq, void *data)
-{
-	int i, mask;
-	bool vddio;
-	u8 mbhc_status;
-	s16 dce_z, sta_z;
-	s32 stamv, stamv_s;
-	s16 *v_btn_high;
-	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
-	int btn = -1, meas = 0;
-	struct wcd9xxx_mbhc *mbhc = data;
-	const struct wcd9xxx_mbhc_btn_detect_cfg *d =
-	    WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
-	short btnmeas[d->n_btn_meas + 1];
-	short dce[d->n_btn_meas + 1], sta;
-	s32 mv[d->n_btn_meas + 1], mv_s[d->n_btn_meas + 1];
-	struct snd_soc_codec *codec = mbhc->codec;
-	struct wcd9xxx_core_resource *core_res = mbhc->resmgr->core_res;
-	int n_btn_meas = d->n_btn_meas;
-	void *calibration = mbhc->mbhc_cfg->calibration;
-
-	pr_debug("%s: enter\n", __func__);
-
-	WCD9XXX_BCL_LOCK(mbhc->resmgr);
-	mutex_lock(&mbhc->mbhc_lock);
-	mbhc_status = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_STATUS) & 0x3E;
-
-	if (mbhc->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
-		pr_debug("%s: mbhc is being recovered, skip button press\n",
-			 __func__);
-		goto done;
-	}
-
-	mbhc->mbhc_state = MBHC_STATE_POTENTIAL;
-
-	if (!mbhc->polling_active) {
-		pr_warn("%s: mbhc polling is not active, skip button press\n",
-			__func__);
-		goto done;
-	}
-
-	/* If switch nterrupt already kicked in, ignore button press */
-	if (mbhc->in_swch_irq_handler) {
-		pr_debug("%s: Swtich level changed, ignore button press\n",
-			 __func__);
-		btn = -1;
-		goto done;
-	}
-
-	/*
-	 * setup internal micbias if codec uses internal micbias for
-	 * headset detection
-	 */
-	if (mbhc->mbhc_cfg->use_int_rbias) {
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
-			mbhc->mbhc_cb->setup_int_rbias(codec, true);
-		else
-			pr_err("%s: internal bias requested but codec did not provide callback\n",
-				__func__);
-	}
-
-
-	/* Measure scaled HW DCE */
-	vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
-		 mbhc->mbhc_micbias_switched);
-
-	dce_z = mbhc->mbhc_data.dce_z;
-	sta_z = mbhc->mbhc_data.sta_z;
-
-	/* Measure scaled HW STA */
-	dce[0] = wcd9xxx_read_dce_result(codec);
-	sta = wcd9xxx_read_sta_result(codec);
-	if (mbhc_status != STATUS_REL_DETECTION) {
-		if (mbhc->mbhc_last_resume &&
-		    !time_after(jiffies, mbhc->mbhc_last_resume + HZ)) {
-			pr_debug("%s: Button is released after resume\n",
-				__func__);
-			n_btn_meas = 0;
-		} else {
-			pr_debug("%s: Button is released without resume",
-				 __func__);
-			if (mbhc->update_z) {
-				wcd9xxx_update_z(mbhc);
-				dce_z = mbhc->mbhc_data.dce_z;
-				sta_z = mbhc->mbhc_data.sta_z;
-				mbhc->update_z = true;
-			}
-			stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
-						mbhc->mbhc_data.micb_mv);
-			if (vddio)
-				stamv_s = scale_v_micb_vddio(mbhc, stamv,
-							     false);
-			else
-				stamv_s = stamv;
-			mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0],
-					  dce_z, mbhc->mbhc_data.micb_mv);
-			mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0],
-							     false) : mv[0];
-			btn = wcd9xxx_determine_button(mbhc, mv_s[0]);
-			if (btn != wcd9xxx_determine_button(mbhc, stamv_s))
-				btn = -1;
-			goto done;
-		}
-	}
-
-	for (meas = 1; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1)));
-	     meas++)
-		dce[meas] = wcd9xxx_codec_sta_dce(mbhc, 1, false);
-
-	if (mbhc->update_z) {
-		wcd9xxx_update_z(mbhc);
-		dce_z = mbhc->mbhc_data.dce_z;
-		sta_z = mbhc->mbhc_data.sta_z;
-		mbhc->update_z = true;
-	}
-
-	stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
-					  mbhc->mbhc_data.micb_mv);
-	if (vddio)
-		stamv_s = scale_v_micb_vddio(mbhc, stamv, false);
-	else
-		stamv_s = stamv;
-	pr_debug("%s: Meas HW - STA 0x%x,%d,%d\n", __func__,
-		 sta & 0xFFFF, stamv, stamv_s);
-
-	/* determine pressed button */
-	mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z,
-					  mbhc->mbhc_data.micb_mv);
-	mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0], false) : mv[0];
-	btnmeas[0] = wcd9xxx_determine_button(mbhc, mv_s[0]);
-	pr_debug("%s: Meas HW - DCE 0x%x,%d,%d button %d\n", __func__,
-		 dce[0] & 0xFFFF, mv[0], mv_s[0], btnmeas[0]);
-	if (n_btn_meas == 0)
-		btn = btnmeas[0];
-	for (meas = 1; (n_btn_meas && d->n_btn_meas &&
-			(meas < (d->n_btn_meas + 1))); meas++) {
-		mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z,
-						     mbhc->mbhc_data.micb_mv);
-		mv_s[meas] = vddio ? scale_v_micb_vddio(mbhc, mv[meas], false) :
-				     mv[meas];
-		btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s[meas]);
-		pr_debug("%s: Meas %d - DCE 0x%x,%d,%d button %d\n",
-			 __func__, meas, dce[meas] & 0xFFFF, mv[meas],
-			 mv_s[meas], btnmeas[meas]);
-		/*
-		 * if large enough measurements are collected,
-		 * start to check if last all n_btn_con measurements were
-		 * in same button low/high range
-		 */
-		if (meas + 1 >= d->n_btn_con) {
-			for (i = 0; i < d->n_btn_con; i++)
-				if ((btnmeas[meas] < 0) ||
-				    (btnmeas[meas] != btnmeas[meas - i]))
-					break;
-			if (i == d->n_btn_con) {
-				/* button pressed */
-				btn = btnmeas[meas];
-				break;
-			} else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
-				/*
-				 * if left measurements are less than n_btn_con,
-				 * it's impossible to find button number
-				 */
-				break;
-			}
-		}
-	}
-
-	if (btn >= 0) {
-		if (mbhc->in_swch_irq_handler) {
-			pr_debug(
-			"%s: Switch irq triggered, ignore button press\n",
-			__func__);
-			goto done;
-		}
-		btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration);
-		v_btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
-						       MBHC_BTN_DET_V_BTN_HIGH);
-		WARN_ON(btn >= btn_det->num_btn);
-		/* reprogram release threshold to catch voltage ramp up early */
-		wcd9xxx_update_rel_threshold(mbhc, v_btn_high[btn], vddio);
-
-		mask = wcd9xxx_get_button_mask(btn);
-		mbhc->buttons_pressed |= mask;
-		wcd9xxx_lock_sleep(core_res);
-		if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
-					  msecs_to_jiffies(400)) == 0) {
-			WARN(1, "Button pressed twice without release event\n");
-			wcd9xxx_unlock_sleep(core_res);
-		}
-	} else {
-		pr_debug("%s: bogus button press, too short press?\n",
-			 __func__);
-	}
-
- done:
-	pr_debug("%s: leave\n", __func__);
-	mutex_unlock(&mbhc->mbhc_lock);
-	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t wcd9xxx_release_handler(int irq, void *data)
-{
-	int ret;
-	bool waitdebounce = true;
-	struct wcd9xxx_mbhc *mbhc = data;
-
-	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_LOCK(mbhc->resmgr);
-	mbhc->mbhc_state = MBHC_STATE_RELEASE;
-
-	if (mbhc->buttons_pressed & WCD9XXX_JACK_BUTTON_MASK) {
-		ret = wcd9xxx_cancel_btn_work(mbhc);
-		if (ret == 0) {
-			pr_debug("%s: Reporting long button release event\n",
-				 __func__);
-			wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
-					    mbhc->buttons_pressed);
-		} else {
-			if (wcd9xxx_is_false_press(mbhc)) {
-				pr_debug("%s: Fake button press interrupt\n",
-					 __func__);
-			} else {
-				if (mbhc->in_swch_irq_handler) {
-					pr_debug("%s: Switch irq kicked in, ignore\n",
-						 __func__);
-				} else {
-					pr_debug("%s: Reporting btn press\n",
-						 __func__);
-					wcd9xxx_jack_report(mbhc,
-							 &mbhc->button_jack,
-							 mbhc->buttons_pressed,
-							 mbhc->buttons_pressed);
-					pr_debug("%s: Reporting btn release\n",
-						 __func__);
-					wcd9xxx_jack_report(mbhc,
-						      &mbhc->button_jack,
-						      0, mbhc->buttons_pressed);
-					waitdebounce = false;
-				}
-			}
-		}
-
-		mbhc->buttons_pressed &= ~WCD9XXX_JACK_BUTTON_MASK;
-	}
-
-	wcd9xxx_calibrate_hs_polling(mbhc);
-
-	if (waitdebounce)
-		msleep(SWCH_REL_DEBOUNCE_TIME_MS);
-	wcd9xxx_start_hs_polling(mbhc);
-
-	pr_debug("%s: leave\n", __func__);
-	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t wcd9xxx_hphl_ocp_irq(int irq, void *data)
-{
-	struct wcd9xxx_mbhc *mbhc = data;
-	struct snd_soc_codec *codec;
-
-	pr_info("%s: received HPHL OCP irq\n", __func__);
-
-	if (mbhc) {
-		codec = mbhc->codec;
-		if ((mbhc->hphlocp_cnt < OCP_ATTEMPT) &&
-		    (!mbhc->hphrocp_cnt)) {
-			pr_info("%s: retry\n", __func__);
-			mbhc->hphlocp_cnt++;
-			snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
-					    0x10, 0x00);
-			snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
-					    0x10, 0x10);
-		} else {
-			wcd9xxx_disable_irq(mbhc->resmgr->core_res,
-					  mbhc->intr_ids->hph_left_ocp);
-			mbhc->hph_status |= SND_JACK_OC_HPHL;
-			wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
-					    mbhc->hph_status,
-					    WCD9XXX_JACK_MASK);
-		}
-	} else {
-		pr_err("%s: Bad wcd9xxx private data\n", __func__);
-	}
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t wcd9xxx_hphr_ocp_irq(int irq, void *data)
-{
-	struct wcd9xxx_mbhc *mbhc = data;
-	struct snd_soc_codec *codec;
-
-	pr_info("%s: received HPHR OCP irq\n", __func__);
-	codec = mbhc->codec;
-	if ((mbhc->hphrocp_cnt < OCP_ATTEMPT) &&
-	    (!mbhc->hphlocp_cnt)) {
-		pr_info("%s: retry\n", __func__);
-		mbhc->hphrocp_cnt++;
-		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
-				    0x00);
-		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
-				    0x10);
-	} else {
-		wcd9xxx_disable_irq(mbhc->resmgr->core_res,
-				    mbhc->intr_ids->hph_right_ocp);
-		mbhc->hph_status |= SND_JACK_OC_HPHR;
-		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
-				    mbhc->hph_status, WCD9XXX_JACK_MASK);
-	}
-
-	return IRQ_HANDLED;
-}
-
-static int wcd9xxx_acdb_mclk_index(const int rate)
-{
-	if (rate == MCLK_RATE_12288KHZ)
-		return 0;
-	else if (rate == MCLK_RATE_9600KHZ)
-		return 1;
-	else {
-		BUG_ON(1);
-		return -EINVAL;
-	}
-}
-
-static void wcd9xxx_update_mbhc_clk_rate(struct wcd9xxx_mbhc *mbhc, u32 rate)
-{
-	u32 dce_wait, sta_wait;
-	u8 ncic, nmeas, navg;
-	void *calibration;
-	u8 *n_cic, *n_ready;
-	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
-	u8 npoll = 4, nbounce_wait = 30;
-	struct snd_soc_codec *codec = mbhc->codec;
-	int idx = wcd9xxx_acdb_mclk_index(rate);
-	int idxmclk = wcd9xxx_acdb_mclk_index(mbhc->mbhc_cfg->mclk_rate);
-
-	pr_debug("%s: Updating clock rate dependents, rate = %u\n", __func__,
-		 rate);
-	calibration = mbhc->mbhc_cfg->calibration;
-
-	/*
-	 * First compute the DCE / STA wait times depending on tunable
-	 * parameters. The value is computed in microseconds
-	 */
-	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration);
-	n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_N_READY);
-	n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_N_CIC);
-	nmeas = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
-	navg = WCD9XXX_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
-
-	/* ncic stays with the same what we had during calibration */
-	ncic = n_cic[idxmclk];
-	dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (rate / 1000);
-	sta_wait = (1000 * 128 * (navg + 1)) / (rate / 1000);
-	mbhc->mbhc_data.t_dce = dce_wait;
-	/* give extra margin to sta for safety */
-	mbhc->mbhc_data.t_sta = sta_wait + 250;
-	mbhc->mbhc_data.t_sta_dce = ((1000 * 256) / (rate / 1000) *
-				     n_ready[idx]) + 10;
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B1_CTL, n_ready[idx]);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B6_CTL, ncic);
-
-	if (rate == MCLK_RATE_12288KHZ) {
-		npoll = 4;
-		nbounce_wait = 30;
-	} else if (rate == MCLK_RATE_9600KHZ) {
-		npoll = 3;
-		nbounce_wait = 23;
-	}
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B2_CTL, npoll);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B3_CTL, nbounce_wait);
-	pr_debug("%s: leave\n", __func__);
-}
-
-static void wcd9xxx_mbhc_cal(struct wcd9xxx_mbhc *mbhc)
-{
-	u8 cfilt_mode;
-	u16 reg0, reg1, reg2;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	pr_debug("%s: enter\n", __func__);
-	wcd9xxx_disable_irq(mbhc->resmgr->core_res,
-			    mbhc->intr_ids->dce_est_complete);
-	wcd9xxx_turn_onoff_rel_detection(codec, false);
-
-	/* t_dce and t_sta are updated by wcd9xxx_update_mbhc_clk_rate() */
-	WARN_ON(!mbhc->mbhc_data.t_dce);
-	WARN_ON(!mbhc->mbhc_data.t_sta);
-
-	/*
-	 * LDOH and CFILT are already configured during pdata handling.
-	 * Only need to make sure CFILT and bandgap are in Fast mode.
-	 * Need to restore defaults once calculation is done.
-	 *
-	 * In case when Micbias is powered by external source, request
-	 * turn on the external voltage source for Calibration.
-	 */
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
-		mbhc->mbhc_cb->enable_mb_source(codec, true, false);
-
-	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
-		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
-	else
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
-				    0x40, 0x00);
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->micbias_pulldown_ctrl)
-		mbhc->mbhc_cb->micbias_pulldown_ctrl(mbhc, false);
-
-	/*
-	 * Micbias, CFILT, LDOH, MBHC MUX mode settings
-	 * to perform ADC calibration
-	 */
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->select_cfilt)
-		mbhc->mbhc_cb->select_cfilt(codec, mbhc);
-	else
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x60,
-			    mbhc->mbhc_cfg->micbias << 5);
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
-	snd_soc_update_bits(codec, WCD9XXX_A_LDO_H_MODE_1, 0x60, 0x60);
-	snd_soc_write(codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0x78);
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->codec_specific_cal)
-		mbhc->mbhc_cb->codec_specific_cal(codec, mbhc);
-	else
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-				    0x04, 0x04);
-
-	/* Pull down micbias to ground */
-	reg0 = snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg);
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 1, 1);
-	/* Disconnect override from micbias */
-	reg1 = snd_soc_read(codec, WCD9XXX_A_MAD_ANA_CTRL);
-	snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
-	/* Connect the MUX to micbias */
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
-		mbhc->mbhc_cb->enable_mux_bias_block(codec);
-	else
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				    0x80, 0x80);
-	/*
-	 * Hardware that has external cap can delay mic bias ramping down up
-	 * to 50ms.
-	 */
-	msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
-	/* DCE measurement for 0 voltage */
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
-	mbhc->mbhc_data.dce_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true, false);
-
-	/* compute dce_z for current source */
-	reg2 = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
-			    WCD9XXX_MBHC_NSC_CS << 3);
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
-	mbhc->mbhc_data.dce_nsc_cs_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true,
-							       false);
-	pr_debug("%s: dce_z with nsc cs: 0x%x\n", __func__,
-						 mbhc->mbhc_data.dce_nsc_cs_z);
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg2);
-
-	/* STA measurement for 0 voltage */
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
-	mbhc->mbhc_data.sta_z = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
-
-	/* Restore registers */
-	snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
-	snd_soc_write(codec, WCD9XXX_A_MAD_ANA_CTRL, reg1);
-
-	/* DCE measurment for MB voltage */
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
-		mbhc->mbhc_cb->enable_mux_bias_block(codec);
-	else
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				    0x80, 0x80);
-	/*
-	 * Hardware that has external cap can delay mic bias ramping down up
-	 * to 50ms.
-	 */
-	msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x04);
-	usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce +
-					WCD9XXX_USLEEP_RANGE_MARGIN_US);
-	mbhc->mbhc_data.dce_mb = wcd9xxx_read_dce_result(codec);
-
-	/* STA Measurement for MB Voltage */
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
-		mbhc->mbhc_cb->enable_mux_bias_block(codec);
-	else
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				    0x80, 0x80);
-	/*
-	 * Hardware that has external cap can delay mic bias ramping down up
-	 * to 50ms.
-	 */
-	msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
-	usleep_range(mbhc->mbhc_data.t_sta, mbhc->mbhc_data.t_sta +
-					WCD9XXX_USLEEP_RANGE_MARGIN_US);
-	mbhc->mbhc_data.sta_mb = wcd9xxx_read_sta_result(codec);
-
-	/* Restore default settings. */
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
-	snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
-		mbhc->mbhc_cb->enable_mux_bias_block(codec);
-	else
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				    0x80, 0x80);
-	usleep_range(100, 110);
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
-		mbhc->mbhc_cb->enable_mb_source(codec, false, false);
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->micbias_pulldown_ctrl)
-		mbhc->mbhc_cb->micbias_pulldown_ctrl(mbhc, true);
-
-	wcd9xxx_enable_irq(mbhc->resmgr->core_res,
-			   mbhc->intr_ids->dce_est_complete);
-	wcd9xxx_turn_onoff_rel_detection(codec, true);
-
-	pr_debug("%s: leave\n", __func__);
-}
-
-static void wcd9xxx_mbhc_setup(struct wcd9xxx_mbhc *mbhc)
-{
-	int n;
-	u8 *gain;
-	struct wcd9xxx_mbhc_general_cfg *generic;
-	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
-	struct snd_soc_codec *codec = mbhc->codec;
-	const int idx = wcd9xxx_acdb_mclk_index(mbhc->mbhc_cfg->mclk_rate);
-
-	pr_debug("%s: enter\n", __func__);
-	generic = WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
-	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
-
-	for (n = 0; n < 8; n++) {
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_FIR_B1_CFG,
-				    0x07, n);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_FIR_B2_CFG,
-			      btn_det->c[n]);
-	}
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B2_CTL, 0x07,
-			    btn_det->nc);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
-			    generic->mbhc_nsa << 4);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
-			    btn_det->n_meas);
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL,
-		      generic->mbhc_navg);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
-			    btn_det->mbhc_nsc << 3);
-
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->get_cdc_type &&
-			mbhc->mbhc_cb->get_cdc_type() !=
-					WCD9XXX_CDC_TYPE_HELICON) {
-		if (mbhc->resmgr->reg_addr->micb_4_mbhc)
-			snd_soc_update_bits(codec,
-					mbhc->resmgr->reg_addr->micb_4_mbhc,
-					0x03, MBHC_MICBIAS2);
-	}
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
-
-	gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_GAIN);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B2_CTL, 0x78,
-			    gain[idx] << 3);
-	snd_soc_update_bits(codec, WCD9XXX_A_MICB_2_MBHC, 0x04, 0x04);
-
-	pr_debug("%s: leave\n", __func__);
-}
-
-static int wcd9xxx_setup_jack_detect_irq(struct wcd9xxx_mbhc *mbhc)
-{
-	int ret = 0;
-	void *core_res = mbhc->resmgr->core_res;
-
-	if (mbhc->mbhc_cfg->gpio) {
-		ret = request_threaded_irq(mbhc->mbhc_cfg->gpio_irq, NULL,
-					   wcd9xxx_mech_plug_detect_irq,
-					   (IRQF_TRIGGER_RISING |
-					    IRQF_TRIGGER_FALLING),
-					   "headset detect", mbhc);
-		if (ret) {
-			pr_err("%s: Failed to request gpio irq %d\n", __func__,
-			       mbhc->mbhc_cfg->gpio_irq);
-		} else {
-			ret = enable_irq_wake(mbhc->mbhc_cfg->gpio_irq);
-			if (ret)
-				pr_err("%s: Failed to enable wake up irq %d\n",
-				       __func__, mbhc->mbhc_cfg->gpio_irq);
-		}
-	} else if (mbhc->mbhc_cfg->insert_detect) {
-		/* Enable HPHL_10K_SW */
-		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_RX_HPH_OCP_CTL,
-				    1 << 1, 1 << 1);
-
-		ret = wcd9xxx_request_irq(core_res,
-					  mbhc->intr_ids->hs_jack_switch,
-					  wcd9xxx_mech_plug_detect_irq,
-					  "Jack Detect",
-					  mbhc);
-		if (ret)
-			pr_err("%s: Failed to request insert detect irq %d\n",
-				__func__, mbhc->intr_ids->hs_jack_switch);
-	}
-
-	return ret;
-}
-
-static int wcd9xxx_init_and_calibrate(struct wcd9xxx_mbhc *mbhc)
-{
-	int ret = 0;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	pr_debug("%s: enter\n", __func__);
-
-	/* Enable MCLK during calibration */
-	wcd9xxx_onoff_ext_mclk(mbhc, true);
-	wcd9xxx_mbhc_setup(mbhc);
-	wcd9xxx_mbhc_cal(mbhc);
-	wcd9xxx_mbhc_calc_thres(mbhc);
-	wcd9xxx_onoff_ext_mclk(mbhc, false);
-	wcd9xxx_calibrate_hs_polling(mbhc);
-
-	/* Enable Mic Bias pull down and HPH Switch to GND */
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01, 0x01);
-	INIT_WORK(&mbhc->correct_plug_swch, wcd9xxx_correct_swch_plug);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
-			    0x10);
-	wcd9xxx_enable_irq(mbhc->resmgr->core_res,
-			   mbhc->intr_ids->hph_left_ocp);
-	wcd9xxx_enable_irq(mbhc->resmgr->core_res,
-			   mbhc->intr_ids->hph_right_ocp);
-
-	/* Initialize mechanical mbhc */
-	ret = wcd9xxx_setup_jack_detect_irq(mbhc);
-
-	if (!ret && mbhc->mbhc_cfg->gpio) {
-		/* Requested with IRQF_DISABLED */
-		enable_irq(mbhc->mbhc_cfg->gpio_irq);
-
-		/* Bootup time detection */
-		wcd9xxx_swch_irq_handler(mbhc);
-	} else if (!ret && mbhc->mbhc_cfg->insert_detect) {
-		pr_debug("%s: Setting up codec own insert detection\n",
-			 __func__);
-		/* Setup for insertion detection */
-		wcd9xxx_insert_detect_setup(mbhc, true);
-	}
-
-	pr_debug("%s: leave\n", __func__);
-
-	return ret;
-}
-
-static void wcd9xxx_mbhc_fw_read(struct work_struct *work)
-{
-	struct delayed_work *dwork;
-	struct wcd9xxx_mbhc *mbhc;
-	struct snd_soc_codec *codec;
-	const struct firmware *fw;
-	struct firmware_cal *fw_data = NULL;
-	int ret = -1, retry = 0;
-	bool use_default_cal = false;
-
-	dwork = to_delayed_work(work);
-	mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_firmware_dwork);
-	codec = mbhc->codec;
-
-	while (retry < FW_READ_ATTEMPTS) {
-		retry++;
-		pr_info("%s:Attempt %d to request MBHC firmware\n",
-				__func__, retry);
-		if (mbhc->mbhc_cb->get_hwdep_fw_cal)
-			fw_data = mbhc->mbhc_cb->get_hwdep_fw_cal(codec,
-					WCD9XXX_MBHC_CAL);
-		if (!fw_data)
-			ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin",
-					codec->dev);
-		/*
-		 * if request_firmware and hwdep cal both fail then
-		 * retry for few times before bailing out
-		 */
-		if ((ret != 0) && !fw_data) {
-			usleep_range(FW_READ_TIMEOUT, FW_READ_TIMEOUT +
-					WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		} else {
-			pr_info("%s: MBHC Firmware read successful\n",
-					__func__);
-			break;
-		}
-	}
-	if (!fw_data)
-		pr_info("%s: using request_firmware\n", __func__);
-	else
-		pr_info("%s: using hwdep cal\n", __func__);
-	if (ret != 0 && !fw_data) {
-		pr_err("%s: Cannot load MBHC firmware use default cal\n",
-				__func__);
-		use_default_cal = true;
-	}
-	if (!use_default_cal) {
-		const void *data;
-		size_t size;
-
-		if (fw_data) {
-			data = fw_data->data;
-			size = fw_data->size;
-		} else {
-			data = fw->data;
-			size = fw->size;
-		}
-		if (wcd9xxx_mbhc_fw_validate(data, size) == false) {
-			pr_err("%s: Invalid MBHC cal data size use default cal\n",
-			       __func__);
-			if (!fw_data)
-				release_firmware(fw);
-		} else {
-			if (fw_data) {
-				mbhc->mbhc_cfg->calibration =
-						(void *)fw_data->data;
-				mbhc->mbhc_cal = fw_data;
-			} else {
-				mbhc->mbhc_cfg->calibration =
-						(void *)fw->data;
-				mbhc->mbhc_fw = fw;
-			}
-		}
-	}
-
-	(void) wcd9xxx_init_and_calibrate(mbhc);
-}
-
-#ifdef CONFIG_DEBUG_FS
-ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
-			      size_t count, loff_t *pos)
-{
-	const int size = 768;
-	char buffer[size];
-	int n = 0;
-	struct wcd9xxx_mbhc *mbhc = file->private_data;
-	const struct mbhc_internal_cal_data *p = &mbhc->mbhc_data;
-	const s16 v_ins_hu =
-	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
-	const s16 v_ins_h =
-	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
-	const s16 v_b1_hu =
-	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
-	const s16 v_b1_h =
-	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
-	const s16 v_br_h =
-	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
-
-	n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n",
-		      p->dce_z, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
-	n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
-		       p->dce_mb, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_mb));
-	n += scnprintf(buffer + n, size - n, "dce_nsc_cs_z = %x(%dmv)\n",
-		      p->dce_nsc_cs_z,
-		      __wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_nsc_cs_z,
-						p->dce_nsc_cs_z,
-						VDDIO_MICBIAS_MV));
-	n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
-		       p->sta_z, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_z));
-	n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
-		       p->sta_mb, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_mb));
-	n += scnprintf(buffer + n, size - n, "t_dce = %d\n",  p->t_dce);
-	n += scnprintf(buffer + n, size - n, "t_sta = %d\n",  p->t_sta);
-	n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n", p->micb_mv);
-	n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)\n",
-		       v_ins_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_ins_hu));
-	n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)\n",
-		       v_ins_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_ins_h));
-	n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
-		       v_b1_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_b1_hu));
-	n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
-		       v_b1_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_b1_h));
-	n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
-		       v_br_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_br_h));
-	n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n",  p->v_brl,
-		       wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_brl));
-	n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
-		       p->v_no_mic,
-		       wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_no_mic));
-	n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
-		       p->v_inval_ins_low);
-	n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
-		       p->v_inval_ins_high);
-	n += scnprintf(buffer + n, size - n, "Insert detect insert = %d\n",
-		       !wcd9xxx_swch_level_remove(mbhc));
-	buffer[n] = 0;
-
-	return simple_read_from_buffer(buf, count, pos, buffer, n);
-}
-
-static int codec_debug_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static ssize_t codec_debug_write(struct file *filp,
-				 const char __user *ubuf, size_t cnt,
-				 loff_t *ppos)
-{
-	char lbuf[32];
-	char *buf;
-	int rc;
-	struct wcd9xxx_mbhc *mbhc = filp->private_data;
-
-	if (cnt > sizeof(lbuf) - 1)
-		return -EINVAL;
-
-	rc = copy_from_user(lbuf, ubuf, cnt);
-	if (rc)
-		return -EFAULT;
-
-	lbuf[cnt] = '\0';
-	buf = (char *)lbuf;
-	mbhc->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
-					     false : true;
-	return rc;
-}
-
-static const struct file_operations mbhc_trrs_debug_ops = {
-	.open = codec_debug_open,
-	.write = codec_debug_write,
-};
-
-static const struct file_operations mbhc_debug_ops = {
-	.open = codec_debug_open,
-	.read = codec_mbhc_debug_read,
-};
-
-static void wcd9xxx_init_debugfs(struct wcd9xxx_mbhc *mbhc)
-{
-	mbhc->debugfs_poke =
-	    debugfs_create_file("TRRS", S_IFREG | 0444, NULL, mbhc,
-				&mbhc_trrs_debug_ops);
-	mbhc->debugfs_mbhc =
-	    debugfs_create_file("wcd9xxx_mbhc", S_IFREG | 0444,
-				NULL, mbhc, &mbhc_debug_ops);
-}
-
-static void wcd9xxx_cleanup_debugfs(struct wcd9xxx_mbhc *mbhc)
-{
-	debugfs_remove(mbhc->debugfs_poke);
-	debugfs_remove(mbhc->debugfs_mbhc);
-}
-#else
-static void wcd9xxx_init_debugfs(struct wcd9xxx_mbhc *mbhc)
-{
-}
-
-static void wcd9xxx_cleanup_debugfs(struct wcd9xxx_mbhc *mbhc)
-{
-}
-#endif
-
-int wcd9xxx_mbhc_set_keycode(struct wcd9xxx_mbhc *mbhc)
-{
-	enum snd_jack_types type = SND_JACK_BTN_0;
-	int i, ret, result = 0;
-	int *btn_key_code;
-
-	btn_key_code = mbhc->mbhc_cfg->key_code;
-
-	for (i = 0 ; i < 8 ; i++) {
-		if (btn_key_code[i] != 0) {
-			switch (i) {
-			case 0:
-				type = SND_JACK_BTN_0;
-				break;
-			case 1:
-				type = SND_JACK_BTN_1;
-				break;
-			case 2:
-				type = SND_JACK_BTN_2;
-				break;
-			case 3:
-				type = SND_JACK_BTN_3;
-				break;
-			case 4:
-				type = SND_JACK_BTN_4;
-				break;
-			case 5:
-				type = SND_JACK_BTN_5;
-				break;
-			default:
-				WARN_ONCE(1, "Wrong button number:%d\n", i);
-				result = -1;
-				break;
-			}
-			ret = snd_jack_set_key(mbhc->button_jack.jack,
-					       type,
-					       btn_key_code[i]);
-			if (ret) {
-				pr_err("%s: Failed to set code for %d\n",
-					__func__, btn_key_code[i]);
-				result = -1;
-			}
-			input_set_capability(
-				mbhc->button_jack.jack->input_dev,
-				EV_KEY, btn_key_code[i]);
-			pr_debug("%s: set btn%d key code:%d\n", __func__,
-				i, btn_key_code[i]);
-		}
-	}
-	return result;
-}
-
-int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
-		       struct wcd9xxx_mbhc_config *mbhc_cfg)
-{
-	int rc = 0;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	pr_debug("%s: enter\n", __func__);
-
-	if (!codec) {
-		pr_err("%s: no codec\n", __func__);
-		return -EINVAL;
-	}
-
-	if (mbhc_cfg->mclk_rate != MCLK_RATE_12288KHZ &&
-	    mbhc_cfg->mclk_rate != MCLK_RATE_9600KHZ) {
-		pr_err("Error: unsupported clock rate %d\n",
-		       mbhc_cfg->mclk_rate);
-		return -EINVAL;
-	}
-
-	/* Save mbhc config */
-	mbhc->mbhc_cfg = mbhc_cfg;
-
-	/* Set btn key code */
-	if (wcd9xxx_mbhc_set_keycode(mbhc))
-		pr_err("Set btn key code error!!!\n");
-
-	/* Get HW specific mbhc registers' address */
-	wcd9xxx_get_mbhc_micbias_regs(mbhc, MBHC_PRIMARY_MIC_MB);
-
-	/* Get HW specific mbhc registers' address for anc */
-	wcd9xxx_get_mbhc_micbias_regs(mbhc, MBHC_ANC_MIC_MB);
-
-	/* Put CFILT in fast mode by default */
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
-		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
-	else
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
-		0x40, WCD9XXX_CFILT_FAST_MODE);
-
-	/*
-	 * setup internal micbias if codec uses internal micbias for
-	 * headset detection
-	 */
-	if (mbhc->mbhc_cfg->use_int_rbias) {
-		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias) {
-			mbhc->mbhc_cb->setup_int_rbias(codec, true);
-		} else {
-			pr_info("%s: internal bias requested but codec did not provide callback\n",
-				__func__);
-		}
-	}
-
-	/*
-	 * If codec has specific clock gating for MBHC,
-	 * remove the clock gate
-	 */
-	if (mbhc->mbhc_cb &&
-			mbhc->mbhc_cb->enable_clock_gate)
-		mbhc->mbhc_cb->enable_clock_gate(mbhc->codec, true);
-
-	if (!mbhc->mbhc_cfg->read_fw_bin ||
-	    (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw) ||
-	    (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_cal)) {
-		rc = wcd9xxx_init_and_calibrate(mbhc);
-	} else {
-		if (!mbhc->mbhc_fw || !mbhc->mbhc_cal)
-			schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
-					     usecs_to_jiffies(FW_READ_TIMEOUT));
-		else
-			pr_debug("%s: Skipping to read mbhc fw, 0x%pK %pK\n",
-				 __func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
-	}
-
-	pr_debug("%s: leave %d\n", __func__, rc);
-	return rc;
-}
-EXPORT_SYMBOL(wcd9xxx_mbhc_start);
-
-void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc)
-{
-	if (mbhc->mbhc_fw || mbhc->mbhc_cal) {
-		cancel_delayed_work_sync(&mbhc->mbhc_firmware_dwork);
-		if (!mbhc->mbhc_cal)
-			release_firmware(mbhc->mbhc_fw);
-		mbhc->mbhc_fw = NULL;
-		mbhc->mbhc_cal = NULL;
-	}
-}
-EXPORT_SYMBOL(wcd9xxx_mbhc_stop);
-
-static enum wcd9xxx_micbias_num
-wcd9xxx_event_to_micbias(const enum wcd9xxx_notify_event event)
-{
-	enum wcd9xxx_micbias_num ret;
-
-	switch (event) {
-	case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
-	case WCD9XXX_EVENT_PRE_MICBIAS_1_OFF:
-	case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
-	case WCD9XXX_EVENT_POST_MICBIAS_1_OFF:
-		ret = MBHC_MICBIAS1;
-		break;
-	case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
-	case WCD9XXX_EVENT_PRE_MICBIAS_2_OFF:
-	case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
-	case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
-		ret = MBHC_MICBIAS2;
-		break;
-	case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
-	case WCD9XXX_EVENT_PRE_MICBIAS_3_OFF:
-	case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
-	case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
-		ret = MBHC_MICBIAS3;
-		break;
-	case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
-	case WCD9XXX_EVENT_PRE_MICBIAS_4_OFF:
-	case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
-	case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
-		ret = MBHC_MICBIAS4;
-		break;
-	default:
-		WARN_ONCE(1, "Cannot convert event %d to micbias\n", event);
-		ret = MBHC_MICBIAS_INVALID;
-		break;
-	}
-	return ret;
-}
-
-static int wcd9xxx_event_to_cfilt(const enum wcd9xxx_notify_event event)
-{
-	int ret;
-
-	switch (event) {
-	case WCD9XXX_EVENT_PRE_CFILT_1_OFF:
-	case WCD9XXX_EVENT_POST_CFILT_1_OFF:
-	case WCD9XXX_EVENT_PRE_CFILT_1_ON:
-	case WCD9XXX_EVENT_POST_CFILT_1_ON:
-		ret = WCD9XXX_CFILT1_SEL;
-		break;
-	case WCD9XXX_EVENT_PRE_CFILT_2_OFF:
-	case WCD9XXX_EVENT_POST_CFILT_2_OFF:
-	case WCD9XXX_EVENT_PRE_CFILT_2_ON:
-	case WCD9XXX_EVENT_POST_CFILT_2_ON:
-		ret = WCD9XXX_CFILT2_SEL;
-		break;
-	case WCD9XXX_EVENT_PRE_CFILT_3_OFF:
-	case WCD9XXX_EVENT_POST_CFILT_3_OFF:
-	case WCD9XXX_EVENT_PRE_CFILT_3_ON:
-	case WCD9XXX_EVENT_POST_CFILT_3_ON:
-		ret = WCD9XXX_CFILT3_SEL;
-		break;
-	default:
-		ret = -1;
-	}
-	return ret;
-}
-
-static int wcd9xxx_get_mbhc_cfilt_sel(struct wcd9xxx_mbhc *mbhc)
-{
-	int cfilt;
-	const struct wcd9xxx_micbias_setting *mb_pdata =
-		mbhc->resmgr->micbias_pdata;
-
-	switch (mbhc->mbhc_cfg->micbias) {
-	case MBHC_MICBIAS1:
-		cfilt = mb_pdata->bias1_cfilt_sel;
-		break;
-	case MBHC_MICBIAS2:
-		cfilt = mb_pdata->bias2_cfilt_sel;
-		break;
-	case MBHC_MICBIAS3:
-		cfilt = mb_pdata->bias3_cfilt_sel;
-		break;
-	case MBHC_MICBIAS4:
-		cfilt = mb_pdata->bias4_cfilt_sel;
-		break;
-	default:
-		cfilt = MBHC_MICBIAS_INVALID;
-		break;
-	}
-	return cfilt;
-}
-
-static void wcd9xxx_enable_mbhc_txfe(struct wcd9xxx_mbhc *mbhc, bool on)
-{
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mbhc_txfe)
-		mbhc->mbhc_cb->enable_mbhc_txfe(mbhc->codec, on);
-	else
-		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL,
-				    0x40, on ? 0x40 : 0x00);
-}
-
-static int wcd9xxx_event_notify(struct notifier_block *self, unsigned long val,
-				void *data)
-{
-	int ret = 0;
-	struct wcd9xxx_mbhc *mbhc = ((struct wcd9xxx_resmgr *)data)->mbhc;
-	struct snd_soc_codec *codec;
-	enum wcd9xxx_notify_event event = (enum wcd9xxx_notify_event)val;
-
-	pr_debug("%s: enter event %s(%d)\n", __func__,
-		 wcd9xxx_get_event_string(event), event);
-
-	if (!mbhc || !mbhc->mbhc_cfg) {
-		pr_debug("mbhc not initialized\n");
-		return 0;
-	}
-	codec = mbhc->codec;
-	mutex_lock(&mbhc->mbhc_lock);
-	switch (event) {
-	/* MICBIAS usage change */
-	case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
-	case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
-	case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
-	case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
-		    wcd9xxx_event_to_micbias(event)) {
-			wcd9xxx_switch_micbias(mbhc, 0);
-			/*
-			 * Enable MBHC TxFE whenever  micbias is
-			 * turned ON and polling is active
-			 */
-			if (mbhc->polling_active)
-				wcd9xxx_enable_mbhc_txfe(mbhc, true);
-		}
-		break;
-	case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
-	case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
-	case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
-	case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
-		    wcd9xxx_event_to_micbias(event) &&
-		    wcd9xxx_mbhc_polling(mbhc)) {
-			/* if polling is on, restart it */
-			wcd9xxx_pause_hs_polling(mbhc);
-			wcd9xxx_start_hs_polling(mbhc);
-		}
-		break;
-	case WCD9XXX_EVENT_POST_MICBIAS_1_OFF:
-	case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
-	case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
-	case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
-		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
-		    wcd9xxx_event_to_micbias(event)) {
-			if (mbhc->event_state &
-			   (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
-				wcd9xxx_switch_micbias(mbhc, 1);
-			/*
-			 * Disable MBHC TxFE, in case it was enabled earlier
-			 * when micbias was enabled and polling is not active.
-			 */
-			if (!mbhc->polling_active)
-				wcd9xxx_enable_mbhc_txfe(mbhc, false);
-		}
-		if (mbhc->micbias_enable && mbhc->polling_active &&
-		    !(snd_soc_read(mbhc->codec, mbhc->mbhc_bias_regs.ctl_reg)
-		    & 0x80)) {
-			pr_debug("%s:Micbias turned off by recording, set up again",
-				 __func__);
-			snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg,
-					    0x80, 0x80);
-		}
-		break;
-	/* PA usage change */
-	case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
-		set_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
-		if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg) & 0x80))
-			/* if micbias is not enabled, switch to vddio */
-			wcd9xxx_switch_micbias(mbhc, 1);
-		break;
-	case WCD9XXX_EVENT_PRE_HPHR_PA_ON:
-		set_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
-		break;
-	case WCD9XXX_EVENT_POST_HPHL_PA_OFF:
-		clear_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
-		/* if HPH PAs are off, report OCP and switch back to CFILT */
-		clear_bit(WCD9XXX_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
-		clear_bit(WCD9XXX_HPHL_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
-		if (mbhc->hph_status & SND_JACK_OC_HPHL)
-			hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
-		if (!(mbhc->event_state &
-		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR |
-		       1 << MBHC_EVENT_PRE_TX_3_ON)))
-			wcd9xxx_switch_micbias(mbhc, 0);
-		break;
-	case WCD9XXX_EVENT_POST_HPHR_PA_OFF:
-		clear_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
-		/* if HPH PAs are off, report OCP and switch back to CFILT */
-		clear_bit(WCD9XXX_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
-		clear_bit(WCD9XXX_HPHR_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
-		if (mbhc->hph_status & SND_JACK_OC_HPHR)
-			hphrocp_off_report(mbhc, SND_JACK_OC_HPHL);
-		if (!(mbhc->event_state &
-		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR |
-		       1 << MBHC_EVENT_PRE_TX_3_ON)))
-			wcd9xxx_switch_micbias(mbhc, 0);
-		break;
-	/* Clock usage change */
-	case WCD9XXX_EVENT_PRE_MCLK_ON:
-		break;
-	case WCD9XXX_EVENT_POST_MCLK_ON:
-		/* Change to lower TxAAF frequency */
-		snd_soc_update_bits(codec, WCD9XXX_A_TX_COM_BIAS, 1 << 4,
-				    1 << 4);
-		/* Re-calibrate clock rate dependent values */
-		wcd9xxx_update_mbhc_clk_rate(mbhc, mbhc->mbhc_cfg->mclk_rate);
-		/* If clock source changes, stop and restart polling */
-		if (wcd9xxx_mbhc_polling(mbhc)) {
-			wcd9xxx_calibrate_hs_polling(mbhc);
-			wcd9xxx_start_hs_polling(mbhc);
-		}
-		break;
-	case WCD9XXX_EVENT_PRE_MCLK_OFF:
-		/* If clock source changes, stop and restart polling */
-		if (wcd9xxx_mbhc_polling(mbhc))
-			wcd9xxx_pause_hs_polling(mbhc);
-		break;
-	case WCD9XXX_EVENT_POST_MCLK_OFF:
-		break;
-	case WCD9XXX_EVENT_PRE_RCO_ON:
-		break;
-	case WCD9XXX_EVENT_POST_RCO_ON:
-		/* Change to higher TxAAF frequency */
-		snd_soc_update_bits(codec, WCD9XXX_A_TX_COM_BIAS, 1 << 4,
-				    0 << 4);
-		/* Re-calibrate clock rate dependent values */
-		wcd9xxx_update_mbhc_clk_rate(mbhc, mbhc->rco_clk_rate);
-		/* If clock source changes, stop and restart polling */
-		if (wcd9xxx_mbhc_polling(mbhc)) {
-			wcd9xxx_calibrate_hs_polling(mbhc);
-			wcd9xxx_start_hs_polling(mbhc);
-		}
-		break;
-	case WCD9XXX_EVENT_PRE_RCO_OFF:
-		/* If clock source changes, stop and restart polling */
-		if (wcd9xxx_mbhc_polling(mbhc))
-			wcd9xxx_pause_hs_polling(mbhc);
-		break;
-	case WCD9XXX_EVENT_POST_RCO_OFF:
-		break;
-	/* CFILT usage change */
-	case WCD9XXX_EVENT_PRE_CFILT_1_ON:
-	case WCD9XXX_EVENT_PRE_CFILT_2_ON:
-	case WCD9XXX_EVENT_PRE_CFILT_3_ON:
-		if (wcd9xxx_get_mbhc_cfilt_sel(mbhc) ==
-		    wcd9xxx_event_to_cfilt(event))
-			/*
-			 * Switch CFILT to slow mode if MBHC CFILT is being
-			 * used.
-			 */
-			wcd9xxx_codec_switch_cfilt_mode(mbhc, false);
-		break;
-	case WCD9XXX_EVENT_POST_CFILT_1_OFF:
-	case WCD9XXX_EVENT_POST_CFILT_2_OFF:
-	case WCD9XXX_EVENT_POST_CFILT_3_OFF:
-		if (wcd9xxx_get_mbhc_cfilt_sel(mbhc) ==
-		    wcd9xxx_event_to_cfilt(event))
-			/*
-			 * Switch CFILT to fast mode if MBHC CFILT is not
-			 * used anymore.
-			 */
-			wcd9xxx_codec_switch_cfilt_mode(mbhc, true);
-		break;
-	/* System resume */
-	case WCD9XXX_EVENT_POST_RESUME:
-		mbhc->mbhc_last_resume = jiffies;
-		break;
-	/* BG mode chage */
-	case WCD9XXX_EVENT_PRE_BG_OFF:
-	case WCD9XXX_EVENT_POST_BG_OFF:
-	case WCD9XXX_EVENT_PRE_BG_AUDIO_ON:
-	case WCD9XXX_EVENT_POST_BG_AUDIO_ON:
-	case WCD9XXX_EVENT_PRE_BG_MBHC_ON:
-	case WCD9XXX_EVENT_POST_BG_MBHC_ON:
-		/* Not used for now */
-		break;
-	case WCD9XXX_EVENT_PRE_TX_3_ON:
-		/*
-		 * if polling is ON, mbhc micbias not enabled
-		 *  switch micbias source to VDDIO
-		 */
-		set_bit(MBHC_EVENT_PRE_TX_3_ON, &mbhc->event_state);
-		if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg)
-		      & 0x80) &&
-		    mbhc->polling_active && !mbhc->mbhc_micbias_switched)
-			wcd9xxx_switch_micbias(mbhc, 1);
-		break;
-	case WCD9XXX_EVENT_POST_TX_3_OFF:
-		/*
-		 * Switch back to micbias if HPH PA or TX3 path
-		 * is disabled
-		 */
-		clear_bit(MBHC_EVENT_PRE_TX_3_ON, &mbhc->event_state);
-		if (mbhc->polling_active && mbhc->mbhc_micbias_switched &&
-		    !(mbhc->event_state & (1 << MBHC_EVENT_PA_HPHL |
-		      1 << MBHC_EVENT_PA_HPHR)))
-			wcd9xxx_switch_micbias(mbhc, 0);
-		break;
-	default:
-		WARN(1, "Unknown event %d\n", event);
-		ret = -EINVAL;
-	}
-	mutex_unlock(&mbhc->mbhc_lock);
-
-	pr_debug("%s: leave\n", __func__);
-
-	return ret;
-}
-
-static s16 wcd9xxx_read_impedance_regs(struct wcd9xxx_mbhc *mbhc)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	short bias_value;
-	int i;
-	s32 z_t = 0;
-	s32 z_loop = z_det_box_car_avg;
-
-	/* Box Car avrg of less than a particular loop count will not be
-	 * accomodated. Similarly if the count is more than a particular number
-	 * it will not be counted. Set z_loop counter to a limit, if its more
-	 * or less than the value in WCD9XXX_BOX_CAR_AVRG_MAX or
-	 * WCD9XXX_BOX_CAR_AVRG_MIN
-	 */
-	if (z_loop < WCD9XXX_BOX_CAR_AVRG_MIN) {
-		dev_dbg(codec->dev,
-			"%s: Box Car avrg counter < %d. Limiting it to %d\n",
-			__func__, WCD9XXX_BOX_CAR_AVRG_MIN,
-			WCD9XXX_BOX_CAR_AVRG_MIN);
-		z_loop = WCD9XXX_BOX_CAR_AVRG_MIN;
-	} else if (z_loop > WCD9XXX_BOX_CAR_AVRG_MAX) {
-		dev_dbg(codec->dev,
-			"%s: Box Car avrg counter > %d. Limiting it to %d\n",
-			__func__, WCD9XXX_BOX_CAR_AVRG_MAX,
-			WCD9XXX_BOX_CAR_AVRG_MAX);
-		z_loop = WCD9XXX_BOX_CAR_AVRG_MAX;
-	}
-
-	/* Take box car average if needed */
-	for (i = 0; i < z_loop; i++) {
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
-		/* Wait for atleast 1800uS to let register write to settle */
-		usleep_range(1800, 1800 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		z_t += wcd9xxx_read_sta_result(codec);
-	}
-	/* Take average of the Z values read */
-	bias_value = (s16) (z_t / z_loop);
-	return bias_value;
-}
-
-static int wcd9xxx_remeasure_z_values(struct wcd9xxx_mbhc *mbhc,
-					s16 l[3], s16 r[3],
-					uint32_t *zl, uint32_t *zr,
-					u32 *zl_stereo, u32 *zl_mono)
-{
-	s16 l_t[3] = {0}, r_t[3] = {0};
-	s16 l2_stereo, l2_mono;
-	bool left, right;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	if (!mbhc->mbhc_cb || !mbhc->mbhc_cb->setup_zdet ||
-		!mbhc->mbhc_cb->compute_impedance) {
-		dev_err(codec->dev, "%s: Invalid parameters\n", __func__);
-		return -EINVAL;
-	}
-
-	left = !!(l);
-	right = !!(r);
-
-	dev_dbg(codec->dev, "%s: Remeasuring impedance values\n", __func__);
-	dev_dbg(codec->dev, "%s: l: %pK, r: %pK, left=%d, right=%d\n", __func__,
-		 l, r, left, right);
-
-	/* Remeasure V2 values */
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
-	if (right)
-		r_t[2] = wcd9xxx_read_impedance_regs(mbhc);
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0);
-	if (left)
-		l_t[2] = wcd9xxx_read_impedance_regs(mbhc);
-
-	/* Ramp down HPHR */
-	mbhc->mbhc_cb->setup_zdet(mbhc, MBHC_ZDET_HPHR_RAMP_DISABLE);
-
-	if (right) {
-		/* Take R0'/R1' */
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_2,
-				    0xFF, 0xF8);
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
-				    0xFF, 0xA0);
-		r_t[1] = wcd9xxx_read_impedance_regs(mbhc);
-		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_2,
-				    0xFF, 0xF0);
-		r_t[0] = wcd9xxx_read_impedance_regs(mbhc);
-	}
-
-	/* Put back gain to 1x */
-	if (!left && right)
-		mbhc->mbhc_cb->setup_zdet(mbhc, MBHC_ZDET_GAIN_0);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0);
-	/* Take L2'' measurement */
-	l2_stereo = wcd9xxx_read_impedance_regs(mbhc);
-
-	/* Turn off HPHR PA and take L2''' */
-	mbhc->mbhc_cb->setup_zdet(mbhc, MBHC_ZDET_HPHR_PA_DISABLE);
-	l2_mono = wcd9xxx_read_impedance_regs(mbhc);
-
-	/* Ramp HPHL from -15mV to 0V */
-	mbhc->mbhc_cb->setup_zdet(mbhc, MBHC_ZDET_HPHL_RAMP_DISABLE);
-
-	/* Take L0' and L1' with iCal */
-	l_t[0] = wcd9xxx_read_impedance_regs(mbhc);
-	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF8);
-	l_t[1] = wcd9xxx_read_impedance_regs(mbhc);
-
-	if (left) {
-		l[0] = l_t[0];
-		l[1] = l_t[1];
-		l[2] = l_t[2];
-	}
-	if (right) {
-		r[0] = r_t[0];
-		r[1] = r_t[1];
-		r[2] = r_t[2];
-	}
-
-	/* compute the new impedance values */
-	mbhc->mbhc_cb->compute_impedance(mbhc, l, r, zl, zr);
-
-	if (!left && right)
-		mbhc->mbhc_cb->setup_zdet(mbhc, MBHC_ZDET_GAIN_UPDATE_1X);
-	/* compute the new ZL'' value */
-	l_t[2] = l2_stereo;
-	mbhc->mbhc_cb->compute_impedance(mbhc, l_t, NULL, zl_stereo, NULL);
-	/* compute the new ZL''' value */
-	l_t[2] = l2_mono;
-	mbhc->mbhc_cb->compute_impedance(mbhc, l_t, NULL, zl_mono, NULL);
-
-	pr_debug("%s: L0': 0x%x, L1': 0x%x L2_stereo: 0x%x, L2_mono: 0x%x\n",
-		 __func__, l_t[0] & 0xffff, l_t[1] & 0xffff,
-		 l2_stereo & 0xffff, l2_mono & 0xffff);
-	pr_debug("%s: ZL_stereo = %u, ZL_mono = %u\n",
-		 __func__, *zl_stereo, *zl_mono);
-
-	return 0;
-}
-
-static enum mbhc_zdet_zones wcd9xxx_assign_zdet_zone(uint32_t zl, uint32_t zr,
-						     int32_t *gain)
-{
-	enum mbhc_zdet_zones zdet_zone;
-
-	if (WCD9XXX_IS_IN_ZDET_ZONE_1(zl) &&
-		 WCD9XXX_IS_IN_ZDET_ZONE_1(zr)) {
-		zdet_zone = ZL_ZONE1__ZR_ZONE1;
-		*gain = 0;
-	} else if (WCD9XXX_IS_IN_ZDET_ZONE_2(zl) &&
-		 WCD9XXX_IS_IN_ZDET_ZONE_2(zr)) {
-		zdet_zone = ZL_ZONE2__ZR_ZONE2;
-		*gain = MBHC_ZDET_GAIN_1;
-	} else if (WCD9XXX_IS_IN_ZDET_ZONE_3(zl) &&
-		 WCD9XXX_IS_IN_ZDET_ZONE_3(zr)) {
-		zdet_zone = ZL_ZONE3__ZR_ZONE3;
-		*gain = MBHC_ZDET_GAIN_2;
-	} else if (WCD9XXX_IS_IN_ZDET_ZONE_2(zl) &&
-		 WCD9XXX_IS_IN_ZDET_ZONE_1(zr)) {
-		zdet_zone = ZL_ZONE2__ZR_ZONE1;
-		*gain = MBHC_ZDET_GAIN_1;
-	} else if (WCD9XXX_IS_IN_ZDET_ZONE_3(zl) &&
-		 WCD9XXX_IS_IN_ZDET_ZONE_1(zr)) {
-		zdet_zone = ZL_ZONE3__ZR_ZONE1;
-		*gain = MBHC_ZDET_GAIN_2;
-	} else if (WCD9XXX_IS_IN_ZDET_ZONE_1(zl) &&
-		 WCD9XXX_IS_IN_ZDET_ZONE_2(zr)) {
-		zdet_zone = ZL_ZONE1__ZR_ZONE2;
-		*gain = MBHC_ZDET_GAIN_1;
-	} else if (WCD9XXX_IS_IN_ZDET_ZONE_1(zl) &&
-		 WCD9XXX_IS_IN_ZDET_ZONE_3(zr)) {
-		zdet_zone = ZL_ZONE1__ZR_ZONE3;
-		*gain = MBHC_ZDET_GAIN_2;
-	} else {
-		zdet_zone = ZL_ZR_NOT_IN_ZONE1;
-		*gain = MBHC_ZDET_GAIN_1;
-	}
-
-	return zdet_zone;
-}
-
-static int wcd9xxx_detect_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
-				    uint32_t *zr)
-{
-	int i;
-	int ret = 0;
-	u8 micb_mbhc_val;
-	s16 l[3], r[3];
-	s16 *z[] = {
-		&l[0], &r[0], &r[1], &l[1], &l[2], &r[2],
-	};
-	u32 zl_stereo, zl_mono;
-	u32 zl_diff_1, zl_diff_2;
-	bool override_en;
-	struct snd_soc_codec *codec = mbhc->codec;
-	const int mux_wait_us = 25;
-	const struct wcd9xxx_reg_mask_val reg_set_mux[] = {
-		/* Phase 1 */
-		/* Set MBHC_MUX for HPHL without ical */
-		{WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0},
-		/* Set MBHC_MUX for HPHR without ical */
-		{WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xA0},
-		/* Set MBHC_MUX for HPHR with ical */
-		{WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF8},
-		/* Set MBHC_MUX for HPHL with ical */
-		{WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0},
-
-		/* Phase 2 */
-		{WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0},
-		/* Set MBHC_MUX for HPHR without ical and wait for 25us */
-		{WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xA0},
-	};
-
-	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-
-	if (!mbhc->mbhc_cb || !mbhc->mbhc_cb->setup_zdet ||
-	    !mbhc->mbhc_cb->compute_impedance || !zl || !zr) {
-		return -EINVAL;
-	}
-
-	/*
-	 * Impedance detection is an intrusive function as it mutes RX paths,
-	 * enable PAs and etc.  Therefore codec drvier including ALSA
-	 * shouldn't read and write hardware registers during detection.
-	 */
-	wcd9xxx_onoff_ext_mclk(mbhc, true);
-
-	/*
-	 * For impedance detection, make sure to disable micbias from
-	 * override signal so that override does not cause micbias
-	 * to be enabled. This setting will be undone after completing
-	 * impedance measurement.
-	 */
-	micb_mbhc_val = snd_soc_read(codec, WCD9XXX_A_MAD_ANA_CTRL);
-	snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL,
-			    0x10, 0x00);
-
-	override_en = (snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x04) ?
-					true : false;
-	if (!override_en)
-		wcd9xxx_turn_onoff_override(mbhc, true);
-	pr_debug("%s: Setting impedance detection\n", __func__);
-
-	/* Codec specific setup for L0, R0, L1 and R1 measurements */
-	mbhc->mbhc_cb->setup_zdet(mbhc, MBHC_ZDET_PRE_MEASURE);
-
-	pr_debug("%s: Performing impedance detection\n", __func__);
-	for (i = 0; i < ARRAY_SIZE(reg_set_mux) - 2; i++) {
-		snd_soc_update_bits(codec, reg_set_mux[i].reg,
-				    reg_set_mux[i].mask,
-				    reg_set_mux[i].val);
-		if (mbhc->mbhc_cb->get_cdc_type &&
-		    mbhc->mbhc_cb->get_cdc_type() ==
-				WCD9XXX_CDC_TYPE_TOMTOM) {
-			*(z[i]) = wcd9xxx_read_impedance_regs(mbhc);
-		} else {
-			if (mbhc->mbhc_cb->enable_mux_bias_block)
-				mbhc->mbhc_cb->enable_mux_bias_block(codec);
-			else
-				snd_soc_update_bits(codec,
-						WCD9XXX_A_MBHC_SCALING_MUX_1,
-						0x80, 0x80);
-			/* 25us is required after mux change to settle down */
-			usleep_range(mux_wait_us,
-				 mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-			*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0,
-							  true, false);
-		}
-	}
-
-	/* Codec specific setup for L2 and R2 measurements */
-	mbhc->mbhc_cb->setup_zdet(mbhc, MBHC_ZDET_POST_MEASURE);
-
-	for (; i < ARRAY_SIZE(reg_set_mux); i++) {
-		snd_soc_update_bits(codec, reg_set_mux[i].reg,
-				    reg_set_mux[i].mask,
-				    reg_set_mux[i].val);
-		if (mbhc->mbhc_cb->get_cdc_type &&
-		    mbhc->mbhc_cb->get_cdc_type() ==
-				WCD9XXX_CDC_TYPE_TOMTOM) {
-			*(z[i]) = wcd9xxx_read_impedance_regs(mbhc);
-		} else {
-			if (mbhc->mbhc_cb->enable_mux_bias_block)
-				mbhc->mbhc_cb->enable_mux_bias_block(codec);
-			else
-				snd_soc_update_bits(codec,
-						WCD9XXX_A_MBHC_SCALING_MUX_1,
-						0x80, 0x80);
-			/* 25us is required after mux change to settle down */
-			usleep_range(mux_wait_us,
-				mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-			*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0,
-							  true, false);
-		}
-	}
-
-	mbhc->mbhc_cb->compute_impedance(mbhc, l, r, zl, zr);
-
-	/*
-	 * For some codecs, an additional step of zdet is needed
-	 * to overcome effects of noise and for better accuracy of
-	 * z values
-	 */
-	if (mbhc->mbhc_cb->get_cdc_type &&
-	     mbhc->mbhc_cb->get_cdc_type() == WCD9XXX_CDC_TYPE_TOMTOM) {
-		uint32_t zl_t = 0, zr_t = 0;
-		s16 *l_p, *r_p;
-		enum mbhc_zdet_zones zdet_zone;
-		int32_t gain;
-
-		zdet_zone = wcd9xxx_assign_zdet_zone(*zl, *zr, &gain);
-		switch (zdet_zone) {
-		case ZL_ZONE1__ZR_ZONE1:
-			l_p = NULL;
-			r_p = NULL;
-			break;
-		case ZL_ZONE2__ZR_ZONE2:
-		case ZL_ZONE3__ZR_ZONE3:
-		case ZL_ZR_NOT_IN_ZONE1:
-			l_p = l;
-			r_p = r;
-			break;
-		case ZL_ZONE2__ZR_ZONE1:
-		case ZL_ZONE3__ZR_ZONE1:
-		/* If ZR falls in Zone 1, further computations with
-		 * gain update are not required
-		 */
-			l_p = l;
-			r_p = NULL;
-			break;
-		case ZL_ZONE1__ZR_ZONE2:
-		case ZL_ZONE1__ZR_ZONE3:
-		/* If ZL falls in Zone 1, further computations with
-		 * gain update are not required
-		 */
-			l_p = NULL;
-			r_p = r;
-			break;
-		}
-		pr_debug("%s:zdet_zone = %d, gain = %d\n", __func__,
-			 zdet_zone, gain);
-		if (gain)
-			mbhc->mbhc_cb->setup_zdet(mbhc, gain);
-
-		wcd9xxx_remeasure_z_values(mbhc, l_p, r_p, &zl_t, &zr_t,
-					   &zl_stereo, &zl_mono);
-
-		*zl = (zl_t) ? zl_t : *zl;
-		*zr = (zr_t) ? zr_t : *zr;
-
-		/* Check for Mono/Stereo Type
-		 * Conditions to classify Mono/Stereo
-		 * i. Difference of zl_stereo and zl_mono > (1/2) of zl_mono
-		 * ii. Absolute difference of zl and zr above a threshold
-		 */
-		zl_diff_1 = (zl_mono > zl_stereo) ? (zl_mono - zl_stereo) :
-						  (zl_stereo - zl_mono);
-		zl_diff_2 = (*zl > *zr) ? (*zl - *zr) : (*zr - *zl);
-
-		mbhc->hph_type = MBHC_HPH_NONE;
-		if (mbhc->current_plug != PLUG_TYPE_HIGH_HPH) {
-			if ((zl_diff_1 > (zl_mono >> 1)) ||
-			    (zl_diff_2 > WCD9XXX_MONO_HS_DIFF_THR) ||
-			    ((*zl < WCD9XXX_MONO_HS_MIN_THR) &&
-			     (*zr > WCD9XXX_MONO_HS_MIN_THR)) ||
-			    ((*zr < WCD9XXX_MONO_HS_MIN_THR) &&
-			     (*zl > WCD9XXX_MONO_HS_MIN_THR))) {
-				pr_debug("%s: MONO plug type detected\n",
-					 __func__);
-				mbhc->hph_type = MBHC_HPH_MONO;
-				*zl = zl_mono;
-			} else {
-				pr_debug("%s: STEREO plug type detected\n",
-					 __func__);
-				mbhc->hph_type = MBHC_HPH_STEREO;
-			}
-		}
-	}
-
-	mbhc->mbhc_cb->setup_zdet(mbhc, MBHC_ZDET_PA_DISABLE);
-
-	/* Calculate z values based on the Q-fuse registers, if used */
-	if (mbhc->mbhc_cb->zdet_error_approx)
-		mbhc->mbhc_cb->zdet_error_approx(mbhc, zl, zr);
-
-	wcd9xxx_onoff_ext_mclk(mbhc, false);
-
-	if (!override_en)
-		wcd9xxx_turn_onoff_override(mbhc, false);
-
-	/* Undo the micbias disable for override */
-	snd_soc_write(codec, WCD9XXX_A_MAD_ANA_CTRL, micb_mbhc_val);
-
-	pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d)\n",
-		 __func__,
-		 l[0] & 0xffff, l[0], l[1] & 0xffff, l[1], l[2] & 0xffff, l[2]);
-	pr_debug("%s: R0: 0x%x(%d), R1: 0x%x(%d), R2: 0x%x(%d)\n",
-		 __func__,
-		 r[0] & 0xffff, r[0], r[1] & 0xffff, r[1], r[2] & 0xffff, r[2]);
-	pr_debug("%s: RL %u milliohm, RR %u milliohm\n", __func__, *zl, *zr);
-	pr_debug("%s: Impedance detection completed\n", __func__);
-
-	return ret;
-}
-
-int wcd9xxx_mbhc_get_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
-			       uint32_t *zr)
-{
-	*zl = mbhc->zl;
-	*zr = mbhc->zr;
-
-	if (*zl && *zr)
-		return 0;
-	else
-		return -EINVAL;
-}
-
-/*
- * wcd9xxx_mbhc_init : initialize MBHC internal structures.
- *
- * NOTE: mbhc->mbhc_cfg is not YET configure so shouldn't be used
- */
-int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
-		      struct snd_soc_codec *codec,
-		      int (*micbias_enable_cb)(struct snd_soc_codec*,  bool,
-						enum wcd9xxx_micbias_num),
-		      const struct wcd9xxx_mbhc_cb *mbhc_cb,
-		      const struct wcd9xxx_mbhc_intr *mbhc_cdc_intr_ids,
-		      int rco_clk_rate,
-		      bool impedance_det_en)
-{
-	int ret;
-	void *core_res;
-
-	pr_debug("%s: enter\n", __func__);
-	memset(&mbhc->mbhc_bias_regs, 0, sizeof(struct mbhc_micbias_regs));
-	memset(&mbhc->mbhc_data, 0, sizeof(struct mbhc_internal_cal_data));
-
-	mbhc->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
-	mbhc->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
-	mbhc->mbhc_data.t_sta = DEFAULT_STA_WAIT;
-	mbhc->mbhc_micbias_switched = false;
-	mbhc->polling_active = false;
-	mbhc->mbhc_state = MBHC_STATE_NONE;
-	mbhc->in_swch_irq_handler = false;
-	mbhc->current_plug = PLUG_TYPE_NONE;
-	mbhc->lpi_enabled = false;
-	mbhc->no_mic_headset_override = false;
-	mbhc->mbhc_last_resume = 0;
-	mbhc->codec = codec;
-	mbhc->resmgr = resmgr;
-	mbhc->resmgr->mbhc = mbhc;
-	mbhc->micbias_enable_cb = micbias_enable_cb;
-	mbhc->rco_clk_rate = rco_clk_rate;
-	mbhc->mbhc_cb = mbhc_cb;
-	mbhc->intr_ids = mbhc_cdc_intr_ids;
-	mbhc->impedance_detect = impedance_det_en;
-	mbhc->hph_type = MBHC_HPH_NONE;
-
-	if (mbhc->intr_ids == NULL) {
-		pr_err("%s: Interrupt mapping not provided\n", __func__);
-		return -EINVAL;
-	}
-
-	if (mbhc->headset_jack.jack == NULL) {
-		ret = snd_soc_card_jack_new(codec->component.card,
-					    "Headset Jack", WCD9XXX_JACK_MASK,
-					    &mbhc->headset_jack, NULL, 0);
-		if (ret) {
-			pr_err("%s: Failed to create new jack\n", __func__);
-			return ret;
-		}
-
-		ret = snd_soc_card_jack_new(codec->component.card,
-					    "Button Jack",
-					    WCD9XXX_JACK_BUTTON_MASK,
-					    &mbhc->button_jack, NULL, 0);
-		if (ret) {
-			pr_err("Failed to create new jack\n");
-			return ret;
-		}
-
-		ret = snd_jack_set_key(mbhc->button_jack.jack,
-				       SND_JACK_BTN_0,
-				       KEY_MEDIA);
-		if (ret) {
-			pr_err("%s: Failed to set code for btn-0\n",
-				__func__);
-			return ret;
-		}
-
-		INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
-				  wcd9xxx_mbhc_fw_read);
-		INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
-		INIT_DELAYED_WORK(&mbhc->mbhc_insert_dwork,
-				  wcd9xxx_mbhc_insert_work);
-	}
-
-	mutex_init(&mbhc->mbhc_lock);
-
-	/* Register event notifier */
-	mbhc->nblock.notifier_call = wcd9xxx_event_notify;
-	ret = wcd9xxx_resmgr_register_notifier(mbhc->resmgr, &mbhc->nblock);
-	if (ret) {
-		pr_err("%s: Failed to register notifier %d\n", __func__, ret);
-		mutex_destroy(&mbhc->mbhc_lock);
-		return ret;
-	}
-
-	wcd9xxx_init_debugfs(mbhc);
-
-	/* Disable Impedance detection by default for certain codec types */
-	if (mbhc->mbhc_cb && mbhc->mbhc_cb->get_cdc_type &&
-	    (mbhc->mbhc_cb->get_cdc_type() == WCD9XXX_CDC_TYPE_HELICON))
-		impedance_detect_en = 0;
-	else
-		impedance_detect_en = impedance_det_en ? 1 : 0;
-
-	core_res = mbhc->resmgr->core_res;
-	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->insertion,
-				  wcd9xxx_hs_insert_irq,
-				  "Headset insert detect", mbhc);
-	if (ret) {
-		pr_err("%s: Failed to request irq %d, ret = %d\n", __func__,
-		       mbhc->intr_ids->insertion, ret);
-		goto err_insert_irq;
-	}
-	wcd9xxx_disable_irq(core_res, mbhc->intr_ids->insertion);
-
-	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->poll_plug_rem,
-				  wcd9xxx_hs_remove_irq,
-				  "Headset remove detect", mbhc);
-	if (ret) {
-		pr_err("%s: Failed to request irq %d\n", __func__,
-			mbhc->intr_ids->poll_plug_rem);
-		goto err_remove_irq;
-	}
-
-	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->dce_est_complete,
-				  wcd9xxx_dce_handler, "DC Estimation detect",
-				  mbhc);
-	if (ret) {
-		pr_err("%s: Failed to request irq %d\n", __func__,
-		       mbhc->intr_ids->dce_est_complete);
-		goto err_potential_irq;
-	}
-
-	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->button_release,
-				  wcd9xxx_release_handler,
-				  "Button Release detect", mbhc);
-	if (ret) {
-		pr_err("%s: Failed to request irq %d\n", __func__,
-			mbhc->intr_ids->button_release);
-		goto err_release_irq;
-	}
-
-	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->hph_left_ocp,
-				  wcd9xxx_hphl_ocp_irq, "HPH_L OCP detect",
-				  mbhc);
-	if (ret) {
-		pr_err("%s: Failed to request irq %d\n", __func__,
-		       mbhc->intr_ids->hph_left_ocp);
-		goto err_hphl_ocp_irq;
-	}
-	wcd9xxx_disable_irq(core_res, mbhc->intr_ids->hph_left_ocp);
-
-	ret = wcd9xxx_request_irq(core_res, mbhc->intr_ids->hph_right_ocp,
-				  wcd9xxx_hphr_ocp_irq, "HPH_R OCP detect",
-				  mbhc);
-	if (ret) {
-		pr_err("%s: Failed to request irq %d\n", __func__,
-		       mbhc->intr_ids->hph_right_ocp);
-		goto err_hphr_ocp_irq;
-	}
-	wcd9xxx_disable_irq(core_res, mbhc->intr_ids->hph_right_ocp);
-
-	wcd9xxx_regmgr_cond_register(resmgr, 1 << WCD9XXX_COND_HPH_MIC |
-					     1 << WCD9XXX_COND_HPH);
-
-	pr_debug("%s: leave ret %d\n", __func__, ret);
-	return ret;
-
-err_hphr_ocp_irq:
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hph_left_ocp, mbhc);
-err_hphl_ocp_irq:
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->button_release, mbhc);
-err_release_irq:
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->dce_est_complete, mbhc);
-err_potential_irq:
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->poll_plug_rem, mbhc);
-err_remove_irq:
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->insertion, mbhc);
-err_insert_irq:
-	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
-
-	mutex_destroy(&mbhc->mbhc_lock);
-
-	pr_debug("%s: leave ret %d\n", __func__, ret);
-	return ret;
-}
-EXPORT_SYMBOL(wcd9xxx_mbhc_init);
-
-void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc)
-{
-	struct wcd9xxx_core_resource *core_res =
-				mbhc->resmgr->core_res;
-
-	wcd9xxx_regmgr_cond_deregister(mbhc->resmgr, 1 << WCD9XXX_COND_HPH_MIC |
-						     1 << WCD9XXX_COND_HPH);
-
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->button_release, mbhc);
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->dce_est_complete, mbhc);
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->poll_plug_rem, mbhc);
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->insertion, mbhc);
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hs_jack_switch, mbhc);
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hph_left_ocp, mbhc);
-	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hph_right_ocp, mbhc);
-
-	mutex_destroy(&mbhc->mbhc_lock);
-	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
-	wcd9xxx_cleanup_debugfs(mbhc);
-}
-EXPORT_SYMBOL(wcd9xxx_mbhc_deinit);
-
-MODULE_DESCRIPTION("wcd9xxx MBHC module");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
deleted file mode 100644
index e35f7d4..0000000
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ /dev/null
@@ -1,492 +0,0 @@
-/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef __WCD9XXX_MBHC_H__
-#define __WCD9XXX_MBHC_H__
-
-#include "wcd9xxx-resmgr.h"
-#include "wcdcal-hwdep.h"
-
-#define WCD9XXX_CFILT_FAST_MODE 0x00
-#define WCD9XXX_CFILT_SLOW_MODE 0x40
-#define WCD9XXX_CFILT_EXT_PRCHG_EN 0x30
-#define WCD9XXX_CFILT_EXT_PRCHG_DSBL 0x00
-
-#define WCD9XXX_USLEEP_RANGE_MARGIN_US 100
-
-struct mbhc_micbias_regs {
-	u16 cfilt_val;
-	u16 cfilt_ctl;
-	u16 mbhc_reg;
-	u16 int_rbias;
-	u16 ctl_reg;
-	u8 cfilt_sel;
-};
-
-enum mbhc_v_index {
-	MBHC_V_IDX_CFILT,
-	MBHC_V_IDX_VDDIO,
-	MBHC_V_IDX_NUM,
-};
-
-enum mbhc_cal_type {
-	MBHC_CAL_MCLK,
-	MBHC_CAL_RCO,
-	MBHC_CAL_NUM,
-};
-
-enum mbhc_impedance_detect_stages {
-	MBHC_ZDET_PRE_MEASURE,
-	MBHC_ZDET_POST_MEASURE,
-	MBHC_ZDET_GAIN_0,
-	MBHC_ZDET_GAIN_1,
-	MBHC_ZDET_GAIN_2,
-	MBHC_ZDET_HPHR_RAMP_DISABLE,
-	MBHC_ZDET_HPHL_RAMP_DISABLE,
-	MBHC_ZDET_RAMP_DISABLE,
-	MBHC_ZDET_HPHR_PA_DISABLE,
-	MBHC_ZDET_PA_DISABLE,
-	MBHC_ZDET_GAIN_UPDATE_1X,
-};
-
-/* Zone assignments used in WCD9330 for Zdet */
-enum mbhc_zdet_zones {
-	ZL_ZONE1__ZR_ZONE1,
-	ZL_ZONE2__ZR_ZONE2,
-	ZL_ZONE3__ZR_ZONE3,
-	ZL_ZONE2__ZR_ZONE1,
-	ZL_ZONE3__ZR_ZONE1,
-	ZL_ZONE1__ZR_ZONE2,
-	ZL_ZONE1__ZR_ZONE3,
-	ZL_ZR_NOT_IN_ZONE1,
-};
-
-/* Data used by MBHC */
-struct mbhc_internal_cal_data {
-	u16 dce_z;
-	u16 dce_nsc_cs_z;
-	u16 dce_mb;
-	u16 sta_z;
-	u16 sta_mb;
-	u32 t_sta_dce;
-	u32 t_dce;
-	u32 t_sta;
-	u32 micb_mv;
-	u16 v_ins_hu[MBHC_V_IDX_NUM];
-	u16 v_ins_h[MBHC_V_IDX_NUM];
-	u16 v_b1_hu[MBHC_V_IDX_NUM];
-	u16 v_b1_h[MBHC_V_IDX_NUM];
-	u16 v_brh[MBHC_V_IDX_NUM];
-	u16 v_brl;
-	u16 v_no_mic;
-	s16 v_inval_ins_low;
-	s16 v_inval_ins_high;
-	u16 v_cs_ins_h;
-};
-
-enum wcd9xxx_mbhc_plug_type {
-	PLUG_TYPE_INVALID = -1,
-	PLUG_TYPE_NONE,
-	PLUG_TYPE_HEADSET,
-	PLUG_TYPE_HEADPHONE,
-	PLUG_TYPE_HIGH_HPH,
-	PLUG_TYPE_GND_MIC_SWAP,
-	PLUG_TYPE_ANC_HEADPHONE,
-};
-
-enum wcd9xxx_mbhc_micbias_type {
-	MBHC_PRIMARY_MIC_MB,
-	MBHC_ANC_MIC_MB,
-};
-
-enum wcd9xxx_micbias_num {
-	MBHC_MICBIAS_INVALID = -1,
-	MBHC_MICBIAS1,
-	MBHC_MICBIAS2,
-	MBHC_MICBIAS3,
-	MBHC_MICBIAS4,
-};
-
-enum hw_jack_type {
-	FOUR_POLE_JACK = 0,
-	FIVE_POLE_JACK,
-	SIX_POLE_JACK,
-};
-
-enum wcd9xx_mbhc_micbias_enable_bits {
-	MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
-	MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
-};
-
-enum wcd9xx_mbhc_cs_enable_bits {
-	MBHC_CS_ENABLE_POLLING,
-	MBHC_CS_ENABLE_INSERTION,
-	MBHC_CS_ENABLE_REMOVAL,
-	MBHC_CS_ENABLE_DET_ANC,
-};
-
-enum wcd9xxx_mbhc_state {
-	MBHC_STATE_NONE = -1,
-	MBHC_STATE_POTENTIAL,
-	MBHC_STATE_POTENTIAL_RECOVERY,
-	MBHC_STATE_RELEASE,
-};
-
-enum wcd9xxx_mbhc_btn_det_mem {
-	MBHC_BTN_DET_V_BTN_LOW,
-	MBHC_BTN_DET_V_BTN_HIGH,
-	MBHC_BTN_DET_N_READY,
-	MBHC_BTN_DET_N_CIC,
-	MBHC_BTN_DET_GAIN
-};
-
-enum wcd9xxx_mbhc_clk_freq {
-	TAIKO_MCLK_12P2MHZ = 0,
-	TAIKO_MCLK_9P6MHZ,
-	TAIKO_NUM_CLK_FREQS,
-};
-
-enum wcd9xxx_mbhc_event_state {
-	MBHC_EVENT_PA_HPHL,
-	MBHC_EVENT_PA_HPHR,
-	MBHC_EVENT_PRE_TX_3_ON,
-	MBHC_EVENT_POST_TX_3_OFF,
-};
-
-enum mbhc_hph_type {
-	MBHC_HPH_NONE = 0,
-	MBHC_HPH_MONO,
-	MBHC_HPH_STEREO,
-};
-
-struct wcd9xxx_mbhc_general_cfg {
-	u8 t_ldoh;
-	u8 t_bg_fast_settle;
-	u8 t_shutdown_plug_rem;
-	u8 mbhc_nsa;
-	u8 mbhc_navg;
-	u8 v_micbias_l;
-	u8 v_micbias;
-	u8 mbhc_reserved;
-	u16 settle_wait;
-	u16 t_micbias_rampup;
-	u16 t_micbias_rampdown;
-	u16 t_supply_bringup;
-} __packed;
-
-struct wcd9xxx_mbhc_plug_detect_cfg {
-	u32 mic_current;
-	u32 hph_current;
-	u16 t_mic_pid;
-	u16 t_ins_complete;
-	u16 t_ins_retry;
-	u16 v_removal_delta;
-	u8 micbias_slow_ramp;
-	u8 reserved0;
-	u8 reserved1;
-	u8 reserved2;
-} __packed;
-
-struct wcd9xxx_mbhc_plug_type_cfg {
-	u8 av_detect;
-	u8 mono_detect;
-	u8 num_ins_tries;
-	u8 reserved0;
-	s16 v_no_mic;
-	s16 v_av_min;
-	s16 v_av_max;
-	s16 v_hs_min;
-	s16 v_hs_max;
-	u16 reserved1;
-} __packed;
-
-struct wcd9xxx_mbhc_btn_detect_cfg {
-	s8 c[8];
-	u8 nc;
-	u8 n_meas;
-	u8 mbhc_nsc;
-	u8 n_btn_meas;
-	u8 n_btn_con;
-	u8 num_btn;
-	u8 reserved0;
-	u8 reserved1;
-	u16 t_poll;
-	u16 t_bounce_wait;
-	u16 t_rel_timeout;
-	s16 v_btn_press_delta_sta;
-	s16 v_btn_press_delta_cic;
-	u16 t_btn0_timeout;
-	s16 _v_btn_low[0]; /* v_btn_low[num_btn] */
-	s16 _v_btn_high[0]; /* v_btn_high[num_btn] */
-	u8 _n_ready[TAIKO_NUM_CLK_FREQS];
-	u8 _n_cic[TAIKO_NUM_CLK_FREQS];
-	u8 _gain[TAIKO_NUM_CLK_FREQS];
-} __packed;
-
-struct wcd9xxx_mbhc_imped_detect_cfg {
-	u8 _hs_imped_detect;
-	u8 _n_rload;
-	u8 _hph_keep_on;
-	u8 _repeat_rload_calc;
-	u16 _t_dac_ramp_time;
-	u16 _rhph_high;
-	u16 _rhph_low;
-	u16 _rload[0]; /* rload[n_rload] */
-	u16 _alpha[0]; /* alpha[n_rload] */
-	u16 _beta[3];
-} __packed;
-
-struct wcd9xxx_mbhc_config {
-	bool read_fw_bin;
-	/*
-	 * void* calibration contains:
-	 *  struct wcd9xxx_mbhc_general_cfg generic;
-	 *  struct wcd9xxx_mbhc_plug_detect_cfg plug_det;
-	 *  struct wcd9xxx_mbhc_plug_type_cfg plug_type;
-	 *  struct wcd9xxx_mbhc_btn_detect_cfg btn_det;
-	 *  struct wcd9xxx_mbhc_imped_detect_cfg imped_det;
-	 * Note: various size depends on btn_det->num_btn
-	 */
-	void *calibration;
-	enum wcd9xxx_micbias_num micbias;
-	enum wcd9xxx_micbias_num anc_micbias;
-	int (*mclk_cb_fn)(struct snd_soc_codec*, int, bool);
-	unsigned int mclk_rate;
-	unsigned int gpio;
-	unsigned int gpio_irq;
-	int gpio_level_insert;
-	bool insert_detect; /* codec has own MBHC_INSERT_DETECT */
-	bool detect_extn_cable;
-	/* bit mask of enum wcd9xx_mbhc_micbias_enable_bits */
-	unsigned long micbias_enable_flags;
-	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
-	bool (*swap_gnd_mic)(struct snd_soc_codec *);
-	unsigned long cs_enable_flags;
-	bool use_int_rbias;
-	bool do_recalibration;
-	bool use_vddio_meas;
-	bool enable_anc_mic_detect;
-	enum hw_jack_type hw_jack_type;
-	int key_code[8];
-};
-
-struct wcd9xxx_cfilt_mode {
-	u8 reg_mode_val;
-	u8 cur_mode_val;
-	u8 reg_mask;
-};
-
-struct wcd9xxx_mbhc_intr {
-	int poll_plug_rem;
-	int shortavg_complete;
-	int potential_button_press;
-	int button_release;
-	int dce_est_complete;
-	int insertion;
-	int hph_left_ocp;
-	int hph_right_ocp;
-	int hs_jack_switch;
-};
-
-struct wcd9xxx_mbhc_cb {
-	void (*enable_mux_bias_block)(struct snd_soc_codec *);
-	void (*cfilt_fast_mode)(struct snd_soc_codec *, struct wcd9xxx_mbhc *);
-	void (*codec_specific_cal)(struct snd_soc_codec *,
-				    struct wcd9xxx_mbhc *);
-	struct wcd9xxx_cfilt_mode (*switch_cfilt_mode)(struct wcd9xxx_mbhc *,
-							bool);
-	void (*select_cfilt)(struct snd_soc_codec *, struct wcd9xxx_mbhc *);
-	enum wcd9xxx_cdc_type (*get_cdc_type)(void);
-	void (*enable_clock_gate)(struct snd_soc_codec *, bool);
-	int (*setup_zdet)(struct wcd9xxx_mbhc *,
-			   enum mbhc_impedance_detect_stages stage);
-	void (*compute_impedance)(struct wcd9xxx_mbhc *, s16 *, s16 *,
-				   uint32_t *, uint32_t *);
-	void (*zdet_error_approx)(struct wcd9xxx_mbhc *, uint32_t *,
-				    uint32_t *);
-	void (*enable_mbhc_txfe)(struct snd_soc_codec *, bool);
-	int (*enable_mb_source)(struct snd_soc_codec *, bool, bool);
-	void (*setup_int_rbias)(struct snd_soc_codec *, bool);
-	void (*pull_mb_to_vddio)(struct snd_soc_codec *, bool);
-	bool (*insert_rem_status)(struct snd_soc_codec *);
-	void (*micbias_pulldown_ctrl)(struct wcd9xxx_mbhc *, bool);
-	int (*codec_rco_ctrl)(struct snd_soc_codec *, bool);
-	void (*hph_auto_pulldown_ctrl)(struct snd_soc_codec *, bool);
-	struct firmware_cal * (*get_hwdep_fw_cal)(struct snd_soc_codec *,
-				enum wcd_cal_type);
-};
-
-struct wcd9xxx_mbhc {
-	bool polling_active;
-	/* Delayed work to report long button press */
-	struct delayed_work mbhc_btn_dwork;
-	int buttons_pressed;
-	enum wcd9xxx_mbhc_state mbhc_state;
-	struct wcd9xxx_mbhc_config *mbhc_cfg;
-	const struct wcd9xxx_mbhc_cb *mbhc_cb;
-
-	struct mbhc_internal_cal_data mbhc_data;
-
-	struct mbhc_micbias_regs mbhc_bias_regs;
-	struct mbhc_micbias_regs mbhc_anc_bias_regs;
-
-	bool mbhc_micbias_switched;
-
-	u32 hph_status; /* track headhpone status */
-	u8 hphlocp_cnt; /* headphone left ocp retry */
-	u8 hphrocp_cnt; /* headphone right ocp retry */
-
-	/* Work to perform MBHC Firmware Read */
-	struct delayed_work mbhc_firmware_dwork;
-	const struct firmware *mbhc_fw;
-	struct firmware_cal *mbhc_cal;
-
-	struct delayed_work mbhc_insert_dwork;
-
-	u8 current_plug;
-	struct work_struct correct_plug_swch;
-	/*
-	 * Work to perform polling on microphone voltage
-	 * in order to correct plug type once plug type
-	 * is detected as headphone
-	 */
-	struct work_struct correct_plug_noswch;
-	bool hs_detect_work_stop;
-
-	bool lpi_enabled; /* low power insertion detection */
-	bool in_swch_irq_handler;
-
-	struct wcd9xxx_resmgr *resmgr;
-	struct snd_soc_codec *codec;
-
-	bool no_mic_headset_override;
-
-	/* track PA/DAC state to sync with userspace */
-	unsigned long hph_pa_dac_state;
-	/*
-	 * save codec's state with resmgr event notification
-	 * bit flags of enum wcd9xxx_mbhc_event_state
-	 */
-	unsigned long event_state;
-
-	unsigned long mbhc_last_resume; /* in jiffies */
-
-	bool insert_detect_level_insert;
-
-	struct snd_soc_jack headset_jack;
-	struct snd_soc_jack button_jack;
-
-	struct notifier_block nblock;
-
-	bool micbias_enable;
-	int (*micbias_enable_cb)(struct snd_soc_codec*,  bool,
-				  enum wcd9xxx_micbias_num);
-
-	bool impedance_detect;
-	/* impedance of hphl and hphr */
-	uint32_t zl, zr;
-
-	u32 rco_clk_rate;
-
-	bool update_z;
-
-	u8   scaling_mux_in;
-	/* Holds codec specific interrupt mapping */
-	const struct wcd9xxx_mbhc_intr *intr_ids;
-
-	/* Indicates status of current source switch */
-	bool is_cs_enabled;
-
-	/* Holds type of Headset - Mono/Stereo */
-	enum mbhc_hph_type hph_type;
-
-#ifdef CONFIG_DEBUG_FS
-	struct dentry *debugfs_poke;
-	struct dentry *debugfs_mbhc;
-#endif
-
-	struct mutex mbhc_lock;
-};
-
-#define WCD9XXX_MBHC_CAL_SIZE(buttons, rload) ( \
-	sizeof(enum wcd9xxx_micbias_num) + \
-	sizeof(struct wcd9xxx_mbhc_general_cfg) + \
-	sizeof(struct wcd9xxx_mbhc_plug_detect_cfg) + \
-	    ((sizeof(s16) + sizeof(s16)) * buttons) + \
-	sizeof(struct wcd9xxx_mbhc_plug_type_cfg) + \
-	sizeof(struct wcd9xxx_mbhc_btn_detect_cfg) + \
-	sizeof(struct wcd9xxx_mbhc_imped_detect_cfg) + \
-	    ((sizeof(u16) + sizeof(u16)) * rload) \
-	)
-
-#define WCD9XXX_MBHC_CAL_GENERAL_PTR(cali) ( \
-	    (struct wcd9xxx_mbhc_general_cfg *) cali)
-#define WCD9XXX_MBHC_CAL_PLUG_DET_PTR(cali) ( \
-	    (struct wcd9xxx_mbhc_plug_detect_cfg *) \
-	    &(WCD9XXX_MBHC_CAL_GENERAL_PTR(cali)[1]))
-#define WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(cali) ( \
-	    (struct wcd9xxx_mbhc_plug_type_cfg *) \
-	    &(WCD9XXX_MBHC_CAL_PLUG_DET_PTR(cali)[1]))
-#define WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali) ( \
-	    (struct wcd9xxx_mbhc_btn_detect_cfg *) \
-	    &(WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(cali)[1]))
-#define WCD9XXX_MBHC_CAL_IMPED_DET_PTR(cali) ( \
-	    (struct wcd9xxx_mbhc_imped_detect_cfg *) \
-	    (((void *)&WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali)[1]) + \
-	     (WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali)->num_btn * \
-	      (sizeof(WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_low[0]) + \
-	       sizeof(WCD9XXX_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_high[0])))) \
-	)
-
-/* minimum size of calibration data assuming there is only one button and
- * one rload.
- */
-#define WCD9XXX_MBHC_CAL_MIN_SIZE ( \
-	    sizeof(struct wcd9xxx_mbhc_general_cfg) + \
-	    sizeof(struct wcd9xxx_mbhc_plug_detect_cfg) + \
-	    sizeof(struct wcd9xxx_mbhc_plug_type_cfg) + \
-	    sizeof(struct wcd9xxx_mbhc_btn_detect_cfg) + \
-	    sizeof(struct wcd9xxx_mbhc_imped_detect_cfg) + \
-	    (sizeof(u16) * 2) \
-	)
-
-#define WCD9XXX_MBHC_CAL_BTN_SZ(cfg_ptr) ( \
-	    sizeof(struct wcd9xxx_mbhc_btn_detect_cfg) + \
-	    (cfg_ptr->num_btn * (sizeof(cfg_ptr->_v_btn_low[0]) + \
-				 sizeof(cfg_ptr->_v_btn_high[0]))))
-
-#define WCD9XXX_MBHC_CAL_IMPED_MIN_SZ ( \
-	    sizeof(struct wcd9xxx_mbhc_imped_detect_cfg) + sizeof(u16) * 2)
-
-#define WCD9XXX_MBHC_CAL_IMPED_SZ(cfg_ptr) ( \
-	    sizeof(struct wcd9xxx_mbhc_imped_detect_cfg) + \
-	    (cfg_ptr->_n_rload * \
-	     (sizeof(cfg_ptr->_rload[0]) + sizeof(cfg_ptr->_alpha[0]))))
-
-int wcd9xxx_mbhc_set_keycode(struct wcd9xxx_mbhc *mbhc);
-int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
-		       struct wcd9xxx_mbhc_config *mbhc_cfg);
-void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc);
-int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
-		      struct snd_soc_codec *codec,
-		      int (*micbias_enable_cb)(struct snd_soc_codec*,  bool,
-						enum wcd9xxx_micbias_num),
-		      const struct wcd9xxx_mbhc_cb *mbhc_cb,
-		      const struct wcd9xxx_mbhc_intr *mbhc_cdc_intr_ids,
-		      int rco_clk_rate,
-		      bool impedance_det_en);
-void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc);
-void *wcd9xxx_mbhc_cal_btn_det_mp(
-			    const struct wcd9xxx_mbhc_btn_detect_cfg *btn_det,
-			    const enum wcd9xxx_mbhc_btn_det_mem mem);
-int wcd9xxx_mbhc_get_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
-			       uint32_t *zr);
-#endif /* __WCD9XXX_MBHC_H__ */
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
index 825aaee..feef0a4 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
@@ -108,6 +108,7 @@
 	}
 	return resmgr->clk_type;
 }
+EXPORT_SYMBOL(wcd_resmgr_get_clk_type);
 
 static void wcd_resmgr_cdc_specific_get_clk(struct wcd9xxx_resmgr_v2 *resmgr,
 						int clk_users)
@@ -123,6 +124,10 @@
 	}
 }
 
+/*
+ * wcd_resmgr_post_ssr_v2
+ * @resmgr: handle to struct wcd9xxx_resmgr_v2
+ */
 void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr)
 {
 	int old_bg_audio_users;
@@ -157,7 +162,7 @@
 
 	WCD9XXX_V2_BG_CLK_UNLOCK(resmgr);
 }
-
+EXPORT_SYMBOL(wcd_resmgr_post_ssr_v2);
 
 /*
  * wcd_resmgr_enable_master_bias: enable codec master bias
@@ -190,6 +195,7 @@
 	mutex_unlock(&resmgr->master_bias_lock);
 	return 0;
 }
+EXPORT_SYMBOL(wcd_resmgr_enable_master_bias);
 
 /*
  * wcd_resmgr_disable_master_bias: disable codec master bias
@@ -213,6 +219,7 @@
 	mutex_unlock(&resmgr->master_bias_lock);
 	return 0;
 }
+EXPORT_SYMBOL(wcd_resmgr_disable_master_bias);
 
 static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
 {
@@ -511,6 +518,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(wcd_resmgr_enable_clk_block);
 
 void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
 					  int sido_src)
@@ -601,6 +609,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(wcd_resmgr_disable_clk_block);
 
 /*
  * wcd_resmgr_init: initialize wcd resource manager
@@ -639,6 +648,7 @@
 
 	return resmgr;
 }
+EXPORT_SYMBOL(wcd_resmgr_init);
 
 /*
  * wcd_resmgr_remove: Clean-up wcd resource manager
@@ -649,6 +659,7 @@
 	mutex_destroy(&resmgr->master_bias_lock);
 	kfree(resmgr);
 }
+EXPORT_SYMBOL(wcd_resmgr_remove);
 
 /*
  * wcd_resmgr_post_init: post init call to assign codec handle
@@ -676,5 +687,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(wcd_resmgr_post_init);
+
 MODULE_DESCRIPTION("wcd9xxx resmgr v2 module");
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
deleted file mode 100644
index 4b02652..0000000
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ /dev/null
@@ -1,1099 +0,0 @@
-/* Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/printk.h>
-#include <linux/ratelimit.h>
-#include <linux/debugfs.h>
-#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
-#include <uapi/linux/mfd/wcd9xxx/wcd9320_registers.h>
-#include <linux/mfd/wcd9xxx/wcd9330_registers.h>
-#include <linux/mfd/wcd9xxx/pdata.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include "wcd9xxx-resmgr.h"
-
-static char wcd9xxx_event_string[][64] = {
-	"WCD9XXX_EVENT_INVALID",
-
-	"WCD9XXX_EVENT_PRE_RCO_ON",
-	"WCD9XXX_EVENT_POST_RCO_ON",
-	"WCD9XXX_EVENT_PRE_RCO_OFF",
-	"WCD9XXX_EVENT_POST_RCO_OFF",
-
-	"WCD9XXX_EVENT_PRE_MCLK_ON",
-	"WCD9XXX_EVENT_POST_MCLK_ON",
-	"WCD9XXX_EVENT_PRE_MCLK_OFF",
-	"WCD9XXX_EVENT_POST_MCLK_OFF",
-
-	"WCD9XXX_EVENT_PRE_BG_OFF",
-	"WCD9XXX_EVENT_POST_BG_OFF",
-	"WCD9XXX_EVENT_PRE_BG_AUDIO_ON",
-	"WCD9XXX_EVENT_POST_BG_AUDIO_ON",
-	"WCD9XXX_EVENT_PRE_BG_MBHC_ON",
-	"WCD9XXX_EVENT_POST_BG_MBHC_ON",
-
-	"WCD9XXX_EVENT_PRE_MICBIAS_1_OFF",
-	"WCD9XXX_EVENT_POST_MICBIAS_1_OFF",
-	"WCD9XXX_EVENT_PRE_MICBIAS_2_OFF",
-	"WCD9XXX_EVENT_POST_MICBIAS_2_OFF",
-	"WCD9XXX_EVENT_PRE_MICBIAS_3_OFF",
-	"WCD9XXX_EVENT_POST_MICBIAS_3_OFF",
-	"WCD9XXX_EVENT_PRE_MICBIAS_4_OFF",
-	"WCD9XXX_EVENT_POST_MICBIAS_4_OFF",
-	"WCD9XXX_EVENT_PRE_MICBIAS_1_ON",
-	"WCD9XXX_EVENT_POST_MICBIAS_1_ON",
-	"WCD9XXX_EVENT_PRE_MICBIAS_2_ON",
-	"WCD9XXX_EVENT_POST_MICBIAS_2_ON",
-	"WCD9XXX_EVENT_PRE_MICBIAS_3_ON",
-	"WCD9XXX_EVENT_POST_MICBIAS_3_ON",
-	"WCD9XXX_EVENT_PRE_MICBIAS_4_ON",
-	"WCD9XXX_EVENT_POST_MICBIAS_4_ON",
-
-	"WCD9XXX_EVENT_PRE_CFILT_1_OFF",
-	"WCD9XXX_EVENT_POST_CFILT_1_OFF",
-	"WCD9XXX_EVENT_PRE_CFILT_2_OFF",
-	"WCD9XXX_EVENT_POST_CFILT_2_OFF",
-	"WCD9XXX_EVENT_PRE_CFILT_3_OFF",
-	"WCD9XXX_EVENT_POST_CFILT_3_OFF",
-	"WCD9XXX_EVENT_PRE_CFILT_1_ON",
-	"WCD9XXX_EVENT_POST_CFILT_1_ON",
-	"WCD9XXX_EVENT_PRE_CFILT_2_ON",
-	"WCD9XXX_EVENT_POST_CFILT_2_ON",
-	"WCD9XXX_EVENT_PRE_CFILT_3_ON",
-	"WCD9XXX_EVENT_POST_CFILT_3_ON",
-
-	"WCD9XXX_EVENT_PRE_HPHL_PA_ON",
-	"WCD9XXX_EVENT_POST_HPHL_PA_OFF",
-	"WCD9XXX_EVENT_PRE_HPHR_PA_ON",
-	"WCD9XXX_EVENT_POST_HPHR_PA_OFF",
-
-	"WCD9XXX_EVENT_POST_RESUME",
-
-	"WCD9XXX_EVENT_PRE_TX_3_ON",
-	"WCD9XXX_EVENT_POST_TX_3_OFF",
-
-	"WCD9XXX_EVENT_LAST",
-};
-
-#define WCD9XXX_RCO_CALIBRATION_RETRY_COUNT 5
-#define WCD9XXX_RCO_CALIBRATION_DELAY_US 5000
-#define WCD9XXX_USLEEP_RANGE_MARGIN_US 100
-#define WCD9XXX_RCO_CALIBRATION_DELAY_INC_US 1000
-
-struct wcd9xxx_resmgr_cond_entry {
-	unsigned short reg;
-	int shift;
-	bool invert;
-	enum wcd9xxx_resmgr_cond cond;
-	struct list_head list;
-};
-
-static enum wcd9xxx_clock_type wcd9xxx_save_clock(struct wcd9xxx_resmgr
-						  *resmgr);
-static void wcd9xxx_restore_clock(struct wcd9xxx_resmgr *resmgr,
-				  enum wcd9xxx_clock_type type);
-
-const char *wcd9xxx_get_event_string(enum wcd9xxx_notify_event type)
-{
-	return wcd9xxx_event_string[type];
-}
-
-void wcd9xxx_resmgr_notifier_call(struct wcd9xxx_resmgr *resmgr,
-				  const enum wcd9xxx_notify_event e)
-{
-	pr_debug("%s: notifier call event %d\n", __func__, e);
-	blocking_notifier_call_chain(&resmgr->notifier, e, resmgr);
-}
-
-static void wcd9xxx_disable_bg(struct wcd9xxx_resmgr *resmgr)
-{
-	/* Notify bg mode change */
-	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_OFF);
-	/* Disable bg */
-	snd_soc_update_bits(resmgr->codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
-			    0x03, 0x00);
-	usleep_range(100, 110);
-	/* Notify bg mode change */
-	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_OFF);
-}
-
-/*
- * BG enablement should always enable in slow mode.
- * The fast mode doesn't need to be enabled as fast mode BG is to be driven
- * by MBHC override.
- */
-static void wcd9xxx_enable_bg(struct wcd9xxx_resmgr *resmgr)
-{
-	struct snd_soc_codec *codec = resmgr->codec;
-
-	/* Enable BG in slow mode and precharge */
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x80, 0x80);
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x04, 0x04);
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x01, 0x01);
-	usleep_range(1000, 1100);
-	snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x80, 0x00);
-}
-
-static void wcd9xxx_enable_bg_audio(struct wcd9xxx_resmgr *resmgr)
-{
-	/* Notify bandgap mode change */
-	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_AUDIO_ON);
-	wcd9xxx_enable_bg(resmgr);
-	/* Notify bandgap mode change */
-	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_AUDIO_ON);
-}
-
-static void wcd9xxx_enable_bg_mbhc(struct wcd9xxx_resmgr *resmgr)
-{
-	struct snd_soc_codec *codec = resmgr->codec;
-
-	/* Notify bandgap mode change */
-	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_MBHC_ON);
-
-	/*
-	 * mclk should be off or clk buff source souldn't be VBG
-	 * Let's turn off mclk always
-	 */
-	WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
-
-	wcd9xxx_enable_bg(resmgr);
-	/* Notify bandgap mode change */
-	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_MBHC_ON);
-}
-
-static void wcd9xxx_disable_clock_block(struct wcd9xxx_resmgr *resmgr)
-{
-	struct snd_soc_codec *codec = resmgr->codec;
-
-	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
-
-	/* Notify */
-	if (resmgr->clk_type == WCD9XXX_CLK_RCO)
-		wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_RCO_OFF);
-	else
-		wcd9xxx_resmgr_notifier_call(resmgr,
-					     WCD9XXX_EVENT_PRE_MCLK_OFF);
-
-	switch (resmgr->codec_type) {
-	case WCD9XXX_CDC_TYPE_TOMTOM:
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
-		usleep_range(50, 55);
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x40, 0x40);
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x40, 0x00);
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x00);
-		break;
-	default:
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
-		usleep_range(50, 55);
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
-		break;
-	}
-	usleep_range(50, 55);
-	/* Notify */
-	if (resmgr->clk_type == WCD9XXX_CLK_RCO) {
-		wcd9xxx_resmgr_notifier_call(resmgr,
-					     WCD9XXX_EVENT_POST_RCO_OFF);
-	} else {
-		wcd9xxx_resmgr_notifier_call(resmgr,
-					     WCD9XXX_EVENT_POST_MCLK_OFF);
-	}
-	pr_debug("%s: leave\n", __func__);
-}
-
-static void wcd9xxx_resmgr_cdc_specific_get_clk(struct wcd9xxx_resmgr *resmgr,
-						int clk_users)
-{
-	/* Caller of this function should have acquired
-	 *  BG_CLK lock
-	 */
-	WCD9XXX_BG_CLK_UNLOCK(resmgr);
-	if (clk_users) {
-		if (resmgr->resmgr_cb &&
-		    resmgr->resmgr_cb->cdc_rco_ctrl) {
-			while (clk_users--)
-				resmgr->resmgr_cb->cdc_rco_ctrl(resmgr->codec,
-								true);
-		}
-	}
-	/* Acquire BG_CLK lock before return */
-	WCD9XXX_BG_CLK_LOCK(resmgr);
-}
-
-void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr)
-{
-	int old_bg_audio_users, old_bg_mbhc_users;
-	int old_clk_rco_users, old_clk_mclk_users;
-
-	pr_debug("%s: enter\n", __func__);
-
-	WCD9XXX_BG_CLK_LOCK(resmgr);
-	old_bg_audio_users = resmgr->bg_audio_users;
-	old_bg_mbhc_users = resmgr->bg_mbhc_users;
-	old_clk_rco_users = resmgr->clk_rco_users;
-	old_clk_mclk_users = resmgr->clk_mclk_users;
-	resmgr->bg_audio_users = 0;
-	resmgr->bg_mbhc_users = 0;
-	resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
-	resmgr->clk_rco_users = 0;
-	resmgr->clk_mclk_users = 0;
-	resmgr->clk_type = WCD9XXX_CLK_OFF;
-
-	if (old_bg_audio_users) {
-		while (old_bg_audio_users--)
-			wcd9xxx_resmgr_get_bandgap(resmgr,
-						  WCD9XXX_BANDGAP_AUDIO_MODE);
-	}
-
-	if (old_bg_mbhc_users) {
-		while (old_bg_mbhc_users--)
-			wcd9xxx_resmgr_get_bandgap(resmgr,
-						  WCD9XXX_BANDGAP_MBHC_MODE);
-	}
-
-	if (old_clk_mclk_users) {
-		while (old_clk_mclk_users--)
-			wcd9xxx_resmgr_get_clk_block(resmgr, WCD9XXX_CLK_MCLK);
-	}
-
-	if (resmgr->codec_type == WCD9XXX_CDC_TYPE_TOMTOM) {
-		wcd9xxx_resmgr_cdc_specific_get_clk(resmgr, old_clk_rco_users);
-	} else if (old_clk_rco_users) {
-		while (old_clk_rco_users--)
-			wcd9xxx_resmgr_get_clk_block(resmgr,
-					WCD9XXX_CLK_RCO);
-	}
-	WCD9XXX_BG_CLK_UNLOCK(resmgr);
-	pr_debug("%s: leave\n", __func__);
-}
-
-/*
- * wcd9xxx_resmgr_get_bandgap : Vote for bandgap ref
- * choice : WCD9XXX_BANDGAP_AUDIO_MODE, WCD9XXX_BANDGAP_MBHC_MODE
- */
-void wcd9xxx_resmgr_get_bandgap(struct wcd9xxx_resmgr *resmgr,
-				const enum wcd9xxx_bandgap_type choice)
-{
-	enum wcd9xxx_clock_type clock_save = WCD9XXX_CLK_OFF;
-
-	pr_debug("%s: enter, wants %d\n", __func__, choice);
-
-	WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
-	switch (choice) {
-	case WCD9XXX_BANDGAP_AUDIO_MODE:
-		resmgr->bg_audio_users++;
-		if (resmgr->bg_audio_users == 1 && resmgr->bg_mbhc_users) {
-			/*
-			 * Current bg is MBHC mode, about to switch to
-			 * audio mode.
-			 */
-			WARN_ON(resmgr->bandgap_type !=
-				WCD9XXX_BANDGAP_MBHC_MODE);
-
-			/* BG mode can be changed only with clock off */
-			if (resmgr->codec_type != WCD9XXX_CDC_TYPE_TOMTOM)
-				clock_save = wcd9xxx_save_clock(resmgr);
-			/* Swtich BG mode */
-			wcd9xxx_disable_bg(resmgr);
-			wcd9xxx_enable_bg_audio(resmgr);
-			/* restore clock */
-			if (resmgr->codec_type != WCD9XXX_CDC_TYPE_TOMTOM)
-				wcd9xxx_restore_clock(resmgr, clock_save);
-		} else if (resmgr->bg_audio_users == 1) {
-			/* currently off, just enable it */
-			WARN_ON(resmgr->bandgap_type != WCD9XXX_BANDGAP_OFF);
-			wcd9xxx_enable_bg_audio(resmgr);
-		}
-		resmgr->bandgap_type = WCD9XXX_BANDGAP_AUDIO_MODE;
-		break;
-	case WCD9XXX_BANDGAP_MBHC_MODE:
-		resmgr->bg_mbhc_users++;
-		if (resmgr->bandgap_type == WCD9XXX_BANDGAP_MBHC_MODE ||
-		    resmgr->bandgap_type == WCD9XXX_BANDGAP_AUDIO_MODE)
-			/* do nothing */
-			break;
-
-		/* bg mode can be changed only with clock off */
-		clock_save = wcd9xxx_save_clock(resmgr);
-		/* enable bg with MBHC mode */
-		wcd9xxx_enable_bg_mbhc(resmgr);
-		/* restore clock */
-		wcd9xxx_restore_clock(resmgr, clock_save);
-		/* save current mode */
-		resmgr->bandgap_type = WCD9XXX_BANDGAP_MBHC_MODE;
-		break;
-	default:
-		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
-		break;
-	}
-
-	pr_debug("%s: bg users audio %d, mbhc %d\n", __func__,
-		 resmgr->bg_audio_users, resmgr->bg_mbhc_users);
-}
-
-/*
- * wcd9xxx_resmgr_put_bandgap : Unvote bandgap ref that has been voted
- * choice : WCD9XXX_BANDGAP_AUDIO_MODE, WCD9XXX_BANDGAP_MBHC_MODE
- */
-void wcd9xxx_resmgr_put_bandgap(struct wcd9xxx_resmgr *resmgr,
-				enum wcd9xxx_bandgap_type choice)
-{
-	enum wcd9xxx_clock_type clock_save;
-
-	pr_debug("%s: enter choice %d\n", __func__, choice);
-
-	WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
-	switch (choice) {
-	case WCD9XXX_BANDGAP_AUDIO_MODE:
-		if (--resmgr->bg_audio_users == 0) {
-			if (resmgr->bg_mbhc_users) {
-				/* bg mode can be changed only with clock off */
-				clock_save = wcd9xxx_save_clock(resmgr);
-				/* switch to MBHC mode */
-				wcd9xxx_enable_bg_mbhc(resmgr);
-				/* restore clock */
-				wcd9xxx_restore_clock(resmgr, clock_save);
-				resmgr->bandgap_type =
-				    WCD9XXX_BANDGAP_MBHC_MODE;
-			} else {
-				/* turn off */
-				wcd9xxx_disable_bg(resmgr);
-				resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
-			}
-		}
-		break;
-	case WCD9XXX_BANDGAP_MBHC_MODE:
-		WARN(resmgr->bandgap_type == WCD9XXX_BANDGAP_OFF,
-		     "Unexpected bandgap type %d\n", resmgr->bandgap_type);
-		if (--resmgr->bg_mbhc_users == 0 &&
-		    resmgr->bandgap_type == WCD9XXX_BANDGAP_MBHC_MODE) {
-			wcd9xxx_disable_bg(resmgr);
-			resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
-		}
-		break;
-	default:
-		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
-		break;
-	}
-
-	pr_debug("%s: bg users audio %d, mbhc %d\n", __func__,
-		 resmgr->bg_audio_users, resmgr->bg_mbhc_users);
-}
-
-void wcd9xxx_resmgr_enable_rx_bias(struct wcd9xxx_resmgr *resmgr, u32 enable)
-{
-	struct snd_soc_codec *codec = resmgr->codec;
-
-	if (enable) {
-		resmgr->rx_bias_count++;
-		if (resmgr->rx_bias_count == 1)
-			snd_soc_update_bits(codec, WCD9XXX_A_RX_COM_BIAS,
-					    0x80, 0x80);
-	} else {
-		resmgr->rx_bias_count--;
-		if (!resmgr->rx_bias_count)
-			snd_soc_update_bits(codec, WCD9XXX_A_RX_COM_BIAS,
-					    0x80, 0x00);
-	}
-}
-
-int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr, int enable)
-{
-	struct snd_soc_codec *codec = resmgr->codec;
-
-	pr_debug("%s: enable = %d\n", __func__, enable);
-	if (enable) {
-		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0);
-		/* bandgap mode to fast */
-		if (resmgr->pdata->mclk_rate == WCD9XXX_MCLK_CLK_12P288MHZ)
-			/* Set current value to 200nA for 12.288MHz clock */
-			snd_soc_write(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x37);
-		else
-			snd_soc_write(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17);
-
-		usleep_range(5, 10);
-		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x80);
-		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x80);
-		usleep_range(10, 20);
-		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_TEST, 0x80, 0);
-		usleep_range(10000, 10100);
-
-		if (resmgr->pdata->mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ)
-			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
-							0x08, 0x08);
-	} else {
-		snd_soc_update_bits(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x1, 0);
-		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0);
-	}
-
-	return 0;
-}
-
-static void wcd9xxx_enable_clock_block(struct wcd9xxx_resmgr *resmgr,
-				enum wcd9xxx_clock_config_mode config_mode)
-{
-	struct snd_soc_codec *codec = resmgr->codec;
-	unsigned long delay = WCD9XXX_RCO_CALIBRATION_DELAY_US;
-	int num_retry = 0;
-	unsigned int valr;
-	unsigned int valr1;
-	unsigned int valw[] = {0x01, 0x01, 0x10, 0x00};
-
-	pr_debug("%s: config_mode = %d\n", __func__, config_mode);
-
-	/* transit to RCO requires mclk off */
-	if (resmgr->codec_type != WCD9XXX_CDC_TYPE_TOMTOM)
-		WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
-
-	if (config_mode == WCD9XXX_CFG_RCO) {
-		/* Notify */
-		wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_RCO_ON);
-		/* enable RCO and switch to it */
-		wcd9xxx_resmgr_enable_config_mode(resmgr, 1);
-		snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
-		usleep_range(1000, 1100);
-	} else if (config_mode == WCD9XXX_CFG_CAL_RCO) {
-		snd_soc_update_bits(codec, TOMTOM_A_BIAS_OSC_BG_CTL,
-				    0x01, 0x01);
-		/* 1ms sleep required after BG enabled */
-		usleep_range(1000, 1100);
-
-		if (resmgr->pdata->mclk_rate == WCD9XXX_MCLK_CLK_12P288MHZ) {
-			/*
-			 * Set RCO clock rate as 12.288MHz rate explicitly
-			 * as the Qfuse values are incorrect for this rate
-			 */
-			snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL,
-					0x50, 0x50);
-		} else {
-			snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL,
-					0x18, 0x10);
-			valr = snd_soc_read(codec,
-					TOMTOM_A_QFUSE_DATA_OUT0) & (0x04);
-			valr1 = snd_soc_read(codec,
-					TOMTOM_A_QFUSE_DATA_OUT1) & (0x08);
-			valr = (valr >> 1) | (valr1 >> 3);
-			snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL, 0x60,
-					valw[valr] << 5);
-		}
-		snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL, 0x80, 0x80);
-
-		do {
-			snd_soc_update_bits(codec,
-					    TOMTOM_A_RCO_CALIBRATION_CTRL1,
-					    0x80, 0x80);
-			snd_soc_update_bits(codec,
-					    TOMTOM_A_RCO_CALIBRATION_CTRL1,
-					    0x80, 0x00);
-			/* RCO calibration takes approx. 5ms */
-			usleep_range(delay, delay +
-					    WCD9XXX_USLEEP_RANGE_MARGIN_US);
-			if (!(snd_soc_read(codec,
-				TOMTOM_A_RCO_CALIBRATION_RESULT1) & 0x10))
-				break;
-			if (num_retry >= 3) {
-				delay = delay +
-					WCD9XXX_RCO_CALIBRATION_DELAY_INC_US;
-			}
-		} while (num_retry++ < WCD9XXX_RCO_CALIBRATION_RETRY_COUNT);
-	} else {
-		/* Notify */
-		wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_MCLK_ON);
-		/* switch to MCLK */
-
-		switch (resmgr->codec_type) {
-		case WCD9XXX_CDC_TYPE_TOMTOM:
-			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
-					    0x08, 0x00);
-			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
-					    0x40, 0x40);
-			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
-					    0x40, 0x00);
-			/* clk source to ext clk and clk buff ref to VBG */
-			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
-					    0x0C, 0x04);
-			break;
-		default:
-			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
-					    0x08, 0x00);
-			/* if RCO is enabled, switch from it */
-			if (snd_soc_read(codec, WCD9XXX_A_RC_OSC_FREQ) & 0x80) {
-				snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2,
-					      0x02);
-				wcd9xxx_resmgr_enable_config_mode(resmgr, 0);
-			}
-			/* clk source to ext clk and clk buff ref to VBG */
-			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
-					    0x0C, 0x04);
-			break;
-		}
-	}
-
-	if (config_mode != WCD9XXX_CFG_CAL_RCO) {
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
-				    0x01, 0x01);
-		/*
-		 * sleep required by codec hardware to
-		 * enable clock buffer
-		 */
-		usleep_range(1000, 1200);
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2,
-				    0x02, 0x00);
-		/* on MCLK */
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2,
-				    0x04, 0x04);
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL,
-				    0x01, 0x01);
-	}
-	usleep_range(50, 55);
-
-	/* Notify */
-	if (config_mode == WCD9XXX_CFG_RCO)
-		wcd9xxx_resmgr_notifier_call(resmgr,
-					     WCD9XXX_EVENT_POST_RCO_ON);
-	else if (config_mode == WCD9XXX_CFG_MCLK)
-		wcd9xxx_resmgr_notifier_call(resmgr,
-					     WCD9XXX_EVENT_POST_MCLK_ON);
-}
-
-/*
- * disable clock and return previous clock state
- */
-static enum wcd9xxx_clock_type wcd9xxx_save_clock(struct wcd9xxx_resmgr *resmgr)
-{
-	WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
-	if (resmgr->clk_type != WCD9XXX_CLK_OFF)
-		wcd9xxx_disable_clock_block(resmgr);
-	return resmgr->clk_type != WCD9XXX_CLK_OFF;
-}
-
-static void wcd9xxx_restore_clock(struct wcd9xxx_resmgr *resmgr,
-				  enum wcd9xxx_clock_type type)
-{
-	if (type != WCD9XXX_CLK_OFF)
-		wcd9xxx_enable_clock_block(resmgr, type == WCD9XXX_CLK_RCO);
-}
-
-void wcd9xxx_resmgr_get_clk_block(struct wcd9xxx_resmgr *resmgr,
-				  enum wcd9xxx_clock_type type)
-{
-	struct snd_soc_codec *codec = resmgr->codec;
-
-	pr_debug("%s: current %d, requested %d, rco_users %d, mclk_users %d\n",
-		 __func__, resmgr->clk_type, type,
-		 resmgr->clk_rco_users, resmgr->clk_mclk_users);
-	WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
-	switch (type) {
-	case WCD9XXX_CLK_RCO:
-		if (++resmgr->clk_rco_users == 1 &&
-		    resmgr->clk_type == WCD9XXX_CLK_OFF) {
-			/* enable RCO and switch to it */
-			wcd9xxx_enable_clock_block(resmgr, WCD9XXX_CFG_RCO);
-			resmgr->clk_type = WCD9XXX_CLK_RCO;
-		} else if (resmgr->clk_rco_users == 1 &&
-			   resmgr->clk_type == WCD9XXX_CLK_MCLK &&
-			   resmgr->codec_type == WCD9XXX_CDC_TYPE_TOMTOM) {
-			/*
-			 * Enable RCO but do not switch CLK MUX to RCO
-			 * unless ext_clk_users is 1, which indicates
-			 * EXT CLK is enabled for RCO calibration
-			 */
-			wcd9xxx_enable_clock_block(resmgr, WCD9XXX_CFG_CAL_RCO);
-			if (resmgr->ext_clk_users == 1) {
-				/* Notify */
-				wcd9xxx_resmgr_notifier_call(resmgr,
-						WCD9XXX_EVENT_PRE_RCO_ON);
-				/* CLK MUX to RCO */
-				if (resmgr->pdata->mclk_rate !=
-						WCD9XXX_MCLK_CLK_12P288MHZ)
-					snd_soc_update_bits(codec,
-						WCD9XXX_A_CLK_BUFF_EN1,
-						0x08, 0x08);
-				resmgr->clk_type = WCD9XXX_CLK_RCO;
-				wcd9xxx_resmgr_notifier_call(resmgr,
-						WCD9XXX_EVENT_POST_RCO_ON);
-			}
-		}
-		break;
-	case WCD9XXX_CLK_MCLK:
-		if (++resmgr->clk_mclk_users == 1 &&
-		    resmgr->clk_type == WCD9XXX_CLK_OFF) {
-			/* switch to MCLK */
-			wcd9xxx_enable_clock_block(resmgr, WCD9XXX_CFG_MCLK);
-			resmgr->clk_type = WCD9XXX_CLK_MCLK;
-		} else if (resmgr->clk_mclk_users == 1 &&
-			   resmgr->clk_type == WCD9XXX_CLK_RCO) {
-			/* RCO to MCLK switch, with RCO still powered on */
-			if (resmgr->codec_type == WCD9XXX_CDC_TYPE_TOMTOM) {
-				wcd9xxx_resmgr_notifier_call(resmgr,
-						WCD9XXX_EVENT_PRE_MCLK_ON);
-				snd_soc_update_bits(codec,
-						WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
-						0x40, 0x00);
-				/* Enable clock buffer */
-				snd_soc_update_bits(codec,
-						WCD9XXX_A_CLK_BUFF_EN1,
-						0x01, 0x01);
-				snd_soc_update_bits(codec,
-						WCD9XXX_A_CLK_BUFF_EN1,
-						0x08, 0x00);
-				wcd9xxx_resmgr_notifier_call(resmgr,
-						WCD9XXX_EVENT_POST_MCLK_ON);
-			} else {
-				/* if RCO is enabled, switch from it */
-				WARN_ON(!(snd_soc_read(resmgr->codec,
-					WCD9XXX_A_RC_OSC_FREQ) & 0x80));
-				/* disable clock block */
-				wcd9xxx_disable_clock_block(resmgr);
-				/* switch to MCLK */
-				wcd9xxx_enable_clock_block(resmgr,
-							   WCD9XXX_CFG_MCLK);
-			}
-			resmgr->clk_type = WCD9XXX_CLK_MCLK;
-		}
-		break;
-	default:
-		pr_err("%s: Error, Invalid clock get request %d\n", __func__,
-		       type);
-		break;
-	}
-	pr_debug("%s: leave\n", __func__);
-}
-
-void wcd9xxx_resmgr_put_clk_block(struct wcd9xxx_resmgr *resmgr,
-				  enum wcd9xxx_clock_type type)
-{
-	struct snd_soc_codec *codec = resmgr->codec;
-
-	pr_debug("%s: current %d, put %d\n", __func__, resmgr->clk_type, type);
-
-	WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
-	switch (type) {
-	case WCD9XXX_CLK_RCO:
-		if (--resmgr->clk_rco_users == 0 &&
-		    resmgr->clk_type == WCD9XXX_CLK_RCO) {
-			wcd9xxx_disable_clock_block(resmgr);
-			if (resmgr->codec_type == WCD9XXX_CDC_TYPE_TOMTOM) {
-				/* Powerdown RCO */
-				snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL,
-						    0x80, 0x00);
-				snd_soc_update_bits(codec,
-						    TOMTOM_A_BIAS_OSC_BG_CTL,
-						    0x01, 0x00);
-			} else {
-				/* if RCO is enabled, switch from it */
-				if (snd_soc_read(resmgr->codec,
-						 WCD9XXX_A_RC_OSC_FREQ)
-						 & 0x80) {
-					snd_soc_write(resmgr->codec,
-						WCD9XXX_A_CLK_BUFF_EN2,
-						0x02);
-					wcd9xxx_resmgr_enable_config_mode(
-								resmgr,	0);
-				}
-			}
-			resmgr->clk_type = WCD9XXX_CLK_OFF;
-		}
-		break;
-	case WCD9XXX_CLK_MCLK:
-		if (--resmgr->clk_mclk_users == 0 &&
-		    resmgr->clk_rco_users == 0) {
-			wcd9xxx_disable_clock_block(resmgr);
-
-			if ((resmgr->codec_type == WCD9XXX_CDC_TYPE_TOMTOM) &&
-			    (snd_soc_read(codec, TOMTOM_A_RCO_CTRL) & 0x80)) {
-				/* powerdown RCO*/
-				snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL,
-						    0x80, 0x00);
-				snd_soc_update_bits(codec,
-						    TOMTOM_A_BIAS_OSC_BG_CTL,
-						    0x01, 0x00);
-			}
-			resmgr->clk_type = WCD9XXX_CLK_OFF;
-		} else if (resmgr->clk_mclk_users == 0 &&
-			   resmgr->clk_rco_users) {
-			if (resmgr->codec_type == WCD9XXX_CDC_TYPE_TOMTOM) {
-				if (!(snd_soc_read(codec, TOMTOM_A_RCO_CTRL) &
-				      0x80)) {
-					dev_dbg(codec->dev, "%s: Enabling RCO\n",
-						__func__);
-					wcd9xxx_enable_clock_block(resmgr,
-							WCD9XXX_CFG_CAL_RCO);
-					snd_soc_update_bits(codec,
-							WCD9XXX_A_CLK_BUFF_EN1,
-							0x01, 0x00);
-				} else {
-					wcd9xxx_resmgr_notifier_call(resmgr,
-						WCD9XXX_EVENT_PRE_MCLK_OFF);
-					snd_soc_update_bits(codec,
-							WCD9XXX_A_CLK_BUFF_EN1,
-							0x08, 0x08);
-					snd_soc_update_bits(codec,
-							WCD9XXX_A_CLK_BUFF_EN1,
-							0x01, 0x00);
-					wcd9xxx_resmgr_notifier_call(resmgr,
-						WCD9XXX_EVENT_POST_MCLK_OFF);
-					/* CLK Mux changed to RCO, notify that
-					 * RCO is ON
-					 */
-					wcd9xxx_resmgr_notifier_call(resmgr,
-						WCD9XXX_EVENT_POST_RCO_ON);
-				}
-			} else {
-				/* disable clock */
-				wcd9xxx_disable_clock_block(resmgr);
-				/* switch to RCO */
-				wcd9xxx_enable_clock_block(resmgr,
-							WCD9XXX_CFG_RCO);
-			}
-			resmgr->clk_type = WCD9XXX_CLK_RCO;
-		}
-		break;
-	default:
-		pr_err("%s: Error, Invalid clock get request %d\n", __func__,
-		       type);
-		break;
-	}
-	WARN_ON(resmgr->clk_rco_users < 0);
-	WARN_ON(resmgr->clk_mclk_users < 0);
-
-	pr_debug("%s: new rco_users %d, mclk_users %d\n", __func__,
-		 resmgr->clk_rco_users, resmgr->clk_mclk_users);
-}
-
-/*
- * wcd9xxx_resmgr_get_clk_type()
- * Returns clk type that is currently enabled
- */
-int wcd9xxx_resmgr_get_clk_type(struct wcd9xxx_resmgr *resmgr)
-{
-	return resmgr->clk_type;
-}
-
-static void wcd9xxx_resmgr_update_cfilt_usage(struct wcd9xxx_resmgr *resmgr,
-					      enum wcd9xxx_cfilt_sel cfilt_sel,
-					      bool inc)
-{
-	u16 micb_cfilt_reg;
-	enum wcd9xxx_notify_event e_pre_on, e_post_off;
-	struct snd_soc_codec *codec = resmgr->codec;
-
-	switch (cfilt_sel) {
-	case WCD9XXX_CFILT1_SEL:
-		micb_cfilt_reg = WCD9XXX_A_MICB_CFILT_1_CTL;
-		e_pre_on = WCD9XXX_EVENT_PRE_CFILT_1_ON;
-		e_post_off = WCD9XXX_EVENT_POST_CFILT_1_OFF;
-		break;
-	case WCD9XXX_CFILT2_SEL:
-		micb_cfilt_reg = WCD9XXX_A_MICB_CFILT_2_CTL;
-		e_pre_on = WCD9XXX_EVENT_PRE_CFILT_2_ON;
-		e_post_off = WCD9XXX_EVENT_POST_CFILT_2_OFF;
-		break;
-	case WCD9XXX_CFILT3_SEL:
-		micb_cfilt_reg = WCD9XXX_A_MICB_CFILT_3_CTL;
-		e_pre_on = WCD9XXX_EVENT_PRE_CFILT_3_ON;
-		e_post_off = WCD9XXX_EVENT_POST_CFILT_3_OFF;
-		break;
-	default:
-		WARN(1, "Invalid CFILT selection %d\n", cfilt_sel);
-		return; /* should not happen */
-	}
-
-	if (inc) {
-		if ((resmgr->cfilt_users[cfilt_sel]++) == 0) {
-			/* Notify */
-			wcd9xxx_resmgr_notifier_call(resmgr, e_pre_on);
-			/* Enable CFILT */
-			snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
-		}
-	} else {
-		/*
-		 * Check if count not zero, decrease
-		 * then check if zero, go ahead disable cfilter
-		 */
-		WARN(resmgr->cfilt_users[cfilt_sel] == 0,
-		     "Invalid CFILT use count 0\n");
-		if ((--resmgr->cfilt_users[cfilt_sel]) == 0) {
-			/* Disable CFILT */
-			snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
-			/* Notify MBHC so MBHC can switch CFILT to fast mode */
-			wcd9xxx_resmgr_notifier_call(resmgr, e_post_off);
-		}
-	}
-}
-
-void wcd9xxx_resmgr_cfilt_get(struct wcd9xxx_resmgr *resmgr,
-			      enum wcd9xxx_cfilt_sel cfilt_sel)
-{
-	return wcd9xxx_resmgr_update_cfilt_usage(resmgr, cfilt_sel, true);
-}
-
-void wcd9xxx_resmgr_cfilt_put(struct wcd9xxx_resmgr *resmgr,
-			      enum wcd9xxx_cfilt_sel cfilt_sel)
-{
-	return wcd9xxx_resmgr_update_cfilt_usage(resmgr, cfilt_sel, false);
-}
-
-int wcd9xxx_resmgr_get_k_val(struct wcd9xxx_resmgr *resmgr,
-			     unsigned int cfilt_mv)
-{
-	int rc = -EINVAL;
-	unsigned int ldoh_v = resmgr->micbias_pdata->ldoh_v;
-	unsigned int min_mv, max_mv;
-
-	switch (ldoh_v) {
-	case WCD9XXX_LDOH_1P95_V:
-		min_mv = 160;
-		max_mv = 1800;
-		break;
-	case WCD9XXX_LDOH_2P35_V:
-		min_mv = 200;
-		max_mv = 2200;
-		break;
-	case WCD9XXX_LDOH_2P75_V:
-		min_mv = 240;
-		max_mv = 2600;
-		break;
-	case WCD9XXX_LDOH_3P0_V:
-		min_mv = 260;
-		max_mv = 2875;
-		break;
-	default:
-		goto done;
-	}
-
-	if (cfilt_mv < min_mv || cfilt_mv > max_mv)
-		goto done;
-
-	for (rc = 4; rc <= 44; rc++) {
-		min_mv = max_mv * (rc) / 44;
-		if (min_mv >= cfilt_mv) {
-			rc -= 4;
-			break;
-		}
-	}
-done:
-	return rc;
-}
-
-static void wcd9xxx_resmgr_cond_trigger_cond(struct wcd9xxx_resmgr *resmgr,
-					     enum wcd9xxx_resmgr_cond cond)
-{
-	struct list_head *l;
-	struct wcd9xxx_resmgr_cond_entry *e;
-	bool set;
-
-	pr_debug("%s: enter\n", __func__);
-	/* update bit if cond isn't available or cond is set */
-	set = !test_bit(cond, &resmgr->cond_avail_flags) ||
-	      !!test_bit(cond, &resmgr->cond_flags);
-	list_for_each(l, &resmgr->update_bit_cond_h) {
-		e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
-		if (e->cond == cond)
-			snd_soc_update_bits(resmgr->codec, e->reg,
-					    1 << e->shift,
-					    (set ? !e->invert : e->invert)
-					    << e->shift);
-	}
-	pr_debug("%s: leave\n", __func__);
-}
-
-/*
- * wcd9xxx_regmgr_cond_register : notify resmgr conditions in the condbits are
- *				  available and notified.
- * condbits : contains bitmask of enum wcd9xxx_resmgr_cond
- */
-void wcd9xxx_regmgr_cond_register(struct wcd9xxx_resmgr *resmgr,
-				  unsigned long condbits)
-{
-	unsigned int cond;
-
-	for_each_set_bit(cond, &condbits, BITS_PER_BYTE * sizeof(condbits)) {
-		mutex_lock(&resmgr->update_bit_cond_lock);
-		WARN(test_bit(cond, &resmgr->cond_avail_flags),
-		     "Condition 0x%0x is already registered\n", cond);
-		set_bit(cond, &resmgr->cond_avail_flags);
-		wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
-		mutex_unlock(&resmgr->update_bit_cond_lock);
-		pr_debug("%s: Condition 0x%x is registered\n", __func__, cond);
-	}
-}
-
-void wcd9xxx_regmgr_cond_deregister(struct wcd9xxx_resmgr *resmgr,
-				    unsigned long condbits)
-{
-	unsigned int cond;
-
-	for_each_set_bit(cond, &condbits, BITS_PER_BYTE * sizeof(condbits)) {
-		mutex_lock(&resmgr->update_bit_cond_lock);
-		WARN(!test_bit(cond, &resmgr->cond_avail_flags),
-		     "Condition 0x%0x isn't registered\n", cond);
-		clear_bit(cond, &resmgr->cond_avail_flags);
-		wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
-		mutex_unlock(&resmgr->update_bit_cond_lock);
-		pr_debug("%s: Condition 0x%x is deregistered\n", __func__,
-			 cond);
-	}
-}
-
-void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
-				     enum wcd9xxx_resmgr_cond cond, bool set)
-{
-	mutex_lock(&resmgr->update_bit_cond_lock);
-	if ((set && !test_and_set_bit(cond, &resmgr->cond_flags)) ||
-	    (!set && test_and_clear_bit(cond, &resmgr->cond_flags))) {
-		pr_debug("%s: Resource %d condition changed to %s\n", __func__,
-			 cond, set ? "set" : "clear");
-		wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
-	}
-	mutex_unlock(&resmgr->update_bit_cond_lock);
-}
-
-int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
-					enum wcd9xxx_resmgr_cond cond,
-					unsigned short reg, int shift,
-					bool invert)
-{
-	struct wcd9xxx_resmgr_cond_entry *entry;
-
-	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
-	if (!entry)
-		return -ENOMEM;
-
-	entry->cond = cond;
-	entry->reg = reg;
-	entry->shift = shift;
-	entry->invert = invert;
-
-	mutex_lock(&resmgr->update_bit_cond_lock);
-	list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
-
-	wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
-	mutex_unlock(&resmgr->update_bit_cond_lock);
-
-	return 0;
-}
-
-/*
- * wcd9xxx_resmgr_rm_cond_update_bits :
- * Clear bit and remove from the conditional bit update list
- */
-int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
-				       enum wcd9xxx_resmgr_cond cond,
-				       unsigned short reg, int shift,
-				       bool invert)
-{
-	struct list_head *l, *next;
-	struct wcd9xxx_resmgr_cond_entry *e = NULL;
-
-	pr_debug("%s: enter\n", __func__);
-	mutex_lock(&resmgr->update_bit_cond_lock);
-	list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
-		e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
-		if (e->reg == reg && e->shift == shift && e->invert == invert) {
-			snd_soc_update_bits(resmgr->codec, e->reg,
-					    1 << e->shift,
-					    e->invert << e->shift);
-			list_del(&e->list);
-			mutex_unlock(&resmgr->update_bit_cond_lock);
-			kfree(e);
-			return 0;
-		}
-	}
-	mutex_unlock(&resmgr->update_bit_cond_lock);
-	pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
-	       __func__, e ? e->reg : 0, e ? e->shift : 0);
-
-	return -EINVAL;
-}
-
-int wcd9xxx_resmgr_register_notifier(struct wcd9xxx_resmgr *resmgr,
-				     struct notifier_block *nblock)
-{
-	return blocking_notifier_chain_register(&resmgr->notifier, nblock);
-}
-
-int wcd9xxx_resmgr_unregister_notifier(struct wcd9xxx_resmgr *resmgr,
-				       struct notifier_block *nblock)
-{
-	return blocking_notifier_chain_unregister(&resmgr->notifier, nblock);
-}
-
-int wcd9xxx_resmgr_init(struct wcd9xxx_resmgr *resmgr,
-			struct snd_soc_codec *codec,
-			struct wcd9xxx_core_resource *core_res,
-			struct wcd9xxx_pdata *pdata,
-			struct wcd9xxx_micbias_setting *micbias_pdata,
-			struct wcd9xxx_reg_address *reg_addr,
-			const struct wcd9xxx_resmgr_cb *resmgr_cb,
-			enum wcd9xxx_cdc_type cdc_type)
-{
-	WARN(ARRAY_SIZE(wcd9xxx_event_string) != WCD9XXX_EVENT_LAST + 1,
-	     "Event string table isn't up to date!, %zd != %d\n",
-	     ARRAY_SIZE(wcd9xxx_event_string), WCD9XXX_EVENT_LAST + 1);
-
-	resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
-	resmgr->codec = codec;
-	resmgr->codec_type = cdc_type;
-	/* This gives access of core handle to lock/unlock suspend */
-	resmgr->core_res = core_res;
-	resmgr->pdata = pdata;
-	resmgr->micbias_pdata = micbias_pdata;
-	resmgr->reg_addr = reg_addr;
-	resmgr->resmgr_cb = resmgr_cb;
-
-	INIT_LIST_HEAD(&resmgr->update_bit_cond_h);
-
-	BLOCKING_INIT_NOTIFIER_HEAD(&resmgr->notifier);
-
-	mutex_init(&resmgr->codec_resource_lock);
-	mutex_init(&resmgr->codec_bg_clk_lock);
-	mutex_init(&resmgr->update_bit_cond_lock);
-
-	return 0;
-}
-
-void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr)
-{
-	mutex_destroy(&resmgr->update_bit_cond_lock);
-	mutex_destroy(&resmgr->codec_bg_clk_lock);
-	mutex_destroy(&resmgr->codec_resource_lock);
-}
-
-void wcd9xxx_resmgr_bcl_lock(struct wcd9xxx_resmgr *resmgr)
-{
-	mutex_lock(&resmgr->codec_resource_lock);
-}
-
-void wcd9xxx_resmgr_bcl_unlock(struct wcd9xxx_resmgr *resmgr)
-{
-	mutex_unlock(&resmgr->codec_resource_lock);
-}
-
-MODULE_DESCRIPTION("wcd9xxx resmgr module");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
deleted file mode 100644
index e35d616..0000000
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ /dev/null
@@ -1,280 +0,0 @@
-/* Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef __WCD9XXX_COMMON_H__
-#define __WCD9XXX_COMMON_H__
-
-#include <linux/notifier.h>
-#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
-
-enum wcd9xxx_bandgap_type {
-	WCD9XXX_BANDGAP_OFF,
-	WCD9XXX_BANDGAP_AUDIO_MODE,
-	WCD9XXX_BANDGAP_MBHC_MODE,
-};
-
-enum wcd9xxx_cdc_type {
-	WCD9XXX_CDC_TYPE_INVALID = 0,
-	WCD9XXX_CDC_TYPE_TAIKO,
-	WCD9XXX_CDC_TYPE_TAPAN,
-	WCD9XXX_CDC_TYPE_HELICON,
-	WCD9XXX_CDC_TYPE_TOMTOM,
-};
-
-enum wcd9xxx_clock_type {
-	WCD9XXX_CLK_OFF,
-	WCD9XXX_CLK_RCO,
-	WCD9XXX_CLK_MCLK,
-};
-
-enum wcd9xxx_clock_config_mode {
-	WCD9XXX_CFG_MCLK = 0,
-	WCD9XXX_CFG_RCO,
-	WCD9XXX_CFG_CAL_RCO,
-};
-
-enum wcd9xxx_cfilt_sel {
-	WCD9XXX_CFILT1_SEL,
-	WCD9XXX_CFILT2_SEL,
-	WCD9XXX_CFILT3_SEL,
-	WCD9XXX_NUM_OF_CFILT,
-};
-
-struct wcd9xxx_reg_address {
-	u16 micb_4_ctl;
-	u16 micb_4_int_rbias;
-	u16 micb_4_mbhc;
-};
-
-enum wcd9xxx_notify_event {
-	WCD9XXX_EVENT_INVALID,
-
-	WCD9XXX_EVENT_PRE_RCO_ON,
-	WCD9XXX_EVENT_POST_RCO_ON,
-	WCD9XXX_EVENT_PRE_RCO_OFF,
-	WCD9XXX_EVENT_POST_RCO_OFF,
-
-	WCD9XXX_EVENT_PRE_MCLK_ON,
-	WCD9XXX_EVENT_POST_MCLK_ON,
-	WCD9XXX_EVENT_PRE_MCLK_OFF,
-	WCD9XXX_EVENT_POST_MCLK_OFF,
-
-	WCD9XXX_EVENT_PRE_BG_OFF,
-	WCD9XXX_EVENT_POST_BG_OFF,
-	WCD9XXX_EVENT_PRE_BG_AUDIO_ON,
-	WCD9XXX_EVENT_POST_BG_AUDIO_ON,
-	WCD9XXX_EVENT_PRE_BG_MBHC_ON,
-	WCD9XXX_EVENT_POST_BG_MBHC_ON,
-
-	WCD9XXX_EVENT_PRE_MICBIAS_1_OFF,
-	WCD9XXX_EVENT_POST_MICBIAS_1_OFF,
-	WCD9XXX_EVENT_PRE_MICBIAS_2_OFF,
-	WCD9XXX_EVENT_POST_MICBIAS_2_OFF,
-	WCD9XXX_EVENT_PRE_MICBIAS_3_OFF,
-	WCD9XXX_EVENT_POST_MICBIAS_3_OFF,
-	WCD9XXX_EVENT_PRE_MICBIAS_4_OFF,
-	WCD9XXX_EVENT_POST_MICBIAS_4_OFF,
-	WCD9XXX_EVENT_PRE_MICBIAS_1_ON,
-	WCD9XXX_EVENT_POST_MICBIAS_1_ON,
-	WCD9XXX_EVENT_PRE_MICBIAS_2_ON,
-	WCD9XXX_EVENT_POST_MICBIAS_2_ON,
-	WCD9XXX_EVENT_PRE_MICBIAS_3_ON,
-	WCD9XXX_EVENT_POST_MICBIAS_3_ON,
-	WCD9XXX_EVENT_PRE_MICBIAS_4_ON,
-	WCD9XXX_EVENT_POST_MICBIAS_4_ON,
-
-	WCD9XXX_EVENT_PRE_CFILT_1_OFF,
-	WCD9XXX_EVENT_POST_CFILT_1_OFF,
-	WCD9XXX_EVENT_PRE_CFILT_2_OFF,
-	WCD9XXX_EVENT_POST_CFILT_2_OFF,
-	WCD9XXX_EVENT_PRE_CFILT_3_OFF,
-	WCD9XXX_EVENT_POST_CFILT_3_OFF,
-	WCD9XXX_EVENT_PRE_CFILT_1_ON,
-	WCD9XXX_EVENT_POST_CFILT_1_ON,
-	WCD9XXX_EVENT_PRE_CFILT_2_ON,
-	WCD9XXX_EVENT_POST_CFILT_2_ON,
-	WCD9XXX_EVENT_PRE_CFILT_3_ON,
-	WCD9XXX_EVENT_POST_CFILT_3_ON,
-
-	WCD9XXX_EVENT_PRE_HPHL_PA_ON,
-	WCD9XXX_EVENT_POST_HPHL_PA_OFF,
-	WCD9XXX_EVENT_PRE_HPHR_PA_ON,
-	WCD9XXX_EVENT_POST_HPHR_PA_OFF,
-
-	WCD9XXX_EVENT_POST_RESUME,
-
-	WCD9XXX_EVENT_PRE_TX_3_ON,
-	WCD9XXX_EVENT_POST_TX_3_OFF,
-
-	WCD9XXX_EVENT_LAST,
-};
-
-struct wcd9xxx_resmgr_cb {
-	int (*cdc_rco_ctrl)(struct snd_soc_codec *, bool);
-};
-
-struct wcd9xxx_resmgr {
-	struct snd_soc_codec *codec;
-	struct wcd9xxx_core_resource *core_res;
-
-	u32 rx_bias_count;
-
-	/*
-	 * bandgap_type, bg_audio_users and bg_mbhc_users have to be
-	 * referred/manipulated after acquiring codec_bg_clk_lock mutex
-	 */
-	enum wcd9xxx_bandgap_type bandgap_type;
-	u16 bg_audio_users;
-	u16 bg_mbhc_users;
-
-	/*
-	 * clk_type, clk_rco_users and clk_mclk_users have to be
-	 * referred/manipulated after acquiring codec_bg_clk_lock mutex
-	 */
-	enum wcd9xxx_clock_type clk_type;
-	u16 clk_rco_users;
-	u16 clk_mclk_users;
-	u16 ext_clk_users;
-
-	/* cfilt users per cfilts */
-	u16 cfilt_users[WCD9XXX_NUM_OF_CFILT];
-
-	struct wcd9xxx_reg_address *reg_addr;
-
-	struct wcd9xxx_pdata *pdata;
-
-	struct wcd9xxx_micbias_setting *micbias_pdata;
-
-	struct blocking_notifier_head notifier;
-	/* Notifier needs mbhc pointer with resmgr */
-	struct wcd9xxx_mbhc *mbhc;
-
-	unsigned long cond_flags;
-	unsigned long cond_avail_flags;
-	struct list_head update_bit_cond_h;
-	struct mutex update_bit_cond_lock;
-
-	/*
-	 * Currently, only used for mbhc purpose, to protect
-	 * concurrent execution of mbhc threaded irq handlers and
-	 * kill race between DAPM and MBHC. But can serve as a
-	 * general lock to protect codec resource
-	 */
-	struct mutex codec_resource_lock;
-	struct mutex codec_bg_clk_lock;
-
-	enum wcd9xxx_cdc_type codec_type;
-
-	const struct wcd9xxx_resmgr_cb *resmgr_cb;
-};
-
-int wcd9xxx_resmgr_init(struct wcd9xxx_resmgr *resmgr,
-			struct snd_soc_codec *codec,
-			struct wcd9xxx_core_resource *core_res,
-			struct wcd9xxx_pdata *pdata,
-			struct wcd9xxx_micbias_setting *micbias_pdata,
-			struct wcd9xxx_reg_address *reg_addr,
-			const struct wcd9xxx_resmgr_cb *resmgr_cb,
-			enum wcd9xxx_cdc_type cdc_type);
-void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr);
-
-int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr,
-				int enable);
-
-void wcd9xxx_resmgr_enable_rx_bias(struct wcd9xxx_resmgr *resmgr, u32 enable);
-void wcd9xxx_resmgr_get_clk_block(struct wcd9xxx_resmgr *resmgr,
-				  enum wcd9xxx_clock_type type);
-void wcd9xxx_resmgr_put_clk_block(struct wcd9xxx_resmgr *resmgr,
-				  enum wcd9xxx_clock_type type);
-void wcd9xxx_resmgr_get_bandgap(struct wcd9xxx_resmgr *resmgr,
-				const enum wcd9xxx_bandgap_type choice);
-void wcd9xxx_resmgr_put_bandgap(struct wcd9xxx_resmgr *resmgr,
-				enum wcd9xxx_bandgap_type choice);
-void wcd9xxx_resmgr_cfilt_get(struct wcd9xxx_resmgr *resmgr,
-			      enum wcd9xxx_cfilt_sel cfilt_sel);
-void wcd9xxx_resmgr_cfilt_put(struct wcd9xxx_resmgr *resmgr,
-			      enum wcd9xxx_cfilt_sel cfilt_sel);
-int wcd9xxx_resmgr_get_clk_type(struct wcd9xxx_resmgr *resmgr);
-
-void wcd9xxx_resmgr_bcl_lock(struct wcd9xxx_resmgr *resmgr);
-void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr);
-#define WCD9XXX_BCL_LOCK(resmgr)			\
-{							\
-	pr_debug("%s: Acquiring BCL\n", __func__);	\
-	wcd9xxx_resmgr_bcl_lock(resmgr);			\
-	pr_debug("%s: Acquiring BCL done\n", __func__);	\
-}
-
-void wcd9xxx_resmgr_bcl_unlock(struct wcd9xxx_resmgr *resmgr);
-#define WCD9XXX_BCL_UNLOCK(resmgr)			\
-{							\
-	pr_debug("%s: Release BCL\n", __func__);	\
-	wcd9xxx_resmgr_bcl_unlock(resmgr);			\
-}
-
-#define WCD9XXX_BCL_ASSERT_LOCKED(resmgr)		\
-{							\
-	WARN_ONCE(!mutex_is_locked(&resmgr->codec_resource_lock), \
-		  "%s: BCL should have acquired\n", __func__); \
-}
-
-#define WCD9XXX_BG_CLK_LOCK(resmgr)			\
-{							\
-	struct wcd9xxx_resmgr *__resmgr = resmgr;	\
-	pr_debug("%s: Acquiring BG_CLK\n", __func__);	\
-	mutex_lock(&__resmgr->codec_bg_clk_lock);	\
-	pr_debug("%s: Acquiring BG_CLK done\n", __func__);	\
-}
-
-#define WCD9XXX_BG_CLK_UNLOCK(resmgr)			\
-{							\
-	struct wcd9xxx_resmgr *__resmgr = resmgr;	\
-	pr_debug("%s: Releasing BG_CLK\n", __func__);	\
-	mutex_unlock(&__resmgr->codec_bg_clk_lock);	\
-}
-
-#define WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr)		\
-{							\
-	WARN_ONCE(!mutex_is_locked(&resmgr->codec_bg_clk_lock), \
-		  "%s: BG_CLK lock should have acquired\n", __func__); \
-}
-
-const char *wcd9xxx_get_event_string(enum wcd9xxx_notify_event type);
-int wcd9xxx_resmgr_get_k_val(struct wcd9xxx_resmgr *resmgr,
-			     unsigned int cfilt_mv);
-int wcd9xxx_resmgr_register_notifier(struct wcd9xxx_resmgr *resmgr,
-				     struct notifier_block *nblock);
-int wcd9xxx_resmgr_unregister_notifier(struct wcd9xxx_resmgr *resmgr,
-				       struct notifier_block *nblock);
-void wcd9xxx_resmgr_notifier_call(struct wcd9xxx_resmgr *resmgr,
-				  const enum wcd9xxx_notify_event e);
-
-enum wcd9xxx_resmgr_cond {
-	WCD9XXX_COND_HPH = 0x01, /* Headphone */
-	WCD9XXX_COND_HPH_MIC = 0x02, /* Microphone on the headset */
-};
-void wcd9xxx_regmgr_cond_register(struct wcd9xxx_resmgr *resmgr,
-				  unsigned long condbits);
-void wcd9xxx_regmgr_cond_deregister(struct wcd9xxx_resmgr *resmgr,
-				    unsigned long condbits);
-int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
-				       enum wcd9xxx_resmgr_cond cond,
-				       unsigned short reg, int shift,
-				       bool invert);
-int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
-					enum wcd9xxx_resmgr_cond cond,
-					unsigned short reg, int shift,
-					bool invert);
-void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
-				     enum wcd9xxx_resmgr_cond cond, bool set);
-
-#endif /* __WCD9XXX_COMMON_H__ */
diff --git a/sound/soc/codecs/wcd9xxx-soc-init.c b/sound/soc/codecs/wcd9xxx-soc-init.c
new file mode 100644
index 0000000..fa8abb7
--- /dev/null
+++ b/sound/soc/codecs/wcd9xxx-soc-init.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <sound/wcd-dsp-mgr.h>
+#include "audio-ext-clk-up.h"
+
+static int __init wcd9xxx_soc_init(void)
+{
+	int ret = 0;
+
+	ret = wcd_dsp_mgr_init();
+	if (!ret) {
+		ret = audio_ref_clk_platform_init();
+		if (ret) {
+			pr_err("%s: init extclk fail: %d\n", __func__, ret);
+			wcd_dsp_mgr_exit();
+		}
+	} else {
+		pr_err("%s: init dsp mgr fail: %d\n", __func__, ret);
+	}
+
+	return ret;
+}
+module_init(wcd9xxx_soc_init);
+
+static void __exit wcd9xxx_soc_exit(void)
+{
+	audio_ref_clk_platform_exit();
+	wcd_dsp_mgr_exit();
+}
+module_exit(wcd9xxx_soc_exit);
+
+MODULE_DESCRIPTION("WCD9XXX CODEC soc init driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c
index 0c2f41a..f2a20d51 100644
--- a/sound/soc/codecs/wcd_cpe_core.c
+++ b/sound/soc/codecs/wcd_cpe_core.c
@@ -648,6 +648,7 @@
 done:
 	return core;
 }
+EXPORT_SYMBOL(wcd_cpe_get_core_handle);
 
 /*
  * svass_engine_irq: threaded interrupt handler for svass engine irq
@@ -3538,6 +3539,8 @@
 	pr_debug("%s: enter payload_size = %d Enable %d\n",
 		 __func__, pld_size, enable);
 
+	memset(&cpe_lab_enable, 0, sizeof(cpe_lab_enable));
+
 	if (fill_lsm_cmd_header_v0_inband(&cpe_lab_enable.hdr, session->id,
 		(u8) pld_size, CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
 		return -EINVAL;
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 4189e59..77aea10 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -104,6 +104,7 @@
 	int state;
 	struct delayed_work ocp_ctl_work;
 	struct device_node *wsa_rst_np;
+	int pa_mute;
 };
 
 #define SWR_SLV_MAX_REG_ADDR	0x390
@@ -170,9 +171,41 @@
 	return 0;
 }
 
-static const struct snd_kcontrol_new wsa_analog_gain_controls[] = {
+static int wsa881x_get_mute(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wsa881x->pa_mute;
+
+	return 0;
+}
+
+static int wsa881x_set_mute(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: mute current %d, new %d\n",
+		__func__, wsa881x->pa_mute, value);
+
+	if (value)
+		snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x80, 0x00);
+	wsa881x->pa_mute = value;
+
+	return 0;
+}
+
+
+static const struct snd_kcontrol_new wsa_snd_controls[] = {
 	SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
 		     wsa_pa_gain_get, wsa_pa_gain_put),
+	SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
+		wsa881x_get_mute, wsa881x_set_mute),
 };
 
 static int codec_debug_open(struct inode *inode, struct file *file)
@@ -1050,8 +1083,8 @@
 	wsa881x->tz_pdata.codec = codec;
 	wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read;
 	wsa881x_init_thermal(&wsa881x->tz_pdata);
-	snd_soc_add_codec_controls(codec, wsa_analog_gain_controls,
-				   ARRAY_SIZE(wsa_analog_gain_controls));
+	snd_soc_add_codec_controls(codec, wsa_snd_controls,
+				   ARRAY_SIZE(wsa_snd_controls));
 	INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work);
 	return 0;
 }
@@ -1092,54 +1125,6 @@
 	},
 };
 
-static int wsa881x_swr_startup(struct swr_device *swr_dev)
-{
-	int ret = 0;
-	u8 devnum = 0;
-	struct wsa881x_priv *wsa881x;
-
-	wsa881x = swr_get_dev_data(swr_dev);
-	if (!wsa881x) {
-		dev_err(&swr_dev->dev, "%s: wsa881x is NULL\n", __func__);
-		return -EINVAL;
-	}
-
-	/*
-	 * Add 5msec delay to provide sufficient time for
-	 * soundwire auto enumeration of slave devices as
-	 * as per HW requirement.
-	 */
-	usleep_range(5000, 5010);
-	ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
-	if (ret) {
-		dev_dbg(&swr_dev->dev,
-			"%s get devnum %d for dev addr %lx failed\n",
-			__func__, devnum, swr_dev->addr);
-		goto err;
-	}
-	swr_dev->dev_num = devnum;
-
-	wsa881x->regmap = devm_regmap_init_swr(swr_dev,
-					       &wsa881x_regmap_config);
-	if (IS_ERR(wsa881x->regmap)) {
-		ret = PTR_ERR(wsa881x->regmap);
-		dev_err(&swr_dev->dev, "%s: regmap_init failed %d\n",
-			__func__, ret);
-		goto err;
-	}
-
-	ret = snd_soc_register_codec(&swr_dev->dev, &soc_codec_dev_wsa881x,
-				     NULL, 0);
-	if (ret) {
-		dev_err(&swr_dev->dev, "%s: Codec registration failed\n",
-			__func__);
-		goto err;
-	}
-
-err:
-	return ret;
-}
-
 static int wsa881x_gpio_ctrl(struct wsa881x_priv *wsa881x, bool enable)
 {
 	int ret = 0;
@@ -1201,6 +1186,8 @@
 {
 	int ret = 0;
 	struct wsa881x_priv *wsa881x;
+	u8 devnum = 0;
+	bool pin_state_current = false;
 
 	wsa881x = devm_kzalloc(&pdev->dev, sizeof(struct wsa881x_priv),
 			    GFP_KERNEL);
@@ -1231,6 +1218,9 @@
 		if (ret)
 			goto err;
 	}
+	if (wsa881x->wsa_rst_np)
+		pin_state_current = msm_cdc_pinctrl_get_state(
+						wsa881x->wsa_rst_np);
 	wsa881x_gpio_ctrl(wsa881x, true);
 	wsa881x->state = WSA881X_DEV_UP;
 
@@ -1257,8 +1247,45 @@
 						&codec_debug_ops);
 		}
 	}
+
+	/*
+	 * Add 5msec delay to provide sufficient time for
+	 * soundwire auto enumeration of slave devices as
+	 * as per HW requirement.
+	 */
+	usleep_range(5000, 5010);
+	ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
+	if (ret) {
+		dev_dbg(&pdev->dev,
+			"%s get devnum %d for dev addr %lx failed\n",
+			__func__, devnum, pdev->addr);
+		goto dev_err;
+	}
+	pdev->dev_num = devnum;
+
+	wsa881x->regmap = devm_regmap_init_swr(pdev,
+					       &wsa881x_regmap_config);
+	if (IS_ERR(wsa881x->regmap)) {
+		ret = PTR_ERR(wsa881x->regmap);
+		dev_err(&pdev->dev, "%s: regmap_init failed %d\n",
+			__func__, ret);
+		goto dev_err;
+	}
+
+	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wsa881x,
+				     NULL, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: Codec registration failed\n",
+			__func__);
+		goto dev_err;
+	}
+
 	return 0;
 
+dev_err:
+	if (pin_state_current == false)
+		wsa881x_gpio_ctrl(wsa881x, false);
+	swr_remove_device(pdev);
 err:
 	return ret;
 }
@@ -1338,6 +1365,7 @@
 		/* Retry after 1 msec delay */
 		usleep_range(1000, 1100);
 	}
+	pdev->dev_num = devnum;
 	regcache_mark_dirty(wsa881x->regmap);
 	regcache_sync(wsa881x->regmap);
 	return 0;
@@ -1392,7 +1420,6 @@
 	.device_up = wsa881x_swr_up,
 	.device_down = wsa881x_swr_down,
 	.reset_device = wsa881x_swr_reset,
-	.startup = wsa881x_swr_startup,
 };
 
 static int __init wsa881x_codec_init(void)
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 18585749..c557ae0 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -192,8 +192,21 @@
 	 the machine driver and the corresponding
 	 DAI-links
 
-config SND_SOC_MSM8998
+config SND_SOC_MACHINE_MSM8998
 	tristate "SoC Machine driver for MSM8998 boards"
+	select SND_SOC_WSA881X
+	select SND_SOC_WCD9335
+	select SND_SOC_WCD934X
+	select SND_SOC_CPE
+
+	help
+	To enable the machine driver and the
+	corresponding DAI-links on MSM8998.
+	All platform specific audio modules are
+	enabled here.
+
+config SND_SOC_MSM8998
+	tristate "Sound SoC drivers to interface with DSP"
 	depends on ARCH_QCOM
 	select SND_SOC_COMPRESS
 	select SND_SOC_QDSP6V2
@@ -205,13 +218,9 @@
 	select MSM_QDSP6_PDR
 	select MSM_QDSP6_NOTIFIER
 	select MSM_QDSP6V2_CODECS
-	select SND_SOC_WCD9335
-	select SND_SOC_WCD934X
-	select SND_SOC_WSA881X
 	select SND_SOC_MSM_HDMI_CODEC_RX
 	select DTS_SRS_TM
 	select QTI_PP
-	select SND_SOC_CPE
 	select MSM_ULTRASOUND
 	select DOLBY_LICENSE
 	select SND_HWDEP
@@ -235,6 +244,17 @@
 	 the machine driver and the corresponding
 	 DAI-links
 
+config SND_SOC_MACHINE_SDM845
+	tristate "SoC Machine driver for SDM845 boards"
+	select SND_SOC_WSA881X
+	select SND_SOC_WCD934X
+
+	help
+	To enable the machine driver and the
+	corresponding DAI-links on SDM845.
+	All platform specific audio modules are
+	enabled here.
+
 config SND_SOC_SDM845
 	tristate "SoC Machine driver for SDM845 boards"
 	depends on ARCH_QCOM
@@ -248,8 +268,6 @@
 	select MSM_QDSP6_PDR
 	select MSM_QDSP6_NOTIFIER
 	select MSM_QDSP6V2_CODECS
-	select SND_SOC_WCD934X
-	select SND_SOC_WSA881X
 	select DTS_SRS_TM
 	select QTI_PP
 	select MSM_ULTRASOUND
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 5105cd9..caf8843 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -18,7 +18,7 @@
 
 # for MSM8998 sound card driver
 snd-soc-msm8998-objs := msm8998.o
-obj-$(CONFIG_SND_SOC_MSM8998) += snd-soc-msm8998.o
+obj-$(CONFIG_SND_SOC_MACHINE_MSM8998) += snd-soc-msm8998.o
 
 # for SDM660 sound card driver
 snd-soc-sdm660-common-objs := sdm660-common.o
@@ -36,4 +36,4 @@
 
 # for SDM845 sound card driver
 snd-soc-sdm845-objs := sdm845.o
-obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
+obj-$(CONFIG_SND_SOC_MACHINE_SDM845) += snd-soc-sdm845.o
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 755b62a..c319ccf 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -113,7 +113,7 @@
 				    SNDRV_PCM_FMTBIT_S24_3LE |
 				    SNDRV_PCM_FMTBIT_S32_LE),
 			.channels_min = 1,
-			.channels_max = 4,
+			.channels_max = 8,
 			.rate_min =     8000,
 			.rate_max =	48000,
 		},
@@ -2582,7 +2582,7 @@
 			.channels_min = 1,
 			.channels_max = 8,
 			.rate_min =     8000,
-			.rate_max =     48000,
+			.rate_max =     192000,
 		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.compress_new = snd_soc_new_compress,
@@ -2608,6 +2608,39 @@
 		.name = "MultiMedia19",
 		.probe = fe_dai_probe,
 	},
+	{
+		.playback = {
+			.stream_name = "MultiMedia20 Playback",
+			.aif_name = "MM_DL20",
+			.rates = (SNDRV_PCM_RATE_8000_384000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE |
+				    SNDRV_PCM_FMTBIT_S24_3LE |
+				    SNDRV_PCM_FMTBIT_S32_LE),
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =     384000,
+		},
+		.capture = {
+			.stream_name = "MultiMedia20 Capture",
+			.aif_name = "MM_UL20",
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
+				    SNDRV_PCM_FMTBIT_S24_LE |
+				    SNDRV_PCM_FMTBIT_S24_3LE |
+				    SNDRV_PCM_FMTBIT_S32_LE),
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.ops = &msm_fe_Multimedia_dai_ops,
+		.name = "MultiMedia20",
+		.probe = fe_dai_probe,
+	},
 };
 
 static int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index d8fcfa7..222c65a 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -4086,7 +4086,6 @@
 			dev_err(rtd->card->dev,
 				"%s lpaif_tert_muxsel_virt_addr is NULL\n",
 				__func__);
-			auxpcm_intf_conf[index].ref_cnt++;
 		}
 	}
 	mutex_unlock(&auxpcm_intf_conf[index].lock);
@@ -4163,9 +4162,6 @@
 		mi2s_clk[dai_id].clk_freq_in_hz =
 		    mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
 	}
-
-	if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
-		mi2s_clk[dai_id].clk_freq_in_hz = 0;
 }
 
 static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
@@ -4214,6 +4210,13 @@
 		ret = -EINVAL;
 		goto err;
 	}
+
+	if (pinctrl_info->pinctrl == NULL) {
+		pr_err("%s: pinctrl_info->pinctrl is NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
 	curr_state = pinctrl_info->curr_state;
 	pinctrl_info->curr_state = new_state;
 	pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
@@ -4482,6 +4485,7 @@
 	struct snd_soc_card *card = rtd->card;
 	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+	int ret_pinctrl = 0;
 
 	dev_dbg(rtd->card->dev,
 		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
@@ -4496,11 +4500,10 @@
 		goto done;
 	}
 	if (index == QUAT_MI2S) {
-		ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
-		if (ret) {
+		ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+		if (ret_pinctrl) {
 			pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
-				__func__, ret);
-			goto done;
+				__func__, ret_pinctrl);
 		}
 	}
 
@@ -4559,6 +4562,7 @@
 	struct snd_soc_card *card = rtd->card;
 	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+	int ret_pinctrl = 0;
 
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
 		 substream->name, substream->stream);
@@ -4570,19 +4574,17 @@
 	mutex_lock(&mi2s_intf_conf[index].lock);
 	if (--mi2s_intf_conf[index].ref_cnt == 0) {
 		ret = msm_mi2s_set_sclk(substream, false);
-		if (ret < 0) {
+		if (ret < 0)
 			pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n",
 				__func__, index, ret);
-			mi2s_intf_conf[index].ref_cnt++;
-		}
 	}
 	mutex_unlock(&mi2s_intf_conf[index].lock);
 
 	if (index == QUAT_MI2S) {
-		ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
-		if (ret)
+		ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+		if (ret_pinctrl)
 			pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
-				__func__, ret);
+				__func__, ret_pinctrl);
 	}
 }
 
@@ -5501,6 +5503,37 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{
+		.name = MSM_DAILINK_NAME(Transcode Loopback Playback),
+		.stream_name = "Transcode Loopback Playback",
+		.cpu_dai_name = "MultiMedia14",
+		.platform_name = "msm-transcode-loopback",
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			 SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		 /* this dainlink has playback support */
+		.id = MSM_FRONTEND_DAI_MULTIMEDIA14,
+	},
+	{
+		.name = MSM_DAILINK_NAME(Transcode Loopback Capture),
+		.stream_name = "Transcode Loopback Capture",
+		.cpu_dai_name = "MultiMedia18",
+		.platform_name = "msm-transcode-loopback",
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			 SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.id = MSM_FRONTEND_DAI_MULTIMEDIA18,
+	},
 };
 
 static struct snd_soc_dai_link msm_common_be_dai_links[] = {
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 36382ba..ceb6b50 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -4,12 +4,12 @@
 			msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
 			msm-lsm-client.o msm-pcm-host-voice-v2.o \
 			msm-audio-effects-q6-v2.o msm-pcm-loopback-v2.o \
-			msm-dai-slim.o \
+			msm-dai-slim.o msm-transcode-loopback-q6-v2.o \
 			adsp_err.o
 obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
 				 msm-dai-stub-v2.o
 obj-$(CONFIG_SND_HWDEP) += msm-pcm-routing-devdep.o
-obj-$(CONFIG_DTS_EAGLE) += msm-dts-eagle.o
+obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
 obj-$(CONFIG_DOLBY_DS2) += msm-ds2-dap-config.o
 obj-$(CONFIG_DOLBY_LICENSE) += msm-ds2-dap-config.o
 obj-$(CONFIG_DTS_SRS_TM) += msm-dts-srs-tm-config.o
diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
index 820aa1b..7e69a7f 100644
--- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c
+++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
@@ -158,9 +158,6 @@
 	case ULP_LSM_CAL_TYPE:
 		size = sizeof(struct audio_cal_info_lsm);
 		break;
-	case DTS_EAGLE_CAL_TYPE:
-		size = 0;
-		break;
 	case AUDIO_CORE_METAINFO_CAL_TYPE:
 		size = sizeof(struct audio_cal_info_metainfo);
 		break;
@@ -307,9 +304,6 @@
 	case ULP_LSM_CAL_TYPE:
 		size = sizeof(struct audio_cal_type_lsm);
 		break;
-	case DTS_EAGLE_CAL_TYPE:
-		size = 0;
-		break;
 	case AUDIO_CORE_METAINFO_CAL_TYPE:
 		size = sizeof(struct audio_cal_type_metainfo);
 		break;
@@ -362,6 +356,15 @@
 	return cal_type;
 }
 
+/**
+ * cal_utils_create_cal_types
+ *
+ * @num_cal_types: number of types
+ * @cal_type: pointer to the cal types pointer
+ * @info: pointer to info
+ *
+ * Returns 0 on success, EINVAL otherwise
+ */
 int cal_utils_create_cal_types(int num_cal_types,
 			struct cal_type_data **cal_type,
 			struct cal_type_info *info)
@@ -417,6 +420,7 @@
 done:
 	return ret;
 }
+EXPORT_SYMBOL(cal_utils_create_cal_types);
 
 static void delete_cal_block(struct cal_block_data *cal_block)
 {
@@ -503,6 +507,13 @@
 	return;
 }
 
+/**
+ * cal_utils_get_only_cal_block
+ *
+ * @cal_type: pointer to the cal type
+ *
+ * Returns cal_block structure
+ */
 struct cal_block_data *cal_utils_get_only_cal_block(
 			struct cal_type_data *cal_type)
 {
@@ -522,7 +533,16 @@
 done:
 	return cal_block;
 }
+EXPORT_SYMBOL(cal_utils_get_only_cal_block);
 
+/**
+ * cal_utils_get_only_cal_block
+ *
+ * @cal_block: pointer to cal block struct
+ * @user_data: pointer to user data
+ *
+ * Returns true on match
+ */
 bool cal_utils_match_buf_num(struct cal_block_data *cal_block,
 					void *user_data)
 {
@@ -534,6 +554,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(cal_utils_match_buf_num);
 
 static struct cal_block_data *get_matching_cal_block(
 					struct cal_type_data *cal_type,
@@ -765,6 +786,17 @@
 	return ret;
 }
 
+/**
+ * cal_utils_alloc_cal
+ *
+ * @data_size: size of data to allocate
+ * @data: data pointer
+ * @cal_type: pointer to the cal type
+ * @client_info_size: client info size
+ * @client_info: pointer to client info
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
 int cal_utils_alloc_cal(size_t data_size, void *data,
 			struct cal_type_data *cal_type,
 			size_t client_info_size, void *client_info)
@@ -833,7 +865,17 @@
 done:
 	return ret;
 }
+EXPORT_SYMBOL(cal_utils_alloc_cal);
 
+/**
+ * cal_utils_dealloc_cal
+ *
+ * @data_size: size of data to allocate
+ * @data: data pointer
+ * @cal_type: pointer to the cal type
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
 int cal_utils_dealloc_cal(size_t data_size, void *data,
 			struct cal_type_data *cal_type)
 {
@@ -893,7 +935,19 @@
 done:
 	return ret;
 }
+EXPORT_SYMBOL(cal_utils_dealloc_cal);
 
+/**
+ * cal_utils_set_cal
+ *
+ * @data_size: size of data to allocate
+ * @data: data pointer
+ * @cal_type: pointer to the cal type
+ * @client_info_size: client info size
+ * @client_info: pointer to client info
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
 int cal_utils_set_cal(size_t data_size, void *data,
 			struct cal_type_data *cal_type,
 			size_t client_info_size, void *client_info)
@@ -973,3 +1027,4 @@
 done:
 	return ret;
 }
+EXPORT_SYMBOL(cal_utils_set_cal);
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
index 225f978..9f08222 100644
--- a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
@@ -15,7 +15,6 @@
 #include <sound/q6asm-v2.h>
 #include <sound/compress_params.h>
 #include <sound/msm-audio-effects-q6-v2.h>
-#include <sound/msm-dts-eagle.h>
 #include <sound/devdep_params.h>
 
 #define MAX_ENABLE_CMD_SIZE 32
@@ -49,26 +48,6 @@
 	case EQ_MODULE:
 		switch (topology) {
 		case ASM_STREAM_POSTPROC_TOPO_ID_SA_PLUS:
-		case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS:
-		case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
-			return true;
-		default:
-			return false;
-		}
-	case DTS_EAGLE_MODULE:
-		switch (topology) {
-		case ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX:
-		case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS:
-		case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
-			return true;
-		default:
-			return false;
-		}
-	case SOFT_VOLUME2_MODULE:
-	case DTS_EAGLE_MODULE_ENABLE:
-		switch (topology) {
-		case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS:
-		case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
 			return true;
 		default:
 			return false;
@@ -275,7 +254,7 @@
 			break;
 		}
 	}
-	if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+	if (params_length && (rc == 0))
 		q6asm_send_audio_effects_params(ac, params,
 						params_length);
 	else
@@ -745,7 +724,7 @@
 			break;
 		}
 	}
-	if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+	if (params_length && (rc == 0))
 		q6asm_send_audio_effects_params(ac, params,
 						params_length);
 	else
@@ -880,7 +859,7 @@
 			break;
 		}
 	}
-	if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+	if (params_length && (rc == 0))
 		q6asm_send_audio_effects_params(ac, params,
 						params_length);
 	else
@@ -1219,7 +1198,7 @@
 			break;
 		}
 	}
-	if (params_length && !msm_dts_eagle_is_hpx_on() && (rc == 0))
+	if (params_length && (rc == 0))
 		q6asm_send_audio_effects_params(ac, params,
 						params_length);
 	else
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index e8e4e04..c885265 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -32,6 +32,7 @@
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/msm_audio_ion.h>
+#include <linux/msm_audio.h>
 
 #include <sound/timer.h>
 #include <sound/tlv.h>
@@ -42,9 +43,8 @@
 #include <sound/compress_offload.h>
 #include <sound/compress_driver.h>
 #include <sound/msm-audio-effects-q6-v2.h>
-#include <sound/msm-dts-eagle.h>
-
 #include "msm-pcm-routing-v2.h"
+#include "msm-qti-pp-config.h"
 
 #define DSP_PP_BUFFERING_IN_MSEC	25
 #define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC	150
@@ -79,15 +79,6 @@
 
 #define MAX_NUMBER_OF_STREAMS 2
 
-/*
- * Max size for getting DTS EAGLE Param through kcontrol
- * Safe for both 32 and 64 bit platforms
- * 64 = size of kcontrol value array on 64 bit platform
- * 4 = size of parameters Eagle expects before cast to 64 bits
- * 40 = size of dts_eagle_param_desc + module_id cast to 64 bits
- */
-#define DTS_EAGLE_MAX_PARAM_SIZE_FOR_ALSA ((64 * 4) - 40)
-
 struct msm_compr_gapless_state {
 	bool set_next_stream_id;
 	int32_t stream_opened[MAX_NUMBER_OF_STREAMS];
@@ -100,7 +91,8 @@
 
 static unsigned int supported_sample_rates[] = {
 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000,
-	88200, 96000, 128000, 176400, 192000, 352800, 384000, 2822400, 5644800
+	88200, 96000, 128000, 144000, 176400, 192000, 352800, 384000, 2822400,
+	5644800
 };
 
 struct msm_compr_pdata {
@@ -186,7 +178,7 @@
 
 const u32 compr_codecs[] = {
 	SND_AUDIOCODEC_AC3, SND_AUDIOCODEC_EAC3, SND_AUDIOCODEC_DTS,
-	SND_AUDIOCODEC_DSD};
+	SND_AUDIOCODEC_DSD, SND_AUDIOCODEC_TRUEHD, SND_AUDIOCODEC_IEC61937};
 
 struct query_audio_effect {
 	uint32_t mod_id;
@@ -312,6 +304,39 @@
 	return ret;
 }
 
+static int msm_compr_enable_adjust_session_clock(struct audio_client *ac,
+		bool enable)
+{
+	int ret;
+
+	pr_debug("%s, enable adjust_session %d\n", __func__, enable);
+
+	ret = q6asm_send_mtmx_strtr_enable_adjust_session_clock(ac, enable);
+	if (ret)
+		pr_err("%s, adjust session clock can't be set error %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static int msm_compr_adjust_session_clock(struct audio_client *ac,
+		uint32_t adjust_session_lsw, uint32_t adjust_session_msw)
+{
+	int ret;
+
+	pr_debug("%s, adjust_session_time_msw 0x%x adjust_session_time_lsw 0x%x\n",
+		 __func__, adjust_session_msw, adjust_session_lsw);
+
+	ret = q6asm_adjust_session_clock(ac,
+			adjust_session_lsw,
+			adjust_session_msw);
+	if (ret)
+		pr_err("%s, adjust session clock can't be set error %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
 static int msm_compr_set_volume(struct snd_compr_stream *cstream,
 				uint32_t volume_l, uint32_t volume_r)
 {
@@ -377,11 +402,6 @@
 	if (rc < 0)
 		pr_err("%s: Send vol gain command failed rc=%d\n",
 		       __func__, rc);
-	else
-		if (msm_dts_eagle_set_stream_gain(prtd->audio_client,
-						volume_l, volume_r))
-			pr_debug("%s: DTS_EAGLE send stream gain failed\n",
-				__func__);
 
 	return rc;
 }
@@ -545,12 +565,19 @@
 	unsigned long flags;
 	uint64_t read_size;
 	uint32_t *buff_addr;
+	struct snd_soc_pcm_runtime *rtd;
+	int ret = 0;
 
 	if (!prtd) {
 		pr_err("%s: prtd is NULL\n", __func__);
 		return;
 	}
 	cstream = prtd->cstream;
+	if (!cstream) {
+		pr_err("%s: cstream is NULL\n", __func__);
+		return;
+	}
+
 	ac = prtd->audio_client;
 
 	/*
@@ -718,6 +745,22 @@
 			prtd->gapless_state.gapless_transition = 0;
 		spin_unlock_irqrestore(&prtd->lock, flags);
 		break;
+	case ASM_STREAM_PP_EVENT:
+	case ASM_STREAM_CMD_ENCDEC_EVENTS:
+		pr_debug("%s: ASM_STREAM_EVENT(0x%x)\n", __func__, opcode);
+		rtd = cstream->private_data;
+		if (!rtd) {
+			pr_err("%s: rtd is NULL\n", __func__);
+			return;
+		}
+
+		ret = msm_adsp_inform_mixer_ctl(rtd, payload);
+		if (ret) {
+			pr_err("%s: failed to inform mixer ctrl. err = %d\n",
+				__func__, ret);
+			return;
+		}
+		break;
 	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
 	case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: {
 		pr_debug("ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY\n");
@@ -821,6 +864,10 @@
 			}
 			atomic_set(&prtd->close, 0);
 			break;
+		case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
+			pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
+				__func__);
+			break;
 		default:
 			break;
 		}
@@ -881,7 +928,7 @@
 			COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
 	prtd->compr_cap.max_fragments =
 			COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
-	prtd->compr_cap.num_codecs = 15;
+	prtd->compr_cap.num_codecs = 17;
 	prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
 	prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
 	prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
@@ -897,6 +944,8 @@
 	prtd->compr_cap.codecs[12] = SND_AUDIOCODEC_DTS;
 	prtd->compr_cap.codecs[13] = SND_AUDIOCODEC_DSD;
 	prtd->compr_cap.codecs[14] = SND_AUDIOCODEC_APTX;
+	prtd->compr_cap.codecs[15] = SND_AUDIOCODEC_TRUEHD;
+	prtd->compr_cap.codecs[16] = SND_AUDIOCODEC_IEC61937;
 }
 
 static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -1151,6 +1200,19 @@
 			pr_err("%s: CMD DSD Format block failed ret %d\n",
 				__func__, ret);
 		break;
+	case FORMAT_TRUEHD:
+		pr_debug("SND_AUDIOCODEC_TRUEHD\n");
+		/* no media format block needed */
+		break;
+	case FORMAT_IEC61937:
+		pr_debug("SND_AUDIOCODEC_IEC61937\n");
+		ret = q6asm_media_format_block_iec(prtd->audio_client,
+						   prtd->sample_rate,
+						   prtd->num_channels);
+		if (ret < 0)
+			pr_err("%s: CMD IEC61937 Format block failed ret %d\n",
+				__func__, ret);
+		break;
 	case FORMAT_APTX:
 		pr_debug("SND_AUDIOCODEC_APTX\n");
 		memset(&aptx_cfg, 0x0, sizeof(struct aptx_dec_bt_addr_cfg));
@@ -1187,26 +1249,6 @@
 	};
 
 	switch (ac->topology) {
-	case ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS: /* HPX + SA+ topology */
-
-		ret = q6asm_set_softvolume_v2(ac, &softvol,
-					      SOFT_VOLUME_INSTANCE_1);
-		if (ret < 0)
-			pr_err("%s: Send SoftVolume Param failed ret=%d\n",
-			__func__, ret);
-
-		ret = q6asm_set_softvolume_v2(ac, &softvol,
-					      SOFT_VOLUME_INSTANCE_2);
-		if (ret < 0)
-			pr_err("%s: Send SoftVolume2 Param failed ret=%d\n",
-			__func__, ret);
-		/*
-		 * HPX module init is trigerred from HAL using ioctl
-		 * DTS_EAGLE_MODULE_ENABLE when stream starts
-		 */
-		break;
-	case ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX: /* HPX topology */
-		break;
 	default:
 		ret = q6asm_set_softvolume_v2(ac, &softvol,
 					      SOFT_VOLUME_INSTANCE_1);
@@ -1557,6 +1599,7 @@
 	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
 	prtd->audio_client->perf_mode = false;
 	prtd->session_id = prtd->audio_client->session;
+	msm_adsp_init_mixer_ctl_pp_event_queue(rtd);
 
 	return 0;
 }
@@ -1712,7 +1755,7 @@
 	q6asm_audio_client_buf_free_contiguous(dir, ac);
 
 	q6asm_audio_client_free(ac);
-
+	msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
 	kfree(pdata->audio_effects[soc_prtd->dai_link->id]);
 	pdata->audio_effects[soc_prtd->dai_link->id] = NULL;
 	kfree(pdata->dec_params[soc_prtd->dai_link->id]);
@@ -1830,8 +1873,11 @@
 	prtd->sample_rate = prtd->codec_param.codec.sample_rate;
 	pr_debug("%s: sample_rate %d\n", __func__, prtd->sample_rate);
 
-	if (prtd->codec_param.codec.compr_passthr >= LEGACY_PCM &&
-	    prtd->codec_param.codec.compr_passthr <= COMPRESSED_PASSTHROUGH_DSD)
+	if ((prtd->codec_param.codec.compr_passthr >= LEGACY_PCM &&
+	    prtd->codec_param.
+	    codec.compr_passthr <= COMPRESSED_PASSTHROUGH_DSD) ||
+	    (prtd->codec_param.
+	    codec.compr_passthr == COMPRESSED_PASSTHROUGH_IEC61937))
 		prtd->compr_passthr = prtd->codec_param.codec.compr_passthr;
 	else
 		prtd->compr_passthr = LEGACY_PCM;
@@ -1948,6 +1994,18 @@
 		break;
 	}
 
+	case SND_AUDIOCODEC_TRUEHD: {
+		pr_debug("%s: SND_AUDIOCODEC_TRUEHD\n", __func__);
+		prtd->codec = FORMAT_TRUEHD;
+		break;
+	}
+
+	case SND_AUDIOCODEC_IEC61937: {
+		pr_debug("%s: SND_AUDIOCODEC_IEC61937\n", __func__);
+		prtd->codec = FORMAT_IEC61937;
+		break;
+	}
+
 	case SND_AUDIOCODEC_APTX: {
 		pr_debug("%s: SND_AUDIOCODEC_APTX\n", __func__);
 		prtd->codec = FORMAT_APTX;
@@ -2815,20 +2873,15 @@
 				SND_AUDIOSTREAMFORMAT_RAW);
 		break;
 	case SND_AUDIOCODEC_AC3:
-		break;
 	case SND_AUDIOCODEC_EAC3:
-		break;
 	case SND_AUDIOCODEC_FLAC:
-		break;
 	case SND_AUDIOCODEC_VORBIS:
-		break;
 	case SND_AUDIOCODEC_ALAC:
-		break;
 	case SND_AUDIOCODEC_APE:
-		break;
 	case SND_AUDIOCODEC_DTS:
-		break;
 	case SND_AUDIOCODEC_DSD:
+	case SND_AUDIOCODEC_TRUEHD:
+	case SND_AUDIOCODEC_IEC61937:
 	case SND_AUDIOCODEC_APTX:
 		break;
 	default:
@@ -2887,6 +2940,14 @@
 	} else if (metadata->key == SNDRV_COMPRESS_START_DELAY) {
 		prtd->start_delay_lsw = metadata->value[0];
 		prtd->start_delay_msw = metadata->value[1];
+	} else if (metadata->key ==
+				SNDRV_COMPRESS_ENABLE_ADJUST_SESSION_CLOCK) {
+		return msm_compr_enable_adjust_session_clock(ac,
+				metadata->value[0]);
+	} else if (metadata->key == SNDRV_COMPRESS_ADJUST_SESSION_CLOCK) {
+		return msm_compr_adjust_session_clock(ac,
+				metadata->value[0],
+				metadata->value[1]);
 	}
 
 	return 0;
@@ -3109,23 +3170,6 @@
 						    &(audio_effects->equalizer),
 						     values);
 		break;
-	case DTS_EAGLE_MODULE:
-		pr_debug("%s: DTS_EAGLE_MODULE\n", __func__);
-		if (!msm_audio_effects_is_effmodule_supp_in_top(effects_module,
-						prtd->audio_client->topology))
-			return 0;
-		msm_dts_eagle_handle_asm(NULL, (void *)values, true,
-					 false, prtd->audio_client, NULL);
-		break;
-	case DTS_EAGLE_MODULE_ENABLE:
-		pr_debug("%s: DTS_EAGLE_MODULE_ENABLE\n", __func__);
-		if (msm_audio_effects_is_effmodule_supp_in_top(effects_module,
-						prtd->audio_client->topology))
-			msm_dts_eagle_enable_asm(prtd->audio_client,
-					(bool)values[0],
-					AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
-
-		break;
 	case SOFT_VOLUME_MODULE:
 		pr_debug("%s: SOFT_VOLUME_MODULE\n", __func__);
 		break;
@@ -3154,7 +3198,6 @@
 	struct msm_compr_audio_effects *audio_effects = NULL;
 	struct snd_compr_stream *cstream = NULL;
 	struct msm_compr_audio *prtd = NULL;
-	long *values = &(ucontrol->value.integer.value[0]);
 
 	pr_debug("%s\n", __func__);
 	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
@@ -3174,28 +3217,6 @@
 		return -EINVAL;
 	}
 
-	switch (audio_effects->query.mod_id) {
-	case DTS_EAGLE_MODULE:
-		pr_debug("%s: DTS_EAGLE_MODULE handling queued get\n",
-			 __func__);
-		values[0] = (long)audio_effects->query.mod_id;
-		values[1] = (long)audio_effects->query.parm_id;
-		values[2] = (long)audio_effects->query.size;
-		values[3] = (long)audio_effects->query.offset;
-		values[4] = (long)audio_effects->query.device;
-		if (values[2] > DTS_EAGLE_MAX_PARAM_SIZE_FOR_ALSA) {
-			pr_err("%s: DTS_EAGLE_MODULE parameter's requested size (%li) too large (max size is %i)\n",
-				__func__, values[2],
-				DTS_EAGLE_MAX_PARAM_SIZE_FOR_ALSA);
-			return -EINVAL;
-		}
-		msm_dts_eagle_handle_asm(NULL, (void *)&values[1],
-					 true, true, prtd->audio_client, NULL);
-		break;
-	default:
-		pr_err("%s: Invalid effects config module\n", __func__);
-		return -EINVAL;
-	}
 	return 0;
 }
 
@@ -3299,6 +3320,8 @@
 	switch (prtd->codec) {
 	case FORMAT_MP3:
 	case FORMAT_MPEG4_AAC:
+	case FORMAT_TRUEHD:
+	case FORMAT_IEC61937:
 	case FORMAT_APTX:
 		pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
 			 prtd->codec);
@@ -3366,6 +3389,8 @@
 	case FORMAT_APE:
 	case FORMAT_DTS:
 	case FORMAT_DSD:
+	case FORMAT_TRUEHD:
+	case FORMAT_IEC61937:
 	case FORMAT_APTX:
 		pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
 			 prtd->codec);
@@ -3419,21 +3444,18 @@
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_RX;
 	int be_id = ucontrol->value.integer.value[3];
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate = 48000;
 
-	app_type = ucontrol->value.integer.value[0];
-	acdb_dev_id = ucontrol->value.integer.value[1];
+	cfg_data.app_type = ucontrol->value.integer.value[0];
+	cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
-		sample_rate = ucontrol->value.integer.value[2];
+		cfg_data.sample_rate = ucontrol->value.integer.value[2];
 	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
-						      be_id, app_type,
-						      acdb_dev_id, sample_rate);
+						      be_id, &cfg_data);
 	if (ret < 0)
 		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -3446,28 +3468,25 @@
 {
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_RX;
-	int be_id = ucontrol->value.integer.value[3];
+	int be_id = 0;
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
 	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
-						      be_id, &app_type,
-						      &acdb_dev_id,
-						      &sample_rate);
+						      &be_id, &cfg_data);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
 		goto done;
 	}
 
-	ucontrol->value.integer.value[0] = app_type;
-	ucontrol->value.integer.value[1] = acdb_dev_id;
-	ucontrol->value.integer.value[2] = sample_rate;
+	ucontrol->value.integer.value[0] = cfg_data.app_type;
+	ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+	ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+	ucontrol->value.integer.value[3] = be_id;
 	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 done:
 	return ret;
 }
@@ -3478,21 +3497,18 @@
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
 	int be_id = ucontrol->value.integer.value[3];
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate = 48000;
 
-	app_type = ucontrol->value.integer.value[0];
-	acdb_dev_id = ucontrol->value.integer.value[1];
+	cfg_data.app_type = ucontrol->value.integer.value[0];
+	cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
-		sample_rate = ucontrol->value.integer.value[2];
+		cfg_data.sample_rate = ucontrol->value.integer.value[2];
 	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
-						      be_id, app_type,
-						      acdb_dev_id, sample_rate);
+						      be_id, &cfg_data);
 	if (ret < 0)
 		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -3505,28 +3521,25 @@
 {
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
-	int be_id = ucontrol->value.integer.value[3];
+	int be_id = 0;
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
 	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
-						      be_id, &app_type,
-						      &acdb_dev_id,
-						      &sample_rate);
+						      &be_id, &cfg_data);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
 		goto done;
 	}
 
-	ucontrol->value.integer.value[0] = app_type;
-	ucontrol->value.integer.value[1] = acdb_dev_id;
-	ucontrol->value.integer.value[2] = sample_rate;
+	ucontrol->value.integer.value[0] = cfg_data.app_type;
+	ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+	ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+	ucontrol->value.integer.value[3] = be_id;
 	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 done:
 	return ret;
 }
@@ -3589,6 +3602,176 @@
 	return rc;
 }
 
+static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	unsigned long fe_id = kcontrol->private_value;
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+				snd_soc_component_get_drvdata(comp);
+	struct snd_compr_stream *cstream = NULL;
+	struct msm_compr_audio *prtd;
+	int ret = 0;
+	struct msm_adsp_event_data *event_data = NULL;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received invalid fe_id %lu\n",
+			__func__, fe_id);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	cstream = pdata->cstream[fe_id];
+	if (cstream == NULL) {
+		pr_err("%s cstream is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	prtd = cstream->runtime->private_data;
+	if (!prtd) {
+		pr_err("%s: prtd is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (prtd->audio_client == NULL) {
+		pr_err("%s: audio_client is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
+	if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
+	    (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
+		pr_err("%s: invalid event_type=%d",
+			__func__, event_data->event_type);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >=
+					sizeof(ucontrol->value.bytes.data)) {
+		pr_err("%s param length=%d  exceeds limit",
+			__func__, event_data->payload_len);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
+	if (ret < 0)
+		pr_err("%s: failed to send stream event cmd, err = %d\n",
+			__func__, ret);
+done:
+	return ret;
+}
+
+static int msm_compr_ion_fd_map_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	unsigned long fe_id = kcontrol->private_value;
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+				snd_soc_component_get_drvdata(comp);
+	struct snd_compr_stream *cstream = NULL;
+	struct msm_compr_audio *prtd;
+	int fd;
+	int ret = 0;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bounds invalid fe_id %lu\n",
+			__func__, fe_id);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	cstream = pdata->cstream[fe_id];
+	if (cstream == NULL) {
+		pr_err("%s cstream is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	prtd = cstream->runtime->private_data;
+	if (!prtd) {
+		pr_err("%s: prtd is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (prtd->audio_client == NULL) {
+		pr_err("%s: audio_client is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	memcpy(&fd, ucontrol->value.bytes.data, sizeof(fd));
+	ret = q6asm_send_ion_fd(prtd->audio_client, fd);
+	if (ret < 0)
+		pr_err("%s: failed to register ion fd\n", __func__);
+done:
+	return ret;
+}
+
+static int msm_compr_rtic_event_ack_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	unsigned long fe_id = kcontrol->private_value;
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	struct snd_compr_stream *cstream = NULL;
+	struct msm_compr_audio *prtd;
+	int ret = 0;
+	int param_length = 0;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received invalid fe_id %lu\n",
+			__func__, fe_id);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	cstream = pdata->cstream[fe_id];
+	if (cstream == NULL) {
+		pr_err("%s cstream is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	prtd = cstream->runtime->private_data;
+	if (!prtd) {
+		pr_err("%s: prtd is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (prtd->audio_client == NULL) {
+		pr_err("%s: audio_client is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	memcpy(&param_length, ucontrol->value.bytes.data,
+		sizeof(param_length));
+	if ((param_length + sizeof(param_length))
+		>= sizeof(ucontrol->value.bytes.data)) {
+		pr_err("%s param length=%d  exceeds limit",
+			__func__, param_length);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = q6asm_send_rtic_event_ack(prtd->audio_client,
+			ucontrol->value.bytes.data + sizeof(param_length),
+			param_length);
+	if (ret < 0)
+		pr_err("%s: failed to send rtic event ack, err = %d\n",
+			__func__, ret);
+done:
+	return ret;
+}
+
 static int msm_compr_gapless_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -3863,6 +4046,117 @@
 	return 0;
 }
 
+static int msm_compr_add_audio_adsp_stream_cmd_control(
+			struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = DSP_STREAM_CMD;
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_cmd_info,
+		.put = msm_compr_adsp_stream_cmd_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
+	fe_audio_adsp_stream_cmd_config_control[0].private_value =
+				rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+		fe_audio_adsp_stream_cmd_config_control,
+		ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
+	if (ret < 0)
+		pr_err("%s: failed to add ctl %s. err = %d\n",
+			__func__, mixer_str, ret);
+
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
+static int msm_compr_add_audio_adsp_stream_callback_control(
+			struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol *kctl;
+
+	struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_callback_info,
+		.get = msm_adsp_stream_callback_get,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s: rtd is  NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_audio_adsp_callback_config_control[0].name = mixer_str;
+	fe_audio_adsp_callback_config_control[0].private_value =
+					rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+			fe_audio_adsp_callback_config_control,
+			ARRAY_SIZE(fe_audio_adsp_callback_config_control));
+	if (ret < 0) {
+		pr_err("%s: failed to add ctl %s. err = %d\n",
+			__func__, mixer_str, ret);
+		ret = -EINVAL;
+		goto free_mixer_str;
+	}
+
+	kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+	if (!kctl) {
+		pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
+		ret = -EINVAL;
+		goto free_mixer_str;
+	}
+
+	kctl->private_data = NULL;
+
+free_mixer_str:
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
 static int msm_compr_add_dec_runtime_params_control(
 						struct snd_soc_pcm_runtime *rtd)
 {
@@ -4037,6 +4331,96 @@
 	return 0;
 }
 
+static int msm_compr_add_io_fd_cmd_control(struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "Playback ION FD";
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol_new fe_ion_fd_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_cmd_info,
+		.put = msm_compr_ion_fd_map_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_ion_fd_config_control[0].name = mixer_str;
+	fe_ion_fd_config_control[0].private_value = rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+				fe_ion_fd_config_control,
+				ARRAY_SIZE(fe_ion_fd_config_control));
+	if (ret < 0)
+		pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
+
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
+static int msm_compr_add_event_ack_cmd_control(struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "Playback Event Ack";
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol_new fe_event_ack_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_cmd_info,
+		.put = msm_compr_rtic_event_ack_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_event_ack_config_control[0].name = mixer_str;
+	fe_event_ack_config_control[0].private_value = rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+				fe_event_ack_config_control,
+				ARRAY_SIZE(fe_event_ack_config_control));
+	if (ret < 0)
+		pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
+
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
 static int msm_compr_new(struct snd_soc_pcm_runtime *rtd)
 {
 	int rc;
@@ -4050,6 +4434,26 @@
 		pr_err("%s: Could not add Compr Audio Effects Control\n",
 			__func__);
 
+	rc = msm_compr_add_audio_adsp_stream_cmd_control(rtd);
+	if (rc)
+		pr_err("%s: Could not add Compr ADSP Stream Cmd Control\n",
+			__func__);
+
+	rc = msm_compr_add_audio_adsp_stream_callback_control(rtd);
+	if (rc)
+		pr_err("%s: Could not add Compr ADSP Stream Callback Control\n",
+			__func__);
+
+	rc = msm_compr_add_io_fd_cmd_control(rtd);
+	if (rc)
+		pr_err("%s: Could not add Compr ion fd Control\n",
+			__func__);
+
+	rc = msm_compr_add_event_ack_cmd_control(rtd);
+	if (rc)
+		pr_err("%s: Could not add Compr event ack Control\n",
+			__func__);
+
 	rc = msm_compr_add_query_audio_effect_control(rtd);
 	if (rc)
 		pr_err("%s: Could not add Compr Query Audio Effect Control\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index 9b072ea..deb1798 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -174,7 +174,7 @@
 	{
 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
 		.iface	= SNDRV_CTL_ELEM_IFACE_PCM,
-		.name	= "HDMI RX Drift",
+		.name	= "HDMI DRIFT",
 		.info	= msm_dai_q6_ext_disp_drift_info,
 		.get	= msm_dai_q6_ext_disp_drift_get,
 	},
@@ -191,7 +191,7 @@
 	{
 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
 		.iface	= SNDRV_CTL_ELEM_IFACE_PCM,
-		.name	= "DISPLAY Port RX Drift",
+		.name	= "DISPLAY_PORT DRIFT",
 		.info	= msm_dai_q6_ext_disp_drift_info,
 		.get	= msm_dai_q6_ext_disp_drift_get,
 	},
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 0c46763..c8b01c6 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -2314,6 +2314,44 @@
 		     msm_dai_q6_afe_input_bit_format_put),
 };
 
+static int msm_dai_q6_slim_rx_drift_info(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = sizeof(struct afe_param_id_dev_timing_stats);
+
+	return 0;
+}
+
+static int msm_dai_q6_slim_rx_drift_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = -EINVAL;
+	struct afe_param_id_dev_timing_stats timing_stats;
+	struct snd_soc_dai *dai = kcontrol->private_data;
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		pr_err("%s: afe port not started. dai_data->status_mask = %ld\n",
+			__func__, *dai_data->status_mask);
+		goto done;
+	}
+
+	memset(&timing_stats, 0, sizeof(struct afe_param_id_dev_timing_stats));
+	ret = afe_get_av_dev_drift(&timing_stats, dai->id);
+	if (ret) {
+		pr_err("%s: Error getting AFE Drift for port %d, err=%d\n",
+			__func__, dai->id, ret);
+
+		goto done;
+	}
+
+	memcpy(ucontrol->value.bytes.data, (void *)&timing_stats,
+			sizeof(struct afe_param_id_dev_timing_stats));
+done:
+	return ret;
+}
+
 static const char * const afe_cal_mode_text[] = {
 	"CAL_MODE_DEFAULT", "CAL_MODE_NONE"
 };
@@ -2366,6 +2404,29 @@
 			msm_dai_q6_usb_audio_endian_cfg_put),
 };
 
+static const struct snd_kcontrol_new avd_drift_config_controls[] = {
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface	= SNDRV_CTL_ELEM_IFACE_PCM,
+		.name	= "SLIMBUS_0_RX DRIFT",
+		.info	= msm_dai_q6_slim_rx_drift_info,
+		.get	= msm_dai_q6_slim_rx_drift_get,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface	= SNDRV_CTL_ELEM_IFACE_PCM,
+		.name	= "SLIMBUS_6_RX DRIFT",
+		.info	= msm_dai_q6_slim_rx_drift_info,
+		.get	= msm_dai_q6_slim_rx_drift_get,
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface	= SNDRV_CTL_ELEM_IFACE_PCM,
+		.name	= "SLIMBUS_7_RX DRIFT",
+		.info	= msm_dai_q6_slim_rx_drift_info,
+		.get	= msm_dai_q6_slim_rx_drift_get,
+	},
+};
 static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
 {
 	struct msm_dai_q6_dai_data *dai_data;
@@ -2413,6 +2474,9 @@
 		rc = snd_ctl_add(dai->component->card->snd_card,
 				 snd_ctl_new1(&afe_enc_config_controls[2],
 				 dai_data));
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				snd_ctl_new1(&avd_drift_config_controls[2],
+					dai));
 		break;
 	case RT_PROXY_DAI_001_RX:
 		rc = snd_ctl_add(dai->component->card->snd_card,
@@ -2440,6 +2504,16 @@
 				 snd_ctl_new1(&usb_audio_cfg_controls[3],
 				 dai_data));
 		break;
+	case SLIMBUS_0_RX:
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				snd_ctl_new1(&avd_drift_config_controls[0],
+					dai));
+		break;
+	case SLIMBUS_6_RX:
+		rc = snd_ctl_add(dai->component->card->snd_card,
+				snd_ctl_new1(&avd_drift_config_controls[1],
+					dai));
+		break;
 	}
 	if (rc < 0)
 		dev_err(dai->dev, "%s: err add config ctl, DAI = %s\n",
@@ -4131,12 +4205,13 @@
 			.stream_name = "INT0 MI2S Playback",
 			.aif_name = "INT0_MI2S_RX",
 			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
-			SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100,
+			SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100 |
+			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
 				SNDRV_PCM_FMTBIT_S24_LE |
 				SNDRV_PCM_FMTBIT_S24_3LE,
 			.rate_min =     8000,
-			.rate_max =     48000,
+			.rate_max =     192000,
 		},
 		.capture = {
 			.stream_name = "INT0 MI2S Capture",
@@ -4235,12 +4310,13 @@
 			.stream_name = "INT4 MI2S Playback",
 			.aif_name = "INT4_MI2S_RX",
 			.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
-			SNDRV_PCM_RATE_16000,
+			SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+			SNDRV_PCM_RATE_192000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
 				SNDRV_PCM_FMTBIT_S24_LE |
 				SNDRV_PCM_FMTBIT_S24_3LE,
 			.rate_min =     8000,
-			.rate_max =     48000,
+			.rate_max =     192000,
 		},
 		.capture = {
 			.stream_name = "INT4 MI2S Capture",
@@ -4934,6 +5010,44 @@
 	},
 };
 
+static int msm_dai_q6_tdm_set_clk_param(u32 group_id,
+					struct afe_clk_set *clk_set, u32 mode)
+{
+	switch (group_id) {
+	case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX:
+	case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX:
+		if (mode)
+			clk_set->clk_id = Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT;
+		else
+			clk_set->clk_id = Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT;
+		break;
+	case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX:
+	case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX:
+		if (mode)
+			clk_set->clk_id = Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT;
+		else
+			clk_set->clk_id = Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT;
+		break;
+	case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX:
+	case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX:
+		if (mode)
+			clk_set->clk_id = Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT;
+		else
+			clk_set->clk_id = Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT;
+		break;
+	case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX:
+	case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX:
+		if (mode)
+			clk_set->clk_id = Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT;
+		else
+			clk_set->clk_id = Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int msm_dai_tdm_q6_probe(struct platform_device *pdev)
 {
 	int rc = 0;
@@ -4941,6 +5055,7 @@
 	uint32_t array_length = 0;
 	int i = 0;
 	int group_idx = 0;
+	u32 clk_mode = 0;
 
 	/* extract tdm group info into static */
 	rc = of_property_read_u32(pdev->dev.of_node,
@@ -5013,6 +5128,26 @@
 	dev_dbg(&pdev->dev, "%s: Clk Rate from DT file %d\n",
 		__func__, tdm_clk_set.clk_freq_in_hz);
 
+	/* extract tdm clk src master/slave info into static */
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,msm-cpudai-tdm-clk-internal",
+		&clk_mode);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: Clk id from DT file %s\n",
+			__func__, "qcom,msm-cpudai-tdm-clk-internal");
+		goto rtn;
+	}
+	dev_dbg(&pdev->dev, "%s: Clk id from DT file %d\n",
+		__func__, clk_mode);
+
+	rc = msm_dai_q6_tdm_set_clk_param(tdm_group_cfg.group_id,
+					  &tdm_clk_set, clk_mode);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: group id not supported 0x%x\n",
+			__func__, tdm_group_cfg.group_id);
+		goto rtn;
+	}
+
 	/* other initializations within device group */
 	group_idx = msm_dai_q6_get_group_idx(tdm_group_cfg.group_id);
 	if (group_idx < 0) {
@@ -5808,48 +5943,6 @@
 {
 	int rc = 0;
 
-	switch (dai_data->group_cfg.tdm_cfg.group_id) {
-	case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX:
-	case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX:
-		if (dai_data->clk_set.clk_freq_in_hz) {
-			dai_data->clk_set.clk_id =
-				Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT;
-		} else
-			dai_data->clk_set.clk_id =
-				Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT;
-		break;
-	case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX:
-	case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX:
-		if (dai_data->clk_set.clk_freq_in_hz) {
-			dai_data->clk_set.clk_id =
-				Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT;
-		} else
-			dai_data->clk_set.clk_id =
-				Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT;
-		break;
-	case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX:
-	case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX:
-		if (dai_data->clk_set.clk_freq_in_hz) {
-			dai_data->clk_set.clk_id =
-				Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT;
-		} else
-			dai_data->clk_set.clk_id =
-				Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT;
-		break;
-	case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX:
-	case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX:
-		if (dai_data->clk_set.clk_freq_in_hz) {
-			dai_data->clk_set.clk_id =
-				Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT;
-		} else
-			dai_data->clk_set.clk_id =
-				Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT;
-		break;
-	default:
-		pr_err("%s: port id 0x%x not supported\n",
-			__func__, port_id);
-		return -EINVAL;
-	}
 	dai_data->clk_set.enable = enable;
 
 	rc = afe_set_lpass_clock_v2(port_id,
@@ -7837,6 +7930,7 @@
 	int rc = 0;
 	u32 tdm_dev_id = 0;
 	int port_idx = 0;
+	struct device_node *tdm_parent_node = NULL;
 
 	/* retrieve device/afe id */
 	rc = of_property_read_u32(pdev->dev.of_node,
@@ -7871,7 +7965,8 @@
 	memset(dai_data, 0, sizeof(*dai_data));
 
 	/* TDM CFG */
-	rc = of_property_read_u32(pdev->dev.of_node,
+	tdm_parent_node = of_get_parent(pdev->dev.of_node);
+	rc = of_property_read_u32(tdm_parent_node,
 		"qcom,msm-cpudai-tdm-sync-mode",
 		(u32 *)&dai_data->port_cfg.tdm.sync_mode);
 	if (rc) {
@@ -7882,7 +7977,7 @@
 	dev_dbg(&pdev->dev, "%s: Sync Mode from DT file 0x%x\n",
 		__func__, dai_data->port_cfg.tdm.sync_mode);
 
-	rc = of_property_read_u32(pdev->dev.of_node,
+	rc = of_property_read_u32(tdm_parent_node,
 		"qcom,msm-cpudai-tdm-sync-src",
 		(u32 *)&dai_data->port_cfg.tdm.sync_src);
 	if (rc) {
@@ -7893,7 +7988,7 @@
 	dev_dbg(&pdev->dev, "%s: Sync Src from DT file 0x%x\n",
 		__func__, dai_data->port_cfg.tdm.sync_src);
 
-	rc = of_property_read_u32(pdev->dev.of_node,
+	rc = of_property_read_u32(tdm_parent_node,
 		"qcom,msm-cpudai-tdm-data-out",
 		(u32 *)&dai_data->port_cfg.tdm.ctrl_data_out_enable);
 	if (rc) {
@@ -7904,7 +7999,7 @@
 	dev_dbg(&pdev->dev, "%s: Data Out from DT file 0x%x\n",
 		__func__, dai_data->port_cfg.tdm.ctrl_data_out_enable);
 
-	rc = of_property_read_u32(pdev->dev.of_node,
+	rc = of_property_read_u32(tdm_parent_node,
 		"qcom,msm-cpudai-tdm-invert-sync",
 		(u32 *)&dai_data->port_cfg.tdm.ctrl_invert_sync_pulse);
 	if (rc) {
@@ -7915,7 +8010,7 @@
 	dev_dbg(&pdev->dev, "%s: Invert Sync from DT file 0x%x\n",
 		__func__, dai_data->port_cfg.tdm.ctrl_invert_sync_pulse);
 
-	rc = of_property_read_u32(pdev->dev.of_node,
+	rc = of_property_read_u32(tdm_parent_node,
 		"qcom,msm-cpudai-tdm-data-delay",
 		(u32 *)&dai_data->port_cfg.tdm.ctrl_sync_data_delay);
 	if (rc) {
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-slim.c b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
index 779a2e6..8115fee 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-slim.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
@@ -313,7 +313,7 @@
 	struct msm_slim_dai_data *dai_data = NULL;
 	struct slim_ch prop;
 	int rc;
-	u8 i;
+	u8 i, j;
 
 	dai_data = msm_slim_get_dai_data(drv_data, dai);
 	if (!dai_data) {
@@ -350,10 +350,6 @@
 		}
 	}
 
-	/* To decrement the channel ref count*/
-	for (i = 0; i < dai_data->ch_cnt; i++)
-		slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
-
 	prop.prot = SLIM_AUTO_ISO;
 	prop.baser = SLIM_RATE_4000HZ;
 	prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
@@ -377,6 +373,8 @@
 
 error_define_chan:
 error_chan_query:
+	for (j = 0; j < i; j++)
+		slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[j]);
 	return rc;
 }
 
@@ -386,6 +384,7 @@
 	struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
 	struct msm_slim_dma_data *dma_data = NULL;
 	struct msm_slim_dai_data *dai_data;
+	int i, rc = 0;
 
 	dai_data = msm_slim_get_dai_data(drv_data, dai);
 	dma_data = snd_soc_dai_get_dma_data(dai, stream);
@@ -404,6 +403,15 @@
 		return;
 	}
 
+	for (i = 0; i < dai_data->ch_cnt; i++) {
+		rc = slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
+		if (rc) {
+			dev_err(dai->dev,
+				"%s: dealloc_ch failed, err = %d\n",
+				__func__, rc);
+		}
+	}
+
 	snd_soc_dai_set_dma_data(dai, stream, NULL);
 	/* clear prepared state for the dai */
 	CLR_DAI_STATE(dai_data->status, DAI_STATE_PREPARED);
diff --git a/sound/soc/msm/qdsp6v2/msm-dts-eagle.c b/sound/soc/msm/qdsp6v2/msm-dts-eagle.c
deleted file mode 100644
index 2ff1e02..0000000
--- a/sound/soc/msm/qdsp6v2/msm-dts-eagle.c
+++ /dev/null
@@ -1,1660 +0,0 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/msm_ion.h>
-#include <linux/mm.h>
-#include <linux/msm_audio_ion.h>
-#include <linux/vmalloc.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/pcm.h>
-#include <sound/q6adm-v2.h>
-#include <sound/q6asm-v2.h>
-#include <sound/apr_audio-v2.h>
-#include <sound/q6audio-v2.h>
-#include <sound/audio_effects.h>
-#include <sound/hwdep.h>
-#include <sound/msm-dts-eagle.h>
-#include <sound/q6core.h>
-
-#include "msm-pcm-routing-v2.h"
-
-#define ION_MEM_SIZE  131072
-#define DEPC_MAX_SIZE 524288
-
-#define MPST				AUDPROC_MODULE_ID_DTS_HPX_POSTMIX
-#define MPRE				AUDPROC_MODULE_ID_DTS_HPX_PREMIX
-
-#define eagle_vol_dbg(fmt, ...) \
-	pr_debug("DTS_EAGLE_DRIVER_VOLUME: " fmt "\n", ##__VA_ARGS__)
-#define eagle_vol_err(fmt, ...) \
-	pr_err("DTS_EAGLE_DRIVER_VOLUME: " fmt "\n", ##__VA_ARGS__)
-#define eagle_drv_dbg(fmt, ...) \
-	pr_debug("DTS_EAGLE_DRIVER: " fmt "\n", ##__VA_ARGS__)
-#define eagle_drv_err(fmt, ...) \
-	pr_err("DTS_EAGLE_DRIVER: " fmt "\n", ##__VA_ARGS__)
-#define eagle_precache_dbg(fmt, ...) \
-	pr_debug("DTS_EAGLE_DRIVER_SENDCACHE_PRE: " fmt "\n", ##__VA_ARGS__)
-#define eagle_precache_err(fmt, ...) \
-	pr_err("DTS_EAGLE_DRIVER_SENDCACHE_PRE: " fmt "\n", ##__VA_ARGS__)
-#define eagle_postcache_dbg(fmt, ...) \
-	pr_debug("DTS_EAGLE_DRIVER_SENDCACHE_POST: " fmt "\n", ##__VA_ARGS__)
-#define eagle_postcache_err(fmt, ...) \
-	pr_err("DTS_EAGLE_DRIVER_SENDCACHE_POST: " fmt "\n", ##__VA_ARGS__)
-#define eagle_ioctl_dbg(fmt, ...) \
-	pr_debug("DTS_EAGLE_DRIVER_IOCTL: " fmt "\n", ##__VA_ARGS__)
-#define eagle_ioctl_err(fmt, ...) \
-	pr_err("DTS_EAGLE_DRIVER_IOCTL: " fmt "\n", ##__VA_ARGS__)
-#define eagle_asm_dbg(fmt, ...) \
-	pr_debug("DTS_EAGLE_DRIVER_ASM: " fmt "\n", ##__VA_ARGS__)
-#define eagle_asm_err(fmt, ...) \
-	pr_err("DTS_EAGLE_DRIVER_ASM: " fmt "\n", ##__VA_ARGS__)
-#define eagle_adm_dbg(fmt, ...) \
-	pr_debug("DTS_EAGLE_DRIVER_ADM: " fmt "\n", ##__VA_ARGS__)
-#define eagle_adm_err(fmt, ...) \
-	pr_err("DTS_EAGLE_DRIVER_ADM: " fmt "\n", ##__VA_ARGS__)
-#define eagle_enable_dbg(fmt, ...) \
-	pr_debug("DTS_EAGLE_ENABLE: " fmt "\n", ##__VA_ARGS__)
-#define eagle_enable_err(fmt, ...) \
-	pr_err("DTS_EAGLE_ENABLE: " fmt "\n", ##__VA_ARGS__)
-#define eagle_ioctl_info(fmt, ...) \
-	pr_err("DTS_EAGLE_IOCTL: " fmt "\n", ##__VA_ARGS__)
-
-enum {
-	AUDIO_DEVICE_OUT_EARPIECE = 0,
-	AUDIO_DEVICE_OUT_SPEAKER,
-	AUDIO_DEVICE_OUT_WIRED_HEADSET,
-	AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
-	AUDIO_DEVICE_OUT_BLUETOOTH_SCO,
-	AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
-	AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,
-	AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
-	AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
-	AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,
-	AUDIO_DEVICE_OUT_AUX_DIGITAL,
-	AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET,
-	AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,
-	AUDIO_DEVICE_OUT_USB_ACCESSORY,
-	AUDIO_DEVICE_OUT_USB_DEVICE,
-	AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-	AUDIO_DEVICE_OUT_ANC_HEADSET,
-	AUDIO_DEVICE_OUT_ANC_HEADPHONE,
-	AUDIO_DEVICE_OUT_PROXY,
-	AUDIO_DEVICE_OUT_FM,
-	AUDIO_DEVICE_OUT_FM_TX,
-
-	AUDIO_DEVICE_OUT_COUNT
-};
-
-#define AUDIO_DEVICE_COMBO 0x400000 /* bit 23 */
-
-enum { /* cache block */
-	CB_0 = 0,
-	CB_1,
-	CB_2,
-	CB_3,
-	CB_4,
-	CB_5,
-	CB_6,
-	CB_7,
-
-	CB_COUNT
-};
-
-enum { /* cache block description */
-	CBD_DEV_MASK = 0,
-	CBD_OFFSG,
-	CBD_CMD0,
-	CBD_SZ0,
-	CBD_OFFS1,
-	CBD_CMD1,
-	CBD_SZ1,
-	CBD_OFFS2,
-	CBD_CMD2,
-	CBD_SZ2,
-	CBD_OFFS3,
-	CBD_CMD3,
-	CBD_SZ3,
-
-	CBD_COUNT,
-};
-
-static s32 _fx_logN(s32 x)
-{
-	s32 t, y = 0xa65af;
-
-	if (x < 0x00008000) {
-		x <<= 16; y -= 0xb1721; }
-	if (x < 0x00800000) {
-		x <<= 8; y -= 0x58b91; }
-	if (x < 0x08000000) {
-		x <<= 4; y -= 0x2c5c8; }
-	if (x < 0x20000000) {
-		x <<= 2; y -= 0x162e4; }
-	if (x < 0x40000000) {
-		x <<= 1; y -= 0x0b172; }
-	t = x + (x >> 1);
-	if ((t & 0x80000000) == 0) {
-		x = t; y -= 0x067cd; }
-	t = x + (x >> 2);
-	if ((t & 0x80000000) == 0) {
-		x = t; y -= 0x03920; }
-	t = x + (x >> 3);
-	if ((t & 0x80000000) == 0) {
-		x = t; y -= 0x01e27; }
-	t = x + (x >> 4);
-	if ((t & 0x80000000) == 0) {
-		x = t; y -= 0x00f85; }
-	t = x + (x >> 5);
-	if ((t & 0x80000000) == 0) {
-		x = t; y -= 0x007e1; }
-	t = x + (x >> 6);
-	if ((t & 0x80000000) == 0) {
-		x = t; y -= 0x003f8; }
-	t = x + (x >> 7);
-	if ((t & 0x80000000) == 0) {
-		x = t; y -= 0x001fe; }
-	x = 0x80000000 - x;
-	y -= x >> 15;
-	return y;
-}
-
-static inline void *_getd(struct dts_eagle_param_desc *depd)
-{
-	return (void *)(((char *)depd) + sizeof(struct dts_eagle_param_desc));
-}
-
-static int _ref_cnt;
-/* dts eagle parameter cache */
-static char *_depc;
-static u32 _depc_size;
-static s32 _c_bl[CB_COUNT][CBD_COUNT];
-static u32 _device_primary;
-static u32 _device_all;
-/* ION states */
-static struct ion_client *_ion_client;
-static struct ion_handle *_ion_handle;
-static struct param_outband _po;
-static struct audio_client *_ac_NT;
-static struct ion_client *_ion_client_NT;
-static struct ion_handle *_ion_handle_NT;
-static struct param_outband _po_NT;
-
-#define SEC_BLOB_MAX_CNT 10
-#define SEC_BLOB_MAX_SIZE 0x4004 /*extra 4 for size*/
-static char *_sec_blob[SEC_BLOB_MAX_CNT];
-
-/* multi-copp support */
-static int _cidx[AFE_MAX_PORTS] = {-1};
-
-/* volume controls */
-#define VOL_CMD_CNT_MAX 10
-static u32 _vol_cmd_cnt;
-static s32 **_vol_cmds;
-struct vol_cmds_d {
-	s32 d[4];
-};
-static struct vol_cmds_d *_vol_cmds_d;
-static const s32 _log10_10_inv_x20 = 0x0008af84;
-
-/* hpx master control */
-static u32 _is_hpx_enabled;
-
-static void _volume_cmds_free(void)
-{
-	int i;
-
-	for (i = 0; i < _vol_cmd_cnt; i++)
-		kfree(_vol_cmds[i]);
-	_vol_cmd_cnt = 0;
-	kfree(_vol_cmds);
-	kfree(_vol_cmds_d);
-	_vol_cmds = NULL;
-	_vol_cmds_d = NULL;
-}
-
-static s32 _volume_cmds_alloc1(s32 size)
-{
-	_volume_cmds_free();
-	_vol_cmd_cnt = size;
-	_vol_cmds = kzalloc(_vol_cmd_cnt * sizeof(int *), GFP_KERNEL);
-	if (_vol_cmds) {
-		_vol_cmds_d = kzalloc(_vol_cmd_cnt * sizeof(struct vol_cmds_d),
-					GFP_KERNEL);
-	} else
-		_vol_cmd_cnt = 0;
-	if (_vol_cmds_d)
-		return 0;
-	_volume_cmds_free();
-	return -ENOMEM;
-}
-
-/* assumes size is equal or less than 0xFFF */
-static s32 _volume_cmds_alloc2(s32 idx, s32 size)
-{
-	kfree(_vol_cmds[idx]);
-	_vol_cmds[idx] = kzalloc(size, GFP_KERNEL);
-	if (_vol_cmds[idx])
-		return 0;
-	_vol_cmds_d[idx].d[0] = 0;
-	return -ENOMEM;
-}
-
-static void _init_cb_descs(void)
-{
-	int i;
-
-	for (i = 0; i < CB_COUNT; i++) {
-		_c_bl[i][CBD_DEV_MASK] = 0;
-		_c_bl[i][CBD_OFFSG] = _c_bl[i][CBD_OFFS1] =
-		_c_bl[i][CBD_OFFS2] = _c_bl[i][CBD_OFFS3] =
-		0xFFFFFFFF;
-		_c_bl[i][CBD_CMD0] = _c_bl[i][CBD_SZ0] =
-		_c_bl[i][CBD_CMD1] = _c_bl[i][CBD_SZ1] =
-		_c_bl[i][CBD_CMD2] = _c_bl[i][CBD_SZ2] =
-		_c_bl[i][CBD_CMD3] = _c_bl[i][CBD_SZ3] = 0;
-	}
-}
-
-static u32 _get_dev_mask_for_pid(int pid)
-{
-	switch (pid) {
-	case SLIMBUS_0_RX:
-		return (1 << AUDIO_DEVICE_OUT_EARPIECE) |
-			(1 << AUDIO_DEVICE_OUT_SPEAKER) |
-			(1 << AUDIO_DEVICE_OUT_WIRED_HEADSET) |
-			(1 << AUDIO_DEVICE_OUT_WIRED_HEADPHONE) |
-			(1 << AUDIO_DEVICE_OUT_ANC_HEADSET) |
-			(1 << AUDIO_DEVICE_OUT_ANC_HEADPHONE);
-		/* fallthrough */
-	case INT_BT_SCO_RX:
-		return (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO) |
-			(1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) |
-			(1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
-		/* fallthrough */
-	case RT_PROXY_PORT_001_RX:
-		return (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) |
-			(1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) |
-			(1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) |
-			(1 << AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) |
-			(1 << AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) |
-			(1 << AUDIO_DEVICE_OUT_USB_ACCESSORY) |
-			(1 << AUDIO_DEVICE_OUT_USB_DEVICE) |
-			(1 << AUDIO_DEVICE_OUT_PROXY);
-		/* fallthrough */
-	case HDMI_RX:
-		return 1 << AUDIO_DEVICE_OUT_AUX_DIGITAL;
-	case INT_FM_RX:
-		return 1 << AUDIO_DEVICE_OUT_FM;
-	case INT_FM_TX:
-		return 1 << AUDIO_DEVICE_OUT_FM_TX;
-	default:
-		return 0;
-	}
-}
-
-static int _get_pid_from_dev(u32 device)
-{
-	if (device & (1 << AUDIO_DEVICE_OUT_EARPIECE) ||
-	    device & (1 << AUDIO_DEVICE_OUT_SPEAKER) ||
-	    device & (1 << AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
-	    device & (1 << AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
-	    device & (1 << AUDIO_DEVICE_OUT_ANC_HEADSET) ||
-	    device & (1 << AUDIO_DEVICE_OUT_ANC_HEADPHONE)) {
-		return SLIMBUS_0_RX;
-	} else if (device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO) ||
-		   device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
-		   device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) {
-		return INT_BT_SCO_RX;
-	} else if (device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) ||
-		   device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) ||
-		   device & (1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
-		   device & (1 << AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) ||
-		   device & (1 << AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ||
-		   device & (1 << AUDIO_DEVICE_OUT_USB_ACCESSORY) ||
-		   device & (1 << AUDIO_DEVICE_OUT_USB_DEVICE) ||
-		   device & (1 << AUDIO_DEVICE_OUT_PROXY)) {
-		return RT_PROXY_PORT_001_RX;
-	} else if (device & (1 << AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
-		return HDMI_RX;
-	} else if (device & (1 << AUDIO_DEVICE_OUT_FM)) {
-		return INT_FM_RX;
-	} else if (device & (1 << AUDIO_DEVICE_OUT_FM_TX)) {
-		return INT_FM_TX;
-	}
-	return 0;
-}
-
-static s32 _get_cb_for_dev(int device)
-{
-	s32 i;
-
-	if (device & AUDIO_DEVICE_COMBO) {
-		for (i = 0; i < CB_COUNT; i++) {
-			if ((_c_bl[i][CBD_DEV_MASK] & device) == device)
-				return i;
-		}
-	} else {
-		for (i = 0; i < CB_COUNT; i++) {
-			if ((_c_bl[i][CBD_DEV_MASK] & device) &&
-			    !(_c_bl[i][CBD_DEV_MASK] & AUDIO_DEVICE_COMBO))
-				return i;
-		}
-	}
-	eagle_drv_err("%s: device %i not found", __func__, device);
-	return -EINVAL;
-}
-
-static int _is_port_open_and_eagle(int pid)
-{
-	if (msm_routing_check_backend_enabled(pid))
-		return 1;
-	return 1;
-}
-
-static int _isNTDevice(u32 device)
-{
-	if (device &
-		((1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO) |
-		(1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) |
-		(1 << AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) |
-		(1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) |
-		(1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) |
-		(1 << AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) |
-		(1 << AUDIO_DEVICE_OUT_AUX_DIGITAL)))
-		return 1;
-	return 0;
-}
-
-static void _reg_ion_mem(void)
-{
-	int rc;
-
-	rc = msm_audio_ion_alloc("DTS_EAGLE", &_ion_client, &_ion_handle,
-			    ION_MEM_SIZE, &_po.paddr, &_po.size, &_po.kvaddr);
-	if (rc)
-		eagle_drv_err("%s: msm audio ion alloc failed with %i",
-				__func__, rc);
-}
-
-static void _unreg_ion_mem(void)
-{
-	int rc;
-
-	rc = msm_audio_ion_free(_ion_client, _ion_handle);
-	if (rc)
-		eagle_drv_err("%s: msm audio ion alloc failed with %i",
-				__func__, rc);
-}
-
-static void _reg_ion_mem_NT(void)
-{
-	int rc;
-
-	eagle_drv_dbg("%s: NT ion mem", __func__);
-	rc = msm_audio_ion_alloc("DTS_EAGLE", &_ion_client_NT,
-				 &_ion_handle_NT, ION_MEM_SIZE,
-				 &_po_NT.paddr, &_po_NT.size, &_po_NT.kvaddr);
-	if (rc) {
-		eagle_drv_err("%s: msm audio ion alloc failed",	__func__);
-		return;
-	}
-	rc = q6asm_memory_map(_ac_NT, _po_NT.paddr,
-			      IN, _po_NT.size, 1);
-	if (rc < 0) {
-		eagle_drv_err("%s: memory map failed", __func__);
-		msm_audio_ion_free(_ion_client_NT, _ion_handle_NT);
-		_ion_client_NT = NULL;
-		_ion_handle_NT = NULL;
-	}
-}
-
-static void _unreg_ion_mem_NT(void)
-{
-	int rc;
-
-	rc = q6asm_memory_unmap(_ac_NT,	_po_NT.paddr, IN);
-	if (rc < 0)
-		eagle_drv_err("%s: mem unmap failed", __func__);
-	rc = msm_audio_ion_free(_ion_client_NT, _ion_handle_NT);
-	if (rc < 0)
-		eagle_drv_err("%s: mem free failed", __func__);
-
-	_ion_client_NT = NULL;
-	_ion_handle_NT = NULL;
-}
-
-static struct audio_client *_getNTDeviceAC(void)
-{
-	return _ac_NT;
-}
-
-static void _set_audioclient(struct audio_client *ac)
-{
-	_ac_NT = ac;
-	_reg_ion_mem_NT();
-}
-
-static void _clear_audioclient(void)
-{
-	_unreg_ion_mem_NT();
-	_ac_NT = NULL;
-}
-
-
-static int _sendcache_pre(struct audio_client *ac)
-{
-	uint32_t offset, size;
-	int32_t cidx, cmd, err = 0;
-
-	cidx = _get_cb_for_dev(_device_primary);
-	if (cidx < 0) {
-		eagle_precache_err("%s: no cache for primary device %i found",
-			__func__, _device_primary);
-		return -EINVAL;
-	}
-	offset = _c_bl[cidx][CBD_OFFSG];
-	cmd = _c_bl[cidx][CBD_CMD0];
-	size = _c_bl[cidx][CBD_SZ0];
-	/* check for integer overflow */
-	if (offset > (UINT_MAX - size))
-		err = -EINVAL;
-	if ((_depc_size == 0) || !_depc || (size == 0) ||
-		cmd == 0 || ((offset + size) > _depc_size) || (err != 0)) {
-		eagle_precache_err("%s: primary device %i cache index %i general error - cache size = %u, cache ptr = %pK, offset = %u, size = %u, cmd = %i",
-			__func__, _device_primary, cidx, _depc_size, _depc,
-			offset, size, cmd);
-		return -EINVAL;
-	}
-
-	if ((offset < (UINT_MAX - 124)) && ((offset + 124) < _depc_size))
-		eagle_precache_dbg("%s: first 6 integers %i %i %i %i %i %i (30th %i)",
-			__func__, *((int *)&_depc[offset]),
-			*((int *)&_depc[offset+4]),
-			*((int *)&_depc[offset+8]),
-			*((int *)&_depc[offset+12]),
-			*((int *)&_depc[offset+16]),
-			*((int *)&_depc[offset+20]),
-			*((int *)&_depc[offset+120]));
-	eagle_precache_dbg("%s: sending full data block to port, with cache index = %d device mask 0x%X, param = 0x%X, offset = %u, and size = %u",
-		  __func__, cidx, _c_bl[cidx][CBD_DEV_MASK], cmd, offset, size);
-
-	if (q6asm_dts_eagle_set(ac, cmd, size, (void *)&_depc[offset],
-				NULL, MPRE))
-		eagle_precache_err("%s: q6asm_dts_eagle_set failed with id = %d and size = %u",
-			__func__, cmd, size);
-	else
-		eagle_precache_dbg("%s: q6asm_dts_eagle_set succeeded with id = %d and size = %u",
-			 __func__, cmd, size);
-	return 0;
-}
-
-static int _sendcache_post(int port_id, int copp_idx, int topology)
-{
-	int cidx = -1, cmd, mask, index, err = 0;
-	uint32_t offset, size;
-
-	if (port_id == -1) {
-		cidx = _get_cb_for_dev(_device_primary);
-		if (cidx < 0) {
-			eagle_postcache_err("%s: no cache for primary device %i found. Port id was 0x%X",
-				__func__, _device_primary, port_id);
-			return -EINVAL;
-		}
-		goto NT_MODE_GOTO;
-	}
-
-	index = adm_validate_and_get_port_index(port_id);
-	if (index < 0) {
-		eagle_postcache_err("%s: Invalid port idx %d port_id %#x",
-			__func__, index, port_id);
-		return -EINVAL;
-	}
-	eagle_postcache_dbg("%s: valid port idx %d for port_id %#x set to %i",
-		__func__, index, port_id, copp_idx);
-	_cidx[index] = copp_idx;
-
-	mask = _get_dev_mask_for_pid(port_id);
-	if (mask & _device_primary) {
-		cidx = _get_cb_for_dev(_device_primary);
-		if (cidx < 0) {
-			eagle_postcache_err("%s: no cache for primary device %i found. Port id was 0x%X",
-				__func__, _device_primary, port_id);
-			return -EINVAL;
-		}
-	} else if (mask & _device_all) {
-		cidx = _get_cb_for_dev(_device_all);
-		if (cidx < 0) {
-			eagle_postcache_err("%s: no cache for combo device %i found. Port id was 0x%X",
-				__func__, _device_all, port_id);
-			return -EINVAL;
-		}
-	} else {
-		eagle_postcache_err("%s: port id 0x%X not for primary or combo device %i",
-			__func__, port_id, _device_primary);
-		return -EINVAL;
-	}
-
-NT_MODE_GOTO:
-	offset = _c_bl[cidx][CBD_OFFSG] + _c_bl[cidx][CBD_OFFS2];
-	cmd = _c_bl[cidx][CBD_CMD2];
-	size = _c_bl[cidx][CBD_SZ2];
-
-	/* check for integer overflow */
-	if (offset > (UINT_MAX - size))
-		err = -EINVAL;
-	if ((_depc_size == 0) || !_depc || (err != 0) || (size == 0) ||
-		(cmd == 0) || (offset + size) > _depc_size) {
-		eagle_postcache_err("%s: primary device %i cache index %i port_id 0x%X general error - cache size = %u, cache ptr = %pK, offset = %u, size = %u, cmd = %i",
-			__func__, _device_primary, cidx, port_id,
-			_depc_size, _depc, offset, size, cmd);
-		return -EINVAL;
-	}
-
-	if ((offset < (UINT_MAX - 24)) && ((offset + 24) < _depc_size))
-		eagle_postcache_dbg("%s: first 6 integers %i %i %i %i %i %i",
-			__func__, *((int *)&_depc[offset]),
-			*((int *)&_depc[offset+4]),
-			*((int *)&_depc[offset+8]),
-			*((int *)&_depc[offset+12]),
-			*((int *)&_depc[offset+16]),
-			*((int *)&_depc[offset+20]));
-	eagle_postcache_dbg("%s: sending full data block to port, with cache index = %d device mask 0x%X, port_id = 0x%X, param = 0x%X, offset = %u, and size = %u",
-		__func__, cidx, _c_bl[cidx][CBD_DEV_MASK], port_id, cmd,
-		offset, size);
-
-	if (_ac_NT) {
-		eagle_postcache_dbg("%s: NT Route detected", __func__);
-		if (q6asm_dts_eagle_set(_getNTDeviceAC(), cmd, size,
-					(void *)&_depc[offset],
-					&_po_NT, MPST))
-			eagle_postcache_err("%s: q6asm_dts_eagle_set failed with id = 0x%X and size = %u",
-				__func__, cmd, size);
-	} else if (adm_dts_eagle_set(port_id, copp_idx, cmd,
-			      (void *)&_depc[offset], size) < 0)
-		eagle_postcache_err("%s: adm_dts_eagle_set failed with id = 0x%X and size = %u",
-			__func__, cmd, size);
-	else
-		eagle_postcache_dbg("%s: adm_dts_eagle_set succeeded with id = 0x%X and size = %u",
-			 __func__, cmd, size);
-	return 0;
-}
-
-static int _enable_post_get_control(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	ucontrol->value.integer.value[0] = _is_hpx_enabled;
-	return 0;
-}
-
-static int _enable_post_put_control(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	int idx = 0, be_index = 0, port_id, topology;
-	int flag = ucontrol->value.integer.value[0];
-	struct msm_pcm_routing_bdai_data msm_bedai;
-
-	eagle_drv_dbg("%s: flag %d", __func__, flag);
-
-	_is_hpx_enabled = flag ? true : false;
-	msm_pcm_routing_acquire_lock();
-	/* send cache postmix params when hpx is set On */
-	for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) {
-		msm_pcm_routing_get_bedai_info(be_index, &msm_bedai);
-		port_id = msm_bedai.port_id;
-		if (!(((port_id == SLIMBUS_0_RX) ||
-		      (port_id == RT_PROXY_PORT_001_RX)) &&
-		      msm_bedai.active))
-			continue;
-		for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
-			topology = adm_get_topology_for_port_copp_idx(
-								port_id, idx);
-			if (topology ==
-				ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX) {
-				msm_dts_eagle_enable_adm(port_id, idx,
-							 _is_hpx_enabled);
-			}
-		}
-	}
-	msm_pcm_routing_release_lock();
-	return 0;
-}
-
-static const struct snd_kcontrol_new _hpx_enabled_controls[] = {
-	SOC_SINGLE_EXT("Set HPX OnOff", SND_SOC_NOPM, 0, 1, 0,
-	_enable_post_get_control, _enable_post_put_control)
-};
-
-/**
- * msm_dts_ion_memmap() - helper function to map ION memory
- * @po_:	Out of band memory structure used as memory.
- *
- * Assign already allocated ION memory for mapping it to dsp.
- *
- * Return: No return value.
- */
-void msm_dts_ion_memmap(struct param_outband *po_)
-{
-	po_->size = ION_MEM_SIZE;
-	po_->kvaddr = _po.kvaddr;
-	po_->paddr = _po.paddr;
-}
-
-/**
- * msm_dts_eagle_enable_asm() - Enable/disable dts module
- * @ac:	Enable/disable module in ASM session associated with this audio client.
- * @enable:	Enable/disable the dts module.
- * @module:	module id.
- *
- * Enable/disable specified dts module id in asm.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_enable_asm(struct audio_client *ac, u32 enable, int module)
-{
-	int ret = 0;
-
-	eagle_enable_dbg("%s: enable = %i on module %i",
-		 __func__, enable, module);
-	_is_hpx_enabled = enable;
-	ret = q6asm_dts_eagle_set(ac, AUDPROC_PARAM_ID_ENABLE,
-				      sizeof(enable), &enable,
-				      NULL, module);
-	if (_is_hpx_enabled) {
-		if (module == MPRE)
-			_sendcache_pre(ac);
-		else if (module == MPST)
-			_sendcache_post(-1, 0, 0);
-	}
-	return ret;
-}
-
-/**
- * msm_dts_eagle_enable_adm() - Enable/disable dts module in adm
- * @port_id:	Send enable/disable param to this port id.
- * @copp_idx:	Send enable/disable param to the relevant copp.
- * @enable:	Enable/disable the dts module.
- *
- * Enable/disable dts module in adm.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_enable_adm(int port_id, int copp_idx, u32 enable)
-{
-	int ret = 0;
-
-	eagle_enable_dbg("%s: enable = %i", __func__, enable);
-	_is_hpx_enabled = enable;
-	ret = adm_dts_eagle_set(port_id, copp_idx, AUDPROC_PARAM_ID_ENABLE,
-			     (char *)&enable, sizeof(enable));
-	if (_is_hpx_enabled)
-		_sendcache_post(port_id, copp_idx, MPST);
-	return ret;
-}
-
-/**
- * msm_dts_eagle_add_controls() -  Add mixer control to Enable/Disable DTS HPX
- * @platform:	Add mixer controls to this platform.
- *
- * Add mixer control to Enable/Disable DTS HPX module in ADM.
- *
- * Return: No return value.
- */
-void msm_dts_eagle_add_controls(struct snd_soc_platform *platform)
-{
-	snd_soc_add_platform_controls(platform, _hpx_enabled_controls,
-				      ARRAY_SIZE(_hpx_enabled_controls));
-}
-
-/**
- * msm_dts_eagle_set_stream_gain() -  Set stream gain to DTS Premix module
- * @ac:	Set stream gain to ASM session associated with this audio client.
- * @lgain:	Left gain value.
- * @rgain:	Right gain value.
- *
- * Set stream gain to DTS Premix module in ASM.
- *
- * Return: failure or success.
- */
-int msm_dts_eagle_set_stream_gain(struct audio_client *ac, int lgain, int rgain)
-{
-	u32 i, val;
-	s32 idx, err = 0;
-
-	eagle_vol_dbg("%s: - entry: vol_cmd_cnt = %u, lgain = %i, rgain = %i",
-		 __func__, _vol_cmd_cnt, lgain, rgain);
-
-	if (_depc_size == 0) {
-		eagle_vol_dbg("%s: driver cache not initialized", __func__);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < _vol_cmd_cnt; i++) {
-		if (_vol_cmds_d[i].d[0] & 0x8000) {
-			idx = (sizeof(struct dts_eagle_param_desc)/sizeof(int))
-				+ (_vol_cmds_d[i].d[0] & 0x3FF);
-			val = _fx_logN(((s32)(lgain+rgain)) << 2);
-			val = ((long long)val * _log10_10_inv_x20) >> 16;
-			_vol_cmds[i][idx] = (s32)clamp((int)(((long long)val *
-						    _vol_cmds_d[i].d[1]) >> 16),
-						    _vol_cmds_d[i].d[2],
-						    _vol_cmds_d[i].d[3]);
-			 eagle_vol_dbg("%s: loop %u cmd desc found %i, idx = %i. volume info: lgain = %i, rgain = %i, volume = %i (scale %i, min %i, max %i)",
-				 __func__, i, _vol_cmds_d[i].d[0], idx, lgain,
-				 rgain, _vol_cmds[i][idx], _vol_cmds_d[i].d[1],
-				 _vol_cmds_d[i].d[2], _vol_cmds_d[i].d[3]);
-		}
-		idx = _get_cb_for_dev(_device_primary);
-		if (idx < 0) {
-			eagle_vol_err("%s: no cache for primary device %i found",
-				__func__, _device_primary);
-			return -EINVAL;
-		}
-		val = _c_bl[idx][CBD_OFFSG] + _vol_cmds[i][2];
-		/* check for integer overflow */
-		if (val > (UINT_MAX - _vol_cmds[i][1]))
-			err = -EINVAL;
-		if ((err != 0) || ((val + _vol_cmds[i][1]) > _depc_size)) {
-			eagle_vol_err("%s: volume size (%u) + offset (%i) out of bounds %i",
-				__func__, val, _vol_cmds[i][1], _depc_size);
-			return -EINVAL;
-		}
-		memcpy((void *)&_depc[val], &_vol_cmds[i][4], _vol_cmds[i][1]);
-		if (q6asm_dts_eagle_set(ac, _vol_cmds[i][0],
-			_vol_cmds[i][1], (void *)&_depc[val], NULL, MPRE))
-			eagle_vol_err("%s: loop %u - volume set failed with id 0x%X, size %i, offset %i, cmd_desc %i, scale %i, min %i, max %i, data(...) %i",
-				__func__, i, _vol_cmds[i][0], _vol_cmds[i][1],
-				_vol_cmds[i][2], _vol_cmds_d[i].d[0],
-				_vol_cmds_d[i].d[1], _vol_cmds_d[i].d[2],
-				_vol_cmds_d[i].d[3], _vol_cmds[i][4]);
-		else
-			eagle_vol_dbg("%s: loop %u - volume set succeeded with id 0x%X, size %i, offset %i, cmd_desc %i, scale %i, min %i, max %i, data(...) %i",
-				 __func__, i, _vol_cmds[i][0], _vol_cmds[i][1],
-				 _vol_cmds[i][2], _vol_cmds_d[i].d[0],
-				 _vol_cmds_d[i].d[1], _vol_cmds_d[i].d[2],
-				 _vol_cmds_d[i].d[3], _vol_cmds[i][4]);
-	}
-	return 0;
-}
-
-/**
- * msm_dts_eagle_handle_asm() - Set or Get params from ASM
- * @depd:	DTS Eagle Params structure.
- * @buf:	Buffer to get queried param value.
- * @for_pre:	For premix module or postmix module.
- * @get:	Getting param from DSP or setting param.
- * @ac:	Set/Get from ASM session associated with this audio client.
- * @po:	Out of band memory to set or get postmix params.
- *
- * Set or Get params from modules in ASM session.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_handle_asm(struct dts_eagle_param_desc *depd, char *buf,
-			     bool for_pre, bool get, struct audio_client *ac,
-			     struct param_outband *po)
-{
-	struct dts_eagle_param_desc depd_ = {0};
-	s32 ret = 0, isALSA = 0, err = 0, i, mod = for_pre ? MPRE : MPST;
-	u32 offset;
-
-	eagle_asm_dbg("%s: set/get asm", __func__);
-
-	/* special handling for ALSA route, to accommodate 64 bit platforms */
-	if (depd == NULL) {
-		long *arg_ = (long *)buf;
-
-		depd = &depd_;
-		depd->id = (u32)*arg_++;
-		depd->size = (u32)*arg_++;
-		depd->offset = (s32)*arg_++;
-		depd->device = (u32)*arg_++;
-		buf = (char *)arg_;
-		isALSA = 1;
-	}
-
-	if (depd->size & 1) {
-		eagle_asm_err("%s: parameter size %u is not a multiple of 2",
-			__func__, depd->size);
-		return -EINVAL;
-	}
-
-	if (get) {
-		void *buf_, *buf_m = NULL;
-
-		eagle_asm_dbg("%s: get requested", __func__);
-		if (depd->offset == -1) {
-			eagle_asm_dbg("%s: get from dsp requested", __func__);
-			if (depd->size > 0 && depd->size <= DEPC_MAX_SIZE) {
-				buf_ = buf_m = vzalloc(depd->size);
-			} else {
-				eagle_asm_err("%s: get size %u invalid",
-					      __func__, depd->size);
-				return -EINVAL;
-			}
-			if (!buf_m) {
-				eagle_asm_err("%s: out of memory", __func__);
-				return -ENOMEM;
-			} else if (q6asm_dts_eagle_get(ac, depd->id,
-						       depd->size, buf_m,
-						       po, mod) < 0) {
-				eagle_asm_err("%s: asm get failed", __func__);
-				ret = -EFAULT;
-				goto DTS_EAGLE_IOCTL_GET_PARAM_PRE_EXIT;
-			}
-			eagle_asm_dbg("%s: get result: param id 0x%x value %d size %u",
-				 __func__, depd->id, *(int *)buf_m, depd->size);
-		} else {
-			s32 tgt = _get_cb_for_dev(depd->device);
-
-			if (tgt < 0) {
-				eagle_asm_err("%s: no cache for device %u found",
-					__func__, depd->device);
-				return -EINVAL;
-			}
-			offset = _c_bl[tgt][CBD_OFFSG] + depd->offset;
-			/* check for integer overflow */
-			if (offset > (UINT_MAX - depd->size))
-				err = -EINVAL;
-			if ((err != 0) || (offset + depd->size) > _depc_size) {
-				eagle_asm_err("%s: invalid size %u and/or offset %u",
-					__func__, depd->size, offset);
-				return -EINVAL;
-			}
-			buf_ = (u32 *)&_depc[offset];
-		}
-		if (isALSA) {
-			if (depd->size == 2) {
-				*(long *)buf = (long)*(__u16 *)buf_;
-				eagle_asm_dbg("%s: asm out 16 bit value %li",
-						__func__, *(long *)buf);
-			} else {
-				s32 *pbuf = (s32 *)buf_;
-				long *bufl = (long *)buf;
-
-				for (i = 0; i < (depd->size >> 2); i++) {
-					*bufl++ = (long)*pbuf++;
-					eagle_asm_dbg("%s: asm out value %li",
-							 __func__, *(bufl-1));
-				}
-			}
-		} else {
-			memcpy(buf, buf_, depd->size);
-		}
-DTS_EAGLE_IOCTL_GET_PARAM_PRE_EXIT:
-		vfree(buf_m);
-		return (int)ret;
-	} else {
-		s32 tgt = _get_cb_for_dev(depd->device);
-
-		if (tgt < 0) {
-			eagle_asm_err("%s: no cache for device %u found",
-				__func__, depd->device);
-			return -EINVAL;
-		}
-		offset = _c_bl[tgt][CBD_OFFSG] + depd->offset;
-		/* check for integer overflow */
-		if (offset > (UINT_MAX - depd->size))
-			err = -EINVAL;
-		if ((err != 0) || ((offset + depd->size) > _depc_size)) {
-			eagle_asm_err("%s: invalid size %u and/or offset %u for parameter (cache is size %u)",
-				__func__, depd->size, offset, _depc_size);
-			return -EINVAL;
-		}
-		if (isALSA) {
-			if (depd->size == 2) {
-				*(__u16 *)&_depc[offset] = (__u16)*(long *)buf;
-				eagle_asm_dbg("%s: asm in 16 bit value %li",
-						__func__, *(long *)buf);
-			} else {
-				s32 *pbuf = (s32 *)&_depc[offset];
-				long *bufl = (long *)buf;
-
-				for (i = 0; i < (depd->size >> 2); i++) {
-					*pbuf++ = (s32)*bufl++;
-					eagle_asm_dbg("%s: asm in value %i",
-							__func__, *(pbuf-1));
-				}
-			}
-		} else {
-			memcpy(&_depc[offset], buf, depd->size);
-		}
-		eagle_asm_dbg("%s: param info: param = 0x%X, size = %u, offset = %i, device = %u, cache block %i, global offset = %u, first bytes as integer = %i",
-			__func__, depd->id, depd->size, depd->offset,
-			depd->device,
-			tgt, offset, *(int *)&_depc[offset]);
-		if (q6asm_dts_eagle_set(ac, depd->id, depd->size,
-					(void *)&_depc[offset], po, mod))
-			eagle_asm_err("%s: q6asm_dts_eagle_set failed with id = 0x%X, size = %u, offset = %d",
-				__func__, depd->id, depd->size, depd->offset);
-		else
-			eagle_asm_dbg("%s: q6asm_dts_eagle_set succeeded with id = 0x%X, size = %u, offset = %d",
-				 __func__, depd->id, depd->size, depd->offset);
-	}
-
-	return (int)ret;
-}
-
-/**
- * msm_dts_eagle_handle_adm() - Set or Get params from ADM
- * @depd:	DTS Eagle Params structure used to set or get.
- * @buf:	Buffer to get queried param value in NT mode.
- * @for_pre:	For premix module or postmix module.
- * @get:	Getting param from DSP or setting param.
- *
- * Set or Get params from modules in ADM session.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_handle_adm(struct dts_eagle_param_desc *depd, char *buf,
-			     bool for_pre, bool get)
-{
-	u32 pid = _get_pid_from_dev(depd->device), cidx;
-	s32 ret = 0;
-
-	eagle_adm_dbg("%s: set/get adm", __func__);
-
-	if (_isNTDevice(depd->device)) {
-		eagle_adm_dbg("%s: NT Route detected", __func__);
-		ret = msm_dts_eagle_handle_asm(depd, buf, for_pre, get,
-					       _getNTDeviceAC(), &_po_NT);
-		if (ret < 0)
-			eagle_adm_err("%s: NT Route set failed with id = 0x%X, size = %u, offset = %i, device = %u",
-				__func__, depd->id, depd->size, depd->offset,
-				depd->device);
-	} else if (get) {
-		cidx = adm_validate_and_get_port_index(pid);
-		eagle_adm_dbg("%s: get from qdsp requested (port id 0x%X)",
-			 __func__, pid);
-		if (adm_dts_eagle_get(pid, _cidx[cidx], depd->id,
-				      buf, depd->size) < 0) {
-			eagle_adm_err("%s: get from qdsp via adm with port id 0x%X failed",
-				 __func__, pid);
-			return -EFAULT;
-		}
-	} else if (_is_port_open_and_eagle(pid)) {
-		cidx = adm_validate_and_get_port_index(pid);
-		eagle_adm_dbg("%s: adm_dts_eagle_set called with id = 0x%X, size = %u, offset = %i, device = %u, port id = %u, copp index = %u",
-				__func__, depd->id, depd->size, depd->offset,
-				depd->device, pid, cidx);
-		ret = adm_dts_eagle_set(pid, _cidx[cidx], depd->id,
-					(void *)buf, depd->size);
-		if (ret < 0)
-			eagle_adm_err("%s: adm_dts_eagle_set failed", __func__);
-		else
-			eagle_adm_dbg("%s: adm_dts_eagle_set succeeded",
-				__func__);
-	} else {
-		ret = -EINVAL;
-		eagle_adm_dbg("%s: port id 0x%X not active or not Eagle",
-			 __func__, pid);
-	}
-	return (int)ret;
-}
-
-/**
- * msm_dts_eagle_ioctl() - ioctl handler function
- * @cmd:	cmd to handle.
- * @arg:	argument to the cmd.
- *
- * Handle DTS Eagle ioctl cmds.
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_ioctl(unsigned int cmd, unsigned long arg)
-{
-	s32 ret = 0;
-
-	switch (cmd) {
-	case DTS_EAGLE_IOCTL_GET_CACHE_SIZE: {
-		eagle_ioctl_info("%s: called with control 0x%X (get param cache size)",
-			__func__, cmd);
-		if (copy_to_user((void *)arg, &_depc_size,
-				 sizeof(_depc_size))) {
-			eagle_ioctl_err("%s: error writing size", __func__);
-			return -EFAULT;
-		}
-		break;
-	}
-	case DTS_EAGLE_IOCTL_SET_CACHE_SIZE: {
-		u32 size = 0;
-
-		eagle_ioctl_info("%s: called with control 0x%X (allocate param cache)",
-			__func__, cmd);
-		if (copy_from_user((void *)&size, (void *)arg, sizeof(size))) {
-			eagle_ioctl_err("%s: error copying size (src:%pK, tgt:%pK, size:%zu)",
-				__func__, (void *)arg, &size, sizeof(size));
-			return -EFAULT;
-		} else if (size > DEPC_MAX_SIZE) {
-			eagle_ioctl_err("%s: cache size %u not allowed (min 0, max %u)",
-				__func__, size, DEPC_MAX_SIZE);
-			return -EINVAL;
-		}
-		if (_depc) {
-			eagle_ioctl_dbg("%s: previous param cache of size %u freed",
-				__func__, _depc_size);
-			_depc_size = 0;
-			vfree(_depc);
-			_depc = NULL;
-		}
-		if (size)
-			_depc = vzalloc(size);
-		else
-			eagle_ioctl_dbg("%s: %u bytes requested for param cache, nothing allocated",
-				__func__, size);
-		if (_depc) {
-			eagle_ioctl_dbg("%s: %u bytes allocated for param cache",
-				__func__, size);
-			_depc_size = size;
-		} else {
-			eagle_ioctl_err("%s: error allocating param cache (vzalloc failed on %u bytes)",
-				__func__, size);
-			_depc_size = 0;
-			return -ENOMEM;
-		}
-		break;
-	}
-	case DTS_EAGLE_IOCTL_GET_PARAM: {
-		struct dts_eagle_param_desc depd;
-		s32 for_pre = 0, get_from_core = 0, err = 0;
-		u32 offset;
-		void *buf, *buf_m = NULL;
-
-		eagle_ioctl_info("%s: control 0x%X (get param)",
-			__func__, cmd);
-		if (copy_from_user((void *)&depd, (void *)arg, sizeof(depd))) {
-			eagle_ioctl_err("%s: error copying dts_eagle_param_desc (src:%pK, tgt:%pK, size:%zu)",
-				__func__, (void *)arg, &depd, sizeof(depd));
-			return -EFAULT;
-		}
-		if (depd.device & DTS_EAGLE_FLAG_IOCTL_PRE) {
-			eagle_ioctl_dbg("%s: using for premix", __func__);
-			for_pre = 1;
-		}
-		if (depd.device & DTS_EAGLE_FLAG_IOCTL_GETFROMCORE) {
-			eagle_ioctl_dbg("%s: 'get from core' requested",
-				__func__);
-			get_from_core = 1;
-			depd.offset = -1;
-		}
-		depd.device &= DTS_EAGLE_FLAG_IOCTL_MASK;
-		if (depd.offset == -1) {
-			if (depd.size > 0 && depd.size <= DEPC_MAX_SIZE) {
-				buf = buf_m = vzalloc(depd.size);
-			} else {
-				eagle_ioctl_err("%s: get size %u invalid",
-						__func__, depd.size);
-				return -EINVAL;
-			}
-			if (!buf_m) {
-				eagle_ioctl_err("%s: out of memory", __func__);
-				return -ENOMEM;
-			}
-			if (get_from_core)
-				ret = core_dts_eagle_get(depd.id, depd.size,
-							 buf);
-			else
-				ret = msm_dts_eagle_handle_adm(&depd, buf,
-								for_pre, true);
-		} else {
-			s32 cb = _get_cb_for_dev(depd.device);
-
-			if (cb < 0) {
-				eagle_ioctl_err("%s: no cache for device %u found",
-					__func__, depd.device);
-				return -EINVAL;
-			}
-			offset = _c_bl[cb][CBD_OFFSG] + depd.offset;
-			/* check for integer overflow */
-			if (offset > (UINT_MAX - depd.size))
-				err = -EINVAL;
-			if ((err != 0) ||
-			    ((offset + depd.size) > _depc_size)) {
-				eagle_ioctl_err("%s: invalid size %u and/or offset %u",
-					__func__, depd.size, offset);
-				return -EINVAL;
-			}
-			buf = (void *)&_depc[offset];
-		}
-		if (ret < 0)
-			eagle_ioctl_err("%s: error %i getting data", __func__,
-				ret);
-		else if (copy_to_user((void *)(((char *)arg)+sizeof(depd)),
-						  buf, depd.size)) {
-			eagle_ioctl_err("%s: error copying get data", __func__);
-			ret = -EFAULT;
-		}
-		vfree(buf_m);
-		break;
-	}
-	case DTS_EAGLE_IOCTL_SET_PARAM: {
-		struct dts_eagle_param_desc depd;
-		s32 just_set_cache = 0, for_pre = 0, err = 0;
-		u32 offset;
-		s32 tgt;
-
-		eagle_ioctl_info("%s: control 0x%X (set param)",
-			__func__, cmd);
-		if (copy_from_user((void *)&depd, (void *)arg, sizeof(depd))) {
-			eagle_ioctl_err("%s: error copying dts_eagle_param_desc (src:%pK, tgt:%pK, size:%zu)",
-				__func__, (void *)arg, &depd, sizeof(depd));
-			return -EFAULT;
-		}
-		if (depd.device & DTS_EAGLE_FLAG_IOCTL_PRE) {
-			eagle_ioctl_dbg("%s: using for premix", __func__);
-			for_pre = 1;
-		}
-		if (depd.device & DTS_EAGLE_FLAG_IOCTL_JUSTSETCACHE) {
-			eagle_ioctl_dbg("%s: 'just set cache' requested",
-				__func__);
-			just_set_cache = 1;
-		}
-		depd.device &= DTS_EAGLE_FLAG_IOCTL_MASK;
-		tgt = _get_cb_for_dev(depd.device);
-		if (tgt < 0) {
-			eagle_ioctl_err("%s: no cache for device %u found",
-				__func__, depd.device);
-			return -EINVAL;
-		}
-		offset = _c_bl[tgt][CBD_OFFSG] + depd.offset;
-		/* check for integer overflow */
-		if (offset > (UINT_MAX - depd.size))
-			err = -EINVAL;
-		if ((err != 0) || ((offset + depd.size) > _depc_size)) {
-			eagle_ioctl_err("%s: invalid size %u and/or offset %u for parameter (target cache block %i with offset %i, global cache is size %u)",
-				__func__, depd.size, offset, tgt,
-				_c_bl[tgt][CBD_OFFSG], _depc_size);
-			return -EINVAL;
-		}
-		if (copy_from_user((void *)&_depc[offset],
-				   (void *)(((char *)arg)+sizeof(depd)),
-					depd.size)) {
-			eagle_ioctl_err("%s: error copying param to cache (src:%pK, tgt:%pK, size:%u)",
-				__func__, ((char *)arg)+sizeof(depd),
-				&_depc[offset], depd.size);
-			return -EFAULT;
-		}
-		eagle_ioctl_dbg("%s: param info: param = 0x%X, size = %u, offset = %i, device = %u, cache block %i, global offset = %u, first bytes as integer = %i",
-			__func__, depd.id, depd.size, depd.offset,
-			depd.device, tgt, offset, *(int *)&_depc[offset]);
-		if (!just_set_cache) {
-			ret = msm_dts_eagle_handle_adm(&depd, &_depc[offset],
-						       for_pre, false);
-		}
-		break;
-	}
-	case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK: {
-		u32 b_[CBD_COUNT+1], *b = &b_[1], cb;
-
-		eagle_ioctl_info("%s: with control 0x%X (set param cache block)",
-			 __func__, cmd);
-		if (copy_from_user((void *)b_, (void *)arg, sizeof(b_))) {
-			eagle_ioctl_err("%s: error copying cache block data (src:%pK, tgt:%pK, size:%zu)",
-				__func__, (void *)arg, b_, sizeof(b_));
-			return -EFAULT;
-		}
-		cb = b_[0];
-		if (cb >= CB_COUNT) {
-			eagle_ioctl_err("%s: cache block %u out of range (max %u)",
-				__func__, cb, CB_COUNT-1);
-			return -EINVAL;
-		}
-		eagle_ioctl_dbg("%s: cache block %i set: devices 0x%X, global offset %i, offsets 1:%u 2:%u 3:%u, cmds/sizes 0:0x%X %u 1:0x%X %u 2:0x%X %u 3:0x%X %u",
-		__func__, cb, _c_bl[cb][CBD_DEV_MASK], _c_bl[cb][CBD_OFFSG],
-		_c_bl[cb][CBD_OFFS1], _c_bl[cb][CBD_OFFS2],
-		_c_bl[cb][CBD_OFFS3], _c_bl[cb][CBD_CMD0], _c_bl[cb][CBD_SZ0],
-		_c_bl[cb][CBD_CMD1], _c_bl[cb][CBD_SZ1], _c_bl[cb][CBD_CMD2],
-		_c_bl[cb][CBD_SZ2], _c_bl[cb][CBD_CMD3], _c_bl[cb][CBD_SZ3]);
-		if ((b[CBD_OFFSG]+b[CBD_OFFS1]+b[CBD_SZ1]) > _depc_size ||
-			(b[CBD_OFFSG]+b[CBD_OFFS2]+b[CBD_SZ2]) > _depc_size ||
-			(b[CBD_OFFSG]+b[CBD_OFFS3]+b[CBD_SZ3]) > _depc_size) {
-			eagle_ioctl_err("%s: cache block bounds out of range",
-					__func__);
-			return -EINVAL;
-		}
-		memcpy(_c_bl[cb], b, sizeof(_c_bl[cb]));
-		break;
-	}
-	case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE: {
-		u32 data[2];
-
-		eagle_ioctl_dbg("%s: with control 0x%X (set active device)",
-			 __func__, cmd);
-		if (copy_from_user((void *)data, (void *)arg, sizeof(data))) {
-			eagle_ioctl_err("%s: error copying active device data (src:%pK, tgt:%pK, size:%zu)",
-				__func__, (void *)arg, data, sizeof(data));
-			return -EFAULT;
-		}
-		if (data[1] != 0) {
-			_device_primary = data[0];
-			eagle_ioctl_dbg("%s: primary device %i", __func__,
-				 data[0]);
-		} else {
-			_device_all = data[0];
-			eagle_ioctl_dbg("%s: all devices 0x%X", __func__,
-				 data[0]);
-		}
-		break;
-	}
-	case DTS_EAGLE_IOCTL_GET_LICENSE: {
-		u32 target = 0, size = 0;
-		s32 size_only;
-
-		eagle_ioctl_dbg("%s: with control 0x%X (get license)",
-			 __func__, cmd);
-		if (copy_from_user((void *)&target, (void *)arg,
-				   sizeof(target))) {
-			eagle_ioctl_err("%s: error reading license index. (src:%pK, tgt:%pK, size:%zu)",
-				__func__, (void *)arg, &target, sizeof(target));
-			return -EFAULT;
-		}
-		size_only = target & (1<<31) ? 1 : 0;
-		target &= 0x7FFFFFFF;
-		if (target >= SEC_BLOB_MAX_CNT) {
-			eagle_ioctl_err("%s: license index %u out of bounds (max index is %i)",
-				   __func__, target, SEC_BLOB_MAX_CNT);
-			return -EINVAL;
-		}
-		if (_sec_blob[target] == NULL) {
-			eagle_ioctl_err("%s: license index %u never initialized",
-				   __func__, target);
-			return -EINVAL;
-		}
-		size = ((u32 *)_sec_blob[target])[0];
-		if ((size == 0) || (size > SEC_BLOB_MAX_SIZE)) {
-			eagle_ioctl_err("%s: license size %u for index %u invalid (min size is 1, max size is %u)",
-				   __func__, size, target, SEC_BLOB_MAX_SIZE);
-			return -EINVAL;
-		}
-		if (size_only) {
-			eagle_ioctl_dbg("%s: reporting size of license data only",
-					__func__);
-			if (copy_to_user((void *)(((char *)arg)+sizeof(target)),
-				 (void *)&size, sizeof(size))) {
-				eagle_ioctl_err("%s: error copying license size",
-						__func__);
-				return -EFAULT;
-			}
-		} else if (copy_to_user((void *)(((char *)arg)+sizeof(target)),
-			   (void *)&(((s32 *)_sec_blob[target])[1]), size)) {
-			eagle_ioctl_err("%s: error copying license data",
-				__func__);
-			return -EFAULT;
-		} else {
-			eagle_ioctl_info("%s: license file %u bytes long from license index %u returned to user",
-				  __func__, size, target);
-		}
-		break;
-	}
-	case DTS_EAGLE_IOCTL_SET_LICENSE: {
-		u32 target[2] = {0, 0};
-
-		eagle_ioctl_dbg("%s: control 0x%X (set license)", __func__,
-				cmd);
-		if (copy_from_user((void *)target, (void *)arg,
-				   sizeof(target))) {
-			eagle_ioctl_err("%s: error reading license index (src:%pK, tgt:%pK, size:%zu)",
-				__func__, (void *)arg, target, sizeof(target));
-			return -EFAULT;
-		}
-		if (target[0] >= SEC_BLOB_MAX_CNT) {
-			eagle_ioctl_err("%s: license index %u out of bounds (max index is %u)",
-				   __func__, target[0], SEC_BLOB_MAX_CNT-1);
-			return -EINVAL;
-		}
-		if (target[1] == 0) {
-			eagle_ioctl_dbg("%s: request to free license index %u",
-				 __func__, target[0]);
-			kfree(_sec_blob[target[0]]);
-			_sec_blob[target[0]] = NULL;
-			break;
-		}
-		if ((target[1] == 0) || (target[1] >= SEC_BLOB_MAX_SIZE)) {
-			eagle_ioctl_err("%s: license size %u for index %u invalid (min size is 1, max size is %u)",
-				__func__, target[1], target[0],
-				SEC_BLOB_MAX_SIZE);
-			return -EINVAL;
-		}
-		if (_sec_blob[target[0]] != NULL) {
-			if (((u32 *)_sec_blob[target[0]])[1] != target[1]) {
-				eagle_ioctl_dbg("%s: request new size for already allocated license index %u",
-					 __func__, target[0]);
-			}
-			kfree(_sec_blob[target[0]]);
-			_sec_blob[target[0]] = NULL;
-		}
-		eagle_ioctl_dbg("%s: allocating %u bytes for license index %u",
-				__func__, target[1], target[0]);
-		_sec_blob[target[0]] = kzalloc(target[1] + 4, GFP_KERNEL);
-		if (!_sec_blob[target[0]]) {
-			eagle_ioctl_err("%s: error allocating license index %u (kzalloc failed on %u bytes)",
-					__func__, target[0], target[1]);
-			return -ENOMEM;
-		}
-		((u32 *)_sec_blob[target[0]])[0] = target[1];
-		if (copy_from_user(
-				(void *)&(((u32 *)_sec_blob[target[0]])[1]),
-				(void *)(((char *)arg)+sizeof(target)),
-				target[1])) {
-			eagle_ioctl_err("%s: error copying license to index %u, size %u (src:%pK, tgt:%pK, size:%u)",
-					__func__, target[0], target[1],
-					((char *)arg)+sizeof(target),
-					&(((u32 *)_sec_blob[target[0]])[1]),
-					target[1]);
-			return -EFAULT;
-		}
-		eagle_ioctl_info("%s: license file %u bytes long copied to index license index %u",
-				  __func__, target[1], target[0]);
-		break;
-	}
-	case DTS_EAGLE_IOCTL_SEND_LICENSE: {
-		u32 target = 0;
-
-		eagle_ioctl_dbg("%s: control 0x%X (send license)", __func__,
-				cmd);
-		if (copy_from_user((void *)&target, (void *)arg,
-				   sizeof(target))) {
-			eagle_ioctl_err("%s: error reading license index (src:%pK, tgt:%pK, size:%zu)",
-				__func__, (void *)arg, &target, sizeof(target));
-			return -EFAULT;
-		}
-		if (target >= SEC_BLOB_MAX_CNT) {
-			eagle_ioctl_err("%s: license index %u out of bounds (max index is %i)",
-					__func__, target, SEC_BLOB_MAX_CNT-1);
-			return -EINVAL;
-		}
-		if (!_sec_blob[target] ||
-		    ((u32 *)_sec_blob[target])[0] == 0) {
-			eagle_ioctl_err("%s: license index %u is invalid",
-				__func__, target);
-			return -EINVAL;
-		}
-		if (core_dts_eagle_set(((s32 *)_sec_blob[target])[0],
-				(char *)&((s32 *)_sec_blob[target])[1]) < 0)
-			eagle_ioctl_err("%s: core_dts_eagle_set failed with id = %u",
-				__func__, target);
-		else
-			eagle_ioctl_info("%s: core_dts_eagle_set succeeded with id = %u",
-				 __func__, target);
-		break;
-	}
-	case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS: {
-		s32 spec = 0;
-
-		eagle_ioctl_info("%s: control 0x%X (set volume commands)",
-				__func__, cmd);
-		if (copy_from_user((void *)&spec, (void *)arg,
-					sizeof(spec))) {
-			eagle_ioctl_err("%s: error reading volume command specifier (src:%pK, tgt:%pK, size:%zu)",
-				__func__, (void *)arg, &spec, sizeof(spec));
-			return -EFAULT;
-		}
-		if (spec & 0x80000000) {
-			u32 idx = (spec & 0x0000F000) >> 12;
-			s32 size = spec & 0x00000FFF;
-
-			eagle_ioctl_dbg("%s: setting volume command %i size: %i",
-				__func__, idx, size);
-			if (idx >= _vol_cmd_cnt) {
-				eagle_ioctl_err("%s: volume command index %u out of bounds (only %u allocated)",
-					__func__, idx, _vol_cmd_cnt);
-				return -EINVAL;
-			}
-			if (_volume_cmds_alloc2(idx, size) < 0) {
-				eagle_ioctl_err("%s: error allocating memory for volume controls",
-						__func__);
-				return -ENOMEM;
-			}
-			if (copy_from_user((void *)&_vol_cmds_d[idx],
-					(void *)(((char *)arg) + sizeof(int)),
-					sizeof(struct vol_cmds_d))) {
-				eagle_ioctl_err("%s: error reading volume command descriptor (src:%pK, tgt:%pK, size:%zu)",
-					__func__, ((char *)arg) + sizeof(int),
-					&_vol_cmds_d[idx],
-					sizeof(struct vol_cmds_d));
-				return -EFAULT;
-			}
-			eagle_ioctl_dbg("%s: setting volume command %i spec (size %zu): %i %i %i %i",
-				  __func__, idx, sizeof(struct vol_cmds_d),
-				  _vol_cmds_d[idx].d[0], _vol_cmds_d[idx].d[1],
-				  _vol_cmds_d[idx].d[2], _vol_cmds_d[idx].d[3]);
-			if (copy_from_user((void *)_vol_cmds[idx],
-					(void *)(((char *)arg) + (sizeof(int) +
-					sizeof(struct vol_cmds_d))), size)) {
-				eagle_ioctl_err("%s: error reading volume command string (src:%pK, tgt:%pK, size:%i)",
-					__func__, ((char *)arg) + (sizeof(int) +
-					sizeof(struct vol_cmds_d)),
-					_vol_cmds[idx], size);
-				return -EFAULT;
-			}
-		} else {
-			eagle_ioctl_dbg("%s: setting volume command size",
-					__func__);
-			if (spec < 0 || spec > VOL_CMD_CNT_MAX) {
-				eagle_ioctl_err("%s: volume command count %i out of bounds (min 0, max %i)",
-					__func__, spec, VOL_CMD_CNT_MAX);
-				return -EINVAL;
-			} else if (spec == 0) {
-				eagle_ioctl_dbg("%s: request to free volume commands",
-						__func__);
-				_volume_cmds_free();
-				break;
-			}
-			eagle_ioctl_dbg("%s: setting volume command size requested = %i",
-				  __func__, spec);
-			if (_volume_cmds_alloc1(spec) < 0) {
-				eagle_ioctl_err("%s: error allocating memory for volume controls",
-						__func__);
-				return -ENOMEM;
-			}
-		}
-		break;
-	}
-	default: {
-		eagle_ioctl_err("%s: control 0x%X (invalid control)",
-			 __func__, cmd);
-		ret = -EINVAL;
-	}
-	}
-	return (int)ret;
-}
-
-/**
- * msm_dts_eagle_compat_ioctl() - To handle 32bit to 64bit ioctl compatibility
- * @cmd:	cmd to handle.
- * @arg:	argument to the cmd.
- *
- * Handle DTS Eagle ioctl cmds from 32bit userspace.
- *
- * Return: Return failure if any.
- */
-#ifdef CONFIG_COMPAT
-int msm_dts_eagle_compat_ioctl(unsigned int cmd, unsigned long arg)
-{
-	switch (cmd) {
-	case DTS_EAGLE_IOCTL_GET_CACHE_SIZE32:
-		cmd = DTS_EAGLE_IOCTL_GET_CACHE_SIZE;
-		break;
-	case DTS_EAGLE_IOCTL_SET_CACHE_SIZE32:
-		cmd = DTS_EAGLE_IOCTL_SET_CACHE_SIZE;
-		break;
-	case DTS_EAGLE_IOCTL_GET_PARAM32:
-		cmd = DTS_EAGLE_IOCTL_GET_PARAM;
-		break;
-	case DTS_EAGLE_IOCTL_SET_PARAM32:
-		cmd = DTS_EAGLE_IOCTL_SET_PARAM;
-		break;
-	case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK32:
-		cmd = DTS_EAGLE_IOCTL_SET_CACHE_BLOCK;
-		break;
-	case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE32:
-		cmd = DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE;
-		break;
-	case DTS_EAGLE_IOCTL_GET_LICENSE32:
-		cmd = DTS_EAGLE_IOCTL_GET_LICENSE;
-		break;
-	case DTS_EAGLE_IOCTL_SET_LICENSE32:
-		cmd = DTS_EAGLE_IOCTL_SET_LICENSE;
-		break;
-	case DTS_EAGLE_IOCTL_SEND_LICENSE32:
-		cmd = DTS_EAGLE_IOCTL_SEND_LICENSE;
-		break;
-	case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS32:
-		cmd = DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS;
-		break;
-	default:
-		break;
-	}
-	return msm_dts_eagle_ioctl(cmd, arg);
-}
-#endif
-/**
- * msm_dts_eagle_init_pre() - Initialize DTS premix module
- * @ac:	Initialize premix module in the ASM session.
- *
- * Initialize DTS premix module on provided ASM session
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_init_pre(struct audio_client *ac)
-{
-	return msm_dts_eagle_enable_asm(ac, _is_hpx_enabled,
-				 AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
-}
-
-/**
- * msm_dts_eagle_deinit_pre() - Deinitialize DTS premix module
- * @ac:	Deinitialize premix module in the ASM session.
- *
- * Deinitialize DTS premix module on provided ASM session
- *
- * Return: Currently does nothing so 0.
- */
-int msm_dts_eagle_deinit_pre(struct audio_client *ac)
-{
-	return 0;
-}
-
-/**
- * msm_dts_eagle_init_post() - Initialize DTS postmix module
- * @port_id:	Port id for the ADM session.
- * @copp_idx:	Copp idx for the ADM session.
- *
- * Initialize DTS postmix module on ADM session
- *
- * Return: Return failure if any.
- */
-int msm_dts_eagle_init_post(int port_id, int copp_idx)
-{
-	return msm_dts_eagle_enable_adm(port_id, copp_idx, _is_hpx_enabled);
-}
-
-/**
- * msm_dts_eagle_deinit_post() - Deinitialize DTS postmix module
- * @port_id:	Port id for the ADM session.
- * @topology:	Topology in use.
- *
- * Deinitialize DTS postmix module on ADM session
- *
- * Return: Currently does nothing so 0.
- */
-int msm_dts_eagle_deinit_post(int port_id, int topology)
-{
-	return 0;
-}
-
-/**
- * msm_dts_eagle_init_master_module() - Initialize both DTS modules
- * @ac:	Initialize modules in the ASM session.
- *
- * Initialize DTS modules on ASM session
- *
- * Return: Success.
- */
-int msm_dts_eagle_init_master_module(struct audio_client *ac)
-{
-	_set_audioclient(ac);
-	msm_dts_eagle_enable_asm(ac, _is_hpx_enabled,
-				 AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
-	msm_dts_eagle_enable_asm(ac, _is_hpx_enabled,
-				 AUDPROC_MODULE_ID_DTS_HPX_POSTMIX);
-	return 0;
-}
-
-/**
- * msm_dts_eagle_deinit_master_module() - Deinitialize both DTS modules
- * @ac:	Deinitialize modules in the ASM session.
- *
- * Deinitialize DTS modules on ASM session
- *
- * Return: Success.
- */
-int msm_dts_eagle_deinit_master_module(struct audio_client *ac)
-{
-	msm_dts_eagle_deinit_pre(ac);
-	msm_dts_eagle_deinit_post(-1, 0);
-	_clear_audioclient();
-	return 0;
-}
-
-/**
- * msm_dts_eagle_is_hpx_on() - Check if HPX effects are On
- *
- * Check if HPX effects are On
- *
- * Return: On/Off.
- */
-int msm_dts_eagle_is_hpx_on(void)
-{
-	return _is_hpx_enabled;
-}
-
-/**
- * msm_dts_eagle_pcm_new() - Create hwdep node
- * @runtime:	snd_soc_pcm_runtime structure.
- *
- * Create hwdep node
- *
- * Return: Success.
- */
-int msm_dts_eagle_pcm_new(struct snd_soc_pcm_runtime *runtime)
-{
-	if (!_ref_cnt++) {
-		_init_cb_descs();
-		_reg_ion_mem();
-	}
-	return 0;
-}
-
-/**
- * msm_dts_eagle_pcm_free() - remove hwdep node
- * @runtime:	snd_soc_pcm_runtime structure.
- *
- * Remove hwdep node
- *
- * Return: void.
- */
-void msm_dts_eagle_pcm_free(struct snd_pcm *pcm)
-{
-	if (!--_ref_cnt)
-		_unreg_ion_mem();
-	vfree(_depc);
-}
-
-MODULE_DESCRIPTION("DTS EAGLE platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.c b/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.c
index 5c6f1df..159f44c 100644
--- a/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dts-srs-tm-config.c
@@ -20,7 +20,6 @@
 #include <sound/control.h>
 #include <sound/q6adm-v2.h>
 #include <sound/asound.h>
-#include <sound/msm-dts-eagle.h>
 #include "msm-dts-srs-tm-config.h"
 #include "msm-pcm-routing-v2.h"
 
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 421769e..3a6cbe6 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -1313,7 +1313,7 @@
 		}
 
 		size = sizeof(*user) + userarg32.payload_size;
-		user = kmalloc(size, GFP_KERNEL);
+		user = kzalloc(size, GFP_KERNEL);
 		if (!user) {
 			dev_err(rtd->dev,
 				"%s: Allocation failed event status size %d\n",
@@ -1335,7 +1335,7 @@
 			err = -EFAULT;
 		}
 		if (!err) {
-			user32 = kmalloc(size, GFP_KERNEL);
+			user32 = kzalloc(size, GFP_KERNEL);
 			if (!user32) {
 				dev_err(rtd->dev,
 					"%s: Allocation event user status size %d\n",
@@ -1380,7 +1380,7 @@
 		}
 
 		size = sizeof(*user) + userarg32.payload_size;
-		user = kmalloc(size, GFP_KERNEL);
+		user = kzalloc(size, GFP_KERNEL);
 		if (!user) {
 			dev_err(rtd->dev,
 				"%s: Allocation failed event status size %d\n",
@@ -1400,7 +1400,7 @@
 			err = -EFAULT;
 		}
 		if (!err) {
-			user32 = kmalloc(size, GFP_KERNEL);
+			user32 = kzalloc(size, GFP_KERNEL);
 			if (!user32) {
 				dev_err(rtd->dev,
 					"%s: Allocation event user status size %d\n",
@@ -1810,7 +1810,7 @@
 
 		size = sizeof(struct snd_lsm_event_status) +
 		userarg.payload_size;
-		user = kmalloc(size, GFP_KERNEL);
+		user = kzalloc(size, GFP_KERNEL);
 		if (!user) {
 			dev_err(rtd->dev,
 				"%s: Allocation failed event status size %d\n",
@@ -1871,7 +1871,7 @@
 
 		size = sizeof(struct snd_lsm_event_status_v3) +
 			userarg.payload_size;
-		user = kmalloc(size, GFP_KERNEL);
+		user = kzalloc(size, GFP_KERNEL);
 		if (!user) {
 			dev_err(rtd->dev,
 				"%s: Allocation failed event status size %d\n",
@@ -2243,21 +2243,18 @@
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
 	int be_id = ucontrol->value.integer.value[3];
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
-	app_type = ucontrol->value.integer.value[0];
-	acdb_dev_id = ucontrol->value.integer.value[1];
-	sample_rate = ucontrol->value.integer.value[2];
+	cfg_data.app_type = ucontrol->value.integer.value[0];
+	cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
+	cfg_data.sample_rate = ucontrol->value.integer.value[2];
 
 	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
-						      be_id, app_type,
-						      acdb_dev_id, sample_rate);
+						      be_id, &cfg_data);
 	if (ret < 0)
 		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -2270,28 +2267,25 @@
 {
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
-	int be_id = ucontrol->value.integer.value[3];
+	int be_id = 0;
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
 	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
-						      be_id, &app_type,
-						      &acdb_dev_id,
-						      &sample_rate);
+						      &be_id, &cfg_data);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
 		goto done;
 	}
 
-	ucontrol->value.integer.value[0] = app_type;
-	ucontrol->value.integer.value[1] = acdb_dev_id;
-	ucontrol->value.integer.value[2] = sample_rate;
+	ucontrol->value.integer.value[0] = cfg_data.app_type;
+	ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+	ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+	ucontrol->value.integer.value[3] = be_id;
 	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 done:
 	return ret;
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
index f668e95..7ef1ca8 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -559,21 +559,18 @@
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_RX;
 	int be_id = ucontrol->value.integer.value[3];
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate = 48000;
 
-	app_type = ucontrol->value.integer.value[0];
-	acdb_dev_id = ucontrol->value.integer.value[1];
+	cfg_data.app_type = ucontrol->value.integer.value[0];
+	cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
-		sample_rate = ucontrol->value.integer.value[2];
+		cfg_data.sample_rate = ucontrol->value.integer.value[2];
 	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
-						      be_id, app_type,
-						      acdb_dev_id, sample_rate);
+						      be_id, &cfg_data);
 	if (ret < 0)
 		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -586,28 +583,25 @@
 {
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_RX;
-	int be_id = ucontrol->value.integer.value[3];
+	int be_id = 0;
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
 	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
-						      be_id, &app_type,
-						      &acdb_dev_id,
-						      &sample_rate);
+						      &be_id, &cfg_data);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
 		goto done;
 	}
 
-	ucontrol->value.integer.value[0] = app_type;
-	ucontrol->value.integer.value[1] = acdb_dev_id;
-	ucontrol->value.integer.value[2] = sample_rate;
+	ucontrol->value.integer.value[0] = cfg_data.app_type;
+	ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+	ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+	ucontrol->value.integer.value[3] = be_id;
 	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 done:
 	return ret;
 }
@@ -618,21 +612,18 @@
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
 	int be_id = ucontrol->value.integer.value[3];
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate = 48000;
 
-	app_type = ucontrol->value.integer.value[0];
-	acdb_dev_id = ucontrol->value.integer.value[1];
+	cfg_data.app_type = ucontrol->value.integer.value[0];
+	cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
-		sample_rate = ucontrol->value.integer.value[2];
+		cfg_data.sample_rate = ucontrol->value.integer.value[2];
 	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
-						      be_id, app_type,
-						      acdb_dev_id, sample_rate);
+						      be_id, &cfg_data);
 	if (ret < 0)
 		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -645,28 +636,25 @@
 {
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
-	int be_id = ucontrol->value.integer.value[3];
+	int be_id = 0;
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
 	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
-						      be_id, &app_type,
-						      &acdb_dev_id,
-						      &sample_rate);
+						      &be_id, &cfg_data);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
 		goto done;
 	}
 
-	ucontrol->value.integer.value[0] = app_type;
-	ucontrol->value.integer.value[1] = acdb_dev_id;
-	ucontrol->value.integer.value[2] = sample_rate;
+	ucontrol->value.integer.value[0] = cfg_data.app_type;
+	ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+	ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+	ucontrol->value.integer.value[3] = be_id;
 	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 done:
 	return ret;
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
index 9b7c6fb..325d642 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
@@ -842,26 +842,21 @@
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_RX;
 	int be_id = ucontrol->value.integer.value[3];
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate = 48000;
 
-	app_type = ucontrol->value.integer.value[0];
-	acdb_dev_id = ucontrol->value.integer.value[1];
+	cfg_data.app_type = ucontrol->value.integer.value[0];
+	cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
-		sample_rate = ucontrol->value.integer.value[2];
-
-	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
-						      be_id, app_type,
-						      acdb_dev_id, sample_rate);
-	if (ret < 0)
-		pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_put failed, err %d\n",
-			__func__, ret);
-
+		cfg_data.sample_rate = ucontrol->value.integer.value[2];
 	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &cfg_data);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+		       __func__, ret);
 	return ret;
 }
 
@@ -870,29 +865,25 @@
 {
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_RX;
-	int be_id = ucontrol->value.integer.value[3];
+	int be_id = 0;
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
 	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
-						      be_id, &app_type,
-						      &acdb_dev_id,
-						      &sample_rate);
+						      &be_id, &cfg_data);
 	if (ret < 0) {
-		pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_get failed, err: %d\n",
-			__func__, ret);
+		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+		       __func__, ret);
 		goto done;
 	}
 
-	ucontrol->value.integer.value[0] = app_type;
-	ucontrol->value.integer.value[1] = acdb_dev_id;
-	ucontrol->value.integer.value[2] = sample_rate;
-
+	ucontrol->value.integer.value[0] = cfg_data.app_type;
+	ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+	ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+	ucontrol->value.integer.value[3] = be_id;
 	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 done:
 	return ret;
 }
@@ -903,26 +894,21 @@
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
 	int be_id = ucontrol->value.integer.value[3];
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate = 48000;
 
-	app_type = ucontrol->value.integer.value[0];
-	acdb_dev_id = ucontrol->value.integer.value[1];
+	cfg_data.app_type = ucontrol->value.integer.value[0];
+	cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
-		sample_rate = ucontrol->value.integer.value[2];
-
-	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
-						      be_id, app_type,
-						      acdb_dev_id, sample_rate);
-	if (ret < 0)
-		pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_put failed, err: %d\n",
-			__func__, ret);
-
+		cfg_data.sample_rate = ucontrol->value.integer.value[2];
 	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
+	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+						      be_id, &cfg_data);
+	if (ret < 0)
+		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+		       __func__, ret);
 
 	return ret;
 }
@@ -932,28 +918,25 @@
 {
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
-	int be_id = ucontrol->value.integer.value[3];
+	int be_id = 0;
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
 	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
-						      be_id, &app_type,
-						      &acdb_dev_id,
-						      &sample_rate);
+						      &be_id, &cfg_data);
 	if (ret < 0) {
-		pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_get failed, err: %d\n",
-			__func__, ret);
+		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+		       __func__, ret);
 		goto done;
 	}
 
-	ucontrol->value.integer.value[0] = app_type;
-	ucontrol->value.integer.value[1] = acdb_dev_id;
-	ucontrol->value.integer.value[2] = sample_rate;
+	ucontrol->value.integer.value[0] = cfg_data.app_type;
+	ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+	ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+	ucontrol->value.integer.value[3] = be_id;
 	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 done:
 	return ret;
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 1799d0d..74e99d3 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -30,6 +30,7 @@
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/msm_audio_ion.h>
+#include <linux/msm_audio.h>
 
 #include <linux/of_device.h>
 #include <sound/tlv.h>
@@ -37,6 +38,7 @@
 
 #include "msm-pcm-q6-v2.h"
 #include "msm-pcm-routing-v2.h"
+#include "msm-qti-pp-config.h"
 
 enum stream_state {
 	IDLE = 0,
@@ -148,6 +150,8 @@
 	uint32_t idx = 0;
 	uint32_t size = 0;
 	uint8_t buf_index;
+	struct snd_soc_pcm_runtime *rtd;
+	int ret = 0;
 
 	switch (opcode) {
 	case ASM_DATA_EVENT_WRITE_DONE_V2: {
@@ -224,6 +228,29 @@
 		}
 		break;
 	}
+	case ASM_STREAM_PP_EVENT:
+	case ASM_STREAM_CMD_ENCDEC_EVENTS: {
+		pr_debug("%s: ASM_STREAM_EVENT (0x%x)\n", __func__, opcode);
+		if (!substream) {
+			pr_err("%s: substream is NULL.\n", __func__);
+			return;
+		}
+
+		rtd = substream->private_data;
+		if (!rtd) {
+			pr_err("%s: rtd is NULL\n", __func__);
+			return;
+		}
+
+		ret = msm_adsp_inform_mixer_ctl(rtd, payload);
+		if (ret) {
+			pr_err("%s: failed to inform mixer ctl. err = %d\n",
+				__func__, ret);
+			return;
+		}
+
+		break;
+	}
 	case APR_BASIC_RSP_RESULT: {
 		switch (payload[0]) {
 		case ASM_SESSION_CMD_RUN_V2:
@@ -253,6 +280,10 @@
 			}
 			atomic_set(&prtd->start, 1);
 			break;
+		case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
+			pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
+				__func__);
+			break;
 		default:
 			pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
 				__func__, payload[0], payload[1]);
@@ -661,6 +692,7 @@
 	prtd->set_channel_map = false;
 	prtd->reset_event = false;
 	runtime->private_data = prtd;
+	msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd);
 
 	return 0;
 }
@@ -803,6 +835,7 @@
 	}
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
 						SNDRV_PCM_STREAM_PLAYBACK);
+	msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
 	kfree(prtd);
 	runtime->private_data = NULL;
 
@@ -1036,6 +1069,182 @@
 	.mmap		= msm_pcm_mmap,
 };
 
+static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_platform *platform = snd_soc_component_to_platform(pcm);
+	struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+	struct snd_pcm_substream *substream;
+	struct msm_audio *prtd;
+	int ret = 0;
+	struct msm_adsp_event_data *event_data = NULL;
+
+	if (!pdata) {
+		pr_err("%s pdata is NULL\n", __func__);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	if (!substream) {
+		pr_err("%s substream not found\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (!substream->runtime) {
+		pr_err("%s substream runtime not found\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	prtd = substream->runtime->private_data;
+	if (prtd->audio_client == NULL) {
+		pr_err("%s prtd is null.\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
+	if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
+	    (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
+		pr_err("%s: invalid event_type=%d",
+			__func__, event_data->event_type);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >=
+					sizeof(ucontrol->value.bytes.data)) {
+		pr_err("%s param length=%d  exceeds limit",
+			__func__, event_data->payload_len);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
+	if (ret < 0)
+		pr_err("%s: failed to send stream event cmd, err = %d\n",
+			__func__, ret);
+done:
+	return ret;
+}
+
+static int msm_pcm_add_audio_adsp_stream_cmd_control(
+			struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = DSP_STREAM_CMD;
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_cmd_info,
+		.put = msm_pcm_adsp_stream_cmd_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s rtd is NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
+	fe_audio_adsp_stream_cmd_config_control[0].private_value =
+		rtd->dai_link->id;
+	pr_debug("Registering new mixer ctl %s\n", mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+		fe_audio_adsp_stream_cmd_config_control,
+		ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
+	if (ret < 0)
+		pr_err("%s: failed add ctl %s. err = %d\n",
+			__func__, mixer_str, ret);
+
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
+static int msm_pcm_add_audio_adsp_stream_callback_control(
+			struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol *kctl;
+
+	struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_callback_info,
+		.get = msm_adsp_stream_callback_get,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
+		 __func__, rtd->dai_link->name, rtd->dai_link->id,
+		 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_audio_adsp_callback_config_control[0].name = mixer_str;
+	fe_audio_adsp_callback_config_control[0].private_value =
+		rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+			fe_audio_adsp_callback_config_control,
+			ARRAY_SIZE(fe_audio_adsp_callback_config_control));
+	if (ret < 0) {
+		pr_err("%s: failed to add ctl %s. err = %d\n",
+			__func__, mixer_str, ret);
+		ret = -EINVAL;
+		goto free_mixer_str;
+	}
+
+	kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+	if (!kctl) {
+		pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
+		ret = -EINVAL;
+		goto free_mixer_str;
+	}
+
+	kctl->private_data = NULL;
+
+free_mixer_str:
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
 static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
 {
 	int rc = 0;
@@ -1347,21 +1556,18 @@
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_RX;
 	int be_id = ucontrol->value.integer.value[3];
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate = 48000;
 
-	app_type = ucontrol->value.integer.value[0];
-	acdb_dev_id = ucontrol->value.integer.value[1];
+	cfg_data.app_type = ucontrol->value.integer.value[0];
+	cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
-		sample_rate = ucontrol->value.integer.value[2];
+		cfg_data.sample_rate = ucontrol->value.integer.value[2];
 	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
-						      be_id, app_type,
-						      acdb_dev_id, sample_rate);
+						      be_id, &cfg_data);
 	if (ret < 0)
 		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -1374,28 +1580,25 @@
 {
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_RX;
-	int be_id = ucontrol->value.integer.value[3];
+	int be_id = 0;
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
 	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
-						      be_id, &app_type,
-						      &acdb_dev_id,
-						      &sample_rate);
+						      &be_id, &cfg_data);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
 		goto done;
 	}
 
-	ucontrol->value.integer.value[0] = app_type;
-	ucontrol->value.integer.value[1] = acdb_dev_id;
-	ucontrol->value.integer.value[2] = sample_rate;
+	ucontrol->value.integer.value[0] = cfg_data.app_type;
+	ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+	ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+	ucontrol->value.integer.value[3] = be_id;
 	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 done:
 	return ret;
 }
@@ -1406,21 +1609,18 @@
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
 	int be_id = ucontrol->value.integer.value[3];
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate = 48000;
 
-	app_type = ucontrol->value.integer.value[0];
-	acdb_dev_id = ucontrol->value.integer.value[1];
+	cfg_data.app_type = ucontrol->value.integer.value[0];
+	cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
 	if (ucontrol->value.integer.value[2] != 0)
-		sample_rate = ucontrol->value.integer.value[2];
+		cfg_data.sample_rate = ucontrol->value.integer.value[2];
 	pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 	ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
-						      be_id, app_type,
-						      acdb_dev_id, sample_rate);
+						      be_id, &cfg_data);
 	if (ret < 0)
 		pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
@@ -1433,28 +1633,25 @@
 {
 	u64 fe_id = kcontrol->private_value;
 	int session_type = SESSION_TYPE_TX;
-	int be_id = ucontrol->value.integer.value[3];
+	int be_id = 0;
+	struct msm_pcm_stream_app_type_cfg cfg_data = {0};
 	int ret = 0;
-	int app_type;
-	int acdb_dev_id;
-	int sample_rate;
 
 	ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
-						      be_id, &app_type,
-						      &acdb_dev_id,
-						      &sample_rate);
+						      &be_id, &cfg_data);
 	if (ret < 0) {
 		pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
 			__func__, ret);
 		goto done;
 	}
 
-	ucontrol->value.integer.value[0] = app_type;
-	ucontrol->value.integer.value[1] = acdb_dev_id;
-	ucontrol->value.integer.value[2] = sample_rate;
+	ucontrol->value.integer.value[0] = cfg_data.app_type;
+	ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+	ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+	ucontrol->value.integer.value[3] = be_id;
 	pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fe_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
 done:
 	return ret;
 }
@@ -1550,6 +1747,16 @@
 		pr_err("%s: Could not add pcm Compress Control %d\n",
 			__func__, ret);
 
+	ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
+	if (ret)
+		pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
+			__func__);
+
+	ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
+	if (ret)
+		pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
+			__func__);
+
 	return ret;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.c
index 1dfbd7a..7335951 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-devdep.c
@@ -16,8 +16,6 @@
 #include <linux/module.h>
 #include <sound/hwdep.h>
 #include <sound/devdep_params.h>
-#include <sound/msm-dts-eagle.h>
-
 #include "msm-pcm-routing-devdep.h"
 #include "msm-ds2-dap-config.h"
 
@@ -56,23 +54,6 @@
 	case SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER:
 		ret = msm_ds2_dap_ioctl(hw, file, cmd, argp);
 		break;
-	case DTS_EAGLE_IOCTL_GET_CACHE_SIZE:
-	case DTS_EAGLE_IOCTL_SET_CACHE_SIZE:
-	case DTS_EAGLE_IOCTL_GET_PARAM:
-	case DTS_EAGLE_IOCTL_SET_PARAM:
-	case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK:
-	case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE:
-	case DTS_EAGLE_IOCTL_GET_LICENSE:
-	case DTS_EAGLE_IOCTL_SET_LICENSE:
-	case DTS_EAGLE_IOCTL_SEND_LICENSE:
-	case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS:
-		ret = msm_dts_eagle_ioctl(cmd, arg);
-		if (ret == -EPERM) {
-			pr_err("%s called with invalid control 0x%X\n",
-				__func__, cmd);
-			ret = -EINVAL;
-		}
-		break;
 	default:
 		pr_err("%s called with invalid control 0x%X\n", __func__, cmd);
 		ret = -EINVAL;
@@ -84,7 +65,6 @@
 void msm_pcm_routing_hwdep_free(struct snd_pcm *pcm)
 {
 	pr_debug("%s\n", __func__);
-	msm_dts_eagle_pcm_free(pcm);
 }
 
 #ifdef CONFIG_COMPAT
@@ -109,23 +89,6 @@
 	case SNDRV_DEVDEP_DAP_IOCTL_GET_VISUALIZER32:
 		ret = msm_ds2_dap_compat_ioctl(hw, file, cmd, argp);
 		break;
-	case DTS_EAGLE_IOCTL_GET_CACHE_SIZE32:
-	case DTS_EAGLE_IOCTL_SET_CACHE_SIZE32:
-	case DTS_EAGLE_IOCTL_GET_PARAM32:
-	case DTS_EAGLE_IOCTL_SET_PARAM32:
-	case DTS_EAGLE_IOCTL_SET_CACHE_BLOCK32:
-	case DTS_EAGLE_IOCTL_SET_ACTIVE_DEVICE32:
-	case DTS_EAGLE_IOCTL_GET_LICENSE32:
-	case DTS_EAGLE_IOCTL_SET_LICENSE32:
-	case DTS_EAGLE_IOCTL_SEND_LICENSE32:
-	case DTS_EAGLE_IOCTL_SET_VOLUME_COMMANDS32:
-		ret = msm_dts_eagle_compat_ioctl(cmd, arg);
-		if (ret == -EPERM) {
-			pr_err("%s called with invalid control 0x%X\n",
-				__func__, cmd);
-			ret = -EINVAL;
-		}
-		break;
 	default:
 		pr_err("%s called with invalid control 0x%X\n", __func__, cmd);
 		ret = -EINVAL;
@@ -171,6 +134,6 @@
 #ifdef CONFIG_COMPAT
 	hwdep->ops.ioctl_compat = msm_pcm_routing_hwdep_compat_ioctl;
 #endif
-	return msm_dts_eagle_pcm_new(runtime);
+	return rc;
 }
 #endif
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 04ece53c..d67296f 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -33,7 +33,6 @@
 #include <sound/pcm_params.h>
 #include <sound/q6core.h>
 #include <sound/audio_cal_utils.h>
-#include <sound/msm-dts-eagle.h>
 #include <sound/audio_effects.h>
 #include <sound/hwdep.h>
 
@@ -80,6 +79,13 @@
 static int msm_route_ext_ec_ref;
 static bool is_custom_stereo_on;
 static bool is_ds2_on;
+static bool swap_ch;
+
+#define WEIGHT_0_DB 0x4000
+/* all the FEs which can support channel mixer */
+static struct msm_pcm_channel_mixer channel_mixer[MSM_FRONTEND_DAI_MM_SIZE];
+/* input BE for each FE */
+static int channel_input[MSM_FRONTEND_DAI_MM_SIZE][ADM_MAX_CHANNELS];
 
 enum {
 	MADNONE,
@@ -136,7 +142,8 @@
 };
 static struct msm_pcm_route_bdai_name be_dai_name_table[MSM_BACKEND_DAI_MAX];
 
-static int msm_routing_send_device_pp_params(int port_id,  int copp_idx);
+static int msm_routing_send_device_pp_params(int port_id,  int copp_idx,
+					     int fe_id);
 
 static int msm_routing_get_bit_width(unsigned int format)
 {
@@ -208,10 +215,6 @@
 					__func__, topology, port_id, rc);
 		}
 		break;
-	case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX:
-		pr_debug("%s: DTS_EAGLE_COPP_TOPOLOGY_ID\n", __func__);
-		msm_dts_eagle_init_post(port_id, copp_idx);
-		break;
 	case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE:
 		pr_debug("%s: TOPOLOGY_ID_AUDIOSPHERE\n", __func__);
 		rc = msm_qti_pp_asphere_init(port_id, copp_idx);
@@ -246,10 +249,6 @@
 			msm_dolby_dap_deinit(port_id);
 		}
 		break;
-	case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX:
-		pr_debug("%s: DTS_EAGLE_COPP_TOPOLOGY_ID\n", __func__);
-		msm_dts_eagle_deinit_post(port_id, topology);
-		break;
 	case ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE:
 		pr_debug("%s: TOPOLOGY_ID_AUDIOSPHERE\n", __func__);
 		msm_qti_pp_asphere_deinit(port_id);
@@ -291,253 +290,256 @@
 
 #define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
 struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
-	{ PRIMARY_I2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_RX},
-	{ PRIMARY_I2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_TX},
-	{ SLIMBUS_0_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_RX},
-	{ SLIMBUS_0_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_TX},
-	{ HDMI_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_HDMI},
-	{ INT_BT_SCO_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_RX},
-	{ INT_BT_SCO_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_TX},
-	{ INT_FM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_RX},
-	{ INT_FM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_TX},
-	{ RT_PROXY_PORT_001_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ PRIMARY_I2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_PRI_I2S_RX},
+	{ PRIMARY_I2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_PRI_I2S_TX},
+	{ SLIMBUS_0_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_0_RX},
+	{ SLIMBUS_0_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_0_TX},
+	{ HDMI_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_HDMI},
+	{ INT_BT_SCO_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_INT_BT_SCO_RX},
+	{ INT_BT_SCO_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_INT_BT_SCO_TX},
+	{ INT_FM_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_INT_FM_RX},
+	{ INT_FM_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_INT_FM_TX},
+	{ RT_PROXY_PORT_001_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_AFE_PCM_RX},
-	{ RT_PROXY_PORT_001_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ RT_PROXY_PORT_001_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_AFE_PCM_TX},
-	{ AFE_PORT_ID_PRIMARY_PCM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_PCM_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_AUXPCM_RX},
-	{ AFE_PORT_ID_PRIMARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_AUXPCM_TX},
-	{ VOICE_PLAYBACK_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ VOICE_PLAYBACK_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_VOICE_PLAYBACK_TX},
-	{ VOICE2_PLAYBACK_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ VOICE2_PLAYBACK_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_VOICE2_PLAYBACK_TX},
-	{ VOICE_RECORD_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ VOICE_RECORD_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INCALL_RECORD_RX},
-	{ VOICE_RECORD_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ VOICE_RECORD_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INCALL_RECORD_TX},
-	{ MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_MI2S_RX},
-	{ MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_MI2S_TX},
-	{ SECONDARY_I2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SEC_I2S_RX},
-	{ SLIMBUS_1_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_RX},
-	{ SLIMBUS_1_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_TX},
-	{ SLIMBUS_2_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_RX},
-	{ SLIMBUS_2_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_TX},
-	{ SLIMBUS_3_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_RX},
-	{ SLIMBUS_3_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_TX},
-	{ SLIMBUS_4_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_RX},
-	{ SLIMBUS_4_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_TX},
-	{ SLIMBUS_5_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_RX},
-	{ SLIMBUS_5_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_TX},
-	{ SLIMBUS_6_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_RX},
-	{ SLIMBUS_6_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_TX},
-	{ SLIMBUS_7_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_RX},
-	{ SLIMBUS_7_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_TX},
-	{ SLIMBUS_8_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_RX},
-	{ SLIMBUS_8_TX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX},
-	{ SLIMBUS_EXTPROC_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_RX},
-	{ SLIMBUS_EXTPROC_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_TX},
-	{ SLIMBUS_EXTPROC_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_1_TX},
-	{ AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_MI2S_RX},
+	{ MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_MI2S_TX},
+	{ SECONDARY_I2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SEC_I2S_RX},
+	{ SLIMBUS_1_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_1_RX},
+	{ SLIMBUS_1_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_1_TX},
+	{ SLIMBUS_2_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_2_RX},
+	{ SLIMBUS_2_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_2_TX},
+	{ SLIMBUS_3_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_3_RX},
+	{ SLIMBUS_3_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_3_TX},
+	{ SLIMBUS_4_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_4_RX},
+	{ SLIMBUS_4_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_4_TX},
+	{ SLIMBUS_5_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_5_RX},
+	{ SLIMBUS_5_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_5_TX},
+	{ SLIMBUS_6_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_6_RX},
+	{ SLIMBUS_6_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_6_TX},
+	{ SLIMBUS_7_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_7_RX},
+	{ SLIMBUS_7_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_7_TX},
+	{ SLIMBUS_8_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_8_RX},
+	{ SLIMBUS_8_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SLIMBUS_8_TX},
+	{ SLIMBUS_EXTPROC_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_STUB_RX},
+	{ SLIMBUS_EXTPROC_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_STUB_TX},
+	{ SLIMBUS_EXTPROC_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_STUB_1_TX},
+	{ AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_MI2S_RX},
-	{ AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_MI2S_TX},
-	{ AFE_PORT_ID_SECONDARY_MI2S_RX,  0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_MI2S_RX,  0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_MI2S_RX},
-	{ AFE_PORT_ID_SECONDARY_MI2S_TX,  0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_MI2S_TX,  0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_MI2S_TX},
-	{ AFE_PORT_ID_PRIMARY_MI2S_RX,    0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_MI2S_RX,    0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_MI2S_RX},
-	{ AFE_PORT_ID_PRIMARY_MI2S_TX,    0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_MI2S_TX,    0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_MI2S_TX},
-	{ AFE_PORT_ID_TERTIARY_MI2S_RX,   0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_MI2S_RX,   0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_MI2S_RX},
-	{ AFE_PORT_ID_TERTIARY_MI2S_TX,   0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_MI2S_TX,   0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_MI2S_TX},
-	{ AUDIO_PORT_ID_I2S_RX,           0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AUDIO_PORT_ID_I2S_RX,           0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_AUDIO_I2S_RX},
-	{ AFE_PORT_ID_SECONDARY_PCM_RX,	  0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_PCM_RX,	  0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_AUXPCM_RX},
-	{ AFE_PORT_ID_SECONDARY_PCM_TX,   0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_PCM_TX,   0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_AUXPCM_TX},
-	{ AFE_PORT_ID_SPDIF_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_SPDIF_RX},
-	{ AFE_PORT_ID_SECONDARY_MI2S_RX_SD1, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SPDIF_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
+	  LPASS_BE_SPDIF_RX},
+	{ AFE_PORT_ID_SECONDARY_MI2S_RX_SD1, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_MI2S_RX_SD1},
-	{ AFE_PORT_ID_QUINARY_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUINARY_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUIN_MI2S_RX},
-	{ AFE_PORT_ID_QUINARY_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUINARY_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUIN_MI2S_TX},
-	{ AFE_PORT_ID_SENARY_MI2S_TX,   0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SENARY_MI2S_TX,   0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SENARY_MI2S_TX},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_RX_0},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_TX_0},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_RX_1},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_TX_1},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_RX_2},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_TX_2},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_RX_3},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_TX_3},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_RX_4},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_TX_4},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_RX_5},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_TX_5},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_RX_6},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_TX_6},
-	{ AFE_PORT_ID_PRIMARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_RX_7},
-	{ AFE_PORT_ID_PRIMARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_PRIMARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_PRI_TDM_TX_7},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_RX_0},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_TX_0},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_RX_1},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_TX_1},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_RX_2},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_TX_2},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_RX_3},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_TX_3},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_RX_4},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_TX_4},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_RX_5},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_TX_5},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_RX_6},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_TX_6},
-	{ AFE_PORT_ID_SECONDARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_RX_7},
-	{ AFE_PORT_ID_SECONDARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_SECONDARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_SEC_TDM_TX_7},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_RX_0},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_TX_0},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_RX_1},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_TX_1},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_RX_2},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_TX_2},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_RX_3},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_TX_3},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_RX_4},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_TX_4},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_RX_5},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_TX_5},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_RX_6},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_TX_6},
-	{ AFE_PORT_ID_TERTIARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_RX_7},
-	{ AFE_PORT_ID_TERTIARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_TDM_TX_7},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_RX_0},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_TX_0},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_1, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_RX_1},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_1, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_TX_1},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_2, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_RX_2},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_2, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_TX_2},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_3, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_RX_3},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_3, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_TX_3},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_4, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_RX_4},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_4, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_TX_4},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_5, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_RX_5},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_5, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_TX_5},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_6, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_RX_6},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_6, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_TX_6},
-	{ AFE_PORT_ID_QUATERNARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_RX_7, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_RX_7},
-	{ AFE_PORT_ID_QUATERNARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_TDM_TX_7, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_TDM_TX_7},
-	{ INT_BT_A2DP_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_A2DP_RX},
-	{ AFE_PORT_ID_USB_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ INT_BT_A2DP_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
+	  LPASS_BE_INT_BT_A2DP_RX},
+	{ AFE_PORT_ID_USB_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_USB_AUDIO_RX},
-	{ AFE_PORT_ID_USB_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_USB_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_USB_AUDIO_TX},
-	{ DISPLAY_PORT_RX, 0, {0}, {0}, 0, 0, 0, 0, 0, LPASS_BE_DISPLAY_PORT},
-	{ AFE_PORT_ID_TERTIARY_PCM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ DISPLAY_PORT_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
+	  LPASS_BE_DISPLAY_PORT},
+	{ AFE_PORT_ID_TERTIARY_PCM_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_AUXPCM_RX},
-	{ AFE_PORT_ID_TERTIARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_TERTIARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_TERT_AUXPCM_TX},
-	{ AFE_PORT_ID_QUATERNARY_PCM_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_PCM_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_AUXPCM_RX},
-	{ AFE_PORT_ID_QUATERNARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_QUATERNARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_QUAT_AUXPCM_TX},
-	{ AFE_PORT_ID_INT0_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT0_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT0_MI2S_RX},
-	{ AFE_PORT_ID_INT0_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT0_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT0_MI2S_TX},
-	{ AFE_PORT_ID_INT1_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT1_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT1_MI2S_RX},
-	{ AFE_PORT_ID_INT1_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT1_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT1_MI2S_TX},
-	{ AFE_PORT_ID_INT2_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT2_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT2_MI2S_RX},
-	{ AFE_PORT_ID_INT2_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT2_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT2_MI2S_TX},
-	{ AFE_PORT_ID_INT3_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT3_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT3_MI2S_RX},
-	{ AFE_PORT_ID_INT3_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT3_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT3_MI2S_TX},
-	{ AFE_PORT_ID_INT4_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT4_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT4_MI2S_RX},
-	{ AFE_PORT_ID_INT4_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT4_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT4_MI2S_TX},
-	{ AFE_PORT_ID_INT5_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT5_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT5_MI2S_RX},
-	{ AFE_PORT_ID_INT5_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT5_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT5_MI2S_TX},
-	{ AFE_PORT_ID_INT6_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT6_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT6_MI2S_RX},
-	{ AFE_PORT_ID_INT6_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, 0,
+	{ AFE_PORT_ID_INT6_MI2S_TX, 0, {0}, {0}, 0, 0, 0, 0, {0},
 	  LPASS_BE_INT6_MI2S_TX},
 };
 
@@ -603,6 +605,9 @@
 	/* MULTIMEDIA19 */
 	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
 	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+	/* MULTIMEDIA20 */
+	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
 	/* CS_VOICE */
 	{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
 	 {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
@@ -678,6 +683,8 @@
 static struct msm_pcm_stream_app_type_cfg
 	fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MAX][2][MSM_BACKEND_DAI_MAX];
 
+static int last_be_id_configured[MSM_FRONTEND_DAI_MAX][MAX_SESSION_TYPES];
+
 /* The caller of this should aqcuire routing lock */
 void msm_pcm_routing_get_bedai_info(int be_idx,
 				    struct msm_pcm_routing_bdai_data *be_dai)
@@ -744,15 +751,22 @@
 	return rc;
 }
 
-int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
-					    int be_id, int app_type,
-					    int acdb_dev_id, int sample_rate)
+int msm_pcm_routing_reg_stream_app_type_cfg(
+	int fedai_id, int session_type, int be_id,
+	struct msm_pcm_stream_app_type_cfg *cfg_data)
 {
 	int ret = 0;
 
+	if (cfg_data == NULL) {
+		pr_err("%s: Received NULL pointer for cfg_data\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
 	pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
 		__func__, fedai_id, session_type, be_id,
-		app_type, acdb_dev_id, sample_rate);
+		cfg_data->app_type, cfg_data->acdb_dev_id,
+		cfg_data->sample_rate);
 
 	if (!is_mm_lsm_fe_id(fedai_id)) {
 		pr_err("%s: Invalid machine driver ID %d\n",
@@ -774,15 +788,18 @@
 		goto done;
 	}
 
-	fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type = app_type;
-	fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id =
-		acdb_dev_id;
-	fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate =
-		sample_rate;
+	fe_dai_app_type_cfg[fedai_id][session_type][be_id] = *cfg_data;
+
+	/*
+	 * Store the BE ID of the configuration information set as the latest so
+	 * the get mixer control knows what to return.
+	 */
+	last_be_id_configured[fedai_id][session_type] = be_id;
 
 done:
 	return ret;
 }
+EXPORT_SYMBOL(msm_pcm_routing_reg_stream_app_type_cfg);
 
 /**
  * msm_pcm_routing_get_stream_app_type_cfg
@@ -794,55 +811,48 @@
  * fedai_id - Passed value, front end ID for which app type config is wanted
  * session_type - Passed value, session type for which app type config
  *                is wanted
- * be_id - Passed value, back end device id for which app type config is wanted
- * app_type - Returned value, app type used by app type config
- * acdb_dev_id - Returned value, ACDB device ID used by app type config
- * sample_rate - Returned value, sample rate used by app type config
+ * be_id - Returned value, back end device id the app type config data is for
+ * cfg_data - Returned value, configuration data used by app type config
  */
-int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
-					    int be_id, int *app_type,
-					    int *acdb_dev_id, int *sample_rate)
+int msm_pcm_routing_get_stream_app_type_cfg(
+	int fedai_id, int session_type, int *bedai_id,
+	struct msm_pcm_stream_app_type_cfg *cfg_data)
 {
+	int be_id;
 	int ret = 0;
 
-	if (app_type == NULL) {
-		pr_err("%s: NULL pointer sent for app_type\n", __func__);
+	if (bedai_id == NULL) {
+		pr_err("%s: Received NULL pointer for backend ID\n", __func__);
 		ret = -EINVAL;
 		goto done;
-	} else if (acdb_dev_id == NULL) {
-		pr_err("%s: NULL pointer sent for acdb_dev_id\n", __func__);
-		ret = -EINVAL;
-		goto done;
-	} else if (sample_rate == NULL) {
-		pr_err("%s: NULL pointer sent for sample rate\n", __func__);
+	} else if (cfg_data == NULL) {
+		pr_err("%s: NULL pointer sent for cfg_data\n", __func__);
 		ret = -EINVAL;
 		goto done;
 	} else if (!is_mm_lsm_fe_id(fedai_id)) {
-		pr_err("%s: Invalid FE ID %d\n",
-			__func__, fedai_id);
+		pr_err("%s: Invalid FE ID %d\n", __func__, fedai_id);
 		ret = -EINVAL;
 		goto done;
 	} else if (session_type != SESSION_TYPE_RX &&
 		   session_type != SESSION_TYPE_TX) {
-		pr_err("%s: Invalid session type %d\n",
-			__func__, session_type);
+		pr_err("%s: Invalid session type %d\n", __func__, session_type);
 		ret = -EINVAL;
 		goto done;
-	} else if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
-		pr_err("%s: Received out of bounds be_id %d\n",
-			__func__, be_id);
-		return -EINVAL;
 	}
 
-	*app_type = fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type;
-	*acdb_dev_id =
-		fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id;
-	*sample_rate =
-		fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate;
+	be_id = last_be_id_configured[fedai_id][session_type];
+	if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+		pr_err("%s: Invalid BE ID %d\n", __func__, be_id);
+		ret = -EINVAL;
+		goto done;
+	}
 
+	*bedai_id = be_id;
+	*cfg_data = fe_dai_app_type_cfg[fedai_id][session_type][be_id];
 	pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
-		__func__, fedai_id, session_type, be_id,
-		*app_type, *acdb_dev_id, *sample_rate);
+		__func__, fedai_id, session_type, *bedai_id,
+		cfg_data->app_type, cfg_data->acdb_dev_id,
+		cfg_data->sample_rate);
 done:
 	return ret;
 }
@@ -1083,7 +1093,10 @@
 		port_type = MSM_AFE_PORT_TYPE_RX;
 	} else if (stream_type == SNDRV_PCM_STREAM_CAPTURE) {
 		session_type = SESSION_TYPE_TX;
-		path_type = ADM_PATH_LIVE_REC;
+		if (passthr_mode != LEGACY_PCM)
+			path_type = ADM_PATH_COMPRESSED_TX;
+		else
+			path_type = ADM_PATH_LIVE_REC;
 		port_type = MSM_AFE_PORT_TYPE_TX;
 	} else {
 		pr_err("%s: invalid stream type %d\n", __func__, stream_type);
@@ -1100,7 +1113,7 @@
 	msm_qti_pp_send_eq_values(fe_id);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
 		if (test_bit(fe_id, &msm_bedais[i].fe_sessions[0]))
-			msm_bedais[i].passthr_mode = passthr_mode;
+			msm_bedais[i].passthr_mode[fe_id] = passthr_mode;
 
 		if (!is_be_dai_extproc(i) &&
 			(afe_get_port_type(msm_bedais[i].port_id) ==
@@ -1204,7 +1217,7 @@
 			    COMPRESSED_PASSTHROUGH_GEN) {
 				msm_routing_send_device_pp_params(
 				msm_bedais[i].port_id,
-				copp_idx);
+				copp_idx, fe_id);
 			}
 		}
 	}
@@ -1255,6 +1268,62 @@
 	return session_id;
 }
 
+static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode,
+				int dspst_id, int stream_type)
+{
+	int copp_idx = 0;
+	int sess_type = 0;
+	int i = 0, j = 0, be_id;
+	int ret = 0;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return 0;
+	}
+
+	if (!(channel_mixer[fe_id].enable)) {
+		pr_debug("%s: channel mixer not enabled for FE %d\n",
+			__func__, fe_id);
+		return 0;
+	}
+
+	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+		sess_type = SESSION_TYPE_RX;
+	else
+		sess_type = SESSION_TYPE_TX;
+
+	for (i = 0; i < ADM_MAX_CHANNELS && channel_input[fe_id][i] > 0;
+		++i) {
+		be_id = channel_input[fe_id][i] - 1;
+		channel_mixer[fe_id].input_channels[i] =
+						msm_bedais[be_id].channel;
+
+		if ((msm_bedais[be_id].active) &&
+			test_bit(fe_id,
+			&msm_bedais[be_id].fe_sessions[0])) {
+			unsigned long copp =
+				session_copp_map[fe_id][sess_type][be_id];
+			for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
+				if (test_bit(j, &copp)) {
+					copp_idx = j;
+					break;
+				}
+			}
+
+			pr_debug("%s: fe %d, be %d, channel %d, copp %d\n",
+				__func__,
+				fe_id, be_id, msm_bedais[be_id].channel,
+				copp_idx);
+			ret = adm_programable_channel_mixer(
+					msm_bedais[be_id].port_id,
+					copp_idx, dspst_id, sess_type,
+					channel_mixer + fe_id, i);
+		}
+	}
+
+	return ret;
+}
+
 int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
 					int dspst_id, int stream_type)
 {
@@ -1263,6 +1332,7 @@
 	u32 channels, sample_rate;
 	uint16_t bits_per_sample = 16;
 	uint32_t passthr_mode = LEGACY_PCM;
+	int ret = 0;
 
 	if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
 		/* bad ID assigned in machine driver */
@@ -1302,7 +1372,7 @@
 				channels = msm_bedais[i].channel;
 			else
 				channels = msm_bedais[i].adm_override_ch;
-			msm_bedais[i].passthr_mode =
+			msm_bedais[i].passthr_mode[fedai_id] =
 				LEGACY_PCM;
 
 			bits_per_sample = msm_routing_get_bit_width(
@@ -1373,7 +1443,7 @@
 				}
 			}
 			if ((perf_mode == LEGACY_PCM_MODE) &&
-				(msm_bedais[i].passthr_mode ==
+				(msm_bedais[i].passthr_mode[fedai_id] ==
 				LEGACY_PCM))
 				msm_pcm_routing_cfg_pp(msm_bedais[i].port_id,
 						       copp_idx, topology,
@@ -1386,8 +1456,11 @@
 		adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
 		msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
 	}
+
+	ret = msm_pcm_routing_channel_mixer(fedai_id, perf_mode,
+				dspst_id, stream_type);
 	mutex_unlock(&routing_lock);
-	return 0;
+	return ret;
 }
 
 int msm_pcm_routing_reg_phy_stream_v2(int fedai_id, int perf_mode,
@@ -1458,7 +1531,7 @@
 			if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID ||
 				topology == DS2_ADM_COPP_TOPOLOGY_ID) &&
 			    (fdai->perf_mode == LEGACY_PCM_MODE) &&
-			    (msm_bedais[i].passthr_mode ==
+			    (msm_bedais[i].passthr_mode[fedai_id] ==
 					LEGACY_PCM))
 				msm_pcm_routing_deinit_pp(msm_bedais[i].port_id,
 							  topology);
@@ -1493,7 +1566,7 @@
 	u32 channels, sample_rate;
 	uint16_t bits_per_sample = 16;
 	struct msm_pcm_routing_fdai_data *fdai;
-	uint32_t passthr_mode = msm_bedais[reg].passthr_mode;
+	uint32_t passthr_mode;
 	bool is_lsm;
 
 	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -1510,6 +1583,7 @@
 		return;
 	}
 
+	passthr_mode = msm_bedais[reg].passthr_mode[val];
 	if (afe_get_port_type(msm_bedais[reg].port_id) ==
 		MSM_AFE_PORT_TYPE_RX) {
 		session_type = SESSION_TYPE_RX;
@@ -1519,7 +1593,10 @@
 			path_type = ADM_PATH_PLAYBACK;
 	} else {
 		session_type = SESSION_TYPE_TX;
-		path_type = ADM_PATH_LIVE_REC;
+		if (passthr_mode != LEGACY_PCM)
+			path_type = ADM_PATH_COMPRESSED_TX;
+		else
+			path_type = ADM_PATH_LIVE_REC;
 	}
 	is_lsm = (val >= MSM_FRONTEND_DAI_LSM1) &&
 			 (val <= MSM_FRONTEND_DAI_LSM8);
@@ -2618,6 +2695,649 @@
 	return 1;
 }
 
+static int msm_pcm_get_channel_rule_index(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	u16 fe_id = 0;
+
+	fe_id = ((struct soc_mixer_control *)
+			kcontrol->private_value)->shift;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+
+	ucontrol->value.integer.value[0] = channel_mixer[fe_id].rule;
+
+	return 0;
+}
+
+static int msm_pcm_put_channel_rule_index(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	u16 fe_id = 0;
+
+	fe_id = ((struct soc_mixer_control *)
+			kcontrol->private_value)->shift;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+
+	channel_mixer[fe_id].rule = ucontrol->value.integer.value[0];
+
+	return 1;
+}
+
+static int msm_pcm_get_out_chs(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u16 fe_id = 0;
+
+	fe_id = ((struct soc_multi_mixer_control *)
+			kcontrol->private_value)->shift;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+
+	ucontrol->value.integer.value[0] =
+		channel_mixer[fe_id].output_channel;
+	return 0;
+}
+
+static int msm_pcm_put_out_chs(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u16 fe_id = 0;
+
+	fe_id = ((struct soc_multi_mixer_control *)
+			kcontrol->private_value)->shift;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: fe_id is %d, output channels = %d\n", __func__,
+			fe_id,
+			(unsigned int)(ucontrol->value.integer.value[0]));
+	channel_mixer[fe_id].output_channel =
+			(unsigned int)(ucontrol->value.integer.value[0]);
+
+	return 1;
+}
+
+static const char *const ch_mixer[] = {"Disable", "Enable"};
+
+/* If new backend is added, need update this array */
+static const char *const be_name[] = {
+"ZERO", "PRI_I2S_RX", "PRI_I2S_TX", "SLIM_0_RX",
+"SLIM_0_TX", "HDMI_RX", "INT_BT_SCO_RX", "INT_BT_SCO_TX",
+"INT_FM_RX", "INT_FM_TX", "AFE_PCM_RX", "AFE_PCM_TX",
+"AUXPCM_RX", "AUXPCM_TX", "VOICE_PLAYBACK_TX", "VOICE2_PLAYBACK_TX",
+"INCALL_RECORD_RX", "INCALL_RECORD_TX", "MI2S_RX", "MI2S_TX",
+"SEC_I2S_RX", "SLIM_1_RX", "SLIM_1_TX", "SLIM_2_RX",
+"SLIM_2_TX", "SLIM_3_RX", "SLIM_3_TX", "SLIM_4_RX",
+"SLIM_4_TX", "SLIM_5_RX", "SLIM_5_TX", "SLIM_6_RX",
+"SLIM_6_TX", "SLIM_7_RX", "SLIM_7_TX", "SLIM_8_RX",
+"SLIM_8_TX", "EXTPROC_RX", "EXTPROC_TX", "EXPROC_EC_TX",
+"QUAT_MI2S_RX", "QUAT_MI2S_TX", "SECOND_MI2S_RX", "SECOND_MI2S_TX",
+"PRI_MI2S_RX", "PRI_MI2S_TX", "TERT_MI2S_RX", "TERT_MI2S_TX",
+"AUDIO_I2S_RX", "SEC_AUXPCM_RX", "SEC_AUXPCM_TX", "SPDIF_RX",
+"SECOND_MI2S_RX_SD1", "QUIN_MI2S_RX", "QUIN_MI2S_TX", "SENARY_MI2S_TX",
+"PRI_TDM_RX_0", "PRI_TDM_TX_0", "PRI_TDM_RX_1", "PRI_TDM_TX_1",
+"PRI_TDM_RX_2", "PRI_TDM_TX_2", "PRI_TDM_RX_3", "PRI_TDM_TX_3",
+"PRI_TDM_RX_4", "PRI_TDM_TX_4", "PRI_TDM_RX_5", "PRI_TDM_TX_5",
+"PRI_TDM_RX_6", "PRI_TDM_TX_6", "PRI_TDM_RX_7", "PRI_TDM_TX_7",
+"SEC_TDM_RX_0", "SEC_TDM_TX_0", "SEC_TDM_RX_1", "SEC_TDM_TX_1",
+"SEC_TDM_RX_2", "SEC_TDM_TX_2", "SEC_TDM_RX_3", "SEC_TDM_TX_3",
+"SEC_TDM_RX_4", "SEC_TDM_TX_4", "SEC_TDM_RX_5", "SEC_TDM_TX_5",
+"SEC_TDM_RX_6", "SEC_TDM_TX_6", "SEC_TDM_RX_7", "SEC_TDM_TX_7",
+"TERT_TDM_RX_0", "TERT_TDM_TX_0", "TERT_TDM_RX_1", "TERT_TDM_TX_1",
+"TERT_TDM_RX_2", "TERT_TDM_TX_2", "TERT_TDM_RX_3", "TERT_TDM_TX_3",
+"TERT_TDM_RX_4", "TERT_TDM_TX_4", "TERT_TDM_RX_5", "TERT_TDM_TX_5",
+"TERT_TDM_RX_6", "TERT_TDM_TX_6", "TERT_TDM_RX_7", "TERT_TDM_TX_7",
+"QUAT_TDM_RX_0", "QUAT_TDM_TX_0", "QUAT_TDM_RX_1", "QUAT_TDM_TX_1",
+"QUAT_TDM_RX_2", "QUAT_TDM_TX_2", "QUAT_TDM_RX_3", "QUAT_TDM_TX_3",
+"QUAT_TDM_RX_4", "QUAT_TDM_TX_4", "QUAT_TDM_RX_5", "QUAT_TDM_TX_5",
+"QUAT_TDM_RX_6", "QUAT_TDM_TX_6", "QUAT_TDM_RX_7", "QUAT_TDM_TX_7",
+"INT_BT_A2DP_RX", "USB_RX", "USB_TX", "DISPLAY_PORT_RX",
+"TERT_AUXPCM_RX", "TERT_AUXPCM_TX", "QUAT_AUXPCM_RX", "QUAT_AUXPCM_TX",
+"INT0_MI2S_RX", "INT0_MI2S_TX", "INT1_MI2S_RX", "INT1_MI2S_TX",
+"INT2_MI2S_RX", "INT2_MI2S_TX", "INT3_MI2S_RX", "INT3_MI2S_TX",
+"INT4_MI2S_RX", "INT4_MI2S_TX", "INT5_MI2S_RX", "INT5_MI2S_TX",
+"INT6_MI2S_RX", "INT6_MI2S_TX"
+};
+
+static SOC_ENUM_SINGLE_DECL(mm1_channel_mux,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, ch_mixer);
+static SOC_ENUM_SINGLE_DECL(mm2_channel_mux,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA2, ch_mixer);
+static SOC_ENUM_SINGLE_DECL(mm3_channel_mux,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA3, ch_mixer);
+static SOC_ENUM_SINGLE_DECL(mm4_channel_mux,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA4, ch_mixer);
+
+static SOC_ENUM_DOUBLE_DECL(mm1_ch1_enum,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 0, be_name);
+static SOC_ENUM_DOUBLE_DECL(mm1_ch2_enum,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, be_name);
+static SOC_ENUM_DOUBLE_DECL(mm1_ch3_enum,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 2, be_name);
+static SOC_ENUM_DOUBLE_DECL(mm1_ch4_enum,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 3, be_name);
+static SOC_ENUM_DOUBLE_DECL(mm1_ch5_enum,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 4, be_name);
+static SOC_ENUM_DOUBLE_DECL(mm1_ch6_enum,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 5, be_name);
+static SOC_ENUM_DOUBLE_DECL(mm1_ch7_enum,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 6, be_name);
+static SOC_ENUM_DOUBLE_DECL(mm1_ch8_enum,
+	SND_SOC_NOPM, MSM_FRONTEND_DAI_MULTIMEDIA1, 7, be_name);
+
+static int msm_pcm_get_ctl_enum_info(struct snd_ctl_elem_info *uinfo,
+		unsigned int channels,
+		unsigned int items, const char *const names[])
+{
+	if (uinfo->value.enumerated.item >= items)
+		uinfo->value.enumerated.item = items - 1;
+
+	WARN(strlen(names[uinfo->value.enumerated.item]) >=
+		sizeof(uinfo->value.enumerated.name),
+		"ALSA: too long item name '%s'\n",
+		names[uinfo->value.enumerated.item]);
+	strlcpy(uinfo->value.enumerated.name,
+		names[uinfo->value.enumerated.item],
+		sizeof(uinfo->value.enumerated.name));
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+
+	uinfo->value.enumerated.items = ARRAY_SIZE(ch_mixer);
+	msm_pcm_get_ctl_enum_info(uinfo, 1, e->items, e->texts);
+
+	return 0;
+}
+static int msm_pcm_channel_mixer_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u16 fe_id = 0;
+
+	fe_id = ((struct soc_enum *)
+			kcontrol->private_value)->shift_l;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: FE %d %s\n", __func__,
+		fe_id,
+		channel_mixer[fe_id].enable ? "Enabled" : "Disabled");
+	ucontrol->value.enumerated.item[0] = channel_mixer[fe_id].enable;
+	return 0;
+}
+
+static int msm_pcm_channel_mixer_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u16 fe_id = 0;
+
+	fe_id = ((struct soc_enum *)
+			kcontrol->private_value)->shift_l;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+
+	channel_mixer[fe_id].enable = ucontrol->value.enumerated.item[0];
+	pr_debug("%s: %s FE %d\n", __func__,
+		channel_mixer[fe_id].enable ? "Enable" : "Disable",
+		fe_id);
+	return 0;
+}
+
+static int msm_pcm_channel_input_be_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+
+	uinfo->value.enumerated.items = ARRAY_SIZE(be_name);
+	msm_pcm_get_ctl_enum_info(uinfo, 1, e->items, e->texts);
+
+	return 0;
+}
+
+static int msm_pcm_channel_input_be_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	u16 fe_id = 0, in_ch = 0;
+
+	fe_id = e->shift_l;
+	in_ch = e->shift_r;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+	if (in_ch >= ADM_MAX_CHANNELS) {
+		pr_err("%s: invalid input channel %d\n", __func__, in_ch);
+		return -EINVAL;
+	}
+
+	channel_input[fe_id][in_ch] = ucontrol->value.enumerated.item[0];
+	return 1;
+}
+
+static int msm_pcm_channel_input_be_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	u16 fe_id = 0, in_ch = 0;
+
+	fe_id = e->shift_l;
+	in_ch = e->shift_r;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+	if (in_ch >= ADM_MAX_CHANNELS) {
+		pr_err("%s: invalid input channel %d\n", __func__, in_ch);
+		return -EINVAL;
+	}
+
+	ucontrol->value.enumerated.item[0] = channel_input[fe_id][in_ch];
+	return 1;
+}
+
+
+static int msm_pcm_channel_weight_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = ADM_MAX_CHANNELS;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = WEIGHT_0_DB;
+
+	return 0;
+}
+
+static int msm_pcm_channel_weight_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u16 fe_id = 0, out_ch = 0;
+	int i, weight;
+
+	fe_id = ((struct soc_multi_mixer_control *)
+			kcontrol->private_value)->shift;
+	out_ch = ((struct soc_multi_mixer_control *)
+			kcontrol->private_value)->rshift;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+	if (out_ch >= ADM_MAX_CHANNELS) {
+		pr_err("%s: invalid input channel %d\n", __func__, out_ch);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: FE_ID: %d, channel weight %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld\n",
+		__func__, fe_id,
+		ucontrol->value.integer.value[0],
+		ucontrol->value.integer.value[1],
+		ucontrol->value.integer.value[2],
+		ucontrol->value.integer.value[3],
+		ucontrol->value.integer.value[4],
+		ucontrol->value.integer.value[5],
+		ucontrol->value.integer.value[6],
+		ucontrol->value.integer.value[7]);
+
+	for (i = 0; i < ADM_MAX_CHANNELS; ++i) {
+		weight = ucontrol->value.integer.value[i];
+		channel_mixer[fe_id].channel_weight[out_ch][i] = weight;
+		pr_debug("%s: FE_ID %d, output %d input %d weight %d\n",
+			__func__, fe_id, out_ch, i,
+			channel_mixer[fe_id].channel_weight[out_ch][i]);
+	}
+
+	return 0;
+}
+
+static int msm_pcm_channel_weight_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	u16 fe_id = 0, out_ch = 0;
+	int i;
+
+	fe_id = ((struct soc_multi_mixer_control *)
+			kcontrol->private_value)->shift;
+	out_ch = ((struct soc_multi_mixer_control *)
+			kcontrol->private_value)->rshift;
+	if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+		pr_err("%s: invalid FE %d\n", __func__, fe_id);
+		return -EINVAL;
+	}
+	if (out_ch >= ADM_MAX_CHANNELS) {
+		pr_err("%s: invalid input channel %d\n", __func__, out_ch);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ADM_MAX_CHANNELS; ++i)
+		ucontrol->value.integer.value[i] =
+			channel_mixer[fe_id].channel_weight[out_ch][i];
+
+	pr_debug("%s: FE_ID: %d, weight  %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld",
+		__func__, fe_id,
+		ucontrol->value.integer.value[0],
+		ucontrol->value.integer.value[1],
+		ucontrol->value.integer.value[2],
+		ucontrol->value.integer.value[3],
+		ucontrol->value.integer.value[4],
+		ucontrol->value.integer.value[5],
+		ucontrol->value.integer.value[6],
+		ucontrol->value.integer.value[7]);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new channel_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1 Channel Rule", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA1, 8, 0,
+			msm_pcm_get_channel_rule_index,
+			msm_pcm_put_channel_rule_index),
+	SOC_SINGLE_EXT("MultiMedia2 Channel Rule", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA2, 8, 0,
+			msm_pcm_get_channel_rule_index,
+			msm_pcm_put_channel_rule_index),
+	SOC_SINGLE_EXT("MultiMedia3 Channel Rule", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA3, 8, 0,
+			msm_pcm_get_channel_rule_index,
+			msm_pcm_put_channel_rule_index),
+	SOC_SINGLE_EXT("MultiMedia4 Channel Rule", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA4, 8, 0,
+			msm_pcm_get_channel_rule_index,
+			msm_pcm_put_channel_rule_index),
+	SOC_SINGLE_EXT("MultiMedia5 Channel Rule", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA5, 8, 0,
+			msm_pcm_get_channel_rule_index,
+			msm_pcm_put_channel_rule_index),
+	SOC_SINGLE_EXT("MultiMedia6 Channel Rule", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA6, 8, 0,
+			msm_pcm_get_channel_rule_index,
+			msm_pcm_put_channel_rule_index),
+
+	SOC_SINGLE_EXT("MultiMedia1 Channels", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA1, 8, 0,
+			msm_pcm_get_out_chs,
+			msm_pcm_put_out_chs),
+	SOC_SINGLE_EXT("MultiMedia2 Channels", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA2, 8, 0,
+			msm_pcm_get_out_chs,
+			msm_pcm_put_out_chs),
+	SOC_SINGLE_EXT("MultiMedia3 Channels", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA3, 8, 0,
+			msm_pcm_get_out_chs,
+			msm_pcm_put_out_chs),
+	SOC_SINGLE_EXT("MultiMedia4 Channels", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA4, 8, 0,
+			msm_pcm_get_out_chs,
+			msm_pcm_put_out_chs),
+	SOC_SINGLE_EXT("MultiMedia5 Channels", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA5, 8, 0,
+			msm_pcm_get_out_chs,
+			msm_pcm_put_out_chs),
+	SOC_SINGLE_EXT("MultiMedia6 Channels", SND_SOC_NOPM,
+			MSM_FRONTEND_DAI_MULTIMEDIA6, 8, 0,
+			msm_pcm_get_out_chs,
+			msm_pcm_put_out_chs),
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Channel Mixer",
+	.info = msm_pcm_channel_mixer_info,
+	.get = msm_pcm_channel_mixer_get,
+	.put = msm_pcm_channel_mixer_put,
+	.private_value = (unsigned long)&(mm1_channel_mux)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia2 Channel Mixer",
+	.info = msm_pcm_channel_mixer_info,
+	.get = msm_pcm_channel_mixer_get,
+	.put = msm_pcm_channel_mixer_put,
+	.private_value = (unsigned long)&(mm2_channel_mux)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia3 Channel Mixer",
+	.info = msm_pcm_channel_mixer_info,
+	.get = msm_pcm_channel_mixer_get,
+	.put = msm_pcm_channel_mixer_put,
+	.private_value = (unsigned long)&(mm3_channel_mux)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia4 Channel Mixer",
+	.info = msm_pcm_channel_mixer_info,
+	.get = msm_pcm_channel_mixer_get,
+	.put = msm_pcm_channel_mixer_put,
+	.private_value = (unsigned long)&(mm4_channel_mux)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Output Channel1",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{ .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 0,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Output Channel2",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{ .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 1, }
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Output Channel3",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{ .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 2,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Output Channel4",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{ .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 3,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Output Channel5",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{ .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 4,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Output Channel6",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{ .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 5,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Output Channel7",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{ .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 6,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Output Channel8",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{ .shift = MSM_FRONTEND_DAI_MULTIMEDIA1, .rshift = 7,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia2 Output Channel1",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{.shift = MSM_FRONTEND_DAI_MULTIMEDIA2, .rshift = 0,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia2 Output Channel2",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{.shift = MSM_FRONTEND_DAI_MULTIMEDIA2, .rshift = 1,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia2 Output Channel3",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{.shift = MSM_FRONTEND_DAI_MULTIMEDIA2, .rshift = 2,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia3 Output Channel1",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{.shift = MSM_FRONTEND_DAI_MULTIMEDIA3, .rshift = 0,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia3 Output Channel2",
+	.info = msm_pcm_channel_weight_info,
+	.get = msm_pcm_channel_weight_get,
+	.put = msm_pcm_channel_weight_put,
+	.private_value = (unsigned long)&(struct soc_multi_mixer_control)
+		{.shift = MSM_FRONTEND_DAI_MULTIMEDIA3, .rshift = 1,}
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Channel1",
+	.info = msm_pcm_channel_input_be_info,
+	.get = msm_pcm_channel_input_be_get,
+	.put = msm_pcm_channel_input_be_put,
+	.private_value = (unsigned long)&(mm1_ch1_enum)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Channel2",
+	.info = msm_pcm_channel_input_be_info,
+	.get = msm_pcm_channel_input_be_get,
+	.put = msm_pcm_channel_input_be_put,
+	.private_value = (unsigned long)&(mm1_ch2_enum)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Channel3",
+	.info = msm_pcm_channel_input_be_info,
+	.get = msm_pcm_channel_input_be_get,
+	.put = msm_pcm_channel_input_be_put,
+	.private_value = (unsigned long)&(mm1_ch3_enum)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Channel4",
+	.info = msm_pcm_channel_input_be_info,
+	.get = msm_pcm_channel_input_be_get,
+	.put = msm_pcm_channel_input_be_put,
+	.private_value = (unsigned long)&(mm1_ch4_enum)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Channel5",
+	.info = msm_pcm_channel_input_be_info,
+	.get = msm_pcm_channel_input_be_get,
+	.put = msm_pcm_channel_input_be_put,
+	.private_value = (unsigned long)&(mm1_ch5_enum)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Channel6",
+	.info = msm_pcm_channel_input_be_info,
+	.get = msm_pcm_channel_input_be_get,
+	.put = msm_pcm_channel_input_be_put,
+	.private_value = (unsigned long)&(mm1_ch6_enum)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Channel7",
+	.info = msm_pcm_channel_input_be_info,
+	.get = msm_pcm_channel_input_be_get,
+	.put = msm_pcm_channel_input_be_put,
+	.private_value = (unsigned long)&(mm1_ch7_enum)
+	},
+	{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.name = "MultiMedia1 Channel8",
+	.info = msm_pcm_channel_input_be_info,
+	.get = msm_pcm_channel_input_be_get,
+	.put = msm_pcm_channel_input_be_put,
+	.private_value = (unsigned long)&(mm1_ch8_enum)
+	},
+};
 static int msm_ec_ref_ch_get(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
@@ -5378,6 +6098,57 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -5427,6 +6198,9 @@
 	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = {
@@ -5529,6 +6303,9 @@
 	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = {
@@ -5580,6 +6357,9 @@
 	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = {
@@ -5631,6 +6411,9 @@
 	SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
 	MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
@@ -6402,6 +7185,9 @@
 	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
 	MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
@@ -6442,6 +7228,70 @@
 	MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
 };
+
+static const struct snd_kcontrol_new mmul20_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
+	MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -7898,6 +8748,9 @@
 	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new sec_auxpcm_rx_port_mixer_controls[] = {
@@ -8085,6 +8938,9 @@
 	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
 	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_PRI_MI2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new usb_rx_port_mixer_controls[] = {
@@ -8115,6 +8971,9 @@
 	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
 	MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new pri_tdm_rx_0_port_mixer_controls[] = {
@@ -9205,6 +10064,9 @@
 	SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
 	MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = {
@@ -9226,6 +10088,9 @@
 	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
 	MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new lsm1_mixer_controls[] = {
@@ -9740,10 +10605,60 @@
 	return 0;
 }
 
+static int msm_routing_put_app_type_gain_control(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	int j, fe_id, be_id, port_type;
+	int ret = 0;
+	unsigned long copp;
+	struct msm_pcm_routing_bdai_data *bedai;
+	int dir = ucontrol->value.integer.value[0] ? SESSION_TYPE_TX :
+						     SESSION_TYPE_RX;
+	int app_type = ucontrol->value.integer.value[1];
+	int gain = (ucontrol->value.integer.value[2] +
+		    ucontrol->value.integer.value[3])/2;
+
+	port_type = (dir == SESSION_TYPE_RX) ? MSM_AFE_PORT_TYPE_RX :
+					       MSM_AFE_PORT_TYPE_TX;
+
+	mutex_lock(&routing_lock);
+	for (be_id = 0; be_id < MSM_BACKEND_DAI_MAX; be_id++) {
+		if (is_be_dai_extproc(be_id))
+			continue;
+
+		bedai = &msm_bedais[be_id];
+		if (afe_get_port_type(bedai->port_id) != port_type)
+			continue;
+
+		if (!bedai->active)
+			continue;
+
+		for (fe_id = 0; fe_id < MSM_FRONTEND_DAI_MAX; fe_id++) {
+			if (!test_bit(fe_id, &bedai->fe_sessions[0]))
+				continue;
+
+			if (app_type !=
+			    fe_dai_app_type_cfg[fe_id][dir][be_id].app_type)
+				continue;
+
+			copp = session_copp_map[fe_id][dir][be_id];
+			for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
+				if (!test_bit(j, &copp))
+					continue;
+				ret |= adm_set_volume(bedai->port_id, j, gain);
+			}
+		}
+	}
+	mutex_unlock(&routing_lock);
+	return ret ? -EINVAL : 0;
+}
+
 static const struct snd_kcontrol_new app_type_cfg_controls[] = {
 	SOC_SINGLE_MULTI_EXT("App Type Config", SND_SOC_NOPM, 0,
 	0xFFFFFFFF, 0, 128, msm_routing_get_app_type_cfg_control,
 	msm_routing_put_app_type_cfg_control),
+	SOC_SINGLE_MULTI_EXT("App Type Gain", SND_SOC_NOPM, 0,
+	0x2000, 0, 4, NULL, msm_routing_put_app_type_gain_control)
 };
 
 static int msm_routing_get_lsm_app_type_cfg_control(
@@ -10467,6 +11382,7 @@
 	SND_SOC_DAPM_AIF_IN("MM_DL14", "MultiMedia14 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MM_DL15", "MultiMedia15 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MM_DL16", "MultiMedia16 Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("MM_DL20", "MultiMedia20 Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
@@ -10479,6 +11395,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL20", "MultiMedia20 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0),
@@ -11176,6 +12093,9 @@
 	SND_SOC_DAPM_MIXER("TERT_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
 				tert_tdm_rx_3_mixer_controls,
 				ARRAY_SIZE(tert_tdm_rx_3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("TERT_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+				tert_tdm_rx_4_mixer_controls,
+				ARRAY_SIZE(tert_tdm_rx_4_mixer_controls)),
 	SND_SOC_DAPM_MIXER("QUAT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
 				quat_tdm_rx_0_mixer_controls,
 				ARRAY_SIZE(quat_tdm_rx_0_mixer_controls)),
@@ -11213,6 +12133,8 @@
 	mmul18_mixer_controls, ARRAY_SIZE(mmul18_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia19 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul19_mixer_controls, ARRAY_SIZE(mmul19_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia20 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul20_mixer_controls, ARRAY_SIZE(mmul20_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -11782,6 +12704,7 @@
 	{"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"MultiMedia18 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
 	{"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
 	{"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -12200,6 +13123,24 @@
 	{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
 	{"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Audio Mixer"},
 
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia6", "MM_DL6"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia7", "MM_DL7"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia8", "MM_DL8"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia10", "MM_DL10"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia11", "MM_DL11"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia12", "MM_DL12"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia13", "MM_DL13"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia14", "MM_DL14"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia15", "MM_DL15"},
+	{"TERT_TDM_RX_4 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"TERT_TDM_RX_4", NULL, "TERT_TDM_RX_4 Audio Mixer"},
+
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -12216,6 +13157,7 @@
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia20", "MM_DL20"},
 	{"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"},
 
 	{"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -12288,6 +13230,7 @@
 	{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"QUAT_TDM_RX_1 Audio Mixer", "MultiMedia20", "MM_DL20"},
 	{"QUAT_TDM_RX_1", NULL, "QUAT_TDM_RX_1 Audio Mixer"},
 
 	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -12306,6 +13249,7 @@
 	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"QUAT_TDM_RX_2 Audio Mixer", "MultiMedia20", "MM_DL20"},
 	{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2 Audio Mixer"},
 
 	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -12324,6 +13268,7 @@
 	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia14", "MM_DL14"},
 	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia15", "MM_DL15"},
 	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
+	{"QUAT_TDM_RX_3 Audio Mixer", "MultiMedia20", "MM_DL20"},
 	{"QUAT_TDM_RX_3", NULL, "QUAT_TDM_RX_3 Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -12375,6 +13320,7 @@
 	{"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
 	{"MultiMedia6 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"MultiMedia6 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"MultiMedia6 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 
 	{"MultiMedia1 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
 	{"MultiMedia1 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
@@ -12504,6 +13450,27 @@
 	{"MultiMedia9 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
 	{"MultiMedia9 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
 
+	{"MultiMedia20 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"MultiMedia20 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+	{"MultiMedia20 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+	{"MultiMedia20 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+	{"MultiMedia20 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"},
+	{"MultiMedia20 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"},
+	{"MultiMedia20 Mixer", "PRI_TDM_TX_2", "PRI_TDM_TX_2"},
+	{"MultiMedia20 Mixer", "PRI_TDM_TX_3", "PRI_TDM_TX_3"},
+	{"MultiMedia20 Mixer", "SEC_TDM_TX_0", "SEC_TDM_TX_0"},
+	{"MultiMedia20 Mixer", "SEC_TDM_TX_1", "SEC_TDM_TX_1"},
+	{"MultiMedia20 Mixer", "SEC_TDM_TX_2", "SEC_TDM_TX_2"},
+	{"MultiMedia20 Mixer", "SEC_TDM_TX_3", "SEC_TDM_TX_3"},
+	{"MultiMedia20 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
+	{"MultiMedia20 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
+	{"MultiMedia20 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
+	{"MultiMedia20 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
+	{"MultiMedia20 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
+	{"MultiMedia20 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
+	{"MultiMedia20 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
+	{"MultiMedia20 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},
+
 	{"MultiMedia1 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
 	{"MultiMedia2 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
 	{"MultiMedia4 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"},
@@ -12622,6 +13589,7 @@
 	{"MM_UL17", NULL, "MultiMedia17 Mixer"},
 	{"MM_UL18", NULL, "MultiMedia18 Mixer"},
 	{"MM_UL19", NULL, "MultiMedia19 Mixer"},
+	{"MM_UL20", NULL, "MultiMedia20 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -13271,6 +14239,7 @@
 	{"SLIM7_UL_HL", NULL, "HFP_SLIM7_UL_HL"},
 	{"HFP_SLIM7_UL_HL", "Switch", "SLIMBUS_7_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
+	{"AUX_PCM_RX", NULL, "INTHFP_DL_HL"},
 	{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
 	{"MI2S_RX", NULL, "MI2S_DL_HL"},
 	{"MI2S_UL_HL", NULL, "MI2S_TX"},
@@ -13675,6 +14644,7 @@
 	{"AUX_PCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"AUX_PCM_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"AUX_PCM_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+	{"AUX_PCM_RX Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX Port Mixer"},
 
 	{"SEC_AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -13830,6 +14800,7 @@
 	{"PRI_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"PRI_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"PRI_MI2S_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"PRI_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
 	{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Port Mixer"},
 
 	{"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -13838,6 +14809,7 @@
 	{"SEC_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
 	{"SEC_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"SEC_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
 	{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Port Mixer"},
 
 	{"TERT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -13845,6 +14817,7 @@
 	{"TERT_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
 	{"TERT_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
 	{"TERT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+	{"TERT_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
 	{"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Port Mixer"},
 
 	{"QUAT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -13854,6 +14827,7 @@
 	{"QUAT_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"QUAT_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"QUAT_MI2S_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"QUAT_MI2S_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"},
 	{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Port Mixer"},
 
 	/* Backend Enablement */
@@ -13909,6 +14883,7 @@
 	{"BE_OUT", NULL, "TERT_TDM_RX_1"},
 	{"BE_OUT", NULL, "TERT_TDM_RX_2"},
 	{"BE_OUT", NULL, "TERT_TDM_RX_3"},
+	{"BE_OUT", NULL, "TERT_TDM_RX_4"},
 	{"BE_OUT", NULL, "QUAT_TDM_RX_0"},
 	{"BE_OUT", NULL, "QUAT_TDM_RX_1"},
 	{"BE_OUT", NULL, "QUAT_TDM_RX_2"},
@@ -14046,7 +15021,7 @@
 			clear_bit(idx,
 				  &session_copp_map[i][session_type][be_id]);
 			if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
-				(bedai->passthr_mode == LEGACY_PCM))
+				(bedai->passthr_mode[i] == LEGACY_PCM))
 				msm_pcm_routing_deinit_pp(bedai->port_id,
 							  topology);
 		}
@@ -14055,6 +15030,10 @@
 	bedai->active = 0;
 	bedai->sample_rate = 0;
 	bedai->channel = 0;
+	for (i = 0; i < MSM_FRONTEND_DAI_MAX; i++) {
+		if (bedai->passthr_mode[i] != LISTEN)
+			bedai->passthr_mode[i] = LEGACY_PCM;
+	}
 	mutex_unlock(&routing_lock);
 
 	return 0;
@@ -14064,7 +15043,8 @@
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	unsigned int be_id = rtd->dai_link->id;
-	int i, path_type, session_type, topology;
+	int i, path_type, topology;
+	int session_type = INVALID_SESSION;
 	struct msm_pcm_routing_bdai_data *bedai;
 	u32 channels, sample_rate;
 	uint16_t bits_per_sample = 16, voc_path_type;
@@ -14083,17 +15063,6 @@
 
 	bedai = &msm_bedais[be_id];
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if (bedai->passthr_mode != LEGACY_PCM)
-			path_type = ADM_PATH_COMPRESSED_RX;
-		else
-			path_type = ADM_PATH_PLAYBACK;
-		session_type = SESSION_TYPE_RX;
-	} else {
-		path_type = ADM_PATH_LIVE_REC;
-		session_type = SESSION_TYPE_TX;
-	}
-
 	mutex_lock(&routing_lock);
 	if (bedai->active == 1)
 		goto done; /* Ignore prepare if back-end already active */
@@ -14110,6 +15079,17 @@
 				route_check_fe_id_adm_support(i)))
 			continue;
 
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			if (bedai->passthr_mode[i] != LEGACY_PCM)
+				path_type = ADM_PATH_COMPRESSED_RX;
+			else
+				path_type = ADM_PATH_PLAYBACK;
+			session_type = SESSION_TYPE_RX;
+		} else {
+			path_type = ADM_PATH_LIVE_REC;
+			session_type = SESSION_TYPE_TX;
+		}
+
 		is_lsm = (i >= MSM_FRONTEND_DAI_LSM1) &&
 				 (i <= MSM_FRONTEND_DAI_LSM8);
 		fdai = &fe_dai_map[i][session_type];
@@ -14188,9 +15168,9 @@
 
 			msm_pcm_routing_build_matrix(i, session_type, path_type,
 						     fdai->perf_mode,
-						     bedai->passthr_mode);
+						     bedai->passthr_mode[i]);
 			if ((fdai->perf_mode == LEGACY_PCM_MODE) &&
-				(bedai->passthr_mode == LEGACY_PCM))
+				(bedai->passthr_mode[i] == LEGACY_PCM))
 				msm_pcm_routing_cfg_pp(bedai->port_id, copp_idx,
 						       topology, channels);
 		}
@@ -14202,10 +15182,10 @@
 			pr_debug("%s voice session_id: 0x%x\n", __func__,
 				 session_id);
 
-			if (session_type == SESSION_TYPE_TX)
-				voc_path_type = TX_PATH;
-			else
+			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 				voc_path_type = RX_PATH;
+			else
+				voc_path_type = TX_PATH;
 
 			voc_set_route_flag(session_id, voc_path_type, 1);
 
@@ -14255,7 +15235,8 @@
 	return 0;
 }
 
-static int msm_routing_send_device_pp_params(int port_id, int copp_idx)
+static int msm_routing_send_device_pp_params(int port_id, int copp_idx,
+					     int fe_id)
 {
 	int index, topo_id, be_idx;
 	unsigned long pp_config = 0;
@@ -14298,8 +15279,8 @@
 		return -EINVAL;
 	}
 
-	if ((msm_bedais[be_idx].passthr_mode == LEGACY_PCM) ||
-		(msm_bedais[be_idx].passthr_mode == LISTEN))
+	if ((msm_bedais[be_idx].passthr_mode[fe_id] == LEGACY_PCM) ||
+		(msm_bedais[be_idx].passthr_mode[fe_id] == LISTEN))
 		compr_passthr_mode = false;
 
 	pp_config = msm_bedais_pp_params[index].pp_params_config;
@@ -14358,12 +15339,12 @@
 		return -EINVAL;
 	}
 
-	if ((msm_bedais[be_idx].passthr_mode == LEGACY_PCM) ||
-		(msm_bedais[be_idx].passthr_mode == LISTEN))
-		compr_passthr_mode = false;
-
 	for_each_set_bit(i, &msm_bedais[be_idx].fe_sessions[0],
 				MSM_FRONTEND_DAI_MM_SIZE) {
+		if ((msm_bedais[be_idx].passthr_mode[i] == LEGACY_PCM) ||
+			(msm_bedais[be_idx].passthr_mode[i] == LISTEN))
+			compr_passthr_mode = false;
+
 		for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
 			unsigned long copp =
 				session_copp_map[i]
@@ -14376,7 +15357,7 @@
 				continue;
 		pr_debug("%s: port: 0x%x, copp %ld, be active: %d, passt: %d\n",
 			 __func__, port_id, copp, msm_bedais[be_idx].active,
-			 msm_bedais[be_idx].passthr_mode);
+			 msm_bedais[be_idx].passthr_mode[i]);
 		switch (pp_id) {
 		case ADM_PP_PARAM_MUTE_ID:
 			pr_debug("%s: ADM_PP_PARAM_MUTE\n", __func__);
@@ -14509,6 +15490,67 @@
 	},
 };
 
+static int msm_routing_stereo_channel_reverse_control_get(
+			struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = swap_ch;
+	pr_debug("%s: Swap channel value: %ld\n", __func__,
+				ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_routing_stereo_channel_reverse_control_put(
+			struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int i, idx, be_index, port_id;
+	int ret = 0;
+	unsigned long copp;
+
+	pr_debug("%s Swap channel value:%ld\n", __func__,
+				ucontrol->value.integer.value[0]);
+
+	swap_ch = ucontrol->value.integer.value[0];
+
+	mutex_lock(&routing_lock);
+	for (be_index = 0; be_index < MSM_BACKEND_DAI_MAX; be_index++) {
+		port_id = msm_bedais[be_index].port_id;
+		if (!msm_bedais[be_index].active)
+			continue;
+
+		for_each_set_bit(i, &msm_bedais[be_index].fe_sessions[0],
+				MSM_FRONTEND_DAI_MM_SIZE) {
+			copp = session_copp_map[i][SESSION_TYPE_RX][be_index];
+			for (idx = 0; idx < MAX_COPPS_PER_PORT; idx++) {
+				if (!test_bit(idx, &copp))
+					continue;
+
+				pr_debug("%s: swap channel control of portid:%d, coppid:%d\n",
+					 __func__, port_id, idx);
+				ret = adm_swap_speaker_channels(
+					port_id, idx,
+					msm_bedais[be_index].sample_rate,
+					swap_ch);
+				if (ret) {
+					pr_err("%s:Swap_channel failed, err=%d\n",
+						 __func__, ret);
+					goto done;
+				}
+			}
+		}
+	}
+done:
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
+static const struct snd_kcontrol_new stereo_channel_reverse_control[] = {
+	SOC_SINGLE_EXT("Swap channel", SND_SOC_NOPM, 0,
+	1, 0, msm_routing_stereo_channel_reverse_control_get,
+	msm_routing_stereo_channel_reverse_control_put),
+};
+
 static const struct snd_pcm_ops msm_routing_pcm_ops = {
 	.hw_params	= msm_pcm_routing_hw_params,
 	.close          = msm_pcm_routing_close,
@@ -14547,6 +15589,9 @@
 	snd_soc_add_platform_controls(platform, ec_ref_param_controls,
 				ARRAY_SIZE(ec_ref_param_controls));
 
+	snd_soc_add_platform_controls(platform, channel_mixer_controls,
+				ARRAY_SIZE(channel_mixer_controls));
+
 	msm_qti_pp_add_controls(platform);
 
 	msm_dts_srs_tm_add_controls(platform);
@@ -14565,8 +15610,6 @@
 		msm_routing_be_dai_name_table_mixer_controls,
 		ARRAY_SIZE(msm_routing_be_dai_name_table_mixer_controls));
 
-	msm_dts_eagle_add_controls(platform);
-
 	snd_soc_add_platform_controls(platform, msm_source_tracking_controls,
 				ARRAY_SIZE(msm_source_tracking_controls));
 	snd_soc_add_platform_controls(platform, adm_channel_config_controls,
@@ -14574,6 +15617,8 @@
 
 	snd_soc_add_platform_controls(platform, aptx_dec_license_controls,
 					ARRAY_SIZE(aptx_dec_license_controls));
+	snd_soc_add_platform_controls(platform, stereo_channel_reverse_control,
+				ARRAY_SIZE(stereo_channel_reverse_control));
 	return 0;
 }
 
@@ -14701,6 +15746,7 @@
 		(routing_cb)msm_pcm_get_dev_acdb_id_by_port_id);
 
 	memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
+	memset(&last_be_id_configured, 0, sizeof(last_be_id_configured));
 
 	return platform_driver_register(&msm_routing_pcm_driver);
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index fcd155e..19e7260 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -192,6 +192,7 @@
 	MSM_FRONTEND_DAI_MULTIMEDIA17,
 	MSM_FRONTEND_DAI_MULTIMEDIA18,
 	MSM_FRONTEND_DAI_MULTIMEDIA19,
+	MSM_FRONTEND_DAI_MULTIMEDIA20,
 	MSM_FRONTEND_DAI_CS_VOICE,
 	MSM_FRONTEND_DAI_VOIP,
 	MSM_FRONTEND_DAI_AFE_RX,
@@ -217,8 +218,8 @@
 	MSM_FRONTEND_DAI_MAX,
 };
 
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA19 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA19
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA20 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA20
 
 enum {
 	MSM_BACKEND_DAI_PRI_I2S_RX = 0,
@@ -384,6 +385,7 @@
 #define INVALID_SESSION -1
 #define SESSION_TYPE_RX 0
 #define SESSION_TYPE_TX 1
+#define MAX_SESSION_TYPES 2
 #define INT_RX_VOL_MAX_STEPS 0x2000
 #define INT_RX_VOL_GAIN 0x2000
 
@@ -423,7 +425,7 @@
 	unsigned int  channel;
 	unsigned int  format;
 	unsigned int  adm_override_ch;
-	u32 passthr_mode;
+	u32 passthr_mode[MSM_FRONTEND_DAI_MAX];
 	char *name;
 };
 
@@ -475,10 +477,10 @@
 void msm_pcm_routing_acquire_lock(void);
 void msm_pcm_routing_release_lock(void);
 
-int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
-					     int be_id, int app_type,
-					     int acdb_dev_id, int sample_rate);
-int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
-					    int be_id, int *app_type,
-					    int *acdb_dev_id, int *sample_rate);
+int msm_pcm_routing_reg_stream_app_type_cfg(
+	int fedai_id, int session_type, int be_id,
+	struct msm_pcm_stream_app_type_cfg *cfg_data);
+int msm_pcm_routing_get_stream_app_type_cfg(
+	int fedai_id, int session_type, int *be_id,
+	struct msm_pcm_stream_app_type_cfg *cfg_data);
 #endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index c60b27f..a885e1e 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -45,21 +45,6 @@
 	EQ_BAND_MAX,
 };
 
-struct msm_audio_eq_band {
-	uint16_t     band_idx; /* The band index, 0 .. 11 */
-	uint32_t     filter_type; /* Filter band type */
-	uint32_t     center_freq_hz; /* Filter band center frequency */
-	uint32_t     filter_gain; /* Filter band initial gain (dB) */
-			/* Range is +12 dB to -12 dB with 1dB increments. */
-	uint32_t     q_factor;
-} __packed;
-
-struct msm_audio_eq_stream_config {
-	uint32_t	enable; /* Number of consequtive bands specified */
-	uint32_t	num_bands;
-	struct msm_audio_eq_band	eq_bands[EQ_BAND_MAX];
-} __packed;
-
 /* Audio Sphere data structures */
 struct msm_audio_pp_asphere_state_s {
 	uint32_t enabled;
@@ -821,6 +806,286 @@
 	return 0;
 }
 
+int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_kcontrol *kctl;
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+	struct dsp_stream_callback_prtd *kctl_prtd = NULL;
+
+	if (!rtd) {
+		pr_err("%s: rtd is NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name,
+		rtd->pcm->device);
+	kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+	kfree(mixer_str);
+	if (!kctl) {
+		pr_err("%s: failed to get kctl.\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (kctl->private_data != NULL) {
+		pr_err("%s: kctl_prtd is not NULL at initialization.\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	kctl_prtd = kzalloc(sizeof(struct dsp_stream_callback_prtd),
+			GFP_KERNEL);
+	if (!kctl_prtd) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	spin_lock_init(&kctl_prtd->prtd_spin_lock);
+	INIT_LIST_HEAD(&kctl_prtd->event_queue);
+	kctl_prtd->event_count = 0;
+	kctl->private_data = kctl_prtd;
+
+done:
+	return ret;
+}
+
+int msm_adsp_clean_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_kcontrol *kctl;
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct dsp_stream_callback_list *node, *n;
+	unsigned long spin_flags;
+	const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+	struct dsp_stream_callback_prtd *kctl_prtd = NULL;
+
+	if (!rtd) {
+		pr_err("%s: rtd is NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name,
+		rtd->pcm->device);
+	kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+	kfree(mixer_str);
+	if (!kctl) {
+		pr_err("%s: failed to get kctl.\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	kctl_prtd = (struct dsp_stream_callback_prtd *)
+			kctl->private_data;
+	if (kctl_prtd != NULL) {
+		spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags);
+		/* clean the queue */
+		list_for_each_entry_safe(node, n,
+				&kctl_prtd->event_queue, list) {
+			list_del(&node->list);
+			kctl_prtd->event_count--;
+			pr_debug("%s: %d remaining events after del.\n",
+				__func__, kctl_prtd->event_count);
+			kfree(node);
+		}
+		spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags);
+	}
+
+	kfree(kctl_prtd);
+	kctl->private_data = NULL;
+
+done:
+	return ret;
+}
+
+int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
+			uint32_t *payload)
+{
+	/* adsp pp event notifier */
+	struct snd_kcontrol *kctl;
+	struct snd_ctl_elem_value control;
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct dsp_stream_callback_list *new_event;
+	struct dsp_stream_callback_list *oldest_event;
+	unsigned long spin_flags;
+	struct dsp_stream_callback_prtd *kctl_prtd = NULL;
+	struct msm_adsp_event_data *event_data = NULL;
+	const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+	struct snd_ctl_elem_info kctl_info;
+
+	if (!rtd || !payload) {
+		pr_err("%s: %s is NULL\n", __func__,
+			(!rtd) ? "rtd" : "payload");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (rtd->card->snd_card == NULL) {
+		pr_err("%s: snd_card is null.\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_ATOMIC);
+	if (!mixer_str) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name,
+		rtd->pcm->device);
+	kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+	kfree(mixer_str);
+	if (!kctl) {
+		pr_err("%s: failed to get kctl.\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	event_data = (struct msm_adsp_event_data *)payload;
+	kctl->info(kctl, &kctl_info);
+	if (sizeof(struct msm_adsp_event_data)
+		+ event_data->payload_len > kctl_info.count) {
+		pr_err("%s: payload length exceeds limit of %u bytes.\n",
+			__func__, kctl_info.count);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	kctl_prtd = (struct dsp_stream_callback_prtd *)
+			kctl->private_data;
+	if (kctl_prtd == NULL) {
+		/* queue is not initialized */
+		ret = -EINVAL;
+		pr_err("%s: event queue is not initialized.\n", __func__);
+		goto done;
+	}
+
+	new_event = kzalloc(sizeof(struct dsp_stream_callback_list)
+			+ event_data->payload_len,
+			GFP_ATOMIC);
+	if (new_event == NULL) {
+		ret = -ENOMEM;
+		goto done;
+	}
+	memcpy((void *)&new_event->event, (void *)payload,
+		   event_data->payload_len
+		   + sizeof(struct msm_adsp_event_data));
+
+	spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags);
+	while (kctl_prtd->event_count >= DSP_STREAM_CALLBACK_QUEUE_SIZE) {
+		pr_info("%s: queue of size %d is full. delete oldest one.\n",
+			__func__, DSP_STREAM_CALLBACK_QUEUE_SIZE);
+		oldest_event = list_first_entry(&kctl_prtd->event_queue,
+				struct dsp_stream_callback_list, list);
+		pr_info("%s: event deleted: type %d length %d\n",
+			__func__, oldest_event->event.event_type,
+			oldest_event->event.payload_len);
+		list_del(&oldest_event->list);
+		kctl_prtd->event_count--;
+		kfree(oldest_event);
+	}
+
+	list_add_tail(&new_event->list, &kctl_prtd->event_queue);
+	kctl_prtd->event_count++;
+	spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags);
+
+	control.id = kctl->id;
+	snd_ctl_notify(rtd->card->snd_card,
+			SNDRV_CTL_EVENT_MASK_INFO,
+			&control.id);
+
+done:
+	return ret;
+}
+
+int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count =
+		sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data);
+
+	return 0;
+}
+
+int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	uint32_t payload_size = 0;
+	struct dsp_stream_callback_list *oldest_event;
+	unsigned long spin_flags;
+	struct dsp_stream_callback_prtd *kctl_prtd = NULL;
+	int ret = 0;
+
+	kctl_prtd = (struct dsp_stream_callback_prtd *)
+			kcontrol->private_data;
+	if (kctl_prtd == NULL) {
+		pr_err("%s: ASM Stream PP event queue is not initialized.\n",
+			__func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags);
+	pr_debug("%s: %d events in queue.\n", __func__, kctl_prtd->event_count);
+	if (list_empty(&kctl_prtd->event_queue)) {
+		pr_err("%s: ASM Stream PP event queue is empty.\n", __func__);
+		ret = -EINVAL;
+		spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags);
+		goto done;
+	}
+
+	oldest_event = list_first_entry(&kctl_prtd->event_queue,
+			struct dsp_stream_callback_list, list);
+	list_del(&oldest_event->list);
+	kctl_prtd->event_count--;
+	spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags);
+
+	payload_size = oldest_event->event.payload_len;
+	pr_debug("%s: event fetched: type %d length %d\n",
+			__func__, oldest_event->event.event_type,
+			oldest_event->event.payload_len);
+	memcpy(ucontrol->value.bytes.data, &oldest_event->event,
+		sizeof(struct msm_adsp_event_data) + payload_size);
+	kfree(oldest_event);
+
+done:
+	return ret;
+}
+
+int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count =
+		sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data);
+
+	return 0;
+}
+
 static int msm_multichannel_ec_primary_mic_ch_put(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
 {
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
index 805fb3e..b67e873 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
@@ -13,7 +13,16 @@
 #define _MSM_QTI_PP_H_
 
 #include <sound/soc.h>
-
+int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
+			uint32_t *payload);
+int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd);
+int msm_adsp_clean_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd);
+int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo);
+int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol);
+int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo);
 #ifdef CONFIG_QTI_PP
 void msm_qti_pp_send_eq_values(int fedai_id);
 int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, int copp_idx,
diff --git a/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c
new file mode 100644
index 0000000..b1bb272
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c
@@ -0,0 +1,971 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_ion.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm_params.h>
+#include <sound/timer.h>
+#include <sound/tlv.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+#include <linux/msm_audio.h>
+
+#include "msm-pcm-routing-v2.h"
+#include "msm-qti-pp-config.h"
+
+#define LOOPBACK_SESSION_MAX_NUM_STREAMS 2
+
+static DEFINE_MUTEX(transcode_loopback_session_lock);
+
+struct trans_loopback_pdata {
+	struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
+};
+
+struct loopback_stream {
+	struct snd_compr_stream *cstream;
+	uint32_t codec_format;
+	bool start;
+};
+
+enum loopback_session_state {
+	/* One or both streams not opened */
+	LOOPBACK_SESSION_CLOSE = 0,
+	/* Loopback streams opened */
+	LOOPBACK_SESSION_READY,
+	/* Loopback streams opened and formats configured */
+	LOOPBACK_SESSION_START,
+	/* Trigger issued on either of streams when in START state */
+	LOOPBACK_SESSION_RUN
+};
+
+struct msm_transcode_loopback {
+	struct loopback_stream source;
+	struct loopback_stream sink;
+
+	struct snd_compr_caps source_compr_cap;
+	struct snd_compr_caps sink_compr_cap;
+
+	uint32_t instance;
+	uint32_t num_streams;
+	int session_state;
+
+	struct mutex lock;
+
+	int session_id;
+	struct audio_client *audio_client;
+};
+
+/* Transcode loopback global info struct */
+static struct msm_transcode_loopback transcode_info;
+
+static void loopback_event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct msm_transcode_loopback *trans =
+			(struct msm_transcode_loopback *)priv;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_compr_stream *cstream;
+	struct audio_client *ac;
+	int stream_id;
+	int ret;
+
+	if (!trans || !payload) {
+		pr_err("%s: rtd or payload is NULL\n", __func__);
+		return;
+	}
+
+	cstream = trans->source.cstream;
+	ac = trans->audio_client;
+
+	/*
+	 * Token for rest of the compressed commands use to set
+	 * session id, stream id, dir etc.
+	 */
+	stream_id = q6asm_get_stream_id_from_token(token);
+
+	switch (opcode) {
+	case ASM_STREAM_CMD_ENCDEC_EVENTS:
+	case ASM_IEC_61937_MEDIA_FMT_EVENT:
+		pr_debug("%s: ASM_IEC_61937_MEDIA_FMT_EVENT\n", __func__);
+		rtd = cstream->private_data;
+		if (!rtd) {
+			pr_err("%s: rtd is NULL\n", __func__);
+			return;
+		}
+
+		ret = msm_adsp_inform_mixer_ctl(rtd, payload);
+		if (ret) {
+			pr_err("%s: failed to inform mixer ctrl. err = %d\n",
+				__func__, ret);
+			return;
+		}
+		break;
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN_V2:
+			pr_debug("%s: ASM_SESSION_CMD_RUN_V2:", __func__);
+			pr_debug("token 0x%x, stream id %d\n", token,
+				  stream_id);
+			break;
+		case ASM_STREAM_CMD_CLOSE:
+			pr_debug("%s: ASM_DATA_CMD_CLOSE:", __func__);
+			pr_debug("token 0x%x, stream id %d\n", token,
+				  stream_id);
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+	default:
+		pr_debug("%s: Not Supported Event opcode[0x%x]\n",
+			  __func__, opcode);
+		break;
+	}
+}
+
+static void populate_codec_list(struct msm_transcode_loopback *trans,
+				struct snd_compr_stream *cstream)
+{
+	struct snd_compr_caps compr_cap;
+
+	pr_debug("%s\n", __func__);
+
+	memset(&compr_cap, 0, sizeof(struct snd_compr_caps));
+
+	if (cstream->direction == SND_COMPRESS_CAPTURE) {
+		compr_cap.direction = SND_COMPRESS_CAPTURE;
+		compr_cap.num_codecs = 3;
+		compr_cap.codecs[0] = SND_AUDIOCODEC_PCM;
+		compr_cap.codecs[1] = SND_AUDIOCODEC_AC3;
+		compr_cap.codecs[2] = SND_AUDIOCODEC_EAC3;
+		memcpy(&trans->source_compr_cap, &compr_cap,
+				sizeof(struct snd_compr_caps));
+	}
+
+	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+		compr_cap.direction = SND_COMPRESS_PLAYBACK;
+		compr_cap.num_codecs = 1;
+		compr_cap.codecs[0] = SND_AUDIOCODEC_PCM;
+		memcpy(&trans->sink_compr_cap, &compr_cap,
+				sizeof(struct snd_compr_caps));
+	}
+}
+
+static int msm_transcode_loopback_open(struct snd_compr_stream *cstream)
+{
+	int ret = 0;
+	struct snd_compr_runtime *runtime;
+	struct snd_soc_pcm_runtime *rtd;
+	struct msm_transcode_loopback *trans = &transcode_info;
+	struct trans_loopback_pdata *pdata;
+
+	if (cstream == NULL) {
+		pr_err("%s: Invalid substream\n", __func__);
+		return -EINVAL;
+	}
+	runtime = cstream->runtime;
+	rtd = snd_pcm_substream_chip(cstream);
+	pdata = snd_soc_platform_get_drvdata(rtd->platform);
+	pdata->cstream[rtd->dai_link->id] = cstream;
+
+	mutex_lock(&trans->lock);
+	if (trans->num_streams > LOOPBACK_SESSION_MAX_NUM_STREAMS) {
+		pr_err("msm_transcode_open failed..invalid stream\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (cstream->direction == SND_COMPRESS_CAPTURE) {
+		if (trans->source.cstream == NULL) {
+			trans->source.cstream = cstream;
+			trans->num_streams++;
+		} else {
+			pr_err("%s: capture stream already opened\n",
+				__func__);
+			ret = -EINVAL;
+			goto exit;
+		}
+	} else if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+		if (trans->sink.cstream == NULL) {
+			trans->sink.cstream = cstream;
+			trans->num_streams++;
+		} else {
+			pr_debug("%s: playback stream already opened\n",
+				__func__);
+			ret = -EINVAL;
+			goto exit;
+		}
+	}
+
+	pr_debug("%s: num stream%d, stream name %s\n", __func__,
+		 trans->num_streams, cstream->name);
+
+	populate_codec_list(trans, cstream);
+
+	if (trans->num_streams == LOOPBACK_SESSION_MAX_NUM_STREAMS)	{
+		pr_debug("%s: Moving loopback session to READY state %d\n",
+			 __func__, trans->session_state);
+		trans->session_state = LOOPBACK_SESSION_READY;
+	}
+
+	runtime->private_data = trans;
+	if (trans->num_streams == 1)
+		msm_adsp_init_mixer_ctl_pp_event_queue(rtd);
+exit:
+	mutex_unlock(&trans->lock);
+	return ret;
+}
+
+static void stop_transcoding(struct msm_transcode_loopback *trans)
+{
+	struct snd_soc_pcm_runtime *soc_pcm_rx;
+	struct snd_soc_pcm_runtime *soc_pcm_tx;
+
+	if (trans->audio_client != NULL) {
+		q6asm_cmd(trans->audio_client, CMD_CLOSE);
+
+		if (trans->sink.cstream != NULL) {
+			soc_pcm_rx = trans->sink.cstream->private_data;
+			msm_pcm_routing_dereg_phy_stream(
+					soc_pcm_rx->dai_link->id,
+					SND_COMPRESS_PLAYBACK);
+		}
+		if (trans->source.cstream != NULL) {
+			soc_pcm_tx = trans->source.cstream->private_data;
+			msm_pcm_routing_dereg_phy_stream(
+					soc_pcm_tx->dai_link->id,
+					SND_COMPRESS_CAPTURE);
+		}
+		q6asm_audio_client_free(trans->audio_client);
+		trans->audio_client = NULL;
+	}
+}
+
+static int msm_transcode_loopback_free(struct snd_compr_stream *cstream)
+{
+	struct snd_compr_runtime *runtime = cstream->runtime;
+	struct msm_transcode_loopback *trans = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(cstream);
+	int ret = 0;
+
+	mutex_lock(&trans->lock);
+
+	pr_debug("%s: Transcode loopback end:%d, streams %d\n", __func__,
+		  cstream->direction, trans->num_streams);
+	trans->num_streams--;
+	stop_transcoding(trans);
+
+	if (cstream->direction == SND_COMPRESS_PLAYBACK)
+		memset(&trans->sink, 0, sizeof(struct loopback_stream));
+	else if (cstream->direction == SND_COMPRESS_CAPTURE)
+		memset(&trans->source, 0, sizeof(struct loopback_stream));
+
+	trans->session_state = LOOPBACK_SESSION_CLOSE;
+	if (trans->num_streams == 1)
+		msm_adsp_clean_mixer_ctl_pp_event_queue(rtd);
+	mutex_unlock(&trans->lock);
+	return ret;
+}
+
+static int msm_transcode_loopback_trigger(struct snd_compr_stream *cstream,
+					  int cmd)
+{
+	struct snd_compr_runtime *runtime = cstream->runtime;
+	struct msm_transcode_loopback *trans = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+
+		if (trans->session_state == LOOPBACK_SESSION_START) {
+			pr_debug("%s: Issue Loopback session %d RUN\n",
+				  __func__, trans->instance);
+			q6asm_run_nowait(trans->audio_client, 0, 0, 0);
+			trans->session_state = LOOPBACK_SESSION_RUN;
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("%s: Issue Loopback session %d STOP\n", __func__,
+			  trans->instance);
+		if (trans->session_state == LOOPBACK_SESSION_RUN)
+			q6asm_cmd_nowait(trans->audio_client, CMD_PAUSE);
+		trans->session_state = LOOPBACK_SESSION_START;
+		break;
+
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream,
+				struct snd_compr_params *codec_param)
+{
+
+	struct snd_compr_runtime *runtime = cstream->runtime;
+	struct msm_transcode_loopback *trans = runtime->private_data;
+	struct snd_soc_pcm_runtime *soc_pcm_rx;
+	struct snd_soc_pcm_runtime *soc_pcm_tx;
+	uint32_t bit_width = 16;
+	int ret = 0;
+
+	if (trans == NULL) {
+		pr_err("%s: Invalid param\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&trans->lock);
+
+	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+		if (codec_param->codec.id == SND_AUDIOCODEC_PCM) {
+			trans->sink.codec_format =
+				FORMAT_LINEAR_PCM;
+			switch (codec_param->codec.format) {
+			case SNDRV_PCM_FORMAT_S32_LE:
+				bit_width = 32;
+				break;
+			case SNDRV_PCM_FORMAT_S24_LE:
+				bit_width = 24;
+				break;
+			case SNDRV_PCM_FORMAT_S24_3LE:
+				bit_width = 24;
+				break;
+			case SNDRV_PCM_FORMAT_S16_LE:
+			default:
+				bit_width = 16;
+				break;
+			}
+		} else {
+			pr_debug("%s: unknown sink codec\n", __func__);
+			ret = -EINVAL;
+			goto exit;
+		}
+		trans->sink.start = true;
+	}
+
+	if (cstream->direction == SND_COMPRESS_CAPTURE) {
+		switch (codec_param->codec.id) {
+		case SND_AUDIOCODEC_PCM:
+			pr_debug("Source SND_AUDIOCODEC_PCM\n");
+			trans->source.codec_format =
+				FORMAT_LINEAR_PCM;
+			break;
+		case SND_AUDIOCODEC_AC3:
+			pr_debug("Source SND_AUDIOCODEC_AC3\n");
+			trans->source.codec_format =
+				FORMAT_AC3;
+			break;
+		case SND_AUDIOCODEC_EAC3:
+			pr_debug("Source SND_AUDIOCODEC_EAC3\n");
+			trans->source.codec_format =
+				FORMAT_EAC3;
+			break;
+		default:
+			pr_debug("%s: unknown source codec\n", __func__);
+			ret = -EINVAL;
+			goto exit;
+		}
+		trans->source.start = true;
+	}
+
+	pr_debug("%s: trans->source.start %d trans->sink.start %d trans->source.cstream %pK trans->sink.cstream %pK trans->session_state %d\n",
+			__func__, trans->source.start, trans->sink.start,
+			trans->source.cstream, trans->sink.cstream,
+			trans->session_state);
+
+	if ((trans->session_state == LOOPBACK_SESSION_READY) &&
+			trans->source.start && trans->sink.start) {
+		pr_debug("%s: Moving loopback session to start state\n",
+			  __func__);
+		trans->session_state = LOOPBACK_SESSION_START;
+	}
+
+	if (trans->session_state == LOOPBACK_SESSION_START) {
+		if (trans->audio_client != NULL) {
+			pr_debug("%s: ASM client already opened, closing\n",
+				 __func__);
+			stop_transcoding(trans);
+		}
+
+		trans->audio_client = q6asm_audio_client_alloc(
+				(app_cb)loopback_event_handler, trans);
+		if (!trans->audio_client) {
+			pr_err("%s: Could not allocate memory\n", __func__);
+			ret = -EINVAL;
+			goto exit;
+		}
+		pr_debug("%s: ASM client allocated, callback %pK\n", __func__,
+						loopback_event_handler);
+		trans->session_id = trans->audio_client->session;
+		trans->audio_client->perf_mode = false;
+		ret = q6asm_open_transcode_loopback(trans->audio_client,
+					bit_width,
+					trans->source.codec_format,
+					trans->sink.codec_format);
+		if (ret < 0) {
+			pr_err("%s: Session transcode loopback open failed\n",
+				__func__);
+			q6asm_audio_client_free(trans->audio_client);
+			trans->audio_client = NULL;
+			goto exit;
+		}
+
+		pr_debug("%s: Starting ADM open for loopback\n", __func__);
+		soc_pcm_rx = trans->sink.cstream->private_data;
+		soc_pcm_tx = trans->source.cstream->private_data;
+		if (trans->source.codec_format != FORMAT_LINEAR_PCM)
+			msm_pcm_routing_reg_phy_compr_stream(
+					soc_pcm_tx->dai_link->id,
+					trans->audio_client->perf_mode,
+					trans->session_id,
+					SNDRV_PCM_STREAM_CAPTURE,
+					true);
+		else
+			msm_pcm_routing_reg_phy_stream(
+					soc_pcm_tx->dai_link->id,
+					trans->audio_client->perf_mode,
+					trans->session_id,
+					SNDRV_PCM_STREAM_CAPTURE);
+
+		msm_pcm_routing_reg_phy_stream(
+					soc_pcm_rx->dai_link->id,
+					trans->audio_client->perf_mode,
+					trans->session_id,
+					SNDRV_PCM_STREAM_PLAYBACK);
+		pr_debug("%s: Successfully opened ADM sessions\n", __func__);
+	}
+exit:
+	mutex_unlock(&trans->lock);
+	return ret;
+}
+
+static int msm_transcode_loopback_get_caps(struct snd_compr_stream *cstream,
+				struct snd_compr_caps *arg)
+{
+	struct snd_compr_runtime *runtime;
+	struct msm_transcode_loopback *trans;
+
+	if (!arg || !cstream) {
+		pr_err("%s: Invalid arguments\n", __func__);
+		return -EINVAL;
+	}
+
+	runtime = cstream->runtime;
+	trans = runtime->private_data;
+	pr_debug("%s\n", __func__);
+	if (cstream->direction == SND_COMPRESS_CAPTURE)
+		memcpy(arg, &trans->source_compr_cap,
+		       sizeof(struct snd_compr_caps));
+	else
+		memcpy(arg, &trans->sink_compr_cap,
+		       sizeof(struct snd_compr_caps));
+	return 0;
+}
+
+static int msm_transcode_stream_cmd_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	unsigned long fe_id = kcontrol->private_value;
+	struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
+				snd_soc_component_get_drvdata(comp);
+	struct snd_compr_stream *cstream = NULL;
+	struct msm_transcode_loopback *prtd;
+	int ret = 0;
+	struct msm_adsp_event_data *event_data = NULL;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received invalid fe_id %lu\n",
+			__func__, fe_id);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	cstream = pdata->cstream[fe_id];
+	if (cstream == NULL) {
+		pr_err("%s cstream is null.\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	prtd = cstream->runtime->private_data;
+	if (!prtd) {
+		pr_err("%s: prtd is null.\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (prtd->audio_client == NULL) {
+		pr_err("%s: audio_client is null.\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
+	if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
+	    (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
+		pr_err("%s: invalid event_type=%d",
+			 __func__, event_data->event_type);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >=
+					sizeof(ucontrol->value.bytes.data)) {
+		pr_err("%s param length=%d  exceeds limit",
+			 __func__, event_data->payload_len);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
+	if (ret < 0)
+		pr_err("%s: failed to send stream event cmd, err = %d\n",
+			__func__, ret);
+done:
+	return ret;
+}
+
+static int msm_transcode_ion_fd_map_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	unsigned long fe_id = kcontrol->private_value;
+	struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
+				snd_soc_component_get_drvdata(comp);
+	struct snd_compr_stream *cstream = NULL;
+	struct msm_transcode_loopback *prtd;
+	int fd;
+	int ret = 0;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bounds invalid fe_id %lu\n",
+			__func__, fe_id);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	cstream = pdata->cstream[fe_id];
+	if (cstream == NULL) {
+		pr_err("%s cstream is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	prtd = cstream->runtime->private_data;
+	if (!prtd) {
+		pr_err("%s: prtd is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (prtd->audio_client == NULL) {
+		pr_err("%s: audio_client is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	memcpy(&fd, ucontrol->value.bytes.data, sizeof(fd));
+	ret = q6asm_send_ion_fd(prtd->audio_client, fd);
+	if (ret < 0)
+		pr_err("%s: failed to register ion fd\n", __func__);
+done:
+	return ret;
+}
+
+static int msm_transcode_rtic_event_ack_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+	unsigned long fe_id = kcontrol->private_value;
+	struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
+					snd_soc_component_get_drvdata(comp);
+	struct snd_compr_stream *cstream = NULL;
+	struct msm_transcode_loopback *prtd;
+	int ret = 0;
+	int param_length = 0;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received invalid fe_id %lu\n",
+			__func__, fe_id);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	cstream = pdata->cstream[fe_id];
+	if (cstream == NULL) {
+		pr_err("%s cstream is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	prtd = cstream->runtime->private_data;
+	if (!prtd) {
+		pr_err("%s: prtd is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (prtd->audio_client == NULL) {
+		pr_err("%s: audio_client is null\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	memcpy(&param_length, ucontrol->value.bytes.data,
+		sizeof(param_length));
+	if ((param_length + sizeof(param_length))
+		>= sizeof(ucontrol->value.bytes.data)) {
+		pr_err("%s param length=%d  exceeds limit",
+			__func__, param_length);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = q6asm_send_rtic_event_ack(prtd->audio_client,
+			ucontrol->value.bytes.data + sizeof(param_length),
+			param_length);
+	if (ret < 0)
+		pr_err("%s: failed to send rtic event ack, err = %d\n",
+			__func__, ret);
+done:
+	return ret;
+}
+
+static int msm_transcode_stream_cmd_control(
+			struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = DSP_STREAM_CMD;
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol_new fe_loopback_stream_cmd_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_cmd_info,
+		.put = msm_transcode_stream_cmd_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_loopback_stream_cmd_config_control[0].name = mixer_str;
+	fe_loopback_stream_cmd_config_control[0].private_value =
+				rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+		fe_loopback_stream_cmd_config_control,
+		ARRAY_SIZE(fe_loopback_stream_cmd_config_control));
+	if (ret < 0)
+		pr_err("%s: failed to add ctl %s. err = %d\n",
+			__func__, mixer_str, ret);
+
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
+static int msm_transcode_stream_callback_control(
+			struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol *kctl;
+
+	struct snd_kcontrol_new fe_loopback_callback_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_callback_info,
+		.get = msm_adsp_stream_callback_get,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s: rtd is  NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_loopback_callback_config_control[0].name = mixer_str;
+	fe_loopback_callback_config_control[0].private_value =
+					rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+			fe_loopback_callback_config_control,
+			ARRAY_SIZE(fe_loopback_callback_config_control));
+	if (ret < 0) {
+		pr_err("%s: failed to add ctl %s. err = %d\n",
+			__func__, mixer_str, ret);
+		ret = -EINVAL;
+		goto free_mixer_str;
+	}
+
+	kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+	if (!kctl) {
+		pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
+		ret = -EINVAL;
+		goto free_mixer_str;
+	}
+
+	kctl->private_data = NULL;
+free_mixer_str:
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
+static int msm_transcode_add_ion_fd_cmd_control(struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "Playback ION FD";
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol_new fe_ion_fd_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_cmd_info,
+		.put = msm_transcode_ion_fd_map_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_ion_fd_config_control[0].name = mixer_str;
+	fe_ion_fd_config_control[0].private_value = rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+				fe_ion_fd_config_control,
+				ARRAY_SIZE(fe_ion_fd_config_control));
+	if (ret < 0)
+		pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
+
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
+static int msm_transcode_add_event_ack_cmd_control(
+					struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "Playback Event Ack";
+	const char *deviceNo = "NN";
+	char *mixer_str = NULL;
+	int ctl_len = 0, ret = 0;
+	struct snd_kcontrol_new fe_event_ack_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_adsp_stream_cmd_info,
+		.put = msm_transcode_rtic_event_ack_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+	fe_event_ack_config_control[0].name = mixer_str;
+	fe_event_ack_config_control[0].private_value = rtd->dai_link->id;
+	pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+	ret = snd_soc_add_platform_controls(rtd->platform,
+				fe_event_ack_config_control,
+				ARRAY_SIZE(fe_event_ack_config_control));
+	if (ret < 0)
+		pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
+
+	kfree(mixer_str);
+done:
+	return ret;
+}
+
+static int msm_transcode_loopback_new(struct snd_soc_pcm_runtime *rtd)
+{
+	int rc;
+
+	rc = msm_transcode_stream_cmd_control(rtd);
+	if (rc)
+		pr_err("%s: ADSP Stream Cmd Control open failed\n", __func__);
+
+	rc = msm_transcode_stream_callback_control(rtd);
+	if (rc)
+		pr_err("%s: ADSP Stream callback Control open failed\n",
+			__func__);
+
+	rc = msm_transcode_add_ion_fd_cmd_control(rtd);
+	if (rc)
+		pr_err("%s: Could not add transcode ion fd Control\n",
+			__func__);
+
+	rc = msm_transcode_add_event_ack_cmd_control(rtd);
+	if (rc)
+		pr_err("%s: Could not add transcode event ack Control\n",
+			__func__);
+
+	return 0;
+}
+
+static struct snd_compr_ops msm_transcode_loopback_ops = {
+	.open			= msm_transcode_loopback_open,
+	.free			= msm_transcode_loopback_free,
+	.trigger		= msm_transcode_loopback_trigger,
+	.set_params		= msm_transcode_loopback_set_params,
+	.get_caps		= msm_transcode_loopback_get_caps,
+};
+
+
+static int msm_transcode_loopback_probe(struct snd_soc_platform *platform)
+{
+	struct trans_loopback_pdata *pdata = NULL;
+
+	pr_debug("%s\n", __func__);
+	pdata = (struct trans_loopback_pdata *)
+			kzalloc(sizeof(struct trans_loopback_pdata),
+			GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	snd_soc_platform_set_drvdata(platform, pdata);
+	return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.probe		= msm_transcode_loopback_probe,
+	.compr_ops	= &msm_transcode_loopback_ops,
+	.pcm_new	= msm_transcode_loopback_new,
+};
+
+static int msm_transcode_dev_probe(struct platform_device *pdev)
+{
+
+	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	if (pdev->dev.of_node)
+		dev_set_name(&pdev->dev, "%s", "msm-transcode-loopback");
+
+	return snd_soc_register_platform(&pdev->dev,
+					&msm_soc_platform);
+}
+
+static int msm_transcode_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id msm_transcode_loopback_dt_match[] = {
+	{.compatible = "qcom,msm-transcode-loopback"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, msm_transcode_loopback_dt_match);
+
+static struct platform_driver msm_transcode_loopback_driver = {
+	.driver = {
+		.name = "msm-transcode-loopback",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_transcode_loopback_dt_match,
+	},
+	.probe = msm_transcode_dev_probe,
+	.remove = msm_transcode_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	memset(&transcode_info, 0, sizeof(struct msm_transcode_loopback));
+	mutex_init(&transcode_info.lock);
+	return platform_driver_register(&msm_transcode_loopback_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	mutex_destroy(&transcode_info.lock);
+	platform_driver_unregister(&msm_transcode_loopback_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Transcode loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 90d640d..1590605 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -24,7 +24,6 @@
 #include <sound/q6afe-v2.h>
 #include <sound/audio_cal_utils.h>
 #include <sound/asound.h>
-#include <sound/msm-dts-eagle.h>
 #include "msm-dts-srs-tm-config.h"
 #include <sound/adsp_err.h>
 
@@ -265,223 +264,6 @@
 	return idx;
 }
 
-int adm_dts_eagle_set(int port_id, int copp_idx, int param_id,
-		      void *data, uint32_t size)
-{
-	struct adm_cmd_set_pp_params_v5	admp;
-	int p_idx, ret = 0, *ob_params;
-
-	pr_debug("DTS_EAGLE_ADM: %s - port id %i, copp idx %i, param id 0x%X size %u\n",
-		__func__, port_id, copp_idx, param_id, size);
-
-	port_id = afe_convert_virtual_to_portid(port_id);
-	p_idx = adm_validate_and_get_port_index(port_id);
-	pr_debug("DTS_EAGLE_ADM: %s - after lookup, port id %i, port idx %i\n",
-		__func__, port_id, p_idx);
-
-	if (p_idx < 0) {
-		pr_err("DTS_EAGLE_ADM: %s: invalid port index 0x%x, port id 0x%x\n",
-			__func__, p_idx, port_id);
-		return -EINVAL;
-	}
-
-	if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
-		pr_err("DTS_EAGLE_ADM: %s: Invalid copp_idx: %d\n", __func__,
-			copp_idx);
-		return -EINVAL;
-	}
-
-	ob_params = (int *)this_adm.outband_memmap.kvaddr;
-	if (ob_params == NULL) {
-		pr_err("DTS_EAGLE_ADM: %s - NULL memmap. Non Eagle topology selected?\n",
-			__func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	/* check for integer overflow */
-	if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
-		ret = -EINVAL;
-	if ((ret < 0) ||
-	    (size + APR_CMD_OB_HDR_SZ > this_adm.outband_memmap.size)) {
-		pr_err("DTS_EAGLE_ADM - %s: ion alloc of size %zu too small for size requested %u\n",
-			__func__, this_adm.outband_memmap.size,
-			size + APR_CMD_OB_HDR_SZ);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	*ob_params++ = AUDPROC_MODULE_ID_DTS_HPX_POSTMIX;
-	*ob_params++ = param_id;
-	*ob_params++ = size;
-	memcpy(ob_params, data, size);
-
-	admp.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	admp.hdr.pkt_size = sizeof(admp);
-	admp.hdr.src_svc = APR_SVC_ADM;
-	admp.hdr.src_domain = APR_DOMAIN_APPS;
-	admp.hdr.src_port = port_id;
-	admp.hdr.dest_svc = APR_SVC_ADM;
-	admp.hdr.dest_domain = APR_DOMAIN_ADSP;
-	admp.hdr.dest_port = atomic_read(&this_adm.copp.id[p_idx][copp_idx]);
-	admp.hdr.token = p_idx << 16 | copp_idx;
-	admp.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
-	admp.payload_addr_lsw = lower_32_bits(this_adm.outband_memmap.paddr);
-	admp.payload_addr_msw = msm_audio_populate_upper_32_bits(
-						this_adm.outband_memmap.paddr);
-	admp.mem_map_handle = atomic_read(&this_adm.mem_map_handles[
-					  ADM_DTS_EAGLE]);
-	admp.payload_size = size + sizeof(struct adm_param_data_v5);
-
-	pr_debug("DTS_EAGLE_ADM: %s - Command was sent now check Q6 - port id = %d, size %d, module id %x, param id %x.\n",
-			__func__, admp.hdr.dest_port,
-			admp.payload_size, AUDPROC_MODULE_ID_DTS_HPX_POSTMIX,
-			param_id);
-	atomic_set(&this_adm.copp.stat[p_idx][copp_idx], -1);
-	ret = apr_send_pkt(this_adm.apr, (uint32_t *)&admp);
-	if (ret < 0) {
-		pr_err("DTS_EAGLE_ADM: %s - ADM enable for port %d failed\n",
-			__func__, port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	ret = wait_event_timeout(this_adm.copp.wait[p_idx][copp_idx],
-			atomic_read(&this_adm.copp.stat
-			[p_idx][copp_idx]) >= 0,
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("DTS_EAGLE_ADM: %s - set params timed out port = %d\n",
-			__func__, port_id);
-		ret = -EINVAL;
-	} else if (atomic_read(&this_adm.copp.stat
-				[p_idx][copp_idx]) > 0) {
-		pr_err("%s: DSP returned error[%s]\n",
-				__func__, adsp_err_get_err_str(
-				atomic_read(&this_adm.copp.stat
-				[p_idx][copp_idx])));
-		ret = adsp_err_get_lnx_err_code(
-				atomic_read(&this_adm.copp.stat
-				[p_idx][copp_idx]));
-	} else {
-		ret = 0;
-	}
-
-fail_cmd:
-	return ret;
-}
-
-int adm_dts_eagle_get(int port_id, int copp_idx, int param_id,
-		      void *data, uint32_t size)
-{
-	struct adm_cmd_get_pp_params_v5	admp;
-	int p_idx, ret = 0, *ob_params;
-	uint32_t orig_size = size;
-
-	pr_debug("DTS_EAGLE_ADM: %s - port id %i, copp idx %i, param id 0x%X\n",
-		 __func__, port_id, copp_idx, param_id);
-
-	port_id = afe_convert_virtual_to_portid(port_id);
-	p_idx = adm_validate_and_get_port_index(port_id);
-	if (p_idx < 0) {
-		pr_err("DTS_EAGLE_ADM: %s - invalid port index %i, port id %i, copp idx %i\n",
-				__func__, p_idx, port_id, copp_idx);
-		return -EINVAL;
-	}
-
-	if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
-		pr_err("DTS_EAGLE_ADM: %s: Invalid copp_idx: %d\n", __func__,
-			copp_idx);
-		return -EINVAL;
-	}
-
-	if ((size == 0) || !data) {
-		pr_err("DTS_EAGLE_ADM: %s - invalid size %u or pointer %pK.\n",
-			__func__, size, data);
-		return -EINVAL;
-	}
-
-	size = (size+3) & 0xFFFFFFFC;
-
-	ob_params = (int *)(this_adm.outband_memmap.kvaddr);
-	if (ob_params == NULL) {
-		pr_err("DTS_EAGLE_ADM: %s - NULL memmap. Non Eagle topology selected?",
-			__func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	/* check for integer overflow */
-	if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
-		ret = -EINVAL;
-	if ((ret < 0) ||
-	    (size + APR_CMD_OB_HDR_SZ > this_adm.outband_memmap.size)) {
-		pr_err("DTS_EAGLE_ADM - %s: ion alloc of size %zu too small for size requested %u\n",
-			__func__, this_adm.outband_memmap.size,
-			size + APR_CMD_OB_HDR_SZ);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	*ob_params++ = AUDPROC_MODULE_ID_DTS_HPX_POSTMIX;
-	*ob_params++ = param_id;
-	*ob_params++ = size;
-
-	admp.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-			     APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	admp.hdr.pkt_size = sizeof(admp);
-	admp.hdr.src_svc = APR_SVC_ADM;
-	admp.hdr.src_domain = APR_DOMAIN_APPS;
-	admp.hdr.src_port = port_id;
-	admp.hdr.dest_svc = APR_SVC_ADM;
-	admp.hdr.dest_domain = APR_DOMAIN_ADSP;
-	admp.hdr.dest_port = atomic_read(&this_adm.copp.id[p_idx][copp_idx]);
-	admp.hdr.token = p_idx << 16 | copp_idx;
-	admp.hdr.opcode = ADM_CMD_GET_PP_PARAMS_V5;
-	admp.data_payload_addr_lsw =
-				lower_32_bits(this_adm.outband_memmap.paddr);
-	admp.data_payload_addr_msw =
-				msm_audio_populate_upper_32_bits(
-						this_adm.outband_memmap.paddr);
-	admp.mem_map_handle = atomic_read(&this_adm.mem_map_handles[
-					  ADM_DTS_EAGLE]);
-	admp.module_id = AUDPROC_MODULE_ID_DTS_HPX_POSTMIX;
-	admp.param_id = param_id;
-	admp.param_max_size = size + sizeof(struct adm_param_data_v5);
-	admp.reserved = 0;
-
-	atomic_set(&this_adm.copp.stat[p_idx][copp_idx], -1);
-
-	ret = apr_send_pkt(this_adm.apr, (uint32_t *)&admp);
-	if (ret < 0) {
-		pr_err("DTS_EAGLE_ADM: %s - Failed to get EAGLE Params on port %d\n",
-			__func__, port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	ret = wait_event_timeout(this_adm.copp.wait[p_idx][copp_idx],
-			atomic_read(&this_adm.copp.stat
-			[p_idx][copp_idx]) >= 0,
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("DTS_EAGLE_ADM: %s - EAGLE get params timed out port = %d\n",
-			__func__, port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
-	} else if (atomic_read(&this_adm.copp.stat
-				[p_idx][copp_idx]) > 0) {
-		pr_err("%s: DSP returned error[%s]\n",
-				__func__, adsp_err_get_err_str(
-				atomic_read(&this_adm.copp.stat
-				[p_idx][copp_idx])));
-		ret = adsp_err_get_lnx_err_code(
-				atomic_read(&this_adm.copp.stat
-					[p_idx][copp_idx]));
-		goto fail_cmd;
-	}
-
-	memcpy(data, ob_params, orig_size);
-	ret = 0;
-fail_cmd:
-	return ret;
-}
-
 int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id,
 		      void *srs_params)
 {
@@ -748,6 +530,267 @@
 	return ret;
 }
 
+static int adm_populate_channel_weight(u16 *ptr,
+					struct msm_pcm_channel_mixer *ch_mixer,
+					int channel_index)
+{
+	u16 i, j, start_index = 0;
+
+	if (channel_index > ch_mixer->output_channel) {
+		pr_err("%s: channel index %d is larger than output_channel %d\n",
+			 __func__, channel_index, ch_mixer->output_channel);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ch_mixer->output_channel; i++) {
+		pr_debug("%s: weight for output %d:", __func__, i);
+		for (j = 0; j < ADM_MAX_CHANNELS; j++)
+			pr_debug(" %d",
+				ch_mixer->channel_weight[i][j]);
+		pr_debug("\n");
+	}
+
+	for (i = 0; i < channel_index; ++i)
+		start_index += ch_mixer->input_channels[i];
+
+	for (i = 0; i < ch_mixer->output_channel; ++i) {
+		for (j = start_index;
+			j < start_index +
+			ch_mixer->input_channels[channel_index]; j++) {
+			*ptr = ch_mixer->channel_weight[i][j];
+			 pr_debug("%s: ptr[%d][%d] = %d\n",
+				__func__, i, j, *ptr);
+			 ptr++;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * adm_programable_channel_mixer
+ *
+ * Receives port_id, copp_idx, session_id, session_type, ch_mixer
+ * and channel_index to send ADM command to mix COPP data.
+ *
+ * port_id - Passed value, port_id for which backend is wanted
+ * copp_idx - Passed value, copp_idx for which COPP is wanted
+ * session_id - Passed value, session_id for which session is needed
+ * session_type - Passed value, session_type for RX or TX
+ * ch_mixer - Passed value, ch_mixer for which channel mixer config is needed
+ * channel_index - Passed value, channel_index for which channel is needed
+ */
+int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id,
+				  int session_type,
+				  struct msm_pcm_channel_mixer *ch_mixer,
+				  int channel_index)
+{
+	struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL;
+	struct adm_param_data_v5 data_v5;
+	int ret = 0, port_idx, sz = 0, param_size = 0;
+	u16 *adm_pspd_params;
+	u16 *ptr;
+	int index = 0;
+
+	pr_debug("%s: port_id = %d\n", __func__, port_id);
+	port_id = afe_convert_virtual_to_portid(port_id);
+	port_idx = adm_validate_and_get_port_index(port_id);
+	if (port_idx < 0) {
+		pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+		return -EINVAL;
+	}
+	/*
+	 * First 8 bytes are 4 bytes as rule number, 2 bytes as output
+	 * channel and 2 bytes as input channel.
+	 * 2 * ch_mixer->output_channel means output channel mapping.
+	 * 2 * ch_mixer->input_channels[channel_index]) means input
+	 * channel mapping.
+	 * 2 * ch_mixer->input_channels[channel_index] *
+	 * ch_mixer->output_channel) means the channel mixer weighting
+	 * coefficients.
+	 * param_size needs to be a multiple of 4 bytes.
+	 */
+
+	param_size = 2 * (4 + ch_mixer->output_channel +
+			ch_mixer->input_channels[channel_index] +
+			ch_mixer->input_channels[channel_index] *
+			ch_mixer->output_channel);
+	roundup(param_size, 4);
+
+	sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) +
+			sizeof(struct default_chmixer_param_id_coeff) +
+			sizeof(struct adm_param_data_v5) + param_size;
+	pr_debug("%s: sz = %d\n", __func__, sz);
+	adm_params = kzalloc(sz, GFP_KERNEL);
+	if (!adm_params)
+		return -ENOMEM;
+
+	adm_params->payload_addr_lsw = 0;
+	adm_params->payload_addr_msw = 0;
+	adm_params->mem_map_handle = 0;
+	adm_params->direction = session_type;
+	adm_params->sessionid = session_id;
+	pr_debug("%s: copp_id = %d, session id  %d\n", __func__,
+		atomic_read(&this_adm.copp.id[port_idx][copp_idx]),
+			session_id);
+	adm_params->deviceid = atomic_read(
+				&this_adm.copp.id[port_idx][copp_idx]);
+	adm_params->reserved = 0;
+
+	data_v5.module_id = MTMX_MODULE_ID_DEFAULT_CHMIXER;
+	data_v5.param_id =  DEFAULT_CHMIXER_PARAM_ID_COEFF;
+	data_v5.reserved = 0;
+	data_v5.param_size = param_size;
+	adm_params->payload_size =
+			sizeof(struct default_chmixer_param_id_coeff) +
+			sizeof(struct adm_param_data_v5) + data_v5.param_size;
+	adm_pspd_params = (u16 *)((u8 *)adm_params +
+			sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5));
+	memcpy(adm_pspd_params, &data_v5, sizeof(data_v5));
+
+	adm_pspd_params = (u16 *)((u8 *)adm_params +
+			sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5)
+			+ sizeof(data_v5));
+
+	adm_pspd_params[0] = ch_mixer->rule;
+	adm_pspd_params[2] = ch_mixer->output_channel;
+	adm_pspd_params[3] = ch_mixer->input_channels[channel_index];
+	index = 4;
+
+	if (ch_mixer->output_channel == 1) {
+		adm_pspd_params[index] = PCM_CHANNEL_FC;
+	} else if (ch_mixer->output_channel == 2) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+	} else if (ch_mixer->output_channel == 3) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+	} else if (ch_mixer->output_channel == 4) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
+		adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
+	} else if (ch_mixer->output_channel == 5) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+		adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
+		adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
+	} else if (ch_mixer->output_channel == 6) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+		adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+		adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+		adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+	} else if (ch_mixer->output_channel == 8) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+		adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+		adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+		adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+		adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
+		adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+	}
+
+	index = index + ch_mixer->output_channel;
+	if (ch_mixer->input_channels[channel_index] == 1) {
+		adm_pspd_params[index] = PCM_CHANNEL_FC;
+	} else if (ch_mixer->input_channels[channel_index] == 2) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+	} else if (ch_mixer->input_channels[channel_index] == 3) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+	} else if (ch_mixer->input_channels[channel_index] == 4) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
+		adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
+	} else if (ch_mixer->input_channels[channel_index] == 5) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+		adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
+		adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
+	} else if (ch_mixer->input_channels[channel_index] == 6) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+		adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+		adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+		adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+	} else if (ch_mixer->input_channels[channel_index] == 8) {
+		adm_pspd_params[index] = PCM_CHANNEL_FL;
+		adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+		adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+		adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+		adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+		adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+		adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
+		adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+	}
+
+	index = index + ch_mixer->input_channels[channel_index];
+	ret = adm_populate_channel_weight(&adm_pspd_params[index],
+					ch_mixer, channel_index);
+	if (!ret) {
+		pr_err("%s: fail to get channel weight with error %d\n",
+			__func__, ret);
+		goto fail_cmd;
+	}
+
+	adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	adm_params->hdr.src_svc = APR_SVC_ADM;
+	adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+	adm_params->hdr.src_port = port_id;
+	adm_params->hdr.dest_svc = APR_SVC_ADM;
+	adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+	adm_params->hdr.dest_port =
+			atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+	adm_params->hdr.token = port_idx << 16 | copp_idx;
+	adm_params->hdr.opcode = ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5;
+	adm_params->hdr.pkt_size = sz;
+	adm_params->payload_addr_lsw = 0;
+	adm_params->payload_addr_msw = 0;
+	adm_params->mem_map_handle = 0;
+	adm_params->reserved = 0;
+
+	ptr = (u16 *)adm_params;
+	for (index = 0; index < (sz / 2); index++)
+		pr_debug("%s: adm_params[%d] = 0x%x\n",
+			__func__, index, (unsigned int)ptr[index]);
+
+	atomic_set(&this_adm.copp.stat[port_idx][copp_idx], 0);
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+	if (ret < 0) {
+		pr_err("%s: Set params failed port %d rc %d\n", __func__,
+			port_id, ret);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+			atomic_read(
+			&this_adm.copp.stat[port_idx][copp_idx]) >= 0,
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: set params timed out port = %d\n",
+			__func__, port_id);
+		ret = -ETIMEDOUT;
+		goto fail_cmd;
+	}
+	ret = 0;
+fail_cmd:
+	kfree(adm_params);
+
+	return ret;
+}
+
 int adm_set_stereo_to_custom_stereo(int port_id, int copp_idx,
 				    unsigned int session_id, char *params,
 				    uint32_t params_length)
@@ -2352,13 +2395,6 @@
 		 __func__, port_id, path, rate, channel_mode, perf_mode,
 		 topology);
 
-	/* For DTS EAGLE only, force 24 bit */
-	if ((topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX) &&
-		(perf_mode == LEGACY_PCM_MODE)) {
-		bit_width = 24;
-		pr_debug("%s: Force open adm in 24-bit for DTS HPX topology 0x%x\n",
-			__func__, topology);
-	}
 	port_id = q6audio_convert_virtual_to_portid(port_id);
 	port_idx = adm_validate_and_get_port_index(port_id);
 	if (port_idx < 0) {
@@ -2380,8 +2416,7 @@
 		flags = ADM_ULL_POST_PROCESSING_DEVICE_SESSION;
 		if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
 		    (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
-		    (topology == SRS_TRUMEDIA_TOPOLOGY_ID) ||
-		    (topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX))
+		    (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
 			topology = DEFAULT_COPP_TOPOLOGY;
 	} else if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
 		flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
@@ -2392,11 +2427,11 @@
 		flags = ADM_LOW_LATENCY_DEVICE_SESSION;
 		if ((topology == DOLBY_ADM_COPP_TOPOLOGY_ID) ||
 		    (topology == DS2_ADM_COPP_TOPOLOGY_ID) ||
-		    (topology == SRS_TRUMEDIA_TOPOLOGY_ID) ||
-		    (topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX))
+		    (topology == SRS_TRUMEDIA_TOPOLOGY_ID))
 			topology = DEFAULT_COPP_TOPOLOGY;
 	} else {
-		if (path == ADM_PATH_COMPRESSED_RX)
+		if ((path == ADM_PATH_COMPRESSED_RX) ||
+		    (path == ADM_PATH_COMPRESSED_TX))
 			flags = 0;
 		else
 			flags = ADM_LEGACY_DEVICE_SESSION;
@@ -2433,7 +2468,8 @@
 			   acdb_id);
 		set_bit(ADM_STATUS_CALIBRATION_REQUIRED,
 		(void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
-		if (path != ADM_PATH_COMPRESSED_RX)
+		if ((path != ADM_PATH_COMPRESSED_RX) &&
+		    (path != ADM_PATH_COMPRESSED_TX))
 			send_adm_custom_topology();
 	}
 
@@ -2463,22 +2499,6 @@
 		(uint32_t)this_adm.outband_memmap.size);
 		}
 	}
-		if ((topology == ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX) &&
-		    (perf_mode == LEGACY_PCM_MODE)) {
-			int res = 0;
-
-			atomic_set(&this_adm.mem_map_index, ADM_DTS_EAGLE);
-			msm_dts_ion_memmap(&this_adm.outband_memmap);
-			res = adm_memory_map_regions(
-				      &this_adm.outband_memmap.paddr,
-				      0,
-				      (uint32_t *)&this_adm.outband_memmap.size,
-				      1);
-			if (res < 0)
-				pr_err("%s: DTS_EAGLE mmap did not work!",
-					__func__);
-		}
-		memset(&open, 0, sizeof(struct adm_cmd_device_open_v5));
 		open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 						   APR_HDR_LEN(APR_HDR_SIZE),
 						   APR_PKT_VER);
@@ -2721,6 +2741,10 @@
 		route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
 		route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX;
 		break;
+	case ADM_PATH_COMPRESSED_TX:
+		route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
+		route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_TX;
+		break;
 	default:
 		pr_err("%s: Wrong path set[%d]\n", __func__, path);
 		break;
@@ -2824,10 +2848,6 @@
 					__func__, port_idx, copp_idx);
 				continue;
 			}
-			if (atomic_read(
-				&this_adm.copp.topology[port_idx][copp_idx]) ==
-				ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX)
-				continue;
 			rtac_add_adm_device(payload_map.port_id[i],
 					    atomic_read(&this_adm.copp.id
 							[port_idx][copp_idx]),
@@ -2941,21 +2961,6 @@
 			}
 		}
 
-		if ((perf_mode == LEGACY_PCM_MODE) &&
-		    (this_adm.outband_memmap.paddr != 0) &&
-		    (atomic_read(
-			&this_adm.copp.topology[port_idx][copp_idx]) ==
-			ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX)) {
-			atomic_set(&this_adm.mem_map_index, ADM_DTS_EAGLE);
-			ret = adm_memory_unmap_regions();
-			if (ret < 0) {
-				pr_err("%s: adm mem unmmap err %d",
-					__func__, ret);
-			} else {
-				atomic_set(&this_adm.mem_map_handles
-					   [ADM_DTS_EAGLE], 0);
-			}
-		}
 
 		if ((afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) &&
 		    this_adm.sourceTrackingData.memmap.paddr) {
@@ -3432,10 +3437,6 @@
 		{NULL, NULL, NULL, NULL, NULL, NULL} },
 		{NULL, NULL, cal_utils_match_buf_num} },
 
-		{{DTS_EAGLE_CAL_TYPE,
-		{NULL, NULL, NULL, NULL, NULL, NULL} },
-		{NULL, NULL, cal_utils_match_buf_num} },
-
 		{{SRS_TRUMEDIA_CAL_TYPE,
 		{NULL, NULL, NULL, NULL, NULL, NULL} },
 		{NULL, NULL, cal_utils_match_buf_num} },
@@ -4309,6 +4310,136 @@
 	return ret;
 }
 
+/**
+ * adm_swap_speaker_channels
+ *
+ * Receives port_id, copp_idx, sample rate, spk_swap and
+ * send MFC command to swap speaker channel.
+ * Return zero on success. On failure returns nonzero.
+ *
+ * port_id - Passed value, port_id for which channels swap is wanted
+ * copp_idx - Passed value, copp_idx for which channels swap is wanted
+ * sample_rate - Passed value, sample rate used by app type config
+ * spk_swap  - Passed value, spk_swap for check if swap flag is set
+ */
+int adm_swap_speaker_channels(int port_id, int copp_idx,
+			int sample_rate, bool spk_swap)
+{
+	struct audproc_mfc_output_media_fmt mfc_cfg;
+	uint16_t num_channels;
+	int port_idx;
+	int ret  = 0;
+
+	pr_debug("%s: Enter, port_id %d, copp_idx %d\n",
+		  __func__, port_id, copp_idx);
+	port_id = q6audio_convert_virtual_to_portid(port_id);
+	port_idx = adm_validate_and_get_port_index(port_id);
+	if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) {
+		pr_err("%s: Invalid port_id %#x\n", __func__, port_id);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) {
+		pr_err("%s: Invalid copp_num: %d\n", __func__, copp_idx);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	num_channels = atomic_read(
+				&this_adm.copp.channels[port_idx][copp_idx]);
+	if (num_channels != 2) {
+		pr_debug("%s: Invalid number of channels: %d\n",
+			__func__, num_channels);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	memset(&mfc_cfg, 0, sizeof(mfc_cfg));
+	mfc_cfg.params.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mfc_cfg.params.hdr.pkt_size =
+				sizeof(mfc_cfg);
+	mfc_cfg.params.hdr.src_svc = APR_SVC_ADM;
+	mfc_cfg.params.hdr.src_domain = APR_DOMAIN_APPS;
+	mfc_cfg.params.hdr.src_port = port_id;
+	mfc_cfg.params.hdr.dest_svc = APR_SVC_ADM;
+	mfc_cfg.params.hdr.dest_domain = APR_DOMAIN_ADSP;
+	mfc_cfg.params.hdr.dest_port =
+			atomic_read(&this_adm.copp.id[port_idx][copp_idx]);
+	mfc_cfg.params.hdr.token = port_idx << 16 | copp_idx;
+	mfc_cfg.params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+	mfc_cfg.params.payload_addr_lsw = 0;
+	mfc_cfg.params.payload_addr_msw = 0;
+	mfc_cfg.params.mem_map_handle = 0;
+	mfc_cfg.params.payload_size = sizeof(mfc_cfg) -
+				sizeof(mfc_cfg.params);
+	mfc_cfg.data.module_id = AUDPROC_MODULE_ID_MFC;
+	mfc_cfg.data.param_id = AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
+	mfc_cfg.data.param_size = mfc_cfg.params.payload_size -
+				sizeof(mfc_cfg.data);
+	mfc_cfg.data.reserved = 0;
+	mfc_cfg.sampling_rate = sample_rate;
+	mfc_cfg.bits_per_sample =
+		atomic_read(&this_adm.copp.bit_width[port_idx][copp_idx]);
+	mfc_cfg.num_channels = num_channels;
+
+	/* Currently applying speaker swap for only 2 channel use case */
+	if (spk_swap) {
+		mfc_cfg.channel_type[0] =
+			(uint16_t) PCM_CHANNEL_FR;
+		mfc_cfg.channel_type[1] =
+			(uint16_t) PCM_CHANNEL_FL;
+	} else {
+		mfc_cfg.channel_type[0] =
+			(uint16_t) PCM_CHANNEL_FL;
+		mfc_cfg.channel_type[1] =
+			(uint16_t) PCM_CHANNEL_FR;
+	}
+
+	atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+	pr_debug("%s: mfc config: port_idx %d copp_idx  %d copp SR %d copp BW %d copp chan %d\n",
+		__func__, port_idx, copp_idx, mfc_cfg.sampling_rate,
+		mfc_cfg.bits_per_sample, mfc_cfg.num_channels);
+
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)&mfc_cfg);
+	if (ret < 0) {
+		pr_err("%s: port_id: for[0x%x] failed %d\n",
+		__func__, port_id, ret);
+		goto done;
+	}
+	/* Wait for the callback with copp id */
+	ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
+		atomic_read(&this_adm.copp.stat
+		[port_idx][copp_idx]) >= 0,
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: mfc_cfg Set params timed out for port_id: for [0x%x]\n",
+					__func__, port_id);
+		ret = -ETIMEDOUT;
+		goto done;
+	}
+
+	if (atomic_read(&this_adm.copp.stat[port_idx][copp_idx]) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+			__func__, adsp_err_get_err_str(
+			atomic_read(&this_adm.copp.stat
+			[port_idx][copp_idx])));
+		ret = adsp_err_get_lnx_err_code(
+			atomic_read(&this_adm.copp.stat
+				[port_idx][copp_idx]));
+		goto done;
+	}
+
+	pr_debug("%s: mfc_cfg Set params returned success", __func__);
+	ret = 0;
+
+done:
+	return ret;
+}
+EXPORT_SYMBOL(adm_swap_speaker_channels);
+
 int adm_set_sound_focus(int port_id, int copp_idx,
 			struct sound_focus_param soundFocusData)
 {
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 05d123b..e1ce947 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -2125,6 +2125,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(afe_set_config);
 
 /*
  * afe_clear_config - If SSR happens ADSP loses AFE configs, let AFE driver know
@@ -2135,6 +2136,7 @@
 {
 	clear_bit(config, &afe_configured_cmd);
 }
+EXPORT_SYMBOL(afe_clear_config);
 
 bool afe_has_config(enum afe_config_type config)
 {
@@ -5191,7 +5193,7 @@
 					AFE_API_VERSION_LOOPBACK_CONFIG;
 	cmd_sidetone.cfg_data.dst_port_id = rx_port_id;
 	cmd_sidetone.cfg_data.routing_mode = LB_MODE_SIDETONE;
-	cmd_sidetone.cfg_data.enable = ((enable == 1) ? sidetone_enable : 0);
+	cmd_sidetone.cfg_data.enable = enable;
 
 	pr_debug("%s rx(0x%x) tx(0x%x) enable(%d) mid(0x%x) gain(%d) sidetone_enable(%d)\n",
 		  __func__, rx_port_id, tx_port_id,
@@ -5749,6 +5751,14 @@
 	return ret;
 }
 
+/**
+ * afe_set_lpass_clk_cfg - Set AFE clk config
+ *
+ * @index: port index
+ * @cfg: pointer to clk set struct
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
 int afe_set_lpass_clk_cfg(int index, struct afe_clk_set *cfg)
 {
 	struct afe_lpass_clk_config_command_v2 clk_cfg;
@@ -5829,7 +5839,16 @@
 	mutex_unlock(&this_afe.afe_cmd_lock);
 	return ret;
 }
+EXPORT_SYMBOL(afe_set_lpass_clk_cfg);
 
+/**
+ * afe_set_lpass_clock_v2 - Enable AFE lpass clock
+ *
+ * @port_id: AFE port id
+ * @cfg: pointer to clk set struct
+ *
+ * Returns 0 on success, appropriate error code otherwise
+ */
 int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg)
 {
 	int index = 0;
@@ -5855,6 +5874,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(afe_set_lpass_clock_v2);
 
 int afe_set_lpass_internal_digital_codec_clock(u16 port_id,
 			struct afe_digital_clk_cfg *cfg)
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index b52c83b..e7e1618 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -38,8 +38,8 @@
 #include <sound/q6asm-v2.h>
 #include <sound/q6audio-v2.h>
 #include <sound/audio_cal_utils.h>
-#include <sound/msm-dts-eagle.h>
 #include <sound/adsp_err.h>
+#include <sound/compress_params.h>
 
 #define TRUE        0x01
 #define FALSE       0x00
@@ -155,6 +155,38 @@
 static char *out_buffer;
 static char *in_buffer;
 
+static uint32_t adsp_reg_event_opcode[] = {
+	ASM_STREAM_CMD_REGISTER_PP_EVENTS,
+	ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS,
+	ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE };
+
+static uint32_t adsp_raise_event_opcode[] = {
+	ASM_STREAM_PP_EVENT,
+	ASM_STREAM_CMD_ENCDEC_EVENTS,
+	ASM_IEC_61937_MEDIA_FMT_EVENT };
+
+static int is_adsp_reg_event(uint32_t cmd)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(adsp_reg_event_opcode); i++) {
+		if (cmd == adsp_reg_event_opcode[i])
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int is_adsp_raise_event(uint32_t cmd)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(adsp_raise_event_opcode); i++) {
+		if (cmd == adsp_raise_event_opcode[i])
+			return i;
+	}
+	return -EINVAL;
+}
+
 static inline void q6asm_set_flag_in_token(union asm_token_struct *asm_token,
 					   int flag, int flag_offset)
 {
@@ -1091,6 +1123,72 @@
 	return NULL;
 }
 
+int q6asm_send_stream_cmd(struct audio_client *ac,
+			  struct msm_adsp_event_data *data)
+{
+	char *asm_params = NULL;
+	struct apr_hdr hdr;
+	int sz, rc;
+
+	if (!data || !ac) {
+		pr_err("%s: %s is NULL\n", __func__,
+			(!data) ? "data" : "ac");
+		rc = -EINVAL;
+		goto done;
+	}
+
+	if (data->event_type >= ARRAY_SIZE(adsp_reg_event_opcode)) {
+		pr_err("%s: event %u out of boundary of array size of (%lu)\n",
+		       __func__, data->event_type,
+		       (long)ARRAY_SIZE(adsp_reg_event_opcode));
+		rc = -EINVAL;
+		goto done;
+	}
+
+	sz = sizeof(struct apr_hdr) + data->payload_len;
+	asm_params = kzalloc(sz, GFP_KERNEL);
+	if (!asm_params) {
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	q6asm_add_hdr_async(ac, &hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state_pp, -1);
+	hdr.opcode = adsp_reg_event_opcode[data->event_type];
+	memcpy(asm_params, &hdr, sizeof(struct apr_hdr));
+	memcpy(asm_params + sizeof(struct apr_hdr),
+		data->payload, data->payload_len);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
+	if (rc < 0) {
+		pr_err("%s: stream event cmd apr pkt failed\n", __func__);
+		rc = -EINVAL;
+		goto fail_send_param;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+				(atomic_read(&ac->cmd_state_pp) >= 0), 1 * HZ);
+	if (!rc) {
+		pr_err("%s: timeout for stream event cmd resp\n", __func__);
+		rc = -ETIMEDOUT;
+		goto fail_send_param;
+	}
+
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
+		pr_err("%s: DSP returned error[%s] for stream event cmd\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&ac->cmd_state_pp)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state_pp));
+		goto fail_send_param;
+	}
+
+	rc = 0;
+fail_send_param:
+	kfree(asm_params);
+done:
+	return rc;
+}
+
 struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
 {
 	struct audio_client *ac;
@@ -1162,6 +1260,7 @@
 		spin_lock_init(&ac->port[lcnt].dsp_lock);
 	}
 	atomic_set(&ac->cmd_state, 0);
+	atomic_set(&ac->cmd_state_pp, 0);
 	atomic_set(&ac->mem_state, 0);
 
 	rc = send_asm_custom_topology(ac);
@@ -1441,7 +1540,6 @@
 			}
 			pr_debug("%s: Clearing custom topology\n", __func__);
 		}
-		this_mmap.apr = NULL;
 
 		cal_utils_clear_cal_block_q6maps(ASM_MAX_CAL_TYPES, cal_data);
 		common_client.mmap_apr = NULL;
@@ -1607,6 +1705,8 @@
 	int32_t  ret = 0;
 	union asm_token_struct asm_token;
 	uint8_t buf_index;
+	struct msm_adsp_event_data *pp_event_package = NULL;
+	uint32_t payload_size = 0;
 
 	if (ac == NULL) {
 		pr_err("%s: ac NULL\n", __func__);
@@ -1639,8 +1739,10 @@
 	if (data->opcode == RESET_EVENTS) {
 		mutex_lock(&ac->cmd_lock);
 		atomic_set(&ac->reset, 1);
-		if (ac->apr == NULL)
+		if (ac->apr == NULL) {
 			ac->apr = ac->apr2;
+			ac->apr2 = NULL;
+		}
 		pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
 			__func__,
 			data->reset_event, data->reset_proc, ac->apr);
@@ -1652,6 +1754,7 @@
 		atomic_set(&ac->time_flag, 0);
 		atomic_set(&ac->cmd_state, 0);
 		atomic_set(&ac->mem_state, 0);
+		atomic_set(&ac->cmd_state_pp, 0);
 		wake_up(&ac->time_wait);
 		wake_up(&ac->cmd_wait);
 		wake_up(&ac->mem_wait);
@@ -1705,7 +1808,11 @@
 		case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
 		case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
 		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+		case ASM_DATA_CMD_IEC_60958_MEDIA_FMT:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		case ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2:
+		case ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS:
+		case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
 		case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
 		case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
 		case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
@@ -1719,14 +1826,31 @@
 				pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
 					__func__, payload[0], payload[1]);
 				if (wakeup_flag) {
-					atomic_set(&ac->cmd_state, payload[1]);
+					if ((is_adsp_reg_event(payload[0]) >= 0)
+					      || (payload[0] ==
+					      ASM_STREAM_CMD_SET_PP_PARAMS_V2))
+						atomic_set(&ac->cmd_state_pp,
+								payload[1]);
+					else
+						atomic_set(&ac->cmd_state,
+								payload[1]);
 					wake_up(&ac->cmd_wait);
 				}
 				return 0;
 			}
-			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
-				atomic_set(&ac->cmd_state, 0);
-				wake_up(&ac->cmd_wait);
+			if ((is_adsp_reg_event(payload[0]) >= 0) ||
+			    (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2)) {
+				if (atomic_read(&ac->cmd_state_pp) &&
+					wakeup_flag) {
+					atomic_set(&ac->cmd_state_pp, 0);
+					wake_up(&ac->cmd_wait);
+				}
+			} else {
+				if (atomic_read(&ac->cmd_state) &&
+					wakeup_flag) {
+					atomic_set(&ac->cmd_state, 0);
+					wake_up(&ac->cmd_wait);
+				}
 			}
 			if (ac->cb)
 				ac->cb(data->opcode, data->token,
@@ -1773,6 +1897,17 @@
 							data->payload_size);
 			}
 			break;
+		case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
+			pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS session %d opcode 0x%x token 0x%x src %d dest %d\n",
+				__func__, ac->session,
+				data->opcode, data->token,
+				data->src_port, data->dest_port);
+			if (payload[1] != 0)
+				pr_err("%s: ASM get param error = %d, resuming\n",
+					__func__, payload[1]);
+			atomic_set(&ac->cmd_state_pp, payload[1]);
+			wake_up(&ac->cmd_wait);
+			break;
 		default:
 			pr_debug("%s: command[0x%x] not expecting rsp\n",
 							__func__, payload[0]);
@@ -1944,6 +2079,39 @@
 	case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
 		q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
 		break;
+	case ASM_STREAM_PP_EVENT:
+	case ASM_STREAM_CMD_ENCDEC_EVENTS:
+	case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
+		pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]",
+				 __func__, payload[0], payload[1]);
+		i = is_adsp_raise_event(data->opcode);
+		if (i < 0)
+			return 0;
+
+		/* repack payload for asm_stream_pp_event
+		 * package is composed of event type + size + actual payload
+		 */
+		payload_size = data->payload_size;
+		pp_event_package = kzalloc(payload_size
+				+ sizeof(struct msm_adsp_event_data),
+				GFP_ATOMIC);
+		if (!pp_event_package)
+			return -ENOMEM;
+
+		pp_event_package->event_type = i;
+		pp_event_package->payload_len = payload_size;
+		memcpy((void *)pp_event_package->payload,
+			data->payload, payload_size);
+		ac->cb(data->opcode, data->token,
+			(void *)pp_event_package, ac->priv);
+		kfree(pp_event_package);
+		return 0;
+	case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2:
+		pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
+			 __func__, ac->session, payload[0], payload[2],
+			 payload[1]);
+		wake_up(&ac->cmd_wait);
+		break;
 	case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
 		pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
 				__func__, ac->session, payload[0], payload[2],
@@ -2306,9 +2474,6 @@
 	open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
 
 	open.preprocopo_id = q6asm_get_asm_topology_cal();
-	if ((open.preprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
-	    (open.preprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS))
-		open.preprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
 	open.bits_per_sample = bits_per_sample;
 	open.mode_flags = 0x0;
 
@@ -2483,7 +2648,12 @@
 	case FORMAT_GEN_COMPR:
 		open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
 		break;
-
+	case FORMAT_TRUEHD:
+		open.fmt_id = ASM_MEDIA_FMT_TRUEHD;
+		break;
+	case FORMAT_IEC61937:
+		open.fmt_id = ASM_MEDIA_FMT_IEC;
+		break;
 	default:
 		pr_err("%s: Invalid format[%d]\n", __func__, format);
 		rc = -EINVAL;
@@ -2501,6 +2671,10 @@
 		open.flags = 0x8;
 		pr_debug("%s: Flag 8 - COMPRESSED_PASSTHROUGH_CONVERT\n",
 			 __func__);
+	} else if (passthrough_flag == COMPRESSED_PASSTHROUGH_IEC61937) {
+		open.flags = 0x1;
+		pr_debug("%s: Flag 1 - COMPRESSED_PASSTHROUGH_IEC61937\n",
+			 __func__);
 	} else {
 		pr_err("%s: Invalid passthrough type[%d]\n",
 			__func__, passthrough_flag);
@@ -2594,16 +2768,9 @@
 	open.bits_per_sample = bits_per_sample;
 
 	open.postprocopo_id = q6asm_get_asm_topology_cal();
-	if ((ac->perf_mode != LEGACY_PCM_MODE) &&
-	    ((open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
-	     (open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS)))
+	if (ac->perf_mode != LEGACY_PCM_MODE)
 		open.postprocopo_id = ASM_STREAM_POSTPROCOPO_ID_NONE;
 
-	/* For DTS EAGLE only, force 24 bit */
-	if ((open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
-	     (open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_PLUS))
-		open.bits_per_sample = 24;
-
 	pr_debug("%s: perf_mode %d asm_topology 0x%x bps %d\n", __func__,
 		 ac->perf_mode, open.postprocopo_id, open.bits_per_sample);
 
@@ -2827,10 +2994,6 @@
 	ac->topology = open.postprocopo_id;
 	ac->app_type = q6asm_get_asm_app_type_cal();
 
-	/* For DTS EAGLE only, force 24 bit */
-	if ((open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_DTS_HPX) ||
-	     (open.postprocopo_id == ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER))
-		open.bits_per_sample = 24;
 
 	switch (wr_format) {
 	case FORMAT_LINEAR_PCM:
@@ -3081,6 +3244,102 @@
 	return rc;
 }
 
+
+int q6asm_open_transcode_loopback(struct audio_client *ac,
+			uint16_t bits_per_sample,
+			uint32_t source_format, uint32_t sink_format)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_transcode_loopback_t open;
+
+	if (ac == NULL) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (ac->apr == NULL) {
+		pr_err("%s: AC APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	atomic_set(&ac->cmd_state, -1);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;
+
+	open.mode_flags = 0;
+	open.src_endpoint_type = 0;
+	open.sink_endpoint_type = 0;
+	switch (source_format) {
+	case FORMAT_LINEAR_PCM:
+	case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+		open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
+		break;
+	case FORMAT_AC3:
+		open.src_format_id = ASM_MEDIA_FMT_AC3;
+		break;
+	case FORMAT_EAC3:
+		open.src_format_id = ASM_MEDIA_FMT_EAC3;
+		break;
+	default:
+		pr_err("%s: Unsupported src fmt [%d]\n",
+		       __func__, source_format);
+		return -EINVAL;
+	}
+	switch (sink_format) {
+	case FORMAT_LINEAR_PCM:
+	case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+		open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3;
+		break;
+	default:
+		pr_err("%s: Unsupported sink fmt [%d]\n",
+		       __func__, sink_format);
+		return -EINVAL;
+	}
+
+	/* source endpoint : matrix */
+	open.audproc_topo_id = q6asm_get_asm_topology_cal();
+
+	ac->app_type = q6asm_get_asm_app_type_cal();
+	if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+		open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
+	else
+		open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
+	ac->topology = open.audproc_topo_id;
+	open.bits_per_sample = bits_per_sample;
+	open.reserved = 0;
+	pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
+		__func__, open.mode_flags, ac->session);
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("%s: open failed op[0x%x]rc[%d]\n",
+				__func__, open.hdr.opcode, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for open_transcode_loopback\n",
+			__func__);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	}
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+				__func__, adsp_err_get_err_str(
+					atomic_read(&ac->cmd_state)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state));
+		goto fail_cmd;
+	}
+
+	return 0;
+fail_cmd:
+	return rc;
+}
+
 static
 int q6asm_set_shared_circ_buff(struct audio_client *ac,
 			       struct asm_stream_cmd_open_shared_io *open,
@@ -3131,11 +3390,12 @@
 	open->shared_circ_buf_start_phy_addr_lsw =
 			lower_32_bits(buf_circ->phys);
 	open->shared_circ_buf_start_phy_addr_msw =
-			upper_32_bits(buf_circ->phys);
+			msm_audio_populate_upper_32_bits(buf_circ->phys);
 	open->shared_circ_buf_size = bufsz * bufcnt;
 
 	open->map_region_circ_buf.shm_addr_lsw = lower_32_bits(buf_circ->phys);
-	open->map_region_circ_buf.shm_addr_msw = upper_32_bits(buf_circ->phys);
+	open->map_region_circ_buf.shm_addr_msw =
+			msm_audio_populate_upper_32_bits(buf_circ->phys);
 	open->map_region_circ_buf.mem_size_bytes = bytes_to_alloc;
 
 	mutex_unlock(&ac->cmd_lock);
@@ -3177,10 +3437,12 @@
 	open->shared_pos_buf_num_regions = 1;
 	open->shared_pos_buf_property_flag = 0x00;
 	open->shared_pos_buf_phy_addr_lsw = lower_32_bits(buf_pos->phys);
-	open->shared_pos_buf_phy_addr_msw = upper_32_bits(buf_pos->phys);
+	open->shared_pos_buf_phy_addr_msw =
+			msm_audio_populate_upper_32_bits(buf_pos->phys);
 
 	open->map_region_pos_buf.shm_addr_lsw = lower_32_bits(buf_pos->phys);
-	open->map_region_pos_buf.shm_addr_msw = upper_32_bits(buf_pos->phys);
+	open->map_region_pos_buf.shm_addr_msw =
+			msm_audio_populate_upper_32_bits(buf_pos->phys);
 	open->map_region_pos_buf.mem_size_bytes = bytes_to_alloc;
 
 done:
@@ -4184,6 +4446,20 @@
 			PCM_CHANNEL_LB : PCM_CHANNEL_LS;
 		lchannel_mapping[5] = use_back_flavor ?
 			PCM_CHANNEL_RB : PCM_CHANNEL_RS;
+	} else if (channels == 7) {
+		/*
+		 * Configured for 5.1 channel mapping + 1 channel for debug
+		 * Can be customized based on DSP.
+		 */
+		lchannel_mapping[0] = PCM_CHANNEL_FL;
+		lchannel_mapping[1] = PCM_CHANNEL_FR;
+		lchannel_mapping[2] = PCM_CHANNEL_FC;
+		lchannel_mapping[3] = PCM_CHANNEL_LFE;
+		lchannel_mapping[4] = use_back_flavor ?
+			PCM_CHANNEL_LB : PCM_CHANNEL_LS;
+		lchannel_mapping[5] = use_back_flavor ?
+			PCM_CHANNEL_RB : PCM_CHANNEL_RS;
+		lchannel_mapping[6] = PCM_CHANNEL_CS;
 	} else if (channels == 8) {
 		lchannel_mapping[0] = PCM_CHANNEL_FL;
 		lchannel_mapping[1] = PCM_CHANNEL_FR;
@@ -5268,6 +5544,62 @@
 }
 EXPORT_SYMBOL(q6asm_media_format_block_gen_compr);
 
+
+/*
+ * q6asm_media_format_block_iec - set up IEC61937 (compressed) or IEC60958
+ *                                (pcm) format params. Both audio standards
+ *                                use the same format and are used for
+ *                                HDMI or SPDIF.
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ */
+int q6asm_media_format_block_iec(struct audio_client *ac,
+				uint32_t rate, uint32_t channels)
+{
+	struct asm_iec_compressed_fmt_blk_t fmt;
+	int rc = 0;
+
+	pr_debug("%s: session[%d]rate[%d]ch[%d]\n",
+		 __func__, ac->session, rate,
+		 channels);
+
+	memset(&fmt, 0, sizeof(fmt));
+	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+	fmt.hdr.opcode = ASM_DATA_CMD_IEC_60958_MEDIA_FMT;
+	fmt.num_channels = channels;
+	fmt.sampling_rate = rate;
+
+	atomic_set(&ac->cmd_state, -1);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+	if (rc < 0) {
+		pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for format update\n", __func__);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	}
+
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+			__func__, adsp_err_get_err_str(
+			atomic_read(&ac->cmd_state)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state));
+	}
+	return 0;
+fail_cmd:
+	return rc;
+}
+EXPORT_SYMBOL(q6asm_media_format_block_iec);
+
 static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
 				struct asm_aac_cfg *cfg, int stream_id)
 {
@@ -6404,7 +6736,7 @@
 	memset(&multi_ch_gain, 0, sizeof(multi_ch_gain));
 	sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
 	q6asm_add_hdr_async(ac, &multi_ch_gain.hdr, sz, TRUE);
-	atomic_set(&ac->cmd_state, -1);
+	atomic_set(&ac->cmd_state_pp, -1);
 	multi_ch_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	multi_ch_gain.param.data_payload_addr_lsw = 0;
 	multi_ch_gain.param.data_payload_addr_msw = 0;
@@ -6430,20 +6762,20 @@
 	}
 
 	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+			(atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
 	if (!rc) {
 		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
 				multi_ch_gain.data.param_id);
 		rc = -ETIMEDOUT;
 		goto fail_cmd;
 	}
-	if (atomic_read(&ac->cmd_state) > 0) {
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
 		pr_err("%s: DSP returned error[%s] , set-params paramid[0x%x]\n",
 					__func__, adsp_err_get_err_str(
-					atomic_read(&ac->cmd_state)),
+					atomic_read(&ac->cmd_state_pp)),
 					multi_ch_gain.data.param_id);
 		rc = adsp_err_get_lnx_err_code(
-				atomic_read(&ac->cmd_state));
+				atomic_read(&ac->cmd_state_pp));
 		goto fail_cmd;
 	}
 	rc = 0;
@@ -6498,7 +6830,7 @@
 	memset(&multich_gain, 0, sizeof(multich_gain));
 	sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
 	q6asm_add_hdr_async(ac, &multich_gain.hdr, sz, TRUE);
-	atomic_set(&ac->cmd_state, 1);
+	atomic_set(&ac->cmd_state_pp, -1);
 	multich_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	multich_gain.param.data_payload_addr_lsw = 0;
 	multich_gain.param.data_payload_addr_msw = 0;
@@ -6536,17 +6868,17 @@
 	}
 
 	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) <= 0), 5*HZ);
+			(atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
 	if (!rc) {
 		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
 				multich_gain.data.param_id);
 		rc = -EINVAL;
 		goto done;
 	}
-	if (atomic_read(&ac->cmd_state) < 0) {
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
 		pr_err("%s: DSP returned error[%d] , set-params paramid[0x%x]\n",
-					__func__, atomic_read(&ac->cmd_state),
-					multich_gain.data.param_id);
+		       __func__, atomic_read(&ac->cmd_state_pp),
+		       multich_gain.data.param_id);
 		rc = -EINVAL;
 		goto done;
 	}
@@ -6574,7 +6906,7 @@
 
 	sz = sizeof(struct asm_volume_ctrl_mute_config);
 	q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
-	atomic_set(&ac->cmd_state, -1);
+	atomic_set(&ac->cmd_state_pp, -1);
 	mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	mute.param.data_payload_addr_lsw = 0;
 	mute.param.data_payload_addr_msw = 0;
@@ -6596,20 +6928,20 @@
 	}
 
 	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+			(atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
 	if (!rc) {
 		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
 				mute.data.param_id);
 		rc = -ETIMEDOUT;
 		goto fail_cmd;
 	}
-	if (atomic_read(&ac->cmd_state) > 0) {
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
 		pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
 				__func__, adsp_err_get_err_str(
-				atomic_read(&ac->cmd_state)),
+				atomic_read(&ac->cmd_state_pp)),
 				mute.data.param_id);
 		rc = adsp_err_get_lnx_err_code(
-				atomic_read(&ac->cmd_state));
+				atomic_read(&ac->cmd_state_pp));
 		goto fail_cmd;
 	}
 	rc = 0;
@@ -6617,229 +6949,6 @@
 	return rc;
 }
 
-int q6asm_dts_eagle_set(struct audio_client *ac, int param_id, uint32_t size,
-			void *data, struct param_outband *po, int m_id)
-{
-	int rc = 0, *ob_params = NULL;
-	uint32_t sz = sizeof(struct asm_dts_eagle_param) + (po ? 0 : size);
-	struct asm_dts_eagle_param *ad;
-
-	if (!ac || ac->apr == NULL || (size == 0) || !data) {
-		pr_err("DTS_EAGLE_ASM - %s: APR handle NULL, invalid size %u or pointer %pK.\n",
-			__func__, size, data);
-		return -EINVAL;
-	}
-
-	ad = kzalloc(sz, GFP_KERNEL);
-	if (!ad)
-		return -ENOMEM;
-
-	pr_debug("DTS_EAGLE_ASM - %s: ac %pK param_id 0x%x size %u data %pK m_id 0x%x\n",
-		__func__, ac, param_id, size, data, m_id);
-	q6asm_add_hdr_async(ac, &ad->hdr, sz, 1);
-	ad->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
-	ad->param.data_payload_addr_lsw = 0;
-	ad->param.data_payload_addr_msw = 0;
-
-	ad->param.mem_map_handle = 0;
-	ad->param.data_payload_size = size +
-					sizeof(struct asm_stream_param_data_v2);
-	ad->data.module_id = m_id;
-	ad->data.param_id = param_id;
-	ad->data.param_size = size;
-	ad->data.reserved = 0;
-	atomic_set(&ac->cmd_state, -1);
-
-	if (po) {
-		struct list_head *ptr, *next;
-		struct asm_buffer_node *node;
-
-		pr_debug("DTS_EAGLE_ASM - %s: using out of band memory (virtual %pK, physical %lu)\n",
-			__func__, po->kvaddr, (long)po->paddr);
-		ad->param.data_payload_addr_lsw = lower_32_bits(po->paddr);
-		ad->param.data_payload_addr_msw =
-				msm_audio_populate_upper_32_bits(po->paddr);
-		list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
-			node = list_entry(ptr, struct asm_buffer_node, list);
-			if (node->buf_phys_addr == po->paddr) {
-				ad->param.mem_map_handle = node->mmap_hdl;
-				break;
-			}
-		}
-		if (ad->param.mem_map_handle == 0) {
-			pr_err("DTS_EAGLE_ASM - %s: mem map handle not found\n",
-				__func__);
-			rc = -EINVAL;
-			goto fail_cmd;
-		}
-		/* check for integer overflow */
-		if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
-			rc = -EINVAL;
-		if ((rc < 0) || (size + APR_CMD_OB_HDR_SZ > po->size)) {
-			pr_err("DTS_EAGLE_ASM - %s: ion alloc of size %zu too small for size requested %u\n",
-				__func__, po->size, size + APR_CMD_OB_HDR_SZ);
-			rc = -EINVAL;
-			goto fail_cmd;
-		}
-		ob_params = (int *)po->kvaddr;
-		*ob_params++ = m_id;
-		*ob_params++ = param_id;
-		*ob_params++ = size;
-		memcpy(ob_params, data, size);
-	} else {
-		pr_debug("DTS_EAGLE_ASM - %s: using in band\n", __func__);
-		memcpy(((char *)ad) + sizeof(struct asm_dts_eagle_param),
-			data, size);
-	}
-	rc = apr_send_pkt(ac->apr, (uint32_t *)ad);
-	if (rc < 0) {
-		pr_err("DTS_EAGLE_ASM - %s: set-params send failed paramid[0x%x]\n",
-			__func__, ad->data.param_id);
-		rc = -EINVAL;
-		goto fail_cmd;
-	}
-
-	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) >= 0), 1*HZ);
-	if (!rc) {
-		pr_err("DTS_EAGLE_ASM - %s: timeout, set-params paramid[0x%x]\n",
-			__func__, ad->data.param_id);
-		rc = -ETIMEDOUT;
-		goto fail_cmd;
-	}
-
-	if (atomic_read(&ac->cmd_state) > 0) {
-		pr_err("%s: DSP returned error[%s]\n",
-				__func__, adsp_err_get_err_str(
-				atomic_read(&ac->cmd_state)));
-		rc = adsp_err_get_lnx_err_code(
-				atomic_read(&ac->cmd_state));
-		goto fail_cmd;
-	}
-	rc = 0;
-fail_cmd:
-	kfree(ad);
-	return rc;
-}
-
-int q6asm_dts_eagle_get(struct audio_client *ac, int param_id, uint32_t size,
-			void *data, struct param_outband *po, int m_id)
-{
-	struct asm_dts_eagle_param_get *ad;
-	int rc = 0, *ob_params = NULL;
-	uint32_t sz = sizeof(struct asm_dts_eagle_param) + APR_CMD_GET_HDR_SZ +
-		 (po ? 0 : size);
-
-	if (!ac || ac->apr == NULL || (size == 0) || !data) {
-		pr_err("DTS_EAGLE_ASM - %s: APR handle NULL, invalid size %u or pointer %pK\n",
-			__func__, size, data);
-		return -EINVAL;
-	}
-	ad = kzalloc(sz, GFP_KERNEL);
-	if (!ad)
-		return -ENOMEM;
-
-	pr_debug("DTS_EAGLE_ASM - %s: ac %pK param_id 0x%x size %u data %pK m_id 0x%x\n",
-		__func__, ac, param_id, size, data, m_id);
-	q6asm_add_hdr(ac, &ad->hdr, sz, TRUE);
-	ad->hdr.opcode = ASM_STREAM_CMD_GET_PP_PARAMS_V2;
-	ad->param.data_payload_addr_lsw = 0;
-	ad->param.data_payload_addr_msw = 0;
-	ad->param.mem_map_handle = 0;
-	ad->param.module_id = m_id;
-	ad->param.param_id = param_id;
-	ad->param.param_max_size = size + APR_CMD_GET_HDR_SZ;
-	ad->param.reserved = 0;
-	atomic_set(&ac->cmd_state, -1);
-
-	generic_get_data = kzalloc(size + sizeof(struct generic_get_data_),
-				   GFP_KERNEL);
-	if (!generic_get_data) {
-		rc = -ENOMEM;
-		goto fail_cmd;
-	}
-
-	if (po) {
-		struct list_head *ptr, *next;
-		struct asm_buffer_node *node;
-
-		pr_debug("DTS_EAGLE_ASM - %s: using out of band memory (virtual %pK, physical %lu)\n",
-			 __func__, po->kvaddr, (long)po->paddr);
-		ad->param.data_payload_addr_lsw = lower_32_bits(po->paddr);
-		ad->param.data_payload_addr_msw =
-				msm_audio_populate_upper_32_bits(po->paddr);
-		list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
-			node = list_entry(ptr, struct asm_buffer_node, list);
-			if (node->buf_phys_addr == po->paddr) {
-				ad->param.mem_map_handle = node->mmap_hdl;
-				break;
-			}
-		}
-		if (ad->param.mem_map_handle == 0) {
-			pr_err("DTS_EAGLE_ASM - %s: mem map handle not found\n",
-				__func__);
-			rc = -EINVAL;
-			goto fail_cmd;
-		}
-		/* check for integer overflow */
-		if (size > (UINT_MAX - APR_CMD_OB_HDR_SZ))
-			rc = -EINVAL;
-		if ((rc < 0) || (size + APR_CMD_OB_HDR_SZ > po->size)) {
-			pr_err("DTS_EAGLE_ASM - %s: ion alloc of size %zu too small for size requested %u\n",
-				__func__, po->size, size + APR_CMD_OB_HDR_SZ);
-			rc = -EINVAL;
-			goto fail_cmd;
-		}
-		ob_params = (int *)po->kvaddr;
-		*ob_params++ = m_id;
-		*ob_params++ = param_id;
-		*ob_params++ = size;
-		generic_get_data->is_inband = 0;
-	} else {
-		pr_debug("DTS_EAGLE_ASM - %s: using in band\n", __func__);
-		generic_get_data->is_inband = 1;
-	}
-
-	rc = apr_send_pkt(ac->apr, (uint32_t *)ad);
-	if (rc < 0) {
-		pr_err("DTS_EAGLE_ASM - %s: Commmand 0x%x failed\n", __func__,
-			ad->hdr.opcode);
-		goto fail_cmd;
-	}
-
-	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) >= 0), 1*HZ);
-	if (!rc) {
-		pr_err("DTS_EAGLE_ASM - %s: timeout in get\n",
-			__func__);
-		rc = -ETIMEDOUT;
-		goto fail_cmd;
-	}
-
-	if (atomic_read(&ac->cmd_state) > 0) {
-		pr_err("%s: DSP returned error[%s]\n",
-				__func__, adsp_err_get_err_str(
-				atomic_read(&ac->cmd_state)));
-		rc = adsp_err_get_lnx_err_code(
-				atomic_read(&ac->cmd_state));
-		goto fail_cmd;
-	}
-
-	if (generic_get_data->valid) {
-		rc = 0;
-		memcpy(data, po ? ob_params : generic_get_data->ints, size);
-	} else {
-		rc = -EINVAL;
-		pr_err("DTS_EAGLE_ASM - %s: EAGLE get params problem getting data - check callback error value\n",
-			__func__);
-	}
-fail_cmd:
-	kfree(ad);
-	kfree(generic_get_data);
-	generic_get_data = NULL;
-	return rc;
-}
-
 static int __q6asm_set_volume(struct audio_client *ac, int volume, int instance)
 {
 	struct asm_volume_ctrl_master_gain vol;
@@ -6870,7 +6979,7 @@
 
 	sz = sizeof(struct asm_volume_ctrl_master_gain);
 	q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
-	atomic_set(&ac->cmd_state, -1);
+	atomic_set(&ac->cmd_state_pp, -1);
 	vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	vol.param.data_payload_addr_lsw = 0;
 	vol.param.data_payload_addr_msw = 0;
@@ -6892,20 +7001,20 @@
 	}
 
 	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+			(atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
 	if (!rc) {
 		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
 				vol.data.param_id);
 		rc = -ETIMEDOUT;
 		goto fail_cmd;
 	}
-	if (atomic_read(&ac->cmd_state) > 0) {
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
 		pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
 				__func__, adsp_err_get_err_str(
-				atomic_read(&ac->cmd_state)),
+				atomic_read(&ac->cmd_state_pp)),
 				vol.data.param_id);
 		rc = adsp_err_get_lnx_err_code(
-				atomic_read(&ac->cmd_state));
+				atomic_read(&ac->cmd_state_pp));
 		goto fail_cmd;
 	}
 
@@ -6987,6 +7096,156 @@
 	return rc;
 }
 
+int q6asm_send_ion_fd(struct audio_client *ac, int fd)
+{
+	struct ion_client *client;
+	struct ion_handle *handle;
+	ion_phys_addr_t paddr;
+	size_t pa_len = 0;
+	void *vaddr;
+	int ret;
+	int sz = 0;
+	struct avs_rtic_shared_mem_addr shm;
+
+	if (ac == NULL) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	if (ac->apr == NULL) {
+		pr_err("%s: AC APR handle NULL\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = msm_audio_ion_import("audio_mem_client",
+				   &client,
+				   &handle,
+				   fd,
+				   NULL,
+				   0,
+				   &paddr,
+				   &pa_len,
+				   &vaddr);
+	if (ret) {
+		pr_err("%s: audio ION import failed, rc = %d\n",
+		       __func__, ret);
+		ret = -ENOMEM;
+		goto fail_cmd;
+	}
+	/* get payload length */
+	sz = sizeof(struct avs_rtic_shared_mem_addr);
+	q6asm_add_hdr_async(ac, &shm.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, -1);
+	shm.shm_buf_addr_lsw = lower_32_bits(paddr);
+	shm.shm_buf_addr_msw = msm_audio_populate_upper_32_bits(paddr);
+	shm.buf_size = pa_len;
+	shm.shm_buf_num_regions = 1;
+	shm.shm_buf_mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+	shm.shm_buf_flag = 0x00;
+	shm.encdec.param_id = AVS_PARAM_ID_RTIC_SHARED_MEMORY_ADDR;
+	shm.encdec.param_size = sizeof(struct avs_rtic_shared_mem_addr) -
+						sizeof(struct apr_hdr) -
+			sizeof(struct asm_stream_cmd_set_encdec_param_v2);
+	shm.encdec.service_id = OUT;
+	shm.encdec.reserved = 0;
+	shm.map_region.shm_addr_lsw = shm.shm_buf_addr_lsw;
+	shm.map_region.shm_addr_msw = shm.shm_buf_addr_msw;
+	shm.map_region.mem_size_bytes = pa_len;
+	shm.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
+	ret = apr_send_pkt(ac->apr, (uint32_t *) &shm);
+	if (ret < 0) {
+		pr_err("%s: set-params send failed paramid[0x%x] rc %d\n",
+		       __func__, shm.encdec.param_id, ret);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(ac->cmd_wait,
+				(atomic_read(&ac->cmd_state) >= 0), 1*HZ);
+	if (!ret) {
+		pr_err("%s: timeout, shm.encdec paramid[0x%x]\n", __func__,
+		       shm.encdec.param_id);
+		ret = -ETIMEDOUT;
+		goto fail_cmd;
+	}
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s] shm.encdec paramid[0x%x]\n",
+		       __func__,
+		       adsp_err_get_err_str(atomic_read(&ac->cmd_state)),
+		       shm.encdec.param_id);
+		ret = adsp_err_get_lnx_err_code(atomic_read(&ac->cmd_state));
+		goto fail_cmd;
+	}
+	ret = 0;
+fail_cmd:
+	return ret;
+}
+
+int q6asm_send_rtic_event_ack(struct audio_client *ac,
+			      void *param, uint32_t params_length)
+{
+	char *asm_params = NULL;
+	int sz, rc;
+	struct avs_param_rtic_event_ack ack;
+
+	if (!param || !ac) {
+		pr_err("%s: %s is NULL\n", __func__,
+			(!param) ? "param" : "ac");
+		rc = -EINVAL;
+		goto done;
+	}
+
+	sz = sizeof(struct avs_param_rtic_event_ack) + params_length;
+	asm_params = kzalloc(sz, GFP_KERNEL);
+	if (!asm_params) {
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	q6asm_add_hdr_async(ac, &ack.hdr,
+			    sizeof(struct avs_param_rtic_event_ack) +
+			    params_length, TRUE);
+	atomic_set(&ac->cmd_state, -1);
+	ack.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2;
+	ack.encdec.param_id = AVS_PARAM_ID_RTIC_EVENT_ACK;
+	ack.encdec.param_size = params_length;
+	ack.encdec.reserved = 0;
+	ack.encdec.service_id = OUT;
+	memcpy(asm_params, &ack, sizeof(struct avs_param_rtic_event_ack));
+	memcpy(asm_params + sizeof(struct avs_param_rtic_event_ack),
+		param, params_length);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
+	if (rc < 0) {
+		pr_err("%s: apr pkt failed for rtic event ack\n", __func__);
+		rc = -EINVAL;
+		goto fail_send_param;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+				(atomic_read(&ac->cmd_state) >= 0), 1 * HZ);
+	if (!rc) {
+		pr_err("%s: timeout for rtic event ack cmd\n", __func__);
+		rc = -ETIMEDOUT;
+		goto fail_send_param;
+	}
+
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s] for rtic event ack cmd\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&ac->cmd_state)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state));
+		goto fail_send_param;
+	}
+	rc = 0;
+
+fail_send_param:
+	kfree(asm_params);
+done:
+	return rc;
+}
+
 int q6asm_set_softpause(struct audio_client *ac,
 			struct asm_softpause_params *pause_param)
 {
@@ -7007,7 +7266,7 @@
 
 	sz = sizeof(struct asm_soft_pause_params);
 	q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
-	atomic_set(&ac->cmd_state, -1);
+	atomic_set(&ac->cmd_state_pp, -1);
 	softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 
 	softpause.param.data_payload_addr_lsw = 0;
@@ -7034,20 +7293,20 @@
 	}
 
 	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+			(atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
 	if (!rc) {
 		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
 						softpause.data.param_id);
 		rc = -ETIMEDOUT;
 		goto fail_cmd;
 	}
-	if (atomic_read(&ac->cmd_state) > 0) {
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
 		pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
 				__func__, adsp_err_get_err_str(
-				atomic_read(&ac->cmd_state)),
+				atomic_read(&ac->cmd_state_pp)),
 				softpause.data.param_id);
 		rc = adsp_err_get_lnx_err_code(
-				atomic_read(&ac->cmd_state));
+				atomic_read(&ac->cmd_state_pp));
 		goto fail_cmd;
 	}
 	rc = 0;
@@ -7087,7 +7346,7 @@
 
 	sz = sizeof(struct asm_soft_step_volume_params);
 	q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
-	atomic_set(&ac->cmd_state, -1);
+	atomic_set(&ac->cmd_state_pp, -1);
 	softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	softvol.param.data_payload_addr_lsw = 0;
 	softvol.param.data_payload_addr_msw = 0;
@@ -7112,20 +7371,20 @@
 	}
 
 	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+			(atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
 	if (!rc) {
 		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
 						softvol.data.param_id);
 		rc = -ETIMEDOUT;
 		goto fail_cmd;
 	}
-	if (atomic_read(&ac->cmd_state) > 0) {
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
 		pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
 				__func__, adsp_err_get_err_str(
-				atomic_read(&ac->cmd_state)),
+				atomic_read(&ac->cmd_state_pp)),
 				softvol.data.param_id);
 		rc = adsp_err_get_lnx_err_code(
-				atomic_read(&ac->cmd_state));
+				atomic_read(&ac->cmd_state_pp));
 		goto fail_cmd;
 	}
 	rc = 0;
@@ -7174,7 +7433,7 @@
 	sz = sizeof(struct asm_eq_params);
 	eq_params = (struct msm_audio_eq_stream_config *) eq_p;
 	q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
-	atomic_set(&ac->cmd_state, -1);
+	atomic_set(&ac->cmd_state_pp, -1);
 
 	eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	eq.param.data_payload_addr_lsw = 0;
@@ -7219,20 +7478,20 @@
 	}
 
 	rc = wait_event_timeout(ac->cmd_wait,
-			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+			(atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
 	if (!rc) {
 		pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
 						eq.data.param_id);
 		rc = -ETIMEDOUT;
 		goto fail_cmd;
 	}
-	if (atomic_read(&ac->cmd_state) > 0) {
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
 		pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
 				__func__, adsp_err_get_err_str(
-				atomic_read(&ac->cmd_state)),
+				atomic_read(&ac->cmd_state_pp)),
 				eq.data.param_id);
 		rc = adsp_err_get_lnx_err_code(
-				atomic_read(&ac->cmd_state));
+				atomic_read(&ac->cmd_state_pp));
 		goto fail_cmd;
 	}
 	rc = 0;
@@ -7850,7 +8109,7 @@
 	q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
 				sizeof(struct asm_stream_cmd_set_pp_params_v2) +
 				params_length), TRUE);
-	atomic_set(&ac->cmd_state, -1);
+	atomic_set(&ac->cmd_state_pp, -1);
 	hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	payload_params.data_payload_addr_lsw = 0;
 	payload_params.data_payload_addr_msw = 0;
@@ -7869,18 +8128,18 @@
 		goto fail_send_param;
 	}
 	rc = wait_event_timeout(ac->cmd_wait,
-				(atomic_read(&ac->cmd_state) >= 0), 1*HZ);
+				(atomic_read(&ac->cmd_state_pp) >= 0), 1*HZ);
 	if (!rc) {
 		pr_err("%s: timeout, audio effects set-params\n", __func__);
 		rc = -ETIMEDOUT;
 		goto fail_send_param;
 	}
-	if (atomic_read(&ac->cmd_state) > 0) {
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
 		pr_err("%s: DSP returned error[%s] set-params\n",
 				__func__, adsp_err_get_err_str(
-				atomic_read(&ac->cmd_state)));
+				atomic_read(&ac->cmd_state_pp)));
 		rc = adsp_err_get_lnx_err_code(
-				atomic_read(&ac->cmd_state));
+				atomic_read(&ac->cmd_state_pp));
 		goto fail_send_param;
 	}
 
@@ -8134,6 +8393,80 @@
 	return rc;
 }
 
+int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
+		bool enable)
+{
+	struct asm_mtmx_strtr_params matrix;
+	struct asm_session_mtmx_param_adjust_session_time_ctl_t adjust_time;
+	int sz = 0;
+	int rc  = 0;
+
+	pr_debug("%s: adjust session enable %d\n", __func__, enable);
+
+	if (!ac) {
+		pr_err("%s: audio client handle is NULL\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (ac->apr == NULL) {
+		pr_err("%s: ac->apr is NULL\n", __func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	adjust_time.enable = enable;
+	memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
+	sz = sizeof(struct asm_mtmx_strtr_params);
+	q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, -1);
+	matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
+
+	matrix.param.data_payload_addr_lsw = 0;
+	matrix.param.data_payload_addr_msw = 0;
+	matrix.param.mem_map_handle = 0;
+	matrix.param.data_payload_size =
+		sizeof(struct asm_stream_param_data_v2) +
+		sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
+	matrix.param.direction = 0; /* RX */
+	matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
+	matrix.data.param_id = ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL;
+	matrix.data.param_size =
+		sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
+	matrix.data.reserved = 0;
+	matrix.config.adj_time_param.enable = adjust_time.enable;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
+	if (rc < 0) {
+		pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
+			__func__, matrix.data.param_id);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
+			__func__, matrix.data.param_id);
+		rc = -ETIMEDOUT;
+		goto exit;
+	}
+
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&ac->cmd_state)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state));
+		goto exit;
+	}
+	rc = 0;
+exit:
+	return rc;
+}
+
+
 static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
 {
 	struct apr_hdr hdr;
@@ -8523,6 +8856,68 @@
 	return -EINVAL;
 }
 
+int q6asm_adjust_session_clock(struct audio_client *ac,
+		uint32_t adjust_time_lsw,
+		uint32_t adjust_time_msw)
+{
+	int rc = 0;
+	int sz = 0;
+	struct asm_session_cmd_adjust_session_clock_v2 adjust_clock;
+
+	pr_debug("%s: adjust_time_lsw is %x, adjust_time_msw is %x\n", __func__,
+		  adjust_time_lsw, adjust_time_msw);
+
+	if (!ac) {
+		pr_err("%s: audio client handle is NULL\n", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	if (ac->apr == NULL) {
+		pr_err("%s: ac->apr is NULL", __func__);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	sz = sizeof(struct asm_session_cmd_adjust_session_clock_v2);
+	q6asm_add_hdr(ac, &adjust_clock.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, -1);
+	adjust_clock.hdr.opcode = ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2;
+
+	adjust_clock.adjustime_lsw = adjust_time_lsw;
+	adjust_clock.adjustime_msw = adjust_time_msw;
+
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &adjust_clock);
+	if (rc < 0) {
+		pr_err("%s: adjust_clock send failed paramid [0x%x]\n",
+			__func__, adjust_clock.hdr.opcode);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, adjust_clock paramid[0x%x]\n",
+			__func__, adjust_clock.hdr.opcode);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	}
+
+	if (atomic_read(&ac->cmd_state) > 0) {
+		pr_err("%s: DSP returned error[%s]\n",
+				__func__, adsp_err_get_err_str(
+				atomic_read(&ac->cmd_state)));
+		rc = adsp_err_get_lnx_err_code(
+				atomic_read(&ac->cmd_state));
+		goto fail_cmd;
+	}
+	rc = 0;
+fail_cmd:
+	return rc;
+}
+
 /*
  * q6asm_get_path_delay() - get the path delay for an audio session
  * @ac: audio client handle
@@ -8733,7 +9128,7 @@
 	q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
 		sizeof(struct asm_stream_cmd_set_pp_params_v2)), TRUE);
 
-	atomic_set(&ac->cmd_state, -1);
+	atomic_set(&ac->cmd_state_pp, -1);
 	hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	payload_params.data_payload_addr_lsw =
 			lower_32_bits(cal_block->cal_data.paddr);
@@ -8759,15 +9154,15 @@
 		goto free;
 	}
 	rc = wait_event_timeout(ac->cmd_wait,
-				(atomic_read(&ac->cmd_state) >= 0), 5 * HZ);
+				(atomic_read(&ac->cmd_state_pp) >= 0), 5 * HZ);
 	if (!rc) {
 		pr_err("%s: timeout, audio audstrm cal send\n", __func__);
 		rc = -ETIMEDOUT;
 		goto free;
 	}
-	if (atomic_read(&ac->cmd_state) > 0) {
+	if (atomic_read(&ac->cmd_state_pp) > 0) {
 		pr_err("%s: DSP returned error[%d] audio audstrm cal send\n",
-				__func__, atomic_read(&ac->cmd_state));
+				__func__, atomic_read(&ac->cmd_state_pp));
 		rc = -EINVAL;
 		goto free;
 	}
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index d6ad97d..3aaaa35 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -168,7 +168,7 @@
 			generic_get_data->valid = 1;
 			generic_get_data->size_in_ints =
 				data->payload_size/sizeof(int);
-			pr_debug("DTS_EAGLE_CORE callback size = %i\n",
+			pr_debug("callback size = %i\n",
 				 data->payload_size);
 			memcpy(generic_get_data->ints, data->payload,
 				data->payload_size);
@@ -350,119 +350,6 @@
 	return ret;
 }
 
-int core_dts_eagle_set(int size, char *data)
-{
-	struct adsp_dts_eagle *payload = NULL;
-	int rc = 0, size_aligned4byte;
-
-	pr_debug("DTS_EAGLE_CORE - %s\n", __func__);
-	if (size <= 0 || !data) {
-		pr_err("DTS_EAGLE_CORE - %s: invalid size %i or pointer %pK.\n",
-			__func__, size, data);
-		return -EINVAL;
-	}
-
-	size_aligned4byte = (size+3) & 0xFFFFFFFC;
-	mutex_lock(&(q6core_lcl.cmd_lock));
-	ocm_core_open();
-	if (q6core_lcl.core_handle_q) {
-		payload = kzalloc(sizeof(struct adsp_dts_eagle) +
-				  size_aligned4byte, GFP_KERNEL);
-		if (!payload) {
-			rc = -ENOMEM;
-			goto exit;
-		}
-		payload->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
-						APR_HDR_LEN(APR_HDR_SIZE),
-						APR_PKT_VER);
-		payload->hdr.pkt_size = sizeof(struct adsp_dts_eagle) +
-					       size_aligned4byte;
-		payload->hdr.src_port = 0;
-		payload->hdr.dest_port = 0;
-		payload->hdr.token = 0;
-		payload->hdr.opcode = ADSP_CMD_SET_DTS_EAGLE_DATA_ID;
-		payload->id = DTS_EAGLE_LICENSE_ID;
-		payload->overwrite = 1;
-		payload->size = size;
-		memcpy(payload->data, data, size);
-		rc = apr_send_pkt(q6core_lcl.core_handle_q,
-				(uint32_t *)payload);
-		if (rc < 0) {
-			pr_err("DTS_EAGLE_CORE - %s: failed op[0x%x]rc[%d]\n",
-				__func__, payload->hdr.opcode, rc);
-		}
-		kfree(payload);
-	}
-
-exit:
-	mutex_unlock(&(q6core_lcl.cmd_lock));
-	return rc;
-}
-
-int core_dts_eagle_get(int id, int size, char *data)
-{
-	struct apr_hdr ah;
-	int rc = 0;
-
-	pr_debug("DTS_EAGLE_CORE - %s\n", __func__);
-	if (size <= 0 || !data) {
-		pr_err("DTS_EAGLE_CORE - %s: invalid size %i or pointer %pK.\n",
-			__func__, size, data);
-		return -EINVAL;
-	}
-	mutex_lock(&(q6core_lcl.cmd_lock));
-	ocm_core_open();
-	if (q6core_lcl.core_handle_q) {
-		ah.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-		ah.pkt_size = sizeof(struct apr_hdr);
-		ah.src_port = 0;
-		ah.dest_port = 0;
-		ah.token = 0;
-		ah.opcode = id;
-
-		q6core_lcl.bus_bw_resp_received = 0;
-		generic_get_data = kzalloc(sizeof(struct generic_get_data_)
-					   + size, GFP_KERNEL);
-		if (!generic_get_data) {
-			rc = -ENOMEM;
-			goto exit;
-		}
-
-		rc = apr_send_pkt(q6core_lcl.core_handle_q,
-				(uint32_t *)&ah);
-		if (rc < 0) {
-			pr_err("DTS_EAGLE_CORE - %s: failed op[0x%x]rc[%d]\n",
-				__func__, ah.opcode, rc);
-			goto exit;
-		}
-
-		rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
-				(q6core_lcl.bus_bw_resp_received == 1),
-				msecs_to_jiffies(TIMEOUT_MS));
-		if (!rc) {
-			pr_err("DTS_EAGLE_CORE - %s: EAGLE get params timed out\n",
-				__func__);
-			rc = -EINVAL;
-			goto exit;
-		}
-		if (generic_get_data->valid) {
-			rc = 0;
-			memcpy(data, generic_get_data->ints, size);
-		} else {
-			rc = -EINVAL;
-			pr_err("DTS_EAGLE_CORE - %s: EAGLE get params problem getting data - check callback error value\n",
-				__func__);
-		}
-	}
-
-exit:
-	kfree(generic_get_data);
-	generic_get_data = NULL;
-	mutex_unlock(&(q6core_lcl.cmd_lock));
-	return rc;
-}
-
 uint32_t core_set_dolby_manufacturer_id(int manufacturer_id)
 {
 	struct adsp_dolby_manufacturer_id payload;
@@ -494,9 +381,14 @@
 	return rc;
 }
 
+/**
+ * q6core_is_adsp_ready - check adsp ready status
+ *
+ * Returns true if adsp is ready otherwise returns false
+ */
 bool q6core_is_adsp_ready(void)
 {
-	int rc;
+	int rc = 0;
 	bool ret = false;
 	struct apr_hdr hdr;
 
@@ -509,28 +401,30 @@
 
 	mutex_lock(&(q6core_lcl.cmd_lock));
 	ocm_core_open();
-	q6core_lcl.bus_bw_resp_received = 0;
-	rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
-	if (rc < 0) {
-		pr_err("%s: Get ADSP state APR packet send event %d\n",
-			__func__, rc);
-		goto bail;
-	}
+	if (q6core_lcl.core_handle_q) {
+		q6core_lcl.bus_bw_resp_received = 0;
+		rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
+		if (rc < 0) {
+			pr_err("%s: Get ADSP state APR packet send event %d\n",
+				__func__, rc);
+			goto bail;
+		}
 
-	rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
-				(q6core_lcl.bus_bw_resp_received == 1),
-				msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
-	if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
-		/* ensure to read updated param by callback thread */
-		rmb();
-		ret = !!q6core_lcl.param;
+		rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+					(q6core_lcl.bus_bw_resp_received == 1),
+					msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
+		if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
+			/* ensure to read updated param by callback thread */
+			rmb();
+			ret = !!q6core_lcl.param;
+		}
 	}
 bail:
 	pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
 	mutex_unlock(&(q6core_lcl.cmd_lock));
 	return ret;
 }
-
+EXPORT_SYMBOL(q6core_is_adsp_ready);
 
 static int q6core_map_memory_regions(phys_addr_t *buf_add, uint32_t mempool_id,
 			uint32_t *bufsz, uint32_t bufcnt, uint32_t *map_handle)
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index 08ddde4..799d1be 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -1240,14 +1240,12 @@
 	mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
 	cal_block = cal_utils_get_only_cal_block(
 		lsm_common.cal_data[LSM_CAL_IDX]);
-	if (cal_block == NULL)
-		goto unlock;
 
-	if (cal_block->cal_data.size <= 0) {
+	if (!cal_block || cal_block->cal_data.size <= 0) {
 		pr_debug("%s: No cal to send!\n", __func__);
-		rc = -EINVAL;
 		goto unlock;
 	}
+
 	if (cal_block->cal_data.size != client->lsm_cal_size) {
 		pr_err("%s: Cal size %zd doesn't match lsm cal size %d\n",
 			__func__, cal_block->cal_data.size,
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index b829c65..15c9e13 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -478,8 +478,10 @@
 
 	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
 		v = &common.voice[i];
-		if (v != NULL)
+		if (v != NULL) {
 			v->voc_state = VOC_ERROR;
+			v->rec_info.recording = 0;
+		}
 	}
 }
 
diff --git a/sound/soc/msm/sdm660-common.c b/sound/soc/msm/sdm660-common.c
index f1fbce3..eddcb45 100644
--- a/sound/soc/msm/sdm660-common.c
+++ b/sound/soc/msm/sdm660-common.c
@@ -2412,9 +2412,6 @@
 		mi2s_clk[dai_id].clk_freq_in_hz =
 		    mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
 	}
-
-	if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
-		mi2s_clk[dai_id].clk_freq_in_hz = 0;
 }
 
 static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
diff --git a/sound/soc/msm/sdm660-external.c b/sound/soc/msm/sdm660-external.c
index b603b8a..2c3d7fc 100644
--- a/sound/soc/msm/sdm660-external.c
+++ b/sound/soc/msm/sdm660-external.c
@@ -1609,6 +1609,9 @@
 		snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
 		snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
 		snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
+	} else {
+		snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT1");
+		snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT2");
 	}
 
 	snd_soc_dapm_sync(dapm);
diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c
index b924cad..802137b 100644
--- a/sound/soc/msm/sdm660-internal.c
+++ b/sound/soc/msm/sdm660-internal.c
@@ -1301,15 +1301,6 @@
 	msm_anlg_cdc_spk_ext_pa_cb(enable_spk_ext_pa, ana_cdc);
 	msm_dig_cdc_hph_comp_cb(msm_config_hph_compander_gpio, dig_cdc);
 
-	mbhc_cfg_ptr->calibration = def_msm_int_wcd_mbhc_cal();
-	if (mbhc_cfg_ptr->calibration) {
-		ret = msm_anlg_cdc_hs_detect(ana_cdc, mbhc_cfg_ptr);
-		if (ret) {
-			pr_err("%s: msm_anlg_cdc_hs_detect failed\n", __func__);
-			kfree(mbhc_cfg_ptr->calibration);
-			return ret;
-		}
-	}
 	card = rtd->card->snd_card;
 	if (!codec_root)
 		codec_root = snd_register_module_info(card->module, "codecs",
@@ -1569,6 +1560,36 @@
 	return ret;
 }
 
+static int msm_snd_card_late_probe(struct snd_soc_card *card)
+{
+	const char *be_dl_name = LPASS_BE_INT0_MI2S_RX;
+	struct snd_soc_codec *ana_cdc;
+	struct snd_soc_pcm_runtime *rtd;
+	int ret = 0;
+
+	rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
+	if (!rtd) {
+		dev_err(card->dev,
+			"%s: snd_soc_get_pcm_runtime for %s failed!\n",
+			__func__, be_dl_name);
+		return -EINVAL;
+	}
+
+	ana_cdc = rtd->codec_dais[ANA_CDC]->codec;
+	mbhc_cfg_ptr->calibration = def_msm_int_wcd_mbhc_cal();
+	if (!mbhc_cfg_ptr->calibration)
+		return -ENOMEM;
+
+	ret = msm_anlg_cdc_hs_detect(ana_cdc, mbhc_cfg_ptr);
+	if (ret) {
+		dev_err(card->dev,
+			"%s: msm_anlg_cdc_hs_detect failed\n", __func__);
+		kfree(mbhc_cfg_ptr->calibration);
+	}
+
+	return ret;
+}
+
 static struct snd_soc_ops msm_tdm_be_ops = {
 	.hw_params = msm_tdm_snd_hw_params
 };
@@ -2930,6 +2951,7 @@
 	.name		= "sdm660-snd-card",
 	.dai_link	= msm_int_dai,
 	.num_links	= ARRAY_SIZE(msm_int_dai),
+	.late_probe	= msm_snd_card_late_probe,
 };
 
 static void msm_disable_int_mclk0(struct work_struct *work)
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 130cc56..e699760 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -3934,6 +3934,13 @@
 		ret = -EINVAL;
 		goto err;
 	}
+
+	if (pinctrl_info->pinctrl == NULL) {
+		pr_err("%s: pinctrl_info->pinctrl is NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
 	curr_state = pinctrl_info->curr_state;
 	pinctrl_info->curr_state = new_state;
 	pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
@@ -4202,6 +4209,7 @@
 	struct snd_soc_card *card = rtd->card;
 	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+	int ret_pinctrl = 0;
 
 	dev_dbg(rtd->card->dev,
 		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
@@ -4216,12 +4224,10 @@
 		goto err;
 	}
 	if (index == QUAT_MI2S) {
-		ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
-		if (ret) {
+		ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+		if (ret_pinctrl)
 			pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
-				__func__, ret);
-			goto err;
-		}
+				__func__, ret_pinctrl);
 	}
 	/*
 	 * Muxtex protection in case the same MI2S
@@ -4278,6 +4284,7 @@
 	struct snd_soc_card *card = rtd->card;
 	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+	int ret_pinctrl = 0;
 
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
 		 substream->name, substream->stream);
@@ -4298,10 +4305,10 @@
 	mutex_unlock(&mi2s_intf_conf[index].lock);
 
 	if (index == QUAT_MI2S) {
-		ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
-		if (ret)
+		ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+		if (ret_pinctrl)
 			pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
-				__func__, ret);
+				__func__, ret_pinctrl);
 	}
 }
 
@@ -5530,6 +5537,22 @@
 		.ignore_pmdown_time = 1,
 		.ignore_suspend = 1,
 	},
+	/* Slimbus VI Recording */
+	{
+		.name = LPASS_BE_SLIMBUS_TX_VI,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16393",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tavil_codec",
+		.codec_dai_name = "tavil_vifeedback",
+		.id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+		.ignore_suspend = 1,
+		.no_pcm = 1,
+		.dpcm_capture = 1,
+		.ignore_pmdown_time = 1,
+	},
 };
 
 static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index e6a67cdd..6b23bf5 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2093,6 +2093,9 @@
 	list_for_each_entry(rtd, &card->rtd_list, list)
 		flush_delayed_work(&rtd->delayed_work);
 
+	/* free the ALSA card at first; this syncs with pending operations */
+	snd_card_free(card->snd_card);
+
 	/* remove and free each DAI */
 	soc_remove_dai_links(card);
 	soc_remove_pcm_runtimes(card);
@@ -2107,9 +2110,7 @@
 	if (card->remove)
 		card->remove(card);
 
-	snd_card_free(card->snd_card);
 	return 0;
-
 }
 
 /* removes a socdev */
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index c3bf5ff..9e7861a 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1013,6 +1013,17 @@
 			cval->res = 384;
 		}
 		break;
+
+	case USB_ID(0x1130, 0x1620): /* Logitech Speakers S150 */
+	/* This audio device has 2 channels and it explicitly requires the
+	 * host to send SET_CUR command on the volume control of both the
+	 * channels. 7936 = 0x1F00 is the default value.
+	 */
+		if (cval->channels == 2)
+			snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
+						(cval->control << 8) | 2, 7936);
+		break;
+
 	}
 }
 
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 834137e..1ab58f7 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -168,6 +168,13 @@
 	if (irq->hw) {
 		val |= GICH_LR_HW;
 		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
+		/*
+		 * Never set pending+active on a HW interrupt, as the
+		 * pending state is kept at the physical distributor
+		 * level.
+		 */
+		if (irq->active && irq->pending)
+			val &= ~GICH_LR_PENDING_BIT;
 	} else {
 		if (irq->config == VGIC_CONFIG_LEVEL)
 			val |= GICH_LR_EOI;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index e6b03fd..f132006 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -151,6 +151,13 @@
 	if (irq->hw) {
 		val |= ICH_LR_HW;
 		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
+		/*
+		 * Never set pending+active on a HW interrupt, as the
+		 * pending state is kept at the physical distributor
+		 * level.
+		 */
+		if (irq->active && irq->pending)
+			val &= ~ICH_LR_PENDING_BIT;
 	} else {
 		if (irq->config == VGIC_CONFIG_LEVEL)
 			val |= ICH_LR_EOI;