Merge "msm: net: ecm: debugfs code cleanup"
diff --git a/Documentation/ata/ahci_msm.txt b/Documentation/ata/ahci_msm.txt
new file mode 100644
index 0000000..2f84834
--- /dev/null
+++ b/Documentation/ata/ahci_msm.txt
@@ -0,0 +1,322 @@
+Introduction
+============
+The SATA Host Controller developed for Qualcomm SoC is used
+to facilitate SATA storage devices that connect to SoC through a
+standard SATA cable interface. The MSM Advanced Host Controller
+Interface (AHCI) driver interfaces with the generic Linux AHCI driver
+and communicates with the AHCI controller for data movement between
+system memory and SATA devices (persistent storage).
+
+Hardware description
+====================
+Serial Advanced Technology Attachment (SATA) is a communication
+protocol designed to transfer data between a computer and storage
+devices (Hard Disk Drive(HDD), Solid State Drives(SSD) etc.).
+First generation (Gen1) SATA interfaces communicate at a serial
+rate of 1.5Gb/s and use low-voltage differential signaling on
+serial links. With 8b-10b encoding, the effective data throughput
+for Gen1 interface is 150MB/s.
+
+The SATA host controller in Qualcomm chipsets adheres to the AHCI 1.3
+specification which describes the interface between system software
+and the host controller, as well as the functional behavior needed
+for software to communicate with the SATA host controller.
+
+The SATA PHY hardware macro in Qualcomm chipsets adheres to the
+SATA 3.0 specification with Gen1 serial interface. This is used to
+serialize and de-serialize data and communicates with SATA HDD. Also,
+the PHY can detect SATA HDD during hot swap and raise an interrupt to
+the CPU through AHCI controller to notify about the detection/removal.
+
+The following figure shows the SATA architecture block diagram as
+implemented in MSM chipsets.
+
+                        +---------+
+                        |SATA Disk|
+                        |  Drive  |
+                        +---------+
+                           ^   ^
+                        Tx |   | Rx
+                           v   v
++--------------+     +--------------+     +-----------+
+| System Memory|     |   SATA PHY   |     |    CPU    |
++--------------+     +--------------+     +-----------+
+      ^                 ^       ^           ^     ^
+      |                 |       |           |     |
+      |                 v       v           |     |
+      |            +------------------+(Interrupt)|
+      |            | SATA CONTROLLER  |-----+     |
+      |            +------------------+           |
+      |                 ^       ^                 |
+      |                 |       |                 |
+      v                 v       v                 v
+ <--------------------------------------------------------->
+<             System Fabric (Control and Data)              >
+ <--------------------------------------------------------->
+
+Some controller capabilities:
+- Supports 64-bit addressing
+- Supports native command queueing (upto 32 commands)
+- Supports First-party DMA to move data to and from system memory
+- ATA-7 command set compliant
+- Port multiplier support for some chipsets
+- Supports aggressive power management (partial, slumber modes)
+- Supports asynchronous notification
+
+Software description
+====================
+The SATA driver uses the generic interface to read/write data to
+the Hard Disk Drive (HDD). It uses following components in Linux
+to interface with the generic block layer which then interfaces
+with file system or user processes.
+
+1) AHCI platform Driver (includes MSM-specific glue driver)
+2) LIBAHCI
+3) LIBATA
+4) SCSI
+
+AHCI platform driver registers as a device driver for platform
+device registered during SoC board initialization. It is responsible
+for platform specific tasks like PHY configuration, clock initial-
+ization, claiming memory resources etc. Also, implements certain
+functionality that deviates from the standard specification.
+
+Library "LIBAHCI" implements software layer functionality described
+in the standard AHCI specification. It interfaces with the LIBATA
+framework to execute SATA the command set. It converts ATA task files
+into AHCI command descriptors and pass them to the controller for
+execution. It handles controller interrupts and sends command
+completion events to the upper layers. It implements a controller-
+specific reset and recover mechanism in case of errors. It implements
+link power management policies - partial, slumber modes, runtime power
+management and platform power management. It abstracts the low-level
+controller details from the LIBATA framework.
+
+"LIBATA" is a helper library for implementing ATA and SATA command
+protocol as described in standard ATA and SATA specifications. It
+builds read/write requests from SCSI commands and pass them to the
+low-level controller driver (LLD). It handshakes with the SATA
+device using standard commands to understand capabilities and carry
+out device configurations. It interfaces with the SCSI layer to manage
+underlying disks. It manages different devices connected to each host
+port using a port multiplier. Also, it manages the link PHY component,
+the interconnect interface and any external interface (cables, etc.)
+that follow the SATA electrical specification.
+
+The SCSI layer is a helper library for translating generic block layer
+commands to SCSI commands and pass them on to the LIBATA framework.
+Certain generic stuff like device scan, media change, and hot plug
+detection are handled. This layer handles all types of SCSI devices,
+and SATA storage devices are one class of SCSI devices. It also provides
+the IOCTL interface to manage disks from userspace.
+
+Following is the logical code flow:
+
+                        +------------------------+
+                        | File System (ext4 etc.)|
+                        +------------------------+
+                                   ^
+                                   |
+                                   v
+                        +------------------------+
+                        |  Generic Block Layer   |
+                        +------------------------+
+                                   ^
+                                   |
+                                   v
+                        +------------------------+
+                        |       SCSI Layer       |
+                        +------------------------+
+                                   ^
+                                   |
+                                   v
+                        +------------------------+
+                        |     LIBATA library     |
+                        +------------------------+
+                                   ^
+                                   |
+                                   v
+                        +------------------------+
+                        |     LIBAHCI library    |
+                        +------------------------+
+                                   ^
+                                   |
+                                   v
+                        +------------------------+
+                        | AHCI platform driver + |
+                        | MSM AHCI glue driver   |
+                        +------------------------+
+
+Design
+======
+The MSM AHCI driver acts as a glue driver for the Linux
+AHCI controller driver. It provides the following functionality:
+- Registers as a driver for msm_sata device which has an AHCI-compliant
+  controller and PHY as resources.
+- Registers an AHCI platform device in the probe function providing
+  ahci platform data
+- AHCI platform data consists of the following callbacks:
+	- init
+		o PHY resource acquisition
+		o Clock and voltage regulator initialization
+		o PHY calibration
+	- exit
+		o PHY power down
+		o Clock and voltage regulator turn off
+	- suspend
+	- resume
+		o Sequence described in the next section.
+- The Linux AHCI platform driver then probes the AHCI device and
+  initializes it according to the standard AHCI specification.
+- The SATA drive is detected as part of scsi_scan_host() called by
+  LIBAHCI after controller initialization.
+
+Power Management
+================
+Various power modes are supported by this driver.
+
+Platform suspend/resume:
+During suspend:
+- PHY analog blocks are powered down
+- Controller and PHY is kept in Power-on-Reset (POR) mode
+- Clocks and voltage regulators are gated
+
+During resume:
+- Clocks and voltage regulators are ungated
+- PHY is powered up and calibrated to functional mode
+- Controller is re-initialized to process commands.
+
+Runtime suspend/resume:
+- Execute the same steps as in platform suspend/resume.
+- Runtime suspend/resume is disabled by default due to regressions
+  in hot-plug detection (specification limitation). The users can
+  enable runtime power management with following shell commands.
+
+  # cd /sys/devices/platform/msm_sata.0/ahci.0/
+  # echo auto > ./power/control
+  # echo auto > ./ata1/power/control
+  # echo auto > ./ata1/host0/target0:0:0/0:0:0:0/power/control
+
+  Note: The device will be runtime-suspended only when user unmounts
+  all the partitions.
+
+Link power management (defined by AHCI 1.3 specification):
+- Automatic low power mode transition are supported.
+- AHCI supports two power modes: partial and slumber.
+- Software uses Inteface Communication Control (ICC) bits in AHCI
+  register space to enable automatic partial/slumber state.
+- Partial mode:
+	- Software asserts automatic partial mode when the use
+	  case demands low latency resume.
+	- Upon receiving partial mode signal, PHY disables byte clocks
+	  and re-enables them during resume and thus has low latency.
+- Slumber mode:
+	- Software asserts automatic slumber mode when the use
+	  case demands low power consumption and can withstand
+	  high resume latencies.
+	- Upon receiving slumber mode signal, PHY disables byte
+	  clocks and some internal circuitry. Upon resume PHY
+	  enables byte clocks and reacquires the PLL lock.
+- Once the software enables partial/slumber modes, the transitioning
+  into these modes are automatic and is handled by hardware without
+  software intervention while the controller is idle with no outstanding
+  commands to process.
+
+- The Linux AHCI link power management defines three modes:
+	- max_performance (default mode)
+	  Doesn't allow partial/slumber transition when host is idle.
+	- medium_power (Partial mode)
+	  Following shell commands are used to enable this mode:
+
+	  # cd /sys/devices/platform/msm_sata.0/ahci.0/
+	  # echo medium_power > ./ata1/host0/scsi_host/host0/link_power_management_policy
+
+	- min_power (Slumber mode)
+	  Following shell commands are used to enable this mode:
+
+	  # cd /sys/devices/platform/msm_sata.0/ahci.0/
+	  # echo min_power > ./ata1/host0/scsi_host/host0/link_power_management_policy
+
+SMP/multi-core
+==============
+The MSM AHCI driver hooks only init, exit, suspend, resume callbacks to
+the AHCI driver which are serialized by design and hence the driver, which
+is inherently SMP safe.
+
+Security
+========
+None.
+
+Performance
+===========
+The theoretical performance with Gen1 SATA PHY is 150MB/s (8b/10b encoding).
+The performance is dependent on various factors, mainly:
+- Capabilities of the external SATA hard disk connected to the MSM SATA port
+- Various system bus frequencies and system loads
+- System memory capabilities
+- Benchmark test applications that collect performance numbers
+
+One example of the maximum performance achieved in a specific system
+configuration follows:
+
+Benchmark: Iozone sequential performance
+Block size: 128K
+File size: 1GB
+Platform: APQ8064 V2 CDP
+CPU Governor: Performance
+
+SanDisk SSD (i100 64GB):
+Read - 135MB/s
+Write - 125MB/s
+
+Western Digital HDD (WD20EURS 2TB):
+Read - 121MB/s
+Write - 98MB/s
+
+Interface
+=========
+The MSM AHCI controller driver provides function pointers as the
+required interface to the Linux AHCI controller driver. The main
+routines implemented are init, exit, suspend, and resume for handling
+MSM-specific initialization, freeing of resources on exit, and
+MSM-specific power management tweaks during suspend power collapse.
+
+Driver parameters
+=================
+None.
+
+Config options
+==============
+Config option SATA_AHCI_MSM in drivers/ata/Kconfig enables this driver.
+
+Dependencies
+============
+The MSM AHCI controller driver is dependent on Linux AHCI driver,
+Linux ATA framework, Linux SCSI framework and Linux generic block layer.
+
+While configuring the kernel, the following options should be set:
+
+- CONFIG_BLOCK
+- CONFIG_SCSI
+- CONFIG_ATA
+- CONFIG_SATA_AHCI_PLATFORM
+
+User space utilities
+====================
+Any user space component that can mount a block device can be used to
+read/write data into persistent storage. However, at the time of this
+writing there are no utilities that author is aware of that can manage
+h/w from userspace.
+
+Other
+=====
+None.
+
+Known issues
+============
+None.
+
+To do
+=====
+- Device tree support.
+- MSM bus frequency voting support.
diff --git a/Documentation/devicetree/bindings/arm/msm/acpuclock/acpuclock-a7.txt b/Documentation/devicetree/bindings/arm/msm/acpuclock/acpuclock-a7.txt
index 7a15f6a..a77d435 100644
--- a/Documentation/devicetree/bindings/arm/msm/acpuclock/acpuclock-a7.txt
+++ b/Documentation/devicetree/bindings/arm/msm/acpuclock/acpuclock-a7.txt
@@ -10,7 +10,6 @@
 - reg-names: name of the bases for the above registers. "rcg_base"
 	     is expected.
 - a7_cpu-supply: regulator to supply a7 cpu
-- a7_mem-supply: regulator to supply a7 l2 cache
 
 Example:
 	qcom,acpuclk@f9011050 {
@@ -18,5 +17,4 @@
 		reg = <0xf9011050 0x8>;
 		reg-names = "rcg_base";
 		a7_cpu-supply = <&pm8026_s2>;
-		a7_mem-supply = <&pm8026_l3>;
 	};
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index a3f3a06..9bc949e 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -112,6 +112,18 @@
 		      compression feature in the rotator.
 - qcom,mdss-has-decimation: Boolean property to indicate the presence of
 			    decimation feature in fetch.
+- qcom,mdss-ad-off:		Array of offset addresses for the available
+				Assertive Display (AD) blocks. These offsets
+				are calculated from the register "mdp_phys"
+				defined in reg property. The number of AD
+				offsets should be less than or equal to the
+				number of mixers driving interfaces defined in
+				property: qcom,mdss-mixer-intf-off. Assumes
+				that AD blocks are aligned with the mixer
+				offsets as well (i.e. the first mixer offset
+				corresponds to the same pathway as the first
+				AD offset).
+
 Optional subnodes:
 Child nodes representing the frame buffer virtual devices.
 
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index a221433..96d95da 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -4,7 +4,7 @@
 controlling LEDs that are part of PMIC on Qualcomm reference
 platforms. The PMIC is connected to Host processor via
 SPMI bus. This driver supports various LED modules such as
-WLED (white LED), RGB LED and flash LED.
+Keypad backlight, WLED (white LED), RGB LED and flash LED.
 
 Each LED module is represented as a node of "leds-qpnp". This
 node will further contain the type of LED supported and its
@@ -76,6 +76,18 @@
 - qcom,source-sel: select power source, default 1 (enabled)
 - qcom,mode-ctrl: select operation mode, default 0x60 = Mode Sink
 
+Keypad backlight is a backlight source for buttons. It supports four rows
+and the required rows are enabled by specifying values in the properties.
+
+Required properties for keypad backlight:
+- qcom,mode: mode the led should operate in, options 0 = PWM, 1 = LPG
+- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
+- qcom,row-src-sel-val: select source for rows. One bit is used for each row.
+			Specify 0 for vph_pwr and 1 for vbst for each row.
+- qcom,row-scan-val: select rows for scanning
+- qcom,row-scan-en: row scan enable
+
 Example:
 
 	qcom,leds@a200 {
@@ -174,3 +186,18 @@
 			};
 	};
 
+	qcom,leds@e200 {
+		status = "okay";
+		qcom,kpdbl {
+			label = "kpdbl";
+			linux,name = "button-backlight";
+			qcom,mode = <0>;
+			qcom,pwm-channel = <8>;
+			qcom,pwm-us = <1000>;
+			qcom,id = <7>;
+			qcom,max-current = <20>;
+			qcom,row-src-sel-val = <0x00>;
+			qcom,row-scan-en = <0x01>;
+			qcom,row-scan-val = <0x01>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 383e50d..9f6cb16 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -458,9 +458,12 @@
 - qcom,sec-auxpcm-gpio-din  : GPIO on which Secondary AUXPCM DIN signal is coming.
 - qcom,sec-auxpcm-gpio-dout : GPIO on which Secondary AUXPCM DOUT signal is coming.
 - qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
-
 Optional properties:
 - qcom,hdmi-audio-rx: specifies if HDMI audio support is enabled or not.
+- qcom,ext-ult-spk-amp-gpio : GPIO for enabling of speaker path amplifier.
+
+- qcom,ext-ult-lo-amp-gpio: GPIO to enable external ultrasound lineout
+			    amplifier.
 
 Example:
 
@@ -502,6 +505,7 @@
 	qcom,us-euro-gpios = <&pm8941_gpios 20 0>;
 
 	qcom,hdmi-audio-rx;
+	qcom,ext-ult-lo-amp-gpio = <&pm8941_gpios 6 0>;
 
 	qcom,prim-auxpcm-gpio-clk  = <&msmgpio 65 0>;
 	qcom,prim-auxpcm-gpio-sync = <&msmgpio 66 0>;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 1613856..de1577d 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -61,6 +61,9 @@
 	    Used for allowing USB to respond for remote wakup.
 - qcom,hsusb-otg-delay-lpm: If present then USB core will wait one second
 	after disconnect before entering low power mode.
+- qcom,hsusb-otg-delay-lpm-hndshk-on-disconnect: If present then USB core will
+	wait for the handshake with the IPA to complete before entering low
+	power mode.
 - <supply-name>-supply: handle to the regulator device tree node.
          Optional "supply-name" is "vbus_otg" to supply vbus in host mode.
 - qcom,vdd-voltage-level: This property must be a list of three integer
@@ -147,6 +150,8 @@
   update USB PID and serial numbers used by bootloader in DLOAD mode.
 - qcom,android-usb-swfi-latency : value to be used by device to vote
   for DMA latency in microsecs.
+- qcom,android-usb-cdrom : if this property is present then device creates
+  a new LUN as CD-ROM
 
 Example Android USB device node :
 	android_usb@fc42b0c8 {
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 5391734..282257c 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -45,6 +45,8 @@
 		bits 6-12  PARAMETER_OVERRIDE_B
 		bits 13-19 PARAMETER_OVERRIDE_C
 		bits 20-25 PARAMETER_OVERRIDE_D
+- qcom,skip-charger-detection: If present then charger detection using BC1.2
+  is not supported and attached host should always be assumed as SDP.
 
 Sub nodes:
 - Sub node for "DWC3- USB3 controller".
diff --git a/arch/arm/boot/dts/apq8084-regulator.dtsi b/arch/arm/boot/dts/apq8084-regulator.dtsi
new file mode 100644
index 0000000..00991b3
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-regulator.dtsi
@@ -0,0 +1,327 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/* QPNP controlled regulators: */
+
+&spmi_bus {
+	qcom,pma8084@1 {
+		pma8084_s1: regulator@1400 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		/* PMA8084 S2 + S12 = 2 phase VDD_CX supply */
+		pma8084_s2: regulator@1700 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s3: regulator@1a00 {
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s4: regulator@1d00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s5: regulator@2000 {
+			regulator-min-microvolt = <2150000>;
+			regulator-max-microvolt = <2150000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		/* PMA8084 S6 + S7 = 2 phase VDD_GFX supply */
+		pma8084_s6: regulator@2300 {
+			regulator-min-microvolt = <815000>;
+			regulator-max-microvolt = <900000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		/* PMA8084 S8 + S9 + S10 + S11 = 4 phase VDD_APC supply */
+		pma8084_s8: regulator@2900 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		/* Output of PMA8084 L1 and L11 is tied together. */
+		pma8084_l1: regulator@4000 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <10000>;
+			status = "okay";
+		};
+
+		pma8084_l2: regulator@4100 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l3: regulator@4200 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l4: regulator@4300 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <1000000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l6: regulator@4500 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l8: regulator@4700 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l9: regulator@4800 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l10: regulator@4900 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l12: regulator@4b00 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l13: regulator@4c00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l14: regulator@4d00 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l15: regulator@4e00 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l16: regulator@4f00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l17: regulator@5000 {
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l18: regulator@5100 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l19: regulator@5200 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l20: regulator@5300 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l21: regulator@5400 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l22: regulator@5500 {
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l23: regulator@5600 {
+			regulator-min-microvolt = <2700000>;
+			regulator-max-microvolt = <2700000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l24: regulator@5700 {
+			regulator-min-microvolt = <3075000>;
+			regulator-max-microvolt = <3075000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l25: regulator@5800 {
+			regulator-min-microvolt = <2100000>;
+			regulator-max-microvolt = <2100000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l26: regulator@5900 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l27: regulator@5a00 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs1: regulator@8000 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs2: regulator@8100 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs3: regulator@8200 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs4: regulator@8300 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_mvs1: regulator@8400 {
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+	};
+};
+
diff --git a/arch/arm/boot/dts/apq8084-sim.dts b/arch/arm/boot/dts/apq8084-sim.dts
index 45d625c..93803dbe 100644
--- a/arch/arm/boot/dts/apq8084-sim.dts
+++ b/arch/arm/boot/dts/apq8084-sim.dts
@@ -71,3 +71,97 @@
 
 	status = "ok";
 };
+
+&pma8084_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+
+	gpio@c800 { /* GPIO 9 */
+	};
+
+	gpio@c900 { /* GPIO 10 */
+	};
+
+	gpio@ca00 { /* GPIO 11 */
+	};
+
+	gpio@cb00 { /* GPIO 12 */
+	};
+
+	gpio@cc00 { /* GPIO 13 */
+	};
+
+	gpio@cd00 { /* GPIO 14 */
+	};
+
+	gpio@ce00 { /* GPIO 15 */
+	};
+
+	gpio@cf00 { /* GPIO 16 */
+	};
+
+	gpio@d000 { /* GPIO 17 */
+	};
+
+	gpio@d100 { /* GPIO 18 */
+	};
+
+	gpio@d200 { /* GPIO 19 */
+	};
+
+	gpio@d300 { /* GPIO 20 */
+	};
+
+	gpio@d400 { /* GPIO 21 */
+	};
+
+	gpio@d500 { /* GPIO 22 */
+	};
+};
+
+&pma8084_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index c3c3759..bc6f030 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -107,4 +107,26 @@
 		qcom,bus-width = <4>;
 		status = "disabled";
 	};
+
+	spmi_bus: qcom,spmi@fc4c0000 {
+		cell-index = <0>;
+		compatible = "qcom,spmi-pmic-arb";
+		reg-names = "core", "intr", "cnfg";
+		reg = <0xfc4cf000 0x1000>,
+		      <0Xfc4cb000 0x1000>,
+		      <0Xfc4ca000 0x1000>;
+		/* 190,ee0_krait_hlos_spmi_periph_irq */
+		/* 187,channel_0_krait_hlos_trans_done_irq */
+		interrupts = <0 190 0>, <0 187 0>;
+		qcom,not-wakeup;
+		qcom,pmic-arb-ee = <0>;
+		qcom,pmic-arb-channel = <0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-controller;
+		#interrupt-cells = <3>;
+	};
 };
+
+/include/ "msm-pma8084.dtsi"
+/include/ "apq8084-regulator.dtsi"
diff --git a/arch/arm/boot/dts/mpq8092-regulator.dtsi b/arch/arm/boot/dts/mpq8092-regulator.dtsi
index b724a3d..e6866e5 100644
--- a/arch/arm/boot/dts/mpq8092-regulator.dtsi
+++ b/arch/arm/boot/dts/mpq8092-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,9 +15,9 @@
 
 &spmi_bus {
 
-	qcom,pm8644@1 {
+	qcom,pma8084@1 {
 
-		pm8644_s3: regulator@1a00 {
+		pma8084_s3: regulator@1a00 {
 			regulator-min-microvolt = <1350000>;
 			regulator-max-microvolt = <1350000>;
 			qcom,enable-time = <500>;
@@ -27,7 +27,7 @@
 			status = "okay";
 		};
 
-		pm8644_s4: regulator@1d00 {
+		pma8084_s4: regulator@1d00 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,enable-time = <500>;
@@ -37,7 +37,7 @@
 			status = "okay";
 		};
 
-		pm8644_s5: regulator@2000 {
+		pma8084_s5: regulator@2000 {
 			regulator-min-microvolt = <2150000>;
 			regulator-max-microvolt = <2150000>;
 			qcom,enable-time = <500>;
@@ -45,7 +45,7 @@
 			status = "okay";
 		};
 
-		pm8644_s6: regulator@2300 {
+		pma8084_s6: regulator@2300 {
 			regulator-min-microvolt = <900000>;
 			regulator-max-microvolt = <900000>;
 			qcom,enable-time = <500>;
@@ -53,7 +53,7 @@
 			status = "okay";
 		};
 
-		pm8644_s7: regulator@2600 {
+		pma8084_s7: regulator@2600 {
 			regulator-min-microvolt = <900000>;
 			regulator-max-microvolt = <900000>;
 			qcom,enable-time = <500>;
@@ -61,7 +61,7 @@
 			status = "okay";
 		};
 
-		pm8644_s8: regulator@2900 {
+		pma8084_s8: regulator@2900 {
 			regulator-min-microvolt = <900000>;
 			regulator-max-microvolt = <900000>;
 			qcom,enable-time = <500>;
@@ -69,8 +69,8 @@
 			status = "okay";
 		};
 
-		pm8644_l1: regulator@4000 {
-			parent-supply = <&pm8644_s3>;
+		pma8084_l1: regulator@4000 {
+			parent-supply = <&pma8084_s3>;
 			regulator-min-microvolt = <1225000>;
 			regulator-max-microvolt = <1225000>;
 			qcom,enable-time = <200>;
@@ -80,8 +80,8 @@
 			status = "okay";
 		};
 
-		pm8644_l2: regulator@4100 {
-			parent-supply = <&pm8644_s3>;
+		pma8084_l2: regulator@4100 {
+			parent-supply = <&pma8084_s3>;
 			regulator-min-microvolt = <900000>;
 			regulator-max-microvolt = <900000>;
 			qcom,enable-time = <200>;
@@ -89,8 +89,8 @@
 			status = "okay";
 		};
 
-		pm8644_l3: regulator@4200 {
-			parent-supply = <&pm8644_s3>;
+		pma8084_l3: regulator@4200 {
+			parent-supply = <&pma8084_s3>;
 			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1200000>;
 			qcom,enable-time = <200>;
@@ -98,8 +98,8 @@
 			status = "okay";
 		};
 
-		pm8644_l4: regulator@4300 {
-			parent-supply = <&pm8644_s3>;
+		pma8084_l4: regulator@4300 {
+			parent-supply = <&pma8084_s3>;
 			regulator-min-microvolt = <1000000>;
 			regulator-max-microvolt = <1000000>;
 			qcom,enable-time = <200>;
@@ -107,8 +107,8 @@
 			status = "okay";
 		};
 
-		pm8644_l6: regulator@4500 {
-			parent-supply = <&pm8644_s5>;
+		pma8084_l6: regulator@4500 {
+			parent-supply = <&pma8084_s5>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,enable-time = <200>;
@@ -116,7 +116,7 @@
 			status = "okay";
 		};
 
-		pm8644_l8: regulator@4700 {
+		pma8084_l8: regulator@4700 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,enable-time = <200>;
@@ -124,7 +124,7 @@
 			status = "okay";
 		};
 
-		pm8644_l9: regulator@4800 {
+		pma8084_l9: regulator@4800 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <2950000>;
 			qcom,enable-time = <200>;
@@ -132,7 +132,7 @@
 			status = "okay";
 		};
 
-		pm8644_l10: regulator@4900 {
+		pma8084_l10: regulator@4900 {
 			regulator-min-microvolt = <2000000>;
 			regulator-max-microvolt = <2000000>;
 			qcom,enable-time = <200>;
@@ -140,8 +140,8 @@
 			status = "okay";
 		};
 
-		pm8644_l11: regulator@4a00 {
-			parent-supply = <&pm8644_s3>;
+		pma8084_l11: regulator@4a00 {
+			parent-supply = <&pma8084_s3>;
 			regulator-min-microvolt = <1300000>;
 			regulator-max-microvolt = <1300000>;
 			qcom,enable-time = <200>;
@@ -149,8 +149,8 @@
 			status = "okay";
 		};
 
-		pm8644_l12: regulator@4b00 {
-			parent-supply = <&pm8644_s5>;
+		pma8084_l12: regulator@4b00 {
+			parent-supply = <&pma8084_s5>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,enable-time = <200>;
@@ -158,7 +158,7 @@
 			status = "okay";
 		};
 
-		pm8644_l13: regulator@4c00 {
+		pma8084_l13: regulator@4c00 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <2950000>;
 			qcom,enable-time = <200>;
@@ -166,8 +166,8 @@
 			status = "okay";
 		};
 
-		pm8644_l14: regulator@4d00 {
-			parent-supply = <&pm8644_s5>;
+		pma8084_l14: regulator@4d00 {
+			parent-supply = <&pma8084_s5>;
 			regulator-min-microvolt = <1000000>;
 			regulator-max-microvolt = <1000000>;
 			qcom,enable-time = <200>;
@@ -175,8 +175,8 @@
 			status = "okay";
 		};
 
-		pm8644_l15: regulator@4e00 {
-			parent-supply = <&pm8644_s5>;
+		pma8084_l15: regulator@4e00 {
+			parent-supply = <&pma8084_s5>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,enable-time = <200>;
@@ -184,8 +184,8 @@
 			status = "okay";
 		};
 
-		pm8644_l16: regulator@4f00 {
-			parent-supply = <&pm8644_s4>;
+		pma8084_l16: regulator@4f00 {
+			parent-supply = <&pma8084_s4>;
 			regulator-min-microvolt = <750000>;
 			regulator-max-microvolt = <750000>;
 			qcom,enable-time = <200>;
@@ -193,7 +193,7 @@
 			status = "okay";
 		};
 
-		pm8644_l17: regulator@5000 {
+		pma8084_l17: regulator@5000 {
 			regulator-min-microvolt = <3150000>;
 			regulator-max-microvolt = <3150000>;
 			qcom,enable-time = <200>;
@@ -203,7 +203,7 @@
 			status = "okay";
 		};
 
-		pm8644_l18: regulator@5100 {
+		pma8084_l18: regulator@5100 {
 			regulator-min-microvolt = <2850000>;
 			regulator-max-microvolt = <2850000>;
 			qcom,enable-time = <200>;
@@ -211,8 +211,8 @@
 			status = "okay";
 		};
 
-		pm8644_l19: regulator@5200 {
-			parent-supply = <&pm8644_s4>;
+		pma8084_l19: regulator@5200 {
+			parent-supply = <&pma8084_s4>;
 			regulator-min-microvolt = <1500000>;
 			regulator-max-microvolt = <1500000>;
 			qcom,enable-time = <200>;
@@ -220,7 +220,7 @@
 			status = "okay";
 		};
 
-		pm8644_l20: regulator@5300 {
+		pma8084_l20: regulator@5300 {
 			regulator-min-microvolt = <2950000>;
 			regulator-max-microvolt = <2950000>;
 			qcom,enable-time = <200>;
@@ -228,7 +228,7 @@
 			status = "okay";
 		};
 
-		pm8644_l21: regulator@5400 {
+		pma8084_l21: regulator@5400 {
 			regulator-min-microvolt = <2950000>;
 			regulator-max-microvolt = <2950000>;
 			qcom,enable-time = <200>;
@@ -236,7 +236,7 @@
 			status = "okay";
 		};
 
-		pm8644_l22: regulator@5500 {
+		pma8084_l22: regulator@5500 {
 			regulator-min-microvolt = <2500000>;
 			regulator-max-microvolt = <2500000>;
 			qcom,enable-time = <200>;
@@ -244,7 +244,7 @@
 			status = "okay";
 		};
 
-		pm8644_l23: regulator@5600 {
+		pma8084_l23: regulator@5600 {
 			regulator-min-microvolt = <3000000>;
 			regulator-max-microvolt = <3000000>;
 			qcom,enable-time = <200>;
@@ -252,7 +252,7 @@
 			status = "okay";
 		};
 
-		pm8644_l24: regulator@5700 {
+		pma8084_l24: regulator@5700 {
 			regulator-min-microvolt = <3075000>;
 			regulator-max-microvolt = <3075000>;
 			qcom,enable-time = <200>;
@@ -260,27 +260,21 @@
 			status = "okay";
 		};
 
-		pm8644_lvs1: regulator@8000 {
-			parent-supply = <&pm8644_s4>;
+		pma8084_lvs1: regulator@8000 {
+			parent-supply = <&pma8084_s4>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
 			status = "okay";
 		};
 
-		pm8644_lvs2: regulator@8100 {
-			parent-supply = <&pm8644_s4>;
+		pma8084_lvs2: regulator@8100 {
+			parent-supply = <&pma8084_s4>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
 			status = "okay";
 		};
 
-		pm8644_mvs1: regulator@8200 {
-			qcom,enable-time = <200>;
-			qcom,pull-down-enable = <1>;
-			status = "okay";
-		};
-
-		pm8644_mvs2: regulator@8300 {
+		pma8084_mvs1: regulator@8400 {
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
 			status = "okay";
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index 0cbfa33..fc07c59 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -28,7 +28,7 @@
 	};
 };
 
-&pm8644_gpios {
+&pma8084_gpios {
 	gpio@c000 { /* GPIO 1 */
 	};
 
@@ -94,72 +94,9 @@
 
 	gpio@d500 { /* GPIO 22 */
 	};
-
-	gpio@d600 { /* GPIO 23 */
-	};
-
-	gpio@d700 { /* GPIO 24 */
-	};
-
-	gpio@d800 { /* GPIO 25 */
-	};
-
-	gpio@d900 { /* GPIO 26 */
-	};
-
-	gpio@da00 { /* GPIO 27 */
-	};
-
-	gpio@db00 { /* GPIO 28 */
-	};
-
-	gpio@dc00 { /* GPIO 29 */
-	};
-
-	gpio@dd00 { /* GPIO 30 */
-	};
-
-	gpio@de00 { /* GPIO 31 */
-	};
-
-	gpio@df00 { /* GPIO 32 */
-	};
-
-	gpio@e000 { /* GPIO 33 */
-	};
-
-	gpio@e100 { /* GPIO 34 */
-	};
-
-	gpio@e200 { /* GPIO 35 */
-	};
-
-	gpio@e300 { /* GPIO 36 */
-	};
-
-	gpio@e400 { /* GPIO 37 */
-	};
-
-	gpio@e500 { /* GPIO 38 */
-	};
-
-	gpio@e600 { /* GPIO 39 */
-	};
-
-	gpio@e700 { /* GPIO 40 */
-	};
-
-	gpio@e800 { /* GPIO 41 */
-	};
-
-	gpio@e900 { /* GPIO 42 */
-	};
-
-	gpio@ea00 { /* GPIO 43 */
-	};
 };
 
-&pm8644_mpps {
+&pma8084_mpps {
 	mpp@a000 { /* MPP 1 */
 	};
 
@@ -177,4 +114,10 @@
 
 	mpp@a500 { /* MPP 6 */
 	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
 };
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 5c904b4..c92dad9 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -151,5 +151,5 @@
 	status = "ok";
 };
 
-/include/ "msm-pm8644.dtsi"
+/include/ "msm-pma8084.dtsi"
 /include/ "mpq8092-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index b88b991..79760c1 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -116,6 +116,66 @@
 			};
 		};
 
+		pm8110_gpios: gpios {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8110-gpio";
+
+			gpio@c000 {
+				reg = <0xc000 0x100>;
+				qcom,pin-num = <1>;
+			};
+
+			gpio@c100 {
+				reg = <0xc100 0x100>;
+				qcom,pin-num = <2>;
+			};
+
+			gpio@c200 {
+				reg = <0xc200 0x100>;
+				qcom,pin-num = <3>;
+			};
+
+			gpio@c300 {
+				reg = <0xc300 0x100>;
+				qcom,pin-num = <4>;
+			};
+		};
+
+		pm8110_mpps: mpps {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8110-mpp";
+
+			mpp@a000 {
+				reg = <0xa000 0x100>;
+				qcom,pin-num = <1>;
+			};
+
+			mpp@a100 {
+				reg = <0xa100 0x100>;
+				qcom,pin-num = <2>;
+			};
+
+			mpp@a200 {
+				reg = <0xa200 0x100>;
+				qcom,pin-num = <3>;
+			};
+
+			mpp@a300 {
+				reg = <0xa300 0x100>;
+				qcom,pin-num = <4>;
+			};
+		};
+
 		pm8110_vadc: vadc@3100 {
 			compatible = "qcom,qpnp-vadc";
 			reg = <0x3100 0x100>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 43b7d03..eadd5d3 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -849,7 +849,7 @@
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
-				qcom,scale-function = <1>;
+				qcom,scale-function = <3>;
 				qcom,hw-settle-time = <0>;
 				qcom,fast-avg-setup = <3>;
 				qcom,btm-channel-number = <0x70>;
diff --git a/arch/arm/boot/dts/msm-pm8644.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
similarity index 76%
rename from arch/arm/boot/dts/msm-pm8644.dtsi
rename to arch/arm/boot/dts/msm-pma8084.dtsi
index 17a6b0b..30525aa 100644
--- a/arch/arm/boot/dts/msm-pm8644.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,20 +16,20 @@
 	interrupt-controller;
 	#interrupt-cells = <3>;
 
-	qcom,pm8644@0 {
+	qcom,pma8084@0 {
 		spmi-slave-container;
 		reg = <0x0>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		pm8644_gpios: gpios {
+		pma8084_gpios: gpios {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
 			gpio-controller;
 			#gpio-cells = <2>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-			label = "pm8644-gpio";
+			label = "pma8084-gpio";
 
 			gpio@c000 {
 				reg = <0xc000 0x100>;
@@ -140,121 +140,16 @@
 				reg = <0xd500 0x100>;
 				qcom,pin-num = <22>;
 			};
-
-			gpio@d600 {
-				reg = <0xd600 0x100>;
-				qcom,pin-num = <23>;
-			};
-
-			gpio@d700 {
-				reg = <0xd700 0x100>;
-				qcom,pin-num = <24>;
-			};
-
-			gpio@d800 {
-				reg = <0xd800 0x100>;
-				qcom,pin-num = <25>;
-			};
-
-			gpio@d900 {
-				reg = <0xd900 0x100>;
-				qcom,pin-num = <26>;
-			};
-
-			gpio@da00 {
-				reg = <0xda00 0x100>;
-				qcom,pin-num = <27>;
-			};
-
-			gpio@db00 {
-				reg = <0xdb00 0x100>;
-				qcom,pin-num = <28>;
-			};
-
-			gpio@dc00 {
-				reg = <0xdc00 0x100>;
-				qcom,pin-num = <29>;
-			};
-
-			gpio@dd00 {
-				reg = <0xdd00 0x100>;
-				qcom,pin-num = <30>;
-			};
-
-			gpio@de00 {
-				reg = <0xde00 0x100>;
-				qcom,pin-num = <31>;
-			};
-
-			gpio@df00 {
-				reg = <0xdf00 0x100>;
-				qcom,pin-num = <32>;
-			};
-
-			gpio@e000 {
-				reg = <0xe000 0x100>;
-				qcom,pin-num = <33>;
-			};
-
-			gpio@e100 {
-				reg = <0xe100 0x100>;
-				qcom,pin-num = <34>;
-			};
-
-			gpio@e200 {
-				reg = <0xe200 0x100>;
-				qcom,pin-num = <35>;
-			};
-
-			gpio@e300 {
-				reg = <0xe300 0x100>;
-				qcom,pin-num = <36>;
-			};
-
-			gpio@e400 {
-				reg = <0xe400 0x100>;
-				qcom,pin-num = <37>;
-			};
-
-			gpio@e500 {
-				reg = <0xe500 0x100>;
-				qcom,pin-num = <38>;
-			};
-
-			gpio@e600 {
-				reg = <0xe600 0x100>;
-				qcom,pin-num = <39>;
-			};
-
-			gpio@e700 {
-				reg = <0xe700 0x100>;
-				qcom,pin-num = <40>;
-			};
-
-			gpio@e800 {
-				reg = <0xe800 0x100>;
-				qcom,pin-num = <41>;
-			};
-
-			gpio@e900 {
-				reg = <0xe900 0x100>;
-				qcom,pin-num = <42>;
-			};
-
-			gpio@ea00 {
-				reg = <0xea00 0x100>;
-				qcom,pin-num = <43>;
-			};
 		};
 
-		pm8644_mpps: mpps {
+		pma8084_mpps: mpps {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
 			gpio-controller;
 			#gpio-cells = <2>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-			label = "pm8644-mpp";
+			label = "pma8084-mpp";
 
 			mpp@a000 {
 				reg = <0xa000 0x100>;
@@ -285,17 +180,27 @@
 				reg = <0xa500 0x100>;
 				qcom,pin-num = <6>;
 			};
+
+			mpp@a600 {
+				reg = <0xa600 0x100>;
+				qcom,pin-num = <7>;
+			};
+
+			mpp@a700 {
+				reg = <0xa700 0x100>;
+				qcom,pin-num = <8>;
+			};
 		};
 	};
 
-	qcom,pm8644@1 {
+	qcom,pma8084@1 {
 		spmi-slave-container;
 		reg = <0x1>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
 		regulator@1400 {
-			regulator-name = "8644_s1";
+			regulator-name = "8084_s1";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -315,7 +220,7 @@
 		};
 
 		regulator@1700 {
-			regulator-name = "8644_s2";
+			regulator-name = "8084_s2";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -335,7 +240,7 @@
 		};
 
 		regulator@1a00 {
-			regulator-name = "8644_s3";
+			regulator-name = "8084_s3";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -355,7 +260,7 @@
 		};
 
 		regulator@1d00 {
-			regulator-name = "8644_s4";
+			regulator-name = "8084_s4";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -375,7 +280,7 @@
 		};
 
 		regulator@2000 {
-			regulator-name = "8644_s5";
+			regulator-name = "8084_s5";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -395,7 +300,7 @@
 		};
 
 		regulator@2300 {
-			regulator-name = "8644_s6";
+			regulator-name = "8084_s6";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -415,7 +320,7 @@
 		};
 
 		regulator@2600 {
-			regulator-name = "8644_s7";
+			regulator-name = "8084_s7";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -435,7 +340,7 @@
 		};
 
 		regulator@2900 {
-			regulator-name = "8644_s8";
+			regulator-name = "8084_s8";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -455,7 +360,7 @@
 		};
 
 		regulator@2c00 {
-			regulator-name = "8644_s9";
+			regulator-name = "8084_s9";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -475,7 +380,7 @@
 		};
 
 		regulator@2f00 {
-			regulator-name = "8644_s10";
+			regulator-name = "8084_s10";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -495,7 +400,7 @@
 		};
 
 		regulator@3200 {
-			regulator-name = "8644_s11";
+			regulator-name = "8084_s11";
 			spmi-dev-container;
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -514,209 +419,248 @@
 			};
 		};
 
+		regulator@3500 {
+			regulator-name = "8084_s12";
+			spmi-dev-container;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qpnp-regulator";
+			reg = <0x3500 0x300>;
+			status = "disabled";
+
+			qcom,ctl@3500 {
+				reg = <0x3500 0x100>;
+			};
+			qcom,ps@3600 {
+				reg = <0x3600 0x100>;
+			};
+			qcom,freq@3700 {
+				reg = <0x3700 0x100>;
+			};
+		};
+
 		regulator@4000 {
-			regulator-name = "8644_l1";
+			regulator-name = "8084_l1";
 			reg = <0x4000 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4100 {
-			regulator-name = "8644_l2";
+			regulator-name = "8084_l2";
 			reg = <0x4100 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4200 {
-			regulator-name = "8644_l3";
+			regulator-name = "8084_l3";
 			reg = <0x4200 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4300 {
-			regulator-name = "8644_l4";
+			regulator-name = "8084_l4";
 			reg = <0x4300 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4400 {
-			regulator-name = "8644_l5";
+			regulator-name = "8084_l5";
 			reg = <0x4400 0x100>;
 			compatible = "qcom,qpnp-regulator";
-			qcom,force-type = <0x04 0x10>;
 			status = "disabled";
 		};
 
 		regulator@4500 {
-			regulator-name = "8644_l6";
+			regulator-name = "8084_l6";
 			reg = <0x4500 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4600 {
-			regulator-name = "8644_l7";
+			regulator-name = "8084_l7";
 			reg = <0x4600 0x100>;
 			compatible = "qcom,qpnp-regulator";
-			qcom,force-type = <0x04 0x10>;
 			status = "disabled";
 		};
 
 		regulator@4700 {
-			regulator-name = "8644_l8";
+			regulator-name = "8084_l8";
 			reg = <0x4700 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4800 {
-			regulator-name = "8644_l9";
+			regulator-name = "8084_l9";
 			reg = <0x4800 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4900 {
-			regulator-name = "8644_l10";
+			regulator-name = "8084_l10";
 			reg = <0x4900 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4a00 {
-			regulator-name = "8644_l11";
+			regulator-name = "8084_l11";
 			reg = <0x4a00 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4b00 {
-			regulator-name = "8644_l12";
+			regulator-name = "8084_l12";
 			reg = <0x4b00 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4c00 {
-			regulator-name = "8644_l13";
+			regulator-name = "8084_l13";
 			reg = <0x4c00 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4d00 {
-			regulator-name = "8644_l14";
+			regulator-name = "8084_l14";
 			reg = <0x4d00 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4e00 {
-			regulator-name = "8644_l15";
+			regulator-name = "8084_l15";
 			reg = <0x4e00 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@4f00 {
-			regulator-name = "8644_l16";
+			regulator-name = "8084_l16";
 			reg = <0x4f00 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@5000 {
-			regulator-name = "8644_l17";
+			regulator-name = "8084_l17";
 			reg = <0x5000 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@5100 {
-			regulator-name = "8644_l18";
+			regulator-name = "8084_l18";
 			reg = <0x5100 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@5200 {
-			regulator-name = "8644_l19";
+			regulator-name = "8084_l19";
 			reg = <0x5200 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@5300 {
-			regulator-name = "8644_l20";
+			regulator-name = "8084_l20";
 			reg = <0x5300 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@5400 {
-			regulator-name = "8644_l21";
+			regulator-name = "8084_l21";
 			reg = <0x5400 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@5500 {
-			regulator-name = "8644_l22";
+			regulator-name = "8084_l22";
 			reg = <0x5500 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@5600 {
-			regulator-name = "8644_l23";
+			regulator-name = "8084_l23";
 			reg = <0x5600 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@5700 {
-			regulator-name = "8644_l24";
+			regulator-name = "8084_l24";
 			reg = <0x5700 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@5800 {
-			regulator-name = "8644_l25";
+			regulator-name = "8084_l25";
 			reg = <0x5800 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
+		regulator@5900 {
+			regulator-name = "8084_l26";
+			reg = <0x5900 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
+		regulator@5a00 {
+			regulator-name = "8084_l27";
+			reg = <0x5a00 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
+
 		regulator@8000 {
-			regulator-name = "8644_lvs1";
+			regulator-name = "8084_lvs1";
 			reg = <0x8000 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@8100 {
-			regulator-name = "8644_lvs2";
+			regulator-name = "8084_lvs2";
 			reg = <0x8100 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@8200 {
-			regulator-name = "8644_mvs1";
+			regulator-name = "8084_lvs3";
 			reg = <0x8200 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
 
 		regulator@8300 {
-			regulator-name = "8644_mvs2";
+			regulator-name = "8084_lvs4";
 			reg = <0x8300 0x100>;
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
+
+		regulator@8400 {
+			regulator-name = "8084_mvs1";
+			reg = <0x8400 0x100>;
+			compatible = "qcom,qpnp-regulator";
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 97b22aa..c62fb3e 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -380,9 +380,9 @@
 		qcom,offset-page-indices = <56>;
 	};
 
-	qcom,rpm-stats@0xfc19dbd0{
+	qcom,rpm-stats@fc19dba0 {
 		compatible = "qcom,rpm-stats";
-		reg = <0xfc19dbd0 0x1000>;
+		reg = <0xfc19dba0 0x1000>;
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index aa03951..c392428 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -248,6 +248,7 @@
 	android_usb@fe8050c8 {
 		compatible = "qcom,android-usb";
 		reg = <0xfe8050c8 0xc8>;
+		qcom,android-usb-cdrom;
 	};
 
 	wcd9xxx_intc: wcd9xxx-irq {
@@ -518,7 +519,7 @@
 
 	qcom,smem@fa00000 {
 		compatible = "qcom,smem";
-		reg = <0xfa00000 0x200000>,
+		reg = <0xfa00000 0x100000>,
 			<0xf9011000 0x1000>,
 			<0xfc428000 0x4000>;
 		reg-names = "smem", "irq-reg-base", "aux-mem1";
@@ -688,7 +689,6 @@
 		reg = <0xf9011050 0x8>;
 		reg-names = "rcg_base";
 		a7_cpu-supply = <&apc_vreg_corner>;
-		a7_mem-supply = <&pm8226_l3>;
 	};
 
 	qcom,ocmem@fdd00000 {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 9b114cc..84eebbf 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -41,6 +41,38 @@
 			};
 		};
 	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msmgpio 73 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msmgpio 74 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msmgpio 72 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
 };
 
 &sdhc_1 {
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 3a26376..90d4a0e 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -41,6 +41,38 @@
 			};
 		};
 	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msmgpio 73 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msmgpio 74 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msmgpio 72 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
 };
 
 &sdhc_1 {
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index e8849f6..baae269 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -382,9 +382,9 @@
 		qcom,offset-page-indices = <56>;
 	};
 
-	qcom,rpm-stats@0xfc19dbd0{
+	qcom,rpm-stats@fc19dba0 {
 		compatible = "qcom,rpm-stats";
-		reg = <0xfc19dbd0 0x1000>;
+		reg = <0xfc19dba0 0x1000>;
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index e406ba8..822c792 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -309,7 +309,7 @@
 
 	qcom,smem@d900000 {
 		compatible = "qcom,smem";
-		reg = <0xd900000 0x200000>,
+		reg = <0xd900000 0x100000>,
 			<0xf9011000 0x1000>,
 			<0xfc428000 0x4000>;
 		reg-names = "smem", "irq-reg-base", "aux-mem1";
@@ -401,7 +401,6 @@
 		reg = <0xf9011050 0x8>;
 		reg-names = "rcg_base";
 		a7_cpu-supply = <&apc_vreg_corner>;
-		a7_mem-supply = <&pm8110_l3_ao>;
 	};
 
 	spmi_bus: qcom,spmi@fc4c0000 {
@@ -430,6 +429,20 @@
 		qcom,i2c-bus-freq = <100000>;
 	};
 
+	i2c@f9928000 { /* BLSP1 QUP6 */
+		cell-index = <6>;
+		compatible = "qcom,i2c-qup";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0xf9928000 0x1000>;
+		interrupt-names = "qup_err_intr";
+		interrupts = <0 100 0>;
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <19200000>;
+		qcom,sda-gpio = <&msmgpio 16 0>;
+		qcom,scl-gpio = <&msmgpio 17 0>;
+	};
 
 	spi_0: spi@f9923000 { /* BLSP1 QUP1 */
 		compatible = "qcom,spi-qup-v2";
@@ -584,8 +597,9 @@
 
 	qcom,wcnss-wlan@fb000000 {
 		compatible = "qcom,wcnss_wlan";
-		reg = <0xfb000000 0x280000>;
-		reg-names = "wcnss_mmio";
+		reg = <0xfb000000 0x280000>,
+			<0xf9011008 0x04>;
+		reg-names = "wcnss_mmio", "wcnss_fiq";
 		interrupts = <0 145 0>, <0 146 0>;
 		interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
 
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 3c1711c..9cfc5fd 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -710,5 +710,12 @@
 		qcom,cdc-micbias1-ext-cap;
 		qcom,cdc-micbias3-ext-cap;
 		qcom,cdc-micbias4-ext-cap;
+
+		/* If boot isn't available, vph_pwr_vreg can be used instead */
+		cdc-vdd-spkdrv-supply = <&pm8941_boost>;
+		qcom,cdc-vdd-spkdrv-voltage = <5000000 5000000>;
+		qcom,cdc-vdd-spkdrv-current = <1250000>;
+
+		qcom,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index eaf326e..7f46a54 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -202,7 +202,34 @@
 
 	sound {
 		qcom,model = "msm8974-taiko-fluid-snd-card";
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"AMIC1", "MIC BIAS1 Internal1",
+			"MIC BIAS1 Internal1", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic",
+			"DMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4",
+			"DMIC5", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic5",
+			"DMIC6", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic6",
+			"Lineout_1 amp", "LINEOUT1",
+			"Lineout_3 amp", "LINEOUT3";
+
 		qcom,hdmi-audio-rx;
+		qcom,ext-ult-lo-amp-gpio = <&pm8941_gpios 6 0>;
 	};
 };
 
@@ -212,6 +239,13 @@
 		qcom,cdc-micbias2-ext-cap;
 		qcom,cdc-micbias3-ext-cap;
 		qcom,cdc-micbias4-ext-cap;
+
+		/* If boot isn't available, vph_pwr_vreg can be used instead */
+		cdc-vdd-spkdrv-supply = <&pm8941_boost>;
+		qcom,cdc-vdd-spkdrv-voltage = <5000000 5000000>;
+		qcom,cdc-vdd-spkdrv-current = <1250000>;
+
+		qcom,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index d9acb81..d8a090b 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -318,6 +318,7 @@
 			"Lineout_3 amp", "LINEOUT3",
 			"Lineout_2 amp", "LINEOUT2",
 			"Lineout_4 amp", "LINEOUT4",
+			"SPK_ultrasound amp", "SPK_OUT",
 			"AMIC1", "MIC BIAS4 External",
 			"MIC BIAS4 External", "Analog Mic4",
 			"AMIC2", "MIC BIAS2 External",
@@ -346,6 +347,7 @@
 		qcom,ext-spk-amp-supply = <&ext_5v>;
 		qcom,ext-spk-amp-gpio = <&pm8841_mpps 1 0>;
 		qcom,dock-plug-det-irq = <&pm8841_mpps 2 0>;
+		qcom,ext-ult-spk-amp-gpio = <&pm8941_gpios 6 0>;
 		qcom,hdmi-audio-rx;
 
 		qcom,prim-auxpcm-gpio-clk  = <&msmgpio 74 0>;
@@ -449,6 +451,14 @@
 	};
 
 	gpio@c500 { /* GPIO 6 */
+		/* ULTRASOUND_EN_1 PA AB enable */
+		qcom,mode = <1>; /* DIG_OUT */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,pull = <4>; /* PULL_DOWN */
+		qcom,vin-sel = <0>; /* VPH */
+		qcom,out-strength = <2>; /* STRENGTH_MED */
+		qcom,src-sel = <0>; /* CONSTANT */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c600 { /* GPIO 7 */
@@ -701,10 +711,24 @@
 	};
 };
 
+&vph_pwr_vreg {
+	status = "ok";
+};
+
 &slim_msm {
 	taiko_codec {
 		qcom,cdc-micbias2-ext-cap;
 		qcom,cdc-micbias3-ext-cap;
+
+		/*
+		 * Liquid has external spkrdrv supply. Give a dummy supply to
+		 * make codec driver's happy.
+		 */
+		cdc-vdd-spkdrv-supply = <&vph_pwr_vreg>;
+		qcom,cdc-vdd-spkdrv-voltage = <0 0>;
+		qcom,cdc-vdd-spkdrv-current = <0>;
+
+		qcom,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 494b12c..def7b8c 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -65,6 +65,7 @@
 	qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>;
 	qcom,mdss-has-bwc;
 	qcom,mdss-has-decimation;
+	qcom,mdss-ad-off = <0x0013100 0x00013300>;
 };
 
 &mdss_hdmi_tx {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index a79f403..abfd7ec 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -155,7 +155,7 @@
 		qcom,hsusb-otg-disable-reset;
 		qcom,hsusb-otg-lpm-on-dev-suspend;
 		qcom,hsusb-otg-clk-always-on-workaround;
-		qcom,hsusb-otg-delay-lpm;
+		qcom,hsusb-otg-delay-lpm-hndshk-on-disconnect;
 
 		qcom,msm-bus,name = "usb2";
 		qcom,msm-bus,num-cases = <2>;
@@ -205,6 +205,7 @@
 			qcom,src-bam-pipe-index = <1>;
 			qcom,data-fifo-size = <0x8000>;
 			qcom,descriptor-fifo-size = <0x2000>;
+			qcom,reset-bam-on-connect;
 		};
 		qcom,pipe1 {
 			label = "hsusb-ipa-in-0";
@@ -217,6 +218,7 @@
 			qcom,dst-bam-pipe-index = <0>;
 			qcom,data-fifo-size = <0x8000>;
 			qcom,descriptor-fifo-size = <0x2000>;
+			qcom,reset-bam-on-connect;
 		};
 		qcom,pipe2 {
 			label = "hsusb-qdss-in-0";
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index f595188..5ba76b6 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -284,6 +284,7 @@
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
 CONFIG_FB_MSM_MDSS=y
@@ -326,6 +327,10 @@
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_MSM=y
 CONFIG_MMC_SDHCI_MSM=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_DIAG_CHAR=y
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_BACKLIGHT=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
new file mode 100644
index 0000000..03ac944
--- /dev/null
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -0,0 +1,368 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="-perf"
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8610=y
+CONFIG_ARCH_MSM8226=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_VENUS=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_OCMEM_POWER_DISABLE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_QPNP_BMS=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_WCD9306_CODEC=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_MSM_CAMERA is not set
+CONFIG_OV8825=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_ISPIF=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_OV9724=y
+CONFIG_MSMB_JPEG=y
+CONFIG_SWITCH=y
+CONFIG_MSM_WFD=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8226=y
+CONFIG_SND_SOC_MSM8X10=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SPS=y
+CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_MSM_IOMMU=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_TPIU=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_ETM=y
+CONFIG_CORESIGHT_EVENT=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_QSEECOM=y
\ No newline at end of file
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 3291919..3322896 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -377,3 +377,7 @@
 CONFIG_CRC_CCITT=y
 CONFIG_QPNP_VIBRATOR=y
 CONFIG_QSEECOM=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 59cafd1..dc84558 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -25,6 +25,7 @@
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index ae73bad..1e0134a 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -25,6 +25,7 @@
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=m
 CONFIG_MODULES=y
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index c1295c4..70d82ec 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -119,16 +119,16 @@
  */
 extern void __iomem *__arm_ioremap_pfn_caller(unsigned long, unsigned long,
 	size_t, unsigned int, void *);
-extern void __iomem *__arm_ioremap_caller(unsigned long, size_t, unsigned int,
+extern void __iomem *__arm_ioremap_caller(phys_addr_t, size_t, unsigned int,
 	void *);
 
 extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
-extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int);
-extern void __iomem *__arm_ioremap_exec(unsigned long, size_t, bool cached);
+extern void __iomem *__arm_ioremap(phys_addr_t, size_t, unsigned int);
+extern void __iomem *__arm_ioremap_exec(phys_addr_t, size_t, bool cached);
 extern void __iounmap(volatile void __iomem *addr);
 extern void __arm_iounmap(volatile void __iomem *addr);
 
-extern void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+extern void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
 	unsigned int, void *);
 extern void (*arch_iounmap)(volatile void __iomem *);
 
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 84560dc..7b6f42a 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -313,6 +313,7 @@
  * We provide our own arch_get_unmapped_area to cope with VIPT caches.
  */
 #define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
 
 /*
  * remap a physical page `pfn' of size `size' with page protection `prot'
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 8e2bb29..07209d7 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -126,6 +126,8 @@
 
 #endif
 
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
+
 #endif
 
 #endif /* __ASM_ARM_PROCESSOR_H */
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index a45f5ec..d5f880a 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -316,6 +316,7 @@
 obj-$(CONFIG_ARCH_MSM8226) += acpuclock-8226.o acpuclock-cortex.o
 obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
+obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index a0727b7..8262946 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -131,7 +131,6 @@
 	[12] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 5 },
 	[13] = { { 1080000, HFPLL, 1, 0x28 }, 1150000, 1150000, 5 },
 	[14] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 5 },
-	[15] = { { 1188000, HFPLL, 1, 0x2C }, 1150000, 1150000, 5 },
 	{ }
 };
 
@@ -149,15 +148,15 @@
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),  1100000 },
 	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(5),  1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),  1125000 },
-	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
-	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
-	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
-	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(14), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(14), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(14), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(14), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1250000 },
 	{ 0, { 0 } }
 };
 
@@ -175,15 +174,15 @@
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),  1050000 },
 	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(5),  1075000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),  1075000 },
-	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1125000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1125000 },
-	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1150000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1150000 },
-	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1175000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1175000 },
-	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1187500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1187500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1200000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(14), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1125000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(14), 1150000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1150000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(14), 1175000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1175000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(14), 1187500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1187500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1200000 },
 	{ 0, { 0 } }
 };
 
@@ -201,15 +200,15 @@
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),  1000000 },
 	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(5),  1025000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),  1025000 },
-	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1075000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
-	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1100000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1100000 },
-	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1125000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
-	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1137500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1137500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1150000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(14), 1075000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(14), 1100000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1100000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(14), 1125000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(14), 1137500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1137500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1150000 },
 	{ 0, { 0 } }
 };
 
@@ -227,15 +226,15 @@
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   975000 },
 	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(5),  1000000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),  1000000 },
-	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1050000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1050000 },
-	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1075000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1075000 },
-	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1100000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1100000 },
-	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1112500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(14), 1050000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1050000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(14), 1075000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1075000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(14), 1100000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1100000 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(14), 1112500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1125000 },
 	{ 0, { 0 } }
 };
 
@@ -247,11 +246,11 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),  1000000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),  1025000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),  1037500 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1087500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1162500 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1087500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1150000 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1162500 },
 	{ 0, { 0 } }
 };
 
@@ -263,11 +262,11 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   975000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),  1000000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),  1012500 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1037500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1087500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1037500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1050000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1087500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1125000 },
 	{ 0, { 0 } }
 };
 
@@ -279,11 +278,11 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   937500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   950000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   975000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1087500 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1087500 },
 	{ 0, { 0 } }
 };
 
@@ -295,11 +294,11 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   900000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   925000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   950000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  975000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  987500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1050000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  975000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  987500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1037500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1050000 },
 	{ 0, { 0 } }
 };
 
@@ -311,11 +310,11 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  950000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  962500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  975000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1012500 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  950000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  962500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14),  975000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1012500 },
 	{ 0, { 0 } }
 };
 
@@ -327,11 +326,11 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  950000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  962500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15),  987500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1000000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  937500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  950000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14),  962500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14),  987500 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14), 1000000 },
 	{ 0, { 0 } }
 };
 
@@ -343,11 +342,11 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  950000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  962500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15),  975000 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15),  987500 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  937500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  950000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14),  962500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14),  975000 },
+	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(14),  987500 },
 	{ 0, { 0 } }
 };
 
@@ -359,13 +358,13 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),  1000000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),  1025000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),  1037500 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1087500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1175000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1225000 },
-	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1250000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1075000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1087500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1125000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1150000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1175000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1225000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(14), 1250000 },
 	{ 0, { 0 } }
 };
 
@@ -377,13 +376,13 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   975000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),  1000000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),  1012500 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1037500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1087500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1150000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1187500 },
-	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1200000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1037500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1050000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1087500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1112500 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1150000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1187500 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(14), 1200000 },
 	{ 0, { 0 } }
 };
 
@@ -395,13 +394,13 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   937500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   950000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   975000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 },
-	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1162500 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1100000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1137500 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(14), 1162500 },
 	{ 0, { 0 } }
 };
 
@@ -413,13 +412,13 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   900000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   925000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   950000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  975000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  987500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1062500 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1100000 },
-	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  975000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  987500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1037500 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1062500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1100000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(14), 1125000 },
 	{ 0, { 0 } }
 };
 
@@ -431,13 +430,13 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  950000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  962500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  975000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 },
-	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1100000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  950000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  962500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14),  975000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1037500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1075000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(14), 1100000 },
 	{ 0, { 0 } }
 };
 
@@ -449,13 +448,13 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  950000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  962500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15),  987500 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 },
-	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1075000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  937500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  950000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14),  962500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14),  987500 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1012500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1050000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(14), 1075000 },
 	{ 0, { 0 } }
 };
 
@@ -467,13 +466,13 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  950000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  962500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15),  975000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1000000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 },
-	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1050000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  937500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  950000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14),  962500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14),  975000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1000000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1025000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(14), 1050000 },
 	{ 0, { 0 } }
 };
 
@@ -485,14 +484,14 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   962500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   975000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),  1000000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1025000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1037500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1062500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1100000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1125000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1175000 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1225000 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1287500 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1025000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1037500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1062500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1100000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1125000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1175000 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(14), 1225000 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(14), 1287500 },
 	{ 0, { 0 } }
 };
 
@@ -504,14 +503,14 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   937500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   950000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   975000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1187500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1250000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14), 1000000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14), 1012500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1037500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1075000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1100000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1137500 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(14), 1187500 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(14), 1250000 },
 	{ 0, { 0 } }
 };
 
@@ -523,14 +522,14 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   912500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   925000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   950000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  975000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  987500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1012500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1050000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1075000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1112500 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1162500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1212500 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  975000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  987500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1012500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1050000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1075000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1112500 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(14), 1162500 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(14), 1212500 },
 	{ 0, { 0 } }
 };
 
@@ -542,14 +541,14 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   900000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   912500 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   937500 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  962500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  975000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1025000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1050000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1087500 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1137500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  962500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  975000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14), 1000000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1025000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1050000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1087500 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(14), 1137500 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(14), 1175000 },
 	{ 0, { 0 } }
 };
 
@@ -561,14 +560,14 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  950000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  962500 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  975000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1112500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1150000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  950000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  962500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14),  975000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14), 1000000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1037500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1075000 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(14), 1112500 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(14), 1150000 },
 	{ 0, { 0 } }
 };
 
@@ -580,14 +579,14 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  950000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  962500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15),  987500 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1087500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  937500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  950000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14),  962500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14),  987500 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1012500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1050000 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(14), 1087500 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(14), 1125000 },
 	{ 0, { 0 } }
 };
 
@@ -599,14 +598,14 @@
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(5),   887500 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(5),   900000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(5),   925000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  950000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  962500 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15),  975000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1000000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 },
-	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(15), 1062500 },
-	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(15), 1100000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(14),  937500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(14),  950000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(14),  962500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(14),  975000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(14), 1000000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(14), 1025000 },
+	{ 1, {  1782000, HFPLL, 1, 0x42 }, L2(14), 1062500 },
+	{ 1, {  1890000, HFPLL, 1, 0x46 }, L2(14), 1100000 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 25bebd1..153be21 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -65,24 +65,25 @@
  * 3) Depending on Frodo version, may need minimum of LVL_NOM
  */
 static struct clkctl_acpu_speed acpu_freq_tbl_8226[] = {
-	{ 0,   19200, CXO,     0, 0,   CPR_CORNER_SVS,   1150000, 0 },
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,   1150000, 4 },
-	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,   1150000, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL,   1150000, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL,   1150000, 7 },
-	{ 0,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1150000, 7 },
-	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1150000, 7 },
+	{ 0,   19200, CXO,     0, 0,   CPR_CORNER_SVS,    0, 0 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,    0, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 0 }
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
-	{ 0,   19200, CXO,     0, 0,   CPR_CORNER_SVS,   1150000, 0 },
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,   1150000, 3 },
-	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,   1150000, 3 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL,   1150000, 4 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL,   1150000, 4 },
-	{ 0,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1275000, 5 },
-	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,   1275000, 5 },
+	{ 0,   19200, CXO,     0, 0,   CPR_CORNER_SVS,    0, 0 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 3 },
+	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,    0, 3 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 4 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 4 },
+	{ 0,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
+	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
 	{ 0 }
 };
 
@@ -91,7 +92,6 @@
 	.current_speed = &(struct clkctl_acpu_speed){ 0 },
 	.bus_scale = &bus_client_pdata,
 	.vdd_max_cpu = CPR_CORNER_TURBO,
-	.vdd_max_mem = 1150000,
 	.src_clocks = {
 		[PLL0].name = "gpll0",
 		[ACPUPLL].name = "a7sspll",
@@ -130,12 +130,6 @@
 		return PTR_ERR(drv_data.vdd_cpu);
 	}
 
-	drv_data.vdd_mem = devm_regulator_get(&pdev->dev, "a7_mem");
-	if (IS_ERR(drv_data.vdd_mem)) {
-		dev_err(&pdev->dev, "regulator for %s get failed\n", "a7_mem");
-		return PTR_ERR(drv_data.vdd_mem);
-	}
-
 	for (i = 0; i < NUM_SRC; i++) {
 		if (!drv_data.src_clocks[i].name)
 			continue;
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 47bf27a..0c80a56 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -66,11 +66,17 @@
 {
 	int rc = 0;
 
-	/* Increase vdd_mem before vdd_cpu. vdd_mem should be >= vdd_cpu. */
-	rc = regulator_set_voltage(priv->vdd_mem, vdd_mem, priv->vdd_max_mem);
-	if (rc) {
-		pr_err("vdd_mem increase failed (%d)\n", rc);
-		return rc;
+	if (priv->vdd_mem) {
+		/*
+		 * Increase vdd_mem before vdd_cpu. vdd_mem should
+		 * be >= vdd_cpu.
+		 */
+		rc = regulator_set_voltage(priv->vdd_mem, vdd_mem,
+						priv->vdd_max_mem);
+		if (rc) {
+			pr_err("vdd_mem increase failed (%d)\n", rc);
+			return rc;
+		}
 	}
 
 	rc = regulator_set_voltage(priv->vdd_cpu, vdd_cpu, priv->vdd_max_cpu);
@@ -92,6 +98,9 @@
 		return;
 	}
 
+	if (!priv->vdd_mem)
+		return;
+
 	/* Decrease vdd_mem after vdd_cpu. vdd_mem should be >= vdd_cpu. */
 	ret = regulator_set_voltage(priv->vdd_mem, vdd_mem, priv->vdd_max_mem);
 	if (ret)
@@ -343,10 +352,12 @@
 	if (rc)
 		goto err_vdd;
 
-	rc = regulator_enable(priv->vdd_mem);
-	if (rc) {
-		dev_err(&pdev->dev, "regulator_enable for mem failed\n");
-		goto err_vdd;
+	if (priv->vdd_mem) {
+		rc = regulator_enable(priv->vdd_mem);
+		if (rc) {
+			dev_err(&pdev->dev, "regulator_enable for mem failed\n");
+			goto err_vdd;
+		}
 	}
 
 	rc = regulator_enable(priv->vdd_cpu);
@@ -369,7 +380,8 @@
 	return 0;
 
 err_vdd_cpu:
-	regulator_disable(priv->vdd_mem);
+	if (priv->vdd_mem)
+		regulator_disable(priv->vdd_mem);
 err_vdd:
 	return rc;
 }
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 828ae9c..0a13c56 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -53,6 +53,14 @@
 	.paddr_to_memtype = apq8084_paddr_to_memtype,
 };
 
+static struct of_dev_auxdata apq8084_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
+			"msm_sdcc.1", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+			"msm_sdcc.2", NULL),
+	{}
+};
+
 void __init apq8084_reserve(void)
 {
 	reserve_info = &apq8084_reserve_info;
@@ -69,6 +77,17 @@
 static struct clk_lookup msm_clocks_dummy[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
+	CLK_DUMMY("core_clk",	SDC1_CLK,	"msm_sdcc.1", OFF),
+	CLK_DUMMY("iface_clk",	SDC1_P_CLK,	"msm_sdcc.1", OFF),
+	CLK_DUMMY("core_clk",	SDC2_CLK,	"msm_sdcc.2", OFF),
+	CLK_DUMMY("iface_clk",	SDC2_P_CLK,	"msm_sdcc.2", OFF),
+	CLK_DUMMY("xo",   NULL, "f9200000.qcom,ssusb", OFF),
+	CLK_DUMMY("core_clk",   NULL, "f9200000.qcom,ssusb", OFF),
+	CLK_DUMMY("iface_clk",  NULL, "f9200000.qcom,ssusb", OFF),
+	CLK_DUMMY("sleep_clk",  NULL, "f9200000.qcom,ssusb", OFF),
+	CLK_DUMMY("sleep_a_clk",   NULL, "f9200000.qcom,ssusb", OFF),
+	CLK_DUMMY("utmi_clk",   NULL, "f9200000.qcom,ssusb", OFF),
+	CLK_DUMMY("ref_clk",    NULL, "f9200000.qcom,ssusb", OFF),
 };
 
 static struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -95,11 +114,13 @@
 
 void __init apq8084_init(void)
 {
+	struct of_dev_auxdata *adata = apq8084_auxdata_lookup;
+
 	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
 
 	apq8084_init_gpiomux();
-	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
 	apq8084_add_drivers();
 }
 
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 4b435de..eada62c 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -23,6 +23,12 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_cam_i2c_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct gpiomux_setting gpio_spi_config = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_6MA,
@@ -60,6 +66,18 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting gpio_keys_active = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting gpio_keys_suspend = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
 	{
 		.gpio = 41,
@@ -91,6 +109,18 @@
 		},
 	},
 	{
+		.gpio      = 16,	/* BLSP1 QUP6 I2C_SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
+		},
+	},
+	{
+		.gpio      = 17,	/* BLSP1 QUP6 I2C_SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
+		},
+	},
+	{
 		.gpio      = 0,		/* BLSP1 QUP1 SPI_DATA_MOSI */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
@@ -154,6 +184,30 @@
 	},
 };
 
+static struct msm_gpiomux_config msm_keypad_configs[] __initdata = {
+	{
+		.gpio = 72,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &gpio_keys_active,
+			[GPIOMUX_SUSPENDED] = &gpio_keys_suspend,
+		},
+	},
+	{
+		.gpio = 73,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &gpio_keys_active,
+			[GPIOMUX_SUSPENDED] = &gpio_keys_suspend,
+		},
+	},
+	{
+		.gpio = 74,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &gpio_keys_active,
+			[GPIOMUX_SUSPENDED] = &gpio_keys_suspend,
+		},
+	},
+};
+
 void __init msm8610_init_gpiomux(void)
 {
 	int rc;
@@ -168,4 +222,6 @@
 	msm_gpiomux_install(wcnss_5wire_interface,
 			ARRAY_SIZE(wcnss_5wire_interface));
 	msm_gpiomux_install(msm_lcd_configs, ARRAY_SIZE(msm_lcd_configs));
+	msm_gpiomux_install(msm_keypad_configs,
+				ARRAY_SIZE(msm_keypad_configs));
 }
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 6ccaba6..f404e42 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2356,6 +2356,7 @@
 	&msm_pcm_hostless,
 	&msm_multi_ch_pcm,
 	&msm_lowlatency_pcm,
+	&msm_fm_loopback,
 };
 
 static void __init msm8930_i2c_init(void)
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index af027f0..1090d89 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2766,6 +2766,7 @@
 	F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
 	PLL_F_END
 };
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 3cb3ea4..c13e595 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -255,6 +255,7 @@
 #define          MMSS_MMSSNOC_AXI_CBCR	    0x506C
 #define                   BIMC_GFX_BCR	    0x5090
 #define                  BIMC_GFX_CBCR	    0x5094
+#define                MMSS_CAMSS_MISC	    0x3718
 
 #define				AUDIO_CORE_GDSCR	    0x7000
 #define                                 SPDM_BCR	    0x1000
@@ -1932,6 +1933,115 @@
 	},
 };
 
+static struct mux_clk csi0phy_mux_clk = {
+	.enable_reg = MMSS_CAMSS_MISC,
+	.enable_mask = BIT(11),
+	.select_reg = MMSS_CAMSS_MISC,
+	.select_mask = BIT(9),
+	.sources = (struct mux_source[]) {
+		{ &csi0phy_clk.c,     0 },
+		{ &csi1phy_clk.c, BIT(9) },
+		{ 0 },
+	},
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0phy_mux_clk",
+		.ops = &clk_ops_mux,
+		CLK_INIT(csi0phy_mux_clk.c),
+	},
+};
+
+static struct mux_clk csi1phy_mux_clk = {
+	.enable_reg = MMSS_CAMSS_MISC,
+	.enable_mask = BIT(10),
+	.select_reg = MMSS_CAMSS_MISC,
+	.select_mask = BIT(8),
+	.sources = (struct mux_source[]) {
+		{ &csi0phy_clk.c,     0 },
+		{ &csi1phy_clk.c, BIT(8) },
+		{ 0 },
+	},
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi1phy_mux_clk",
+		.ops = &clk_ops_mux,
+		CLK_INIT(csi1phy_mux_clk.c),
+	},
+};
+
+static struct mux_clk csi0pix_mux_clk = {
+	.enable_reg = MMSS_CAMSS_MISC,
+	.enable_mask = BIT(7),
+	.select_reg = MMSS_CAMSS_MISC,
+	.select_mask = BIT(3),
+	.sources = (struct mux_source[]) {
+		{ &csi0pix_clk.c,      0 },
+		{ &csi1pix_clk.c, BIT(3) },
+		{ 0 },
+	},
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0pix_mux_clk",
+		.ops = &clk_ops_mux,
+		CLK_INIT(csi0pix_mux_clk.c),
+	},
+};
+
+
+static struct mux_clk rdi2_mux_clk = {
+	.enable_reg = MMSS_CAMSS_MISC,
+	.enable_mask = BIT(6),
+	.select_reg = MMSS_CAMSS_MISC,
+	.select_mask = BIT(2),
+	.sources = (struct mux_source[]) {
+		{ &csi0rdi_clk.c,      0 },
+		{ &csi1rdi_clk.c, BIT(2) },
+		{ 0 },
+	},
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "rdi2_mux_clk",
+		.ops = &clk_ops_mux,
+		CLK_INIT(rdi2_mux_clk.c),
+	},
+};
+
+static struct mux_clk rdi1_mux_clk = {
+	.enable_reg = MMSS_CAMSS_MISC,
+	.enable_mask = BIT(5),
+	.select_reg = MMSS_CAMSS_MISC,
+	.select_mask = BIT(1),
+	.sources = (struct mux_source[]) {
+		{ &csi0rdi_clk.c,      0 },
+		{ &csi1rdi_clk.c, BIT(1) },
+		{ 0 },
+	},
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "rdi1_mux_clk",
+		.ops = &clk_ops_mux,
+		CLK_INIT(rdi1_mux_clk.c),
+	},
+};
+
+static struct mux_clk rdi0_mux_clk = {
+	.enable_reg = MMSS_CAMSS_MISC,
+	.enable_mask = BIT(4),
+	.select_reg = MMSS_CAMSS_MISC,
+	.select_mask = BIT(0),
+	.sources = (struct mux_source[]) {
+		{ &csi0rdi_clk.c,      0 },
+		{ &csi1rdi_clk.c, BIT(0) },
+		{ 0 },
+	},
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "rdi0_mux_clk",
+		.ops = &clk_ops_mux,
+		CLK_INIT(rdi0_mux_clk.c),
+	},
+};
+
 static struct branch_clk csi_ahb_clk = {
 	.cbcr_reg = CSI_AHB_CBCR,
 	.has_sibling = 1,
@@ -2691,7 +2801,8 @@
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup4_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup5_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup5_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk",  gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9928000.i2c"),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup6_i2c_apps_clk.c, "f9928000.i2c"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup6_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",     gcc_blsp1_uart1_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",     gcc_blsp1_uart2_apps_clk.c, ""),
@@ -2773,6 +2884,13 @@
 	CLK_LOOKUP("core_clk",                  vfe_ahb_clk.c, ""),
 	CLK_LOOKUP("core_clk",                  vfe_axi_clk.c, ""),
 
+	CLK_LOOKUP("core_clk",              csi0pix_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",              csi0phy_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",              csi1phy_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 rdi2_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 rdi1_mux_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 rdi0_mux_clk.c, ""),
+
 	CLK_LOOKUP("core_clk",   oxili_gfx3d_clk.c, "fdc00000.qcom,kgsl-3d0"),
 	CLK_LOOKUP("iface_clk",    oxili_ahb_clk.c, "fdc00000.qcom,kgsl-3d0"),
 	CLK_LOOKUP("mem_iface_clk", bimc_gfx_clk.c, "fdc00000.qcom,kgsl-3d0"),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 4984255..9a768e5 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -1620,11 +1620,6 @@
 	{&gcc_sdcc2_ahb_clk.c,			GCC_BASE, 0x0071},
 	{&gcc_ce1_clk.c,			GCC_BASE, 0x0138},
 	{&gcc_sys_noc_ipa_axi_clk.c,		GCC_BASE, 0x0007},
-	{&gcc_ipa_clk.c,			GCC_BASE, 0x01E0},
-	{&gcc_ipa_cnoc_clk.c,			GCC_BASE, 0x01E1},
-	{&gcc_ipa_sleep_clk.c,			GCC_BASE, 0x01E2},
-	{&gcc_qpic_clk.c,			GCC_BASE, 0x01D8},
-	{&gcc_qpic_ahb_clk.c,			GCC_BASE, 0x01D9},
 
 	{&a5_m_clk,				APCS_BASE, 0x3},
 
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index d540f2b..fe43b72 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -21,10 +21,23 @@
 #include <linux/clk.h>
 #include <linux/list.h>
 #include <linux/clkdev.h>
+#include <linux/uaccess.h>
 #include <mach/clk-provider.h>
 
 #include "clock.h"
 
+static LIST_HEAD(clk_list);
+static DEFINE_SPINLOCK(clk_list_lock);
+
+static struct dentry *debugfs_base;
+static u32 debug_suspend;
+
+struct clk_table {
+	struct list_head node;
+	struct clk_lookup *clocks;
+	size_t num_clocks;
+};
+
 static int clock_debug_rate_set(void *data, u64 val)
 {
 	struct clk *clock = data;
@@ -218,35 +231,68 @@
 	.release	= seq_release,
 };
 
-static int clock_parent_show(struct seq_file *m, void *unused)
+static ssize_t clock_parent_read(struct file *filp, char __user *ubuf,
+		size_t cnt, loff_t *ppos)
 {
-	struct clk *clock = m->private;
-	struct clk *parent = clk_get_parent(clock);
+	struct clk *clock = filp->private_data;
+	struct clk *p = clock->parent;
+	char name[256] = {0};
 
-	seq_printf(m, "%s\n", (parent ? parent->dbg_name : "None"));
+	snprintf(name, sizeof(name), "%s\n", p ? p->dbg_name : "None\n");
 
-	return 0;
+	return simple_read_from_buffer(ubuf, cnt, ppos, name, strlen(name));
 }
 
-static int clock_parent_open(struct inode *inode, struct file *file)
+
+static ssize_t clock_parent_write(struct file *filp,
+		const char __user *ubuf, size_t cnt, loff_t *ppos)
 {
-	return single_open(file, clock_parent_show, inode->i_private);
+	struct clk *clock = filp->private_data;
+	char buf[256];
+	char *cmp;
+	unsigned long flags;
+	struct clk_table *table;
+	int i, ret;
+	struct clk *parent = NULL;
+
+	cnt = min(cnt, sizeof(buf) - 1);
+	if (copy_from_user(&buf, ubuf, cnt))
+		return -EFAULT;
+	buf[cnt] = '\0';
+	cmp = strstrip(buf);
+
+	spin_lock_irqsave(&clk_list_lock, flags);
+	list_for_each_entry(table, &clk_list, node) {
+		for (i = 0; i < table->num_clocks; i++)
+			if (!strcmp(cmp, table->clocks[i].clk->dbg_name)) {
+				parent = table->clocks[i].clk;
+				break;
+			}
+		if (parent)
+			break;
+	}
+
+	if (!parent) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	spin_unlock_irqrestore(&clk_list_lock, flags);
+	ret = clk_set_parent(clock, table->clocks[i].clk);
+	if (ret)
+		return ret;
+
+	return cnt;
+err:
+	spin_unlock_irqrestore(&clk_list_lock, flags);
+	return ret;
 }
 
+
 static const struct file_operations clock_parent_fops = {
-	.open		= clock_parent_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-static struct dentry *debugfs_base;
-static u32 debug_suspend;
-
-struct clk_table {
-	struct list_head node;
-	struct clk_lookup *clocks;
-	size_t num_clocks;
+	.open		= simple_open,
+	.read		= clock_parent_read,
+	.write		= clock_parent_write,
 };
 
 static int clock_debug_add(struct clk *clock)
@@ -305,8 +351,6 @@
 	debugfs_remove_recursive(clk_dir);
 	return -ENOMEM;
 }
-static LIST_HEAD(clk_list);
-static DEFINE_SPINLOCK(clk_list_lock);
 
 /**
  * clock_debug_register() - Add additional clocks to clock debugfs hierarchy
diff --git a/arch/arm/mach-msm/clock-dsi-8610.c b/arch/arm/mach-msm/clock-dsi-8610.c
new file mode 100644
index 0000000..44b332e
--- /dev/null
+++ b/arch/arm/mach-msm/clock-dsi-8610.c
@@ -0,0 +1,408 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/iopoll.h>
+#include <linux/clk.h>
+
+#include <asm/processor.h>
+#include <mach/msm_iomap.h>
+#include <mach/clk-provider.h>
+
+#include "clock-dsi-8610.h"
+
+#define DSI_PHY_PHYS		0xFDD00000
+#define DSI_PHY_SIZE		0x00100000
+
+#define DSI_CTRL		0x0000
+#define DSI_DSIPHY_PLL_CTRL_0	0x0200
+#define DSI_DSIPHY_PLL_CTRL_1	0x0204
+#define DSI_DSIPHY_PLL_CTRL_2	0x0208
+#define DSI_DSIPHY_PLL_CTRL_3	0x020C
+#define DSI_DSIPHY_PLL_RDY	0x0280
+#define DSI_DSIPHY_PLL_CTRL_8	0x0220
+#define DSI_DSIPHY_PLL_CTRL_9	0x0224
+#define DSI_DSIPHY_PLL_CTRL_10	0x0228
+
+#define DSI_BPP			3
+#define DSI_PLL_RDY_BIT		0x01
+#define DSI_PLL_RDY_LOOP_COUNT	80000
+#define DSI_MAX_DIVIDER		256
+
+static unsigned char *dsi_base;
+static struct clk *dsi_ahb_clk;
+
+int __init dsi_clk_ctrl_init(struct clk *ahb_clk)
+{
+	dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
+	if (!dsi_base) {
+		pr_err("unable to remap dsi base\n");
+		return -ENODEV;
+	}
+
+	dsi_ahb_clk = ahb_clk;
+	return 0;
+}
+
+static int dsi_pll_vco_enable(struct clk *c)
+{
+	u32 status;
+	int i = 0, ret = 0;
+
+	ret = clk_enable(dsi_ahb_clk);
+	if (ret) {
+		pr_err("fail to enable dsi ahb clk\n");
+		return ret;
+	}
+
+	writel_relaxed(0x01, dsi_base + DSI_DSIPHY_PLL_CTRL_0);
+
+	do {
+		status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_RDY);
+	} while (!(status & DSI_PLL_RDY_BIT) && (i++ < DSI_PLL_RDY_LOOP_COUNT));
+
+	if (!(status & DSI_PLL_RDY_BIT)) {
+		pr_err("DSI PLL not ready, polling time out!\n");
+		ret = -ETIMEDOUT;
+	}
+
+	clk_disable(dsi_ahb_clk);
+
+	return ret;
+}
+
+static void dsi_pll_vco_disable(struct clk *c)
+{
+	int ret;
+
+	ret = clk_enable(dsi_ahb_clk);
+	if (ret) {
+		pr_err("fail to enable dsi ahb clk\n");
+		return;
+	}
+
+	writel_relaxed(0x00, dsi_base + DSI_DSIPHY_PLL_CTRL_0);
+	clk_disable(dsi_ahb_clk);
+}
+
+static int dsi_pll_vco_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret;
+	u32 temp, val;
+	unsigned long fb_divider;
+	struct clk *parent = c->parent;
+	struct dsi_pll_vco_clk *vco_clk =
+				container_of(c, struct dsi_pll_vco_clk, c);
+
+	if (!rate)
+		return 0;
+
+	ret = clk_prepare_enable(dsi_ahb_clk);
+	if (ret) {
+		pr_err("fail to enable dsi ahb clk\n");
+		return ret;
+	}
+
+	temp = rate / 10;
+	val = parent->rate / 10;
+	fb_divider = (temp * vco_clk->pref_div_ratio) / val;
+	fb_divider = fb_divider / 2 - 1;
+
+	temp =  readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_1);
+	val = (temp & 0xFFFFFF00) | (fb_divider & 0xFF);
+	writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_1);
+
+	temp =  readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_2);
+	val = (temp & 0xFFFFFFF8) | ((fb_divider >> 8) & 0x07);
+	writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_2);
+
+	temp =  readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_3);
+	val = (temp & 0xFFFFFFC0) | (vco_clk->pref_div_ratio - 1);
+	writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_3);
+
+	clk_disable_unprepare(dsi_ahb_clk);
+
+	return 0;
+}
+
+/* rate is the bit clk rate */
+static long dsi_pll_vco_round_rate(struct clk *c, unsigned long rate)
+{
+	long vco_rate;
+	struct dsi_pll_vco_clk *vco_clk =
+		container_of(c, struct dsi_pll_vco_clk, c);
+
+
+	vco_rate = rate;
+	if (rate < vco_clk->vco_clk_min)
+		vco_rate = vco_clk->vco_clk_min;
+	else if (rate > vco_clk->vco_clk_max)
+		vco_rate = vco_clk->vco_clk_max;
+
+	return vco_rate;
+}
+
+static unsigned long dsi_pll_vco_get_rate(struct clk *c)
+{
+	u32 fb_divider, ref_divider, vco_rate;
+	u32 temp, status;
+	struct clk *parent = c->parent;
+
+	status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_RDY);
+	if (status & DSI_PLL_RDY_BIT) {
+		fb_divider = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_1);
+		fb_divider &= 0xFF;
+		temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_2) & 0x07;
+		fb_divider = (temp << 8) | fb_divider;
+		fb_divider += 1;
+
+		ref_divider = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_3);
+		ref_divider &= 0x3F;
+		ref_divider += 1;
+
+		vco_rate = (parent->rate / ref_divider) * fb_divider;
+	} else {
+		vco_rate = 0;
+	}
+	return vco_rate;
+}
+
+static enum handoff dsi_pll_vco_handoff(struct clk *c)
+{
+	u32 status;
+
+	if (clk_prepare_enable(dsi_ahb_clk)) {
+		pr_err("fail to enable dsi ahb clk\n");
+		return HANDOFF_DISABLED_CLK;
+	}
+
+	status = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_0);
+	if (!status & DSI_PLL_RDY_BIT) {
+		pr_err("DSI PLL not ready\n");
+		clk_disable(dsi_ahb_clk);
+		return HANDOFF_DISABLED_CLK;
+	}
+
+	c->rate = dsi_pll_vco_get_rate(c);
+
+	clk_disable_unprepare(dsi_ahb_clk);
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+static int dsi_byteclk_set_rate(struct clk *c, unsigned long rate)
+{
+	int div, ret;
+	long vco_rate;
+	unsigned long bitclk_rate;
+	u32 temp, val;
+	struct clk *parent = clk_get_parent(c);
+
+	if (rate == 0) {
+		ret = clk_set_rate(parent, 0);
+		return ret;
+	}
+
+	bitclk_rate = rate * 8;
+	for (div = 1; div < DSI_MAX_DIVIDER; div++) {
+		vco_rate = clk_round_rate(parent, bitclk_rate * div);
+
+		if (vco_rate == bitclk_rate * div)
+			break;
+
+		if (vco_rate < bitclk_rate * div)
+			return -EINVAL;
+	}
+
+	if (vco_rate != bitclk_rate * div)
+		return -EINVAL;
+
+	ret = clk_set_rate(parent, vco_rate);
+	if (ret) {
+		pr_err("fail to set vco rate\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(dsi_ahb_clk);
+	if (ret) {
+		pr_err("fail to enable dsi ahb clk\n");
+		return ret;
+	}
+
+	/* set the bit clk divider */
+	temp =  readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_8);
+	val = (temp & 0xFFFFFFF0) | (div - 1);
+	writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_8);
+
+	/* set the byte clk divider */
+	temp = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_9);
+	val = (temp & 0xFFFFFF00) | (vco_rate / rate - 1);
+	writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_9);
+	clk_disable_unprepare(dsi_ahb_clk);
+
+	return 0;
+}
+
+static long dsi_byteclk_round_rate(struct clk *c, unsigned long rate)
+{
+	int div;
+	long vco_rate;
+	unsigned long bitclk_rate;
+	struct clk *parent = clk_get_parent(c);
+
+	if (rate == 0)
+		return -EINVAL;
+
+	bitclk_rate = rate * 8;
+	for (div = 1; div < DSI_MAX_DIVIDER; div++) {
+		vco_rate = clk_round_rate(parent, bitclk_rate * div);
+		if (vco_rate == bitclk_rate * div)
+			break;
+		if (vco_rate < bitclk_rate * div)
+			return -EINVAL;
+	}
+
+	if (vco_rate != bitclk_rate * div)
+		return -EINVAL;
+
+	return rate;
+}
+
+static enum handoff dsi_byteclk_handoff(struct clk *c)
+{
+	struct clk *parent = clk_get_parent(c);
+	unsigned long vco_rate = clk_get_rate(parent);
+	u32 out_div2;
+
+	if (vco_rate == 0)
+		return HANDOFF_DISABLED_CLK;
+
+	if (clk_prepare_enable(dsi_ahb_clk)) {
+		pr_err("fail to enable dsi ahb clk\n");
+		return HANDOFF_DISABLED_CLK;
+	}
+
+	out_div2 = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_9);
+	out_div2 &= 0xFF;
+	c->rate = vco_rate / (out_div2 + 1);
+	clk_disable_unprepare(dsi_ahb_clk);
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+static int dsi_dsiclk_set_rate(struct clk *c, unsigned long rate)
+{
+	u32 temp, val;
+	int ret;
+	struct clk *parent = clk_get_parent(c);
+	unsigned long vco_rate = clk_get_rate(parent);
+
+	if (rate == 0)
+		return 0;
+
+	if (vco_rate % rate != 0) {
+		pr_err("dsiclk_set_rate invalid rate\n");
+		return -EINVAL;
+	}
+
+	ret = clk_prepare_enable(dsi_ahb_clk);
+	if (ret) {
+		pr_err("fail to enable dsi ahb clk\n");
+		return ret;
+	}
+	temp =	readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_10);
+	val = (temp & 0xFFFFFF00) | (vco_rate / rate - 1);
+	writel_relaxed(val, dsi_base + DSI_DSIPHY_PLL_CTRL_10);
+	clk_disable_unprepare(dsi_ahb_clk);
+
+	return 0;
+}
+
+static long dsi_dsiclk_round_rate(struct clk *c, unsigned long rate)
+{
+	/* rate is the pixel clk rate, translate into dsi clk rate*/
+	struct clk *parent = clk_get_parent(c);
+	unsigned long vco_rate = clk_get_rate(parent);
+
+	rate *= DSI_BPP;
+
+	if (vco_rate < rate)
+		return -EINVAL;
+
+	if (vco_rate % rate != 0)
+		return -EINVAL;
+
+	return rate;
+}
+
+static enum handoff dsi_dsiclk_handoff(struct clk *c)
+{
+	struct clk *parent = clk_get_parent(c);
+	unsigned long vco_rate = clk_get_rate(parent);
+	u32 out_div3;
+
+	if (vco_rate == 0)
+		return HANDOFF_DISABLED_CLK;
+
+	if (clk_prepare_enable(dsi_ahb_clk)) {
+		pr_err("fail to enable dsi ahb clk\n");
+		return HANDOFF_DISABLED_CLK;
+	}
+
+	out_div3 = readl_relaxed(dsi_base + DSI_DSIPHY_PLL_CTRL_10);
+	out_div3 &= 0xFF;
+	c->rate = vco_rate / (out_div3 + 1);
+	clk_disable_unprepare(dsi_ahb_clk);
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+int dsi_prepare(struct clk *clk)
+{
+	return clk_prepare(dsi_ahb_clk);
+}
+
+void dsi_unprepare(struct clk *clk)
+{
+	clk_unprepare(dsi_ahb_clk);
+}
+
+struct clk_ops clk_ops_dsi_dsiclk = {
+	.prepare = dsi_prepare,
+	.unprepare = dsi_unprepare,
+	.set_rate = dsi_dsiclk_set_rate,
+	.round_rate = dsi_dsiclk_round_rate,
+	.handoff = dsi_dsiclk_handoff,
+};
+
+struct clk_ops clk_ops_dsi_byteclk = {
+	.prepare = dsi_prepare,
+	.unprepare = dsi_unprepare,
+	.set_rate = dsi_byteclk_set_rate,
+	.round_rate = dsi_byteclk_round_rate,
+	.handoff = dsi_byteclk_handoff,
+};
+
+struct clk_ops clk_ops_dsi_vco = {
+	.prepare = dsi_prepare,
+	.unprepare = dsi_unprepare,
+	.enable = dsi_pll_vco_enable,
+	.disable = dsi_pll_vco_disable,
+	.set_rate = dsi_pll_vco_set_rate,
+	.round_rate = dsi_pll_vco_round_rate,
+	.handoff = dsi_pll_vco_handoff,
+};
+
diff --git a/arch/arm/mach-msm/clock-dsi-8610.h b/arch/arm/mach-msm/clock-dsi-8610.h
new file mode 100644
index 0000000..4c09790
--- /dev/null
+++ b/arch/arm/mach-msm/clock-dsi-8610.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_DSI_8610
+#define __ARCH_ARM_MACH_MSM_CLOCK_DSI_8610
+
+#include <mach/clk-provider.h>
+
+struct dsi_pll_vco_clk {
+	const unsigned long vco_clk_min;
+	const unsigned long vco_clk_max;
+	const unsigned pref_div_ratio;
+	int factor;
+	struct clk c;
+};
+
+extern struct clk_ops clk_ops_dsi_vco;
+extern struct clk_ops clk_ops_dsi_byteclk;
+extern struct clk_ops clk_ops_dsi_dsiclk;
+
+int dsi_clk_ctrl_init(struct clk *ahb_clk);
+
+#endif
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 0d1104e..f6c11b0 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -476,10 +476,7 @@
 	if (branch->max_div)
 		return branch->c.rate;
 
-	if (!branch->has_sibling)
-		return clk_get_rate(c->parent);
-
-	return 0;
+	return clk_get_rate(c->parent);
 }
 
 static int branch_clk_list_rate(struct clk *c, unsigned n)
@@ -812,6 +809,155 @@
 }
 
 
+#define ENABLE_REG(x)	(*(x)->base + (x)->enable_reg)
+#define SELECT_REG(x)	(*(x)->base + (x)->select_reg)
+
+/*
+ * mux clock functions
+ */
+static void mux_clk_halt_check(void)
+{
+	/* Ensure that the delay starts after the mux disable/enable. */
+	mb();
+	udelay(HALT_CHECK_DELAY_US);
+}
+
+static int mux_clk_enable(struct clk *c)
+{
+	unsigned long flags;
+	u32 regval;
+	struct mux_clk *mux = to_mux_clk(c);
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	regval = readl_relaxed(ENABLE_REG(mux));
+	regval |= mux->enable_mask;
+	writel_relaxed(regval, ENABLE_REG(mux));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	/* Wait for clock to enable before continuing. */
+	mux_clk_halt_check();
+
+	return 0;
+}
+
+static void mux_clk_disable(struct clk *c)
+{
+	unsigned long flags;
+	struct mux_clk *mux = to_mux_clk(c);
+	u32 regval;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	regval = readl_relaxed(ENABLE_REG(mux));
+	regval &= ~mux->enable_mask;
+	writel_relaxed(regval, ENABLE_REG(mux));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	/* Wait for clock to disable before continuing. */
+	mux_clk_halt_check();
+}
+
+static int mux_source_switch(struct mux_clk *mux, struct mux_source *dest)
+{
+	unsigned long flags;
+	u32 regval;
+	int ret = 0;
+
+	ret = __clk_pre_reparent(&mux->c, dest->clk, &flags);
+	if (ret)
+		goto out;
+
+	regval = readl_relaxed(SELECT_REG(mux));
+	regval &= ~mux->select_mask;
+	regval |= dest->select_val;
+	writel_relaxed(regval, SELECT_REG(mux));
+
+	/* Make sure switch request goes through before proceeding. */
+	mb();
+
+	__clk_post_reparent(&mux->c, mux->c.parent, &flags);
+out:
+	return ret;
+}
+
+static int mux_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	struct mux_source *dest = NULL;
+	int ret;
+
+	if (!mux->sources || !parent)
+		return -EPERM;
+
+	dest = mux->sources;
+
+	while (dest->clk) {
+		if (dest->clk == parent)
+			break;
+		dest++;
+	}
+
+	if (!dest->clk)
+		return -EPERM;
+
+	ret = mux_source_switch(mux, dest);
+	if (ret)
+		return ret;
+
+	mux->c.rate = clk_get_rate(dest->clk);
+
+	return 0;
+}
+
+static enum handoff mux_clk_handoff(struct clk *c)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	u32 mask = mux->enable_mask;
+	u32 regval = readl_relaxed(ENABLE_REG(mux));
+
+	c->rate = clk_get_rate(c->parent);
+
+	if (mask == (regval & mask))
+		return HANDOFF_ENABLED_CLK;
+
+	return HANDOFF_DISABLED_CLK;
+}
+
+static struct clk *mux_clk_get_parent(struct clk *c)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	struct mux_source *parent = NULL;
+	u32 regval = readl_relaxed(SELECT_REG(mux));
+
+	if (!mux->sources)
+		return ERR_PTR(-EPERM);
+
+	parent = mux->sources;
+
+	while (parent->clk) {
+		if ((regval & mux->select_mask) == parent->select_val)
+			return parent->clk;
+
+		parent++;
+	}
+
+	return ERR_PTR(-EPERM);
+}
+
+static int mux_clk_list_rate(struct clk *c, unsigned n)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	int i;
+
+	for (i = 0; i < n; i++)
+		if (!mux->sources[i].clk)
+			break;
+
+	if (!mux->sources[i].clk)
+		return -ENXIO;
+
+	return clk_get_rate(mux->sources[i].clk);
+}
+
 struct clk_ops clk_ops_empty;
 
 struct clk_ops clk_ops_rcg = {
@@ -875,3 +1021,14 @@
 	.reset = local_vote_clk_reset,
 	.handoff = local_vote_clk_handoff,
 };
+
+struct clk_ops clk_ops_mux = {
+	.enable = mux_clk_enable,
+	.disable = mux_clk_disable,
+	.set_parent = mux_clk_set_parent,
+	.get_parent = mux_clk_get_parent,
+	.handoff = mux_clk_handoff,
+	.list_rate = mux_clk_list_rate,
+};
+
+
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 7ac7bd3..7882edb 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -157,6 +157,38 @@
 	return container_of(clk, struct measure_clk, c);
 }
 
+struct mux_source {
+	struct clk *const clk;
+	const u32 select_val;
+};
+
+/**
+ * struct mux_clk - branch clock
+ * @c: clk
+ * @enable_reg: register that contains the enable bit(s) for the mux
+ * @select_reg: register that contains the source selection bits for the mux
+ * @enable_mask: mask that enables the mux
+ * @select_mask: mask for the source selection bits
+ * @sources: list of mux sources
+ * @base: pointer to base address of ioremapped registers.
+ */
+struct mux_clk {
+	struct clk c;
+	const u32 enable_reg;
+	const u32 select_reg;
+	const u32 enable_mask;
+	const u32 select_mask;
+
+	struct mux_source *sources;
+
+	void *const __iomem *base;
+};
+
+static inline struct mux_clk *to_mux_clk(struct clk *clk)
+{
+	return container_of(clk, struct mux_clk, c);
+}
+
 /*
  * Generic set-rate implementations
  */
@@ -168,6 +200,7 @@
  */
 extern spinlock_t local_clock_reg_lock;
 
+extern struct clk_ops clk_ops_mux;
 extern struct clk_ops clk_ops_empty;
 extern struct clk_ops clk_ops_rcg;
 extern struct clk_ops clk_ops_rcg_mnd;
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 837aef3..cb8ffc1 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2510,6 +2510,11 @@
 	.id	= -1,
 };
 
+struct platform_device msm_fm_loopback = {
+	.name	= "msm-pcm-loopback",
+	.id	= -1,
+};
+
 static struct fs_driver_data gfx2d0_fs_data = {
 	.clks = (struct fs_clk_data[]){
 		{ .name = "core_clk" },
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 327c11d..eb12383 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -260,6 +260,7 @@
 extern struct platform_device msm_i2s_cpudai4;
 extern struct platform_device msm_i2s_cpudai5;
 extern struct platform_device msm_cpudai_stub;
+extern struct platform_device msm_fm_loopback;
 
 extern struct platform_device msm_pil_q6v3;
 extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 9a89508..7157d12 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -122,6 +122,7 @@
 					unsigned long size);
 
 extern int msm_register_domain(struct msm_iova_layout *layout);
+extern int msm_unregister_domain(struct iommu_domain *domain);
 
 #else
 static inline void msm_iommu_set_client_name(struct iommu_domain *domain,
@@ -195,6 +196,11 @@
 {
 	return -ENODEV;
 }
+
+static inline int msm_unregister_domain(struct iommu_domain *domain)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index a90e78a..8f48e94 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -115,7 +115,8 @@
 
 
 #if defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_MSM7X27) \
-	|| defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM9625)
+	|| defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM9625) \
+	|| defined(CONFIG_ARCH_MSM8610) || defined(CONFIG_ARCH_MSM8226)
 #define MSM_SHARED_RAM_SIZE	SZ_1M
 #else
 #define MSM_SHARED_RAM_SIZE	SZ_2M
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index 68313c5..da7c039 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -42,6 +42,12 @@
 	OCI_MEM,		/* Shared memory among peripherals */
 };
 
+enum usb_bam_event_type {
+	USB_BAM_EVENT_WAKEUP_PIPE = 0,	/* Wake a pipe */
+	USB_BAM_EVENT_WAKEUP,		/* Wake a bam (first pipe waked) */
+	USB_BAM_EVENT_INACTIVITY,	/* Inactivity on all pipes */
+};
+
 struct usb_bam_connect_ipa_params {
 	u8 src_idx;
 	u8 dst_idx;
@@ -57,16 +63,20 @@
 	void *priv;
 	void (*notify)(void *priv, enum ipa_dp_evt_type evt,
 			unsigned long data);
+	int (*activity_notify)(void *priv);
+	int (*inactivity_notify)(void *priv);
 };
 
 /**
 * struct usb_bam_event_info: suspend/resume event information.
+* @type: usb bam event type.
 * @event: holds event data.
 * @callback: suspend/resume callback.
 * @param: port num (for suspend) or NULL (for resume).
 * @event_w: holds work queue parameters.
 */
 struct usb_bam_event_info {
+	enum usb_bam_event_type type;
 	struct sps_register_event event;
 	int (*callback)(void *);
 	void *param;
@@ -89,8 +99,12 @@
 * @desc_fifo_size: descriptor fifo size.
 * @data_mem_buf: data fifo buffer.
 * @desc_mem_buf: descriptor fifo buffer.
-* @wake_event: event for wakeup.
+* @event: event for wakeup.
 * @enabled: true if pipe is enabled.
+* @priv: private data to return upon activity_notify
+*	or inactivity_notify callbacks.
+* @activity_notify: callback to invoke on activity on one of the in pipes.
+* @inactivity_notify: callback to invoke on inactivity on all pipes.
 */
 struct usb_bam_pipe_connect {
 	const char *name;
@@ -109,8 +123,11 @@
 	u32 desc_fifo_size;
 	struct sps_mem_buffer data_mem_buf;
 	struct sps_mem_buffer desc_mem_buf;
-	struct usb_bam_event_info wake_event;
+	struct usb_bam_event_info event;
 	bool enabled;
+	void *priv;
+	int (*activity_notify)(void *priv);
+	int (*inactivity_notify)(void *priv);
 };
 
 /**
@@ -154,7 +171,10 @@
 /**
  * Connect USB-to-IPA SPS connection.
  *
- * This function returns the allocated pipes number and clnt handles.
+ * This function returns the allocated pipes number and clnt
+ * handles. Assumes that the user first connects producer pipes
+ * and only after that consumer pipes, since that's the correct
+ * sequence for the handshake with the IPA.
  *
  * @ipa_params - in/out parameters
  *
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 18562a3..f4ac37e 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/idr.h>
 #include <asm/sizes.h>
 #include <asm/page.h>
 #include <mach/iommu.h>
@@ -36,9 +37,14 @@
 	int domain_num;
 };
 
+struct msm_iommu_data_entry {
+	struct list_head list;
+	void *data;
+};
+
 static struct rb_root domain_root;
 DEFINE_MUTEX(domain_mutex);
-static atomic_t domain_nums = ATOMIC_INIT(-1);
+static DEFINE_IDA(domain_nums);
 
 void msm_iommu_set_client_name(struct iommu_domain *domain, char const *name)
 {
@@ -273,6 +279,27 @@
 	return 0;
 }
 
+static int remove_domain(struct iommu_domain *domain)
+{
+	struct rb_root *root = &domain_root;
+	struct rb_node *n;
+	struct msm_iova_data *node;
+	int ret = -EINVAL;
+
+	mutex_lock(&domain_mutex);
+
+	for (n = rb_first(root); n; n = rb_next(n)) {
+		node = rb_entry(n, struct msm_iova_data, node);
+		if (node->domain == domain) {
+			rb_erase(&node->node, &domain_root);
+			ret = 0;
+			break;
+		}
+	}
+	mutex_unlock(&domain_mutex);
+	return ret;
+}
+
 struct iommu_domain *msm_get_iommu_domain(int domain_num)
 {
 	struct msm_iova_data *data;
@@ -307,6 +334,27 @@
 }
 EXPORT_SYMBOL(msm_find_domain_no);
 
+static struct msm_iova_data *msm_domain_to_iova_data(struct iommu_domain
+						     const *domain)
+{
+	struct rb_root *root = &domain_root;
+	struct rb_node *n;
+	struct msm_iova_data *node;
+	struct msm_iova_data *iova_data = ERR_PTR(-EINVAL);
+
+	mutex_lock(&domain_mutex);
+
+	for (n = rb_first(root); n; n = rb_next(n)) {
+		node = rb_entry(n, struct msm_iova_data, node);
+		if (node->domain == domain) {
+			iova_data = node;
+			break;
+		}
+	}
+	mutex_unlock(&domain_mutex);
+	return iova_data;
+}
+
 int msm_allocate_iova_address(unsigned int iommu_domain,
 					unsigned int partition_no,
 					unsigned long size,
@@ -330,7 +378,9 @@
 	if (!pool->gpool)
 		return -EINVAL;
 
+	mutex_lock(&pool->pool_mutex);
 	va = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
+	mutex_unlock(&pool->pool_mutex);
 	if (va) {
 		pool->free -= size;
 		/* Offset because genpool can't handle 0 addresses */
@@ -375,7 +425,9 @@
 	if (pool->paddr == 0)
 		iova += SZ_4K;
 
+	mutex_lock(&pool->pool_mutex);
 	gen_pool_free(pool->gpool, iova, size);
+	mutex_unlock(&pool->pool_mutex);
 }
 
 int msm_register_domain(struct msm_iova_layout *layout)
@@ -393,11 +445,11 @@
 	if (!data)
 		return -ENOMEM;
 
-	pools = kmalloc(sizeof(struct mem_pool) * layout->npartitions,
+	pools = kzalloc(sizeof(struct mem_pool) * layout->npartitions,
 			GFP_KERNEL);
 
 	if (!pools)
-		goto out;
+		goto free_data;
 
 	for (i = 0; i < layout->npartitions; i++) {
 		if (layout->partitions[i].size == 0)
@@ -410,6 +462,7 @@
 
 		pools[i].paddr = layout->partitions[i].start;
 		pools[i].size = layout->partitions[i].size;
+		mutex_init(&pools[i].pool_mutex);
 
 		/*
 		 * genalloc can't handle a pool starting at address 0.
@@ -435,10 +488,13 @@
 
 	data->pools = pools;
 	data->npools = layout->npartitions;
-	data->domain_num = atomic_inc_return(&domain_nums);
+	data->domain_num = ida_simple_get(&domain_nums, 0, 0, GFP_KERNEL);
+	if (data->domain_num < 0)
+		goto free_pools;
+
 	data->domain = iommu_domain_alloc(bus, layout->domain_flags);
 	if (!data->domain)
-		goto out;
+		goto free_domain_num;
 
 	msm_iommu_set_client_name(data->domain, layout->client_name);
 
@@ -446,13 +502,50 @@
 
 	return data->domain_num;
 
-out:
+free_domain_num:
+	ida_simple_remove(&domain_nums, data->domain_num);
+
+free_pools:
+	for (i = 0; i < layout->npartitions; i++) {
+		if (pools[i].gpool)
+			gen_pool_destroy(pools[i].gpool);
+	}
+	kfree(pools);
+free_data:
 	kfree(data);
 
 	return -EINVAL;
 }
 EXPORT_SYMBOL(msm_register_domain);
 
+int msm_unregister_domain(struct iommu_domain *domain)
+{
+	unsigned int i;
+	struct msm_iova_data *data = msm_domain_to_iova_data(domain);
+
+	if (IS_ERR_OR_NULL(data)) {
+		pr_err("%s: Could not find iova_data\n", __func__);
+		return -EINVAL;
+	}
+
+	if (remove_domain(data->domain)) {
+		pr_err("%s: Domain not found. Failed to remove domain\n",
+			__func__);
+	}
+
+	iommu_domain_free(domain);
+
+	ida_simple_remove(&domain_nums, data->domain_num);
+
+	for (i = 0; i < data->npools; ++i)
+		gen_pool_destroy(data->pools[i].gpool);
+
+	kfree(data->pools);
+	kfree(data);
+	return 0;
+}
+EXPORT_SYMBOL(msm_unregister_domain);
+
 static int find_and_add_contexts(struct iommu_group *group,
 				 const struct device_node *node,
 				 unsigned int num_contexts)
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 0d617a6..c31c969 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -133,15 +133,21 @@
 	struct msm_ipc_router_xprt_info *xprt_info;
 };
 
+struct msm_ipc_resume_tx_port {
+	struct list_head list;
+	uint32_t port_id;
+	uint32_t node_id;
+};
+
 #define RP_HASH_SIZE 32
 struct msm_ipc_router_remote_port {
 	struct list_head list;
 	uint32_t node_id;
 	uint32_t port_id;
 	uint32_t restart_state;
-	wait_queue_head_t quota_wait;
 	uint32_t tx_quota_cnt;
 	struct mutex quota_lock;
+	struct list_head resume_tx_port_list;
 	void *sec_rule;
 };
 
@@ -657,8 +663,8 @@
 	rport_ptr->restart_state = RESTART_NORMAL;
 	rport_ptr->sec_rule = NULL;
 	rport_ptr->tx_quota_cnt = 0;
-	init_waitqueue_head(&rport_ptr->quota_wait);
 	mutex_init(&rport_ptr->quota_lock);
+	INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
 	list_add_tail(&rport_ptr->list,
 		      &rt_entry->remote_port_list[key]);
 	mutex_unlock(&rt_entry->lock);
@@ -666,6 +672,97 @@
 	return rport_ptr;
 }
 
+/**
+ * msm_ipc_router_free_resume_tx_port() - Free the resume_tx ports
+ * @rport_ptr: Pointer to the remote port.
+ *
+ * This function deletes all the resume_tx ports associated with a remote port
+ * and frees the memory allocated to each resume_tx port.
+ *
+ * Must be called with rport_ptr->quota_lock locked.
+ */
+static void msm_ipc_router_free_resume_tx_port(
+	struct msm_ipc_router_remote_port *rport_ptr)
+{
+	struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
+
+	list_for_each_entry_safe(rtx_port, tmp_rtx_port,
+			&rport_ptr->resume_tx_port_list, list) {
+		list_del(&rtx_port->list);
+		kfree(rtx_port);
+	}
+}
+
+/**
+ * msm_ipc_router_lookup_resume_tx_port() - Lookup resume_tx port list
+ * @rport_ptr: Remote port whose resume_tx port list needs to be looked.
+ * @port_id: Port ID which needs to be looked from the list.
+ *
+ * return 1 if the port_id is found in the list, else 0.
+ *
+ * This function is used to lookup the existence of a local port in
+ * remote port's resume_tx list. This function is used to ensure that
+ * the same port is not added to the remote_port's resume_tx list repeatedly.
+ *
+ * Must be called with rport_ptr->quota_lock locked.
+ */
+static int msm_ipc_router_lookup_resume_tx_port(
+	struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
+{
+	struct msm_ipc_resume_tx_port *rtx_port;
+
+	list_for_each_entry(rtx_port, &rport_ptr->resume_tx_port_list, list) {
+		if (port_id == rtx_port->port_id)
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * post_resume_tx() - Post the resume_tx event
+ * @rport_ptr: Pointer to the remote port
+ * @pkt : The data packet that is received on a resume_tx event
+ *
+ * This function informs about the reception of the resume_tx message from a
+ * remote port pointed by rport_ptr to all the local ports that are in the
+ * resume_tx_ports_list of this remote port. On posting the information, this
+ * function sequentially deletes each entry in the resume_tx_port_list of the
+ * remote port.
+ *
+ * Must be called with rport_ptr->quota_lock locked.
+ */
+static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
+						   struct rr_packet *pkt)
+{
+	struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
+	struct msm_ipc_port *local_port;
+	struct rr_packet *cloned_pkt;
+
+	list_for_each_entry_safe(rtx_port, tmp_rtx_port,
+				&rport_ptr->resume_tx_port_list, list) {
+		mutex_lock(&local_ports_lock);
+		local_port =
+			msm_ipc_router_lookup_local_port(rtx_port->port_id);
+		if (local_port) {
+			cloned_pkt = clone_pkt(pkt);
+			if (cloned_pkt) {
+				mutex_lock(&local_port->port_rx_q_lock);
+				list_add_tail(&cloned_pkt->list,
+						&local_port->port_rx_q);
+				wake_up(&local_port->port_rx_wait_q);
+				mutex_unlock(&local_port->port_rx_q_lock);
+			} else {
+				pr_err("%s: Clone_pkt failed for %08x:%08x\n",
+					__func__, local_port->this_port.node_id,
+					local_port->this_port.port_id);
+			}
+		}
+		mutex_unlock(&local_ports_lock);
+		list_del(&rtx_port->list);
+		kfree(rtx_port);
+	}
+}
+
 static void msm_ipc_router_destroy_remote_port(
 	struct msm_ipc_router_remote_port *rport_ptr)
 {
@@ -683,7 +780,9 @@
 		pr_err("%s: Node %d is not up\n", __func__, node_id);
 		return;
 	}
-
+	mutex_lock(&rport_ptr->quota_lock);
+	msm_ipc_router_free_resume_tx_port(rport_ptr);
+	mutex_unlock(&rport_ptr->quota_lock);
 	mutex_lock(&rt_entry->lock);
 	list_del(&rport_ptr->list);
 	kfree(rport_ptr);
@@ -1158,7 +1257,7 @@
 	}
 	mutex_lock(&rport_ptr->quota_lock);
 	rport_ptr->restart_state = RESTART_PEND;
-	wake_up(&rport_ptr->quota_wait);
+	msm_ipc_router_free_resume_tx_port(rport_ptr);
 	mutex_unlock(&rport_ptr->quota_lock);
 	return;
 }
@@ -1240,7 +1339,8 @@
 						continue;
 					mutex_lock(&rport_ptr->quota_lock);
 					rport_ptr->restart_state = RESTART_PEND;
-					wake_up(&rport_ptr->quota_wait);
+					msm_ipc_router_free_resume_tx_port(
+								rport_ptr);
 					mutex_unlock(&rport_ptr->quota_lock);
 					ctl.cli.node_id = rport_ptr->node_id;
 					ctl.cli.port_id = rport_ptr->port_id;
@@ -1531,8 +1631,8 @@
 		}
 		mutex_lock(&rport_ptr->quota_lock);
 		rport_ptr->tx_quota_cnt = 0;
+		post_resume_tx(rport_ptr, pkt);
 		mutex_unlock(&rport_ptr->quota_lock);
-		wake_up(&rport_ptr->quota_wait);
 		break;
 
 	case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
@@ -1939,8 +2039,8 @@
 	struct rr_header *hdr;
 	struct msm_ipc_router_xprt_info *xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
+	struct msm_ipc_resume_tx_port  *resume_tx_port;
 	int ret;
-	DEFINE_WAIT(__wait);
 
 	if (!rport_ptr || !src || !pkt)
 		return -EINVAL;
@@ -1965,29 +2065,33 @@
 	hdr->dst_port_id = rport_ptr->port_id;
 	pkt->length += IPC_ROUTER_HDR_SIZE;
 
-	for (;;) {
-		prepare_to_wait(&rport_ptr->quota_wait, &__wait,
-				TASK_INTERRUPTIBLE);
-		mutex_lock(&rport_ptr->quota_lock);
-		if (rport_ptr->restart_state != RESTART_NORMAL)
-			break;
-		if (rport_ptr->tx_quota_cnt <
-		     IPC_ROUTER_DEFAULT_RX_QUOTA)
-			break;
-		if (signal_pending(current))
-			break;
-		mutex_unlock(&rport_ptr->quota_lock);
-		schedule();
-	}
-	finish_wait(&rport_ptr->quota_wait, &__wait);
-
+	mutex_lock(&rport_ptr->quota_lock);
 	if (rport_ptr->restart_state != RESTART_NORMAL) {
 		mutex_unlock(&rport_ptr->quota_lock);
 		return -ENETRESET;
 	}
-	if (signal_pending(current)) {
+	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
+		if (msm_ipc_router_lookup_resume_tx_port(
+			rport_ptr, src->this_port.port_id)) {
+			mutex_unlock(&rport_ptr->quota_lock);
+			return -EAGAIN;
+		}
+		resume_tx_port =
+			kzalloc(sizeof(struct msm_ipc_resume_tx_port),
+							GFP_KERNEL);
+		if (!resume_tx_port) {
+			pr_err("%s: Resume_Tx port allocation failed\n",
+								__func__);
+			mutex_unlock(&rport_ptr->quota_lock);
+			return -ENOMEM;
+		}
+		INIT_LIST_HEAD(&resume_tx_port->list);
+		resume_tx_port->port_id = src->this_port.port_id;
+		resume_tx_port->node_id = src->this_port.node_id;
+		list_add_tail(&resume_tx_port->list,
+				&rport_ptr->resume_tx_port_list);
 		mutex_unlock(&rport_ptr->quota_lock);
-		return -ERESTARTSYS;
+		return -EAGAIN;
 	}
 	rport_ptr->tx_quota_cnt++;
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 342663e..64d8fed 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -197,6 +197,7 @@
 	struct sockaddr_msm_ipc *addr;
 	struct rr_header *hdr;
 	struct sk_buff *temp;
+	union rr_control_msg *ctl_msg;
 	int offset = 0, data_len = 0, copy_len;
 
 	if (!m || !msg_head) {
@@ -207,6 +208,16 @@
 
 	temp = skb_peek(msg_head);
 	hdr = (struct rr_header *)(temp->data);
+	if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
+		skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+		ctl_msg = (union rr_control_msg *)(temp->data);
+		addr->family = AF_MSM_IPC;
+		addr->address.addrtype = MSM_IPC_ADDR_ID;
+		addr->address.addr.port_addr.node_id = ctl_msg->cli.node_id;
+		addr->address.addr.port_addr.port_id = ctl_msg->cli.port_id;
+		m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
+		return offset;
+	}
 	if (addr && (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
 		addr->family = AF_MSM_IPC;
 		addr->address.addrtype = MSM_IPC_ADDR_ID;
@@ -415,8 +426,10 @@
 				return -EFAULT;
 		}
 
-		if (timeout == 0)
+		if (timeout == 0) {
+			m->msg_namelen = 0;
 			return 0;
+		}
 		lock_sock(sk);
 		mutex_lock(&port_ptr->port_rx_q_lock);
 	}
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 52d20e3..33a0aff 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -550,9 +550,15 @@
 	if (kvreg->mode == HS_MODE)
 		return 0;
 	/* enable bhs */
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_EN_MASK, BHS_EN_MASK);
+	/* complete the above write before the delay */
+	mb();
+	/* wait for the bhs to settle */
+	udelay(BHS_SETTLING_DELAY_US);
+
+	/* Turn on BHS segments */
 	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
-		BHS_SEG_EN_MASK | BHS_EN_MASK,
-		BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS | BHS_EN_MASK);
+		BHS_SEG_EN_MASK, BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
 
 	/* complete the above write before the delay */
 	mb();
@@ -1329,32 +1335,32 @@
 
 void secondary_cpu_hs_init(void *base_ptr)
 {
+	uint32_t reg_val;
+
 	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
-	writel_relaxed(
-		BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
+	reg_val =  BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
 		| LDO_PWR_DWN_MASK
 		| CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS
-		| BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS
-		| BHS_EN_MASK,
-		base_ptr + APC_PWR_GATE_CTL);
+		| BHS_EN_MASK;
+	writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
 
 	/* complete the above write before the delay */
 	mb();
+	/* wait for the bhs to settle */
+	udelay(BHS_SETTLING_DELAY_US);
 
-	/*
-	 * wait for the bhs to settle
-	 */
+	/* Turn on BHS segments */
+	reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
+	writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+
+	/* complete the above write before the delay */
+	mb();
+	 /* wait for the bhs to settle */
 	udelay(BHS_SETTLING_DELAY_US);
 
 	/* Finally turn on the bypass so that BHS supplies power */
-	writel_relaxed(
-		BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
-		| LDO_PWR_DWN_MASK
-		| CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS
-		| LDO_BYP_MASK
-		| BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS
-		| BHS_EN_MASK,
-		base_ptr + APC_PWR_GATE_CTL);
+	reg_val |= LDO_BYP_MASK;
+	writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
 }
 
 MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 4adfe4d..6ff8152 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -314,7 +314,7 @@
 	struct msm_bus_inode_info *info;
 	int next_pnode;
 	int64_t add_bw = req_bw - curr_bw;
-	unsigned bwsum = 0;
+	uint64_t bwsum = 0;
 	uint64_t req_clk_hz, curr_clk_hz, bwsum_hz;
 	int *master_tiers;
 	struct msm_bus_fabric_device *fabdev = msm_bus_get_fabric_device
@@ -398,7 +398,7 @@
 		/* Update Bandwidth */
 		fabdev->algo->update_bw(fabdev, hop, info, add_bw,
 			master_tiers, ctx);
-		bwsum = (uint16_t)*hop->link_info.sel_bw;
+		bwsum = *hop->link_info.sel_bw;
 		/* Update Fabric clocks */
 		curr_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth,
 			curr_clk);
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 4ea1de9..4ed4eda 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -97,9 +97,12 @@
 #define REGION_SLEEP_PERI_ON 0x00007777
 
 #define REGION_DEFAULT_OFF REGION_SLEEP_NO_RETENTION
-#define REGION_DEFAULT_ON REGION_NORMAL_PASSTHROUGH
+#define REGION_DEFAULT_ON REGION_FORCE_CORE_ON
 #define REGION_DEFAULT_RETENTION REGION_SLEEP_PERI_OFF
 
+#define REGION_STAGING_SET(x) (REGION_SLEEP_PERI_OFF & (0xF << (x * 0x4)))
+#define REGION_ON_SET(x) (REGION_DEFAULT_OFF & (0xF << (x * 0x4)))
+
 enum rpm_macro_state {
 	rpm_macro_off = 0x0,
 	rpm_macro_retain,
@@ -195,6 +198,51 @@
 
 	return state;
 }
+#ifndef CONFIG_MSM_OCMEM_POWER_DISABLE
+static int commit_region_staging(unsigned region_num, unsigned start_m,
+				unsigned new_state)
+{
+	int rc = -1;
+	unsigned state = 0x0;
+	unsigned read_state = 0x0;
+	unsigned curr_state = 0x0;
+
+	if (region_num >= num_regions)
+		return -EINVAL;
+
+	if (rpm_power_control)
+		return 0;
+	else {
+		if (new_state != REGION_DEFAULT_OFF) {
+			curr_state = read_region_state(region_num);
+			state = curr_state | REGION_STAGING_SET(start_m);
+			rc = ocmem_write(state,
+				ocmem_base + PSCGC_CTL_n(region_num));
+			/* Barrier to commit the region state */
+			mb();
+			read_state = read_region_state(region_num);
+			if (new_state == REGION_DEFAULT_ON) {
+				curr_state = read_region_state(region_num);
+				state = curr_state ^ REGION_ON_SET(start_m);
+				rc = ocmem_write(state,
+					ocmem_base + PSCGC_CTL_n(region_num));
+				/* Barrier to commit the region state */
+				mb();
+				read_state = read_region_state(region_num);
+			}
+		} else {
+			curr_state = read_region_state(region_num);
+			state = curr_state ^ REGION_STAGING_SET(start_m);
+			rc = ocmem_write(state,
+				ocmem_base + PSCGC_CTL_n(region_num));
+			/* Barrier to commit the region state */
+			mb();
+			read_state = read_region_state(region_num);
+		}
+	}
+	return 0;
+}
+#endif
 
 /* Returns the current state of a OCMEM macro that belongs to a region */
 static int read_macro_state(unsigned region_num, unsigned macro_num)
@@ -948,9 +996,11 @@
 			apply_macro_vote(id, i, j,
 				hw_macro_state(new_state));
 			aggregate_macro_state(i, j);
+			commit_region_staging(i, j, new_state);
 		}
 		aggregate_region_state(i);
-		commit_region_state(i);
+		if (rpm_power_control)
+			commit_region_state(i);
 		len -= region_size;
 
 		/* If we voted ON/retain the banks must never be OFF */
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 8afe695..a14b960 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -1515,6 +1515,18 @@
 				pr_err("ocmem: Failed to unmap %p\n", req);
 				goto free_fail;
 			}
+			/* Turn off the memory */
+			if (req->req_sz != 0) {
+
+				offset = phys_to_offset(req->req_start);
+				rc = ocmem_memory_off(req->owner, offset,
+					req->req_sz);
+
+				if (rc < 0) {
+					pr_err("Failed to switch OFF memory macros\n");
+					goto free_fail;
+				}
+			}
 
 			rc = do_free(req);
 			if (rc < 0) {
@@ -1525,21 +1537,19 @@
 			pr_debug("request %p was already shrunk to 0\n", req);
 	}
 
-	/* Turn off the memory */
-	if (req->req_sz != 0) {
+	if (!TEST_STATE(req, R_FREE)) {
+		/* Turn off the memory */
+		if (req->req_sz != 0) {
 
-		offset = phys_to_offset(req->req_start);
+			offset = phys_to_offset(req->req_start);
+			rc = ocmem_memory_off(req->owner, offset, req->req_sz);
 
-		rc = ocmem_memory_off(req->owner, offset, req->req_sz);
-
-		if (rc < 0) {
-			pr_err("Failed to switch OFF memory macros\n");
-			goto free_fail;
+			if (rc < 0) {
+				pr_err("Failed to switch OFF memory macros\n");
+				goto free_fail;
+			}
 		}
 
-	}
-
-	if (!TEST_STATE(req, R_FREE)) {
 		/* free the allocation */
 		rc = do_free(req);
 		if (rc < 0)
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index 249032f..f41c569 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -125,4 +125,11 @@
 		.idle_enabled = 1,
 		.suspend_enabled = 0,
 	},
+
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_NR)] = {
+		.idle_supported = 0,
+		.suspend_supported = 0,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
 };
diff --git a/arch/arm/mach-msm/rpm_log.c b/arch/arm/mach-msm/rpm_log.c
index 53d5752..58e8588 100644
--- a/arch/arm/mach-msm/rpm_log.c
+++ b/arch/arm/mach-msm/rpm_log.c
@@ -213,7 +213,7 @@
 		return -EINVAL;
 	if (!buf->data)
 		return -ENOMEM;
-	if (!bufu || count < 0)
+	if (!bufu || count == 0)
 		return -EINVAL;
 	if (!access_ok(VERIFY_WRITE, bufu, count))
 		return -EFAULT;
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 424d310..20a6165 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -41,7 +41,7 @@
 #ifdef CONFIG_ARCH_FSM9XXX
 #define NUM_SMD_PKT_PORTS 4
 #else
-#define NUM_SMD_PKT_PORTS 27
+#define NUM_SMD_PKT_PORTS 28
 #endif
 
 #define PDRIVER_NAME_MAX_SIZE 32
@@ -729,6 +729,7 @@
 	"smd_test_framework",
 	"smd_logging_0",
 	"smd_data_0",
+	"apr",
 	"smd_pkt_loopback",
 };
 
@@ -759,6 +760,7 @@
 	"TESTFRAMEWORK",
 	"LOGGING",
 	"DATA",
+	"apr",
 	"LOOPBACK",
 };
 
@@ -789,6 +791,7 @@
 	SMD_APPS_QDSP,
 	SMD_APPS_QDSP,
 	SMD_APPS_QDSP,
+	SMD_APPS_QDSP,
 	SMD_APPS_MODEM,
 };
 #endif
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 174d444..8e94b3a 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -76,7 +76,7 @@
 	info.vlevel = vlevel;
 	info.err = -ENODEV;
 
-	if (cpu_online(cpu)) {
+	if ((smp_processor_id() != cpu) && cpu_online(cpu)) {
 		/**
 		 * We do not want to set the voltage of another core from
 		 * this core, as its possible that we may race the vdd change
@@ -404,21 +404,28 @@
 	memset(&modes, 0,
 		(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		goto fail;
-
-	spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
-					resource_size(res));
-	if (!spm_data.reg_base_addr)
-		return -ENOMEM;
-
 	key = "qcom,core-id";
 	ret = of_property_read_u32(node, key, &val);
 	if (ret)
 		goto fail;
 	cpu = val;
 
+	/*
+	 * Device with id 0..NR_CPUS are SPM for apps cores
+	 * Device with id 0xFFFF is for L2 SPM.
+	 */
+	if (cpu >= 0 && cpu < num_possible_cpus()) {
+		mode_of_data = of_cpu_modes;
+		num_modes = ARRAY_SIZE(of_cpu_modes);
+		dev = &per_cpu(msm_cpu_spm_device, cpu);
+
+	} else if (cpu == 0xffff) {
+		mode_of_data = of_l2_modes;
+		num_modes = ARRAY_SIZE(of_l2_modes);
+		dev = &msm_spm_l2_device;
+	} else
+		return ret;
+
 	key = "qcom,saw2-ver-reg";
 	ret = of_property_read_u32(node, key, &val);
 	if (ret)
@@ -429,21 +436,17 @@
 	ret = of_property_read_u32(node, key, &val);
 	if (!ret)
 		spm_data.vctl_timeout_us = val;
+	else if (cpu == 0xffff)
+		goto fail;
 
-	/*
-	 * Device with id 0..NR_CPUS are SPM for apps cores
-	 * Device with id 0xFFFF is for L2 SPM.
-	 */
-	if (cpu >= 0 && cpu < num_possible_cpus()) {
-		mode_of_data = of_cpu_modes;
-		num_modes = ARRAY_SIZE(of_cpu_modes);
-		dev = &per_cpu(msm_cpu_spm_device, cpu);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto fail;
 
-	} else {
-		mode_of_data = of_l2_modes;
-		num_modes = ARRAY_SIZE(of_l2_modes);
-		dev = &msm_spm_l2_device;
-	}
+	spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!spm_data.reg_base_addr)
+		return -ENOMEM;
 
 	spm_data.vctl_port = -1;
 	spm_data.phase_port = -1;
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 8df41e2..07b6f6c 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -280,11 +280,11 @@
 	return (void __iomem *) (offset + addr);
 }
 
-void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
+void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
 	unsigned int mtype, void *caller)
 {
-	unsigned long last_addr;
- 	unsigned long offset = phys_addr & ~PAGE_MASK;
+	phys_addr_t last_addr;
+	phys_addr_t offset = phys_addr & ~PAGE_MASK;
  	unsigned long pfn = __phys_to_pfn(phys_addr);
 
  	/*
@@ -316,12 +316,12 @@
 }
 EXPORT_SYMBOL(__arm_ioremap_pfn);
 
-void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
 				      unsigned int, void *) =
 	__arm_ioremap_caller;
 
 void __iomem *
-__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+__arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
 {
 	return arch_ioremap_caller(phys_addr, size, mtype,
 		__builtin_return_address(0));
@@ -336,7 +336,7 @@
  * CONFIG_GENERIC_ALLOCATOR for allocating external memory.
  */
 void __iomem *
-__arm_ioremap_exec(unsigned long phys_addr, size_t size, bool cached)
+__arm_ioremap_exec(phys_addr_t phys_addr, size_t size, bool cached)
 {
 	unsigned int mtype;
 
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index 06262c5..ce8cb19 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -11,10 +11,49 @@
 #include <linux/random.h>
 #include <asm/cachetype.h>
 
+static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
+					      unsigned long pgoff)
+{
+	unsigned long base = addr & ~(SHMLBA-1);
+	unsigned long off = (pgoff << PAGE_SHIFT) & (SHMLBA-1);
+
+	if (base + off <= addr)
+		return base + off;
+
+	return base - off;
+}
+
 #define COLOUR_ALIGN(addr,pgoff)		\
 	((((addr)+SHMLBA-1)&~(SHMLBA-1)) +	\
 	 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
 
+/* gap between mmap and stack */
+#define MIN_GAP (128*1024*1024UL)
+#define MAX_GAP ((TASK_SIZE)/6*5)
+
+static int mmap_is_legacy(void)
+{
+	if (current->personality & ADDR_COMPAT_LAYOUT)
+		return 1;
+
+	if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
+		return 1;
+
+	return sysctl_legacy_va_layout;
+}
+
+static unsigned long mmap_base(unsigned long rnd)
+{
+	unsigned long gap = rlimit(RLIMIT_STACK);
+
+	if (gap < MIN_GAP)
+		gap = MIN_GAP;
+	else if (gap > MAX_GAP)
+		gap = MAX_GAP;
+
+	return PAGE_ALIGN(TASK_SIZE - gap - rnd);
+}
+
 /*
  * We need to ensure that shared mappings are correctly aligned to
  * avoid aliasing issues with VIPT caches.  We need to ensure that
@@ -68,13 +107,9 @@
 	if (len > mm->cached_hole_size) {
 	        start_addr = addr = mm->free_area_cache;
 	} else {
-		start_addr = addr = TASK_UNMAPPED_BASE;
+	        start_addr = addr = mm->mmap_base;
 	        mm->cached_hole_size = 0;
 	}
-	/* 8 bits of randomness in 20 address space bits */
-	if ((current->flags & PF_RANDOMIZE) &&
-	    !(current->personality & ADDR_NO_RANDOMIZE))
-		addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
 
 full_search:
 	if (do_align)
@@ -111,6 +146,134 @@
 	}
 }
 
+unsigned long
+arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
+			const unsigned long len, const unsigned long pgoff,
+			const unsigned long flags)
+{
+	struct vm_area_struct *vma;
+	struct mm_struct *mm = current->mm;
+	unsigned long addr = addr0;
+	int do_align = 0;
+	int aliasing = cache_is_vipt_aliasing();
+
+	/*
+	 * We only need to do colour alignment if either the I or D
+	 * caches alias.
+	 */
+	if (aliasing)
+		do_align = filp || (flags & MAP_SHARED);
+
+	/* requested length too big for entire address space */
+	if (len > TASK_SIZE)
+		return -ENOMEM;
+
+	if (flags & MAP_FIXED) {
+		if (aliasing && flags & MAP_SHARED &&
+		    (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
+			return -EINVAL;
+		return addr;
+	}
+
+	/* requesting a specific address */
+	if (addr) {
+		if (do_align)
+			addr = COLOUR_ALIGN(addr, pgoff);
+		else
+			addr = PAGE_ALIGN(addr);
+		vma = find_vma(mm, addr);
+		if (TASK_SIZE - len >= addr &&
+				(!vma || addr + len <= vma->vm_start))
+			return addr;
+	}
+
+	/* check if free_area_cache is useful for us */
+	if (len <= mm->cached_hole_size) {
+		mm->cached_hole_size = 0;
+		mm->free_area_cache = mm->mmap_base;
+	}
+
+	/* either no address requested or can't fit in requested address hole */
+	addr = mm->free_area_cache;
+	if (do_align) {
+		unsigned long base = COLOUR_ALIGN_DOWN(addr - len, pgoff);
+		addr = base + len;
+	}
+
+	/* make sure it can fit in the remaining address space */
+	if (addr > len) {
+		vma = find_vma(mm, addr-len);
+		if (!vma || addr <= vma->vm_start)
+			/* remember the address as a hint for next time */
+			return (mm->free_area_cache = addr-len);
+	}
+
+	if (mm->mmap_base < len)
+		goto bottomup;
+
+	addr = mm->mmap_base - len;
+	if (do_align)
+		addr = COLOUR_ALIGN_DOWN(addr, pgoff);
+
+	do {
+		/*
+		 * Lookup failure means no vma is above this address,
+		 * else if new region fits below vma->vm_start,
+		 * return with success:
+		 */
+		vma = find_vma(mm, addr);
+		if (!vma || addr+len <= vma->vm_start)
+			/* remember the address as a hint for next time */
+			return (mm->free_area_cache = addr);
+
+		/* remember the largest hole we saw so far */
+		if (addr + mm->cached_hole_size < vma->vm_start)
+			mm->cached_hole_size = vma->vm_start - addr;
+
+		/* try just below the current vma->vm_start */
+		addr = vma->vm_start - len;
+		if (do_align)
+			addr = COLOUR_ALIGN_DOWN(addr, pgoff);
+	} while (len < vma->vm_start);
+
+bottomup:
+	/*
+	 * A failed mmap() very likely causes application failure,
+	 * so fall back to the bottom-up function here. This scenario
+	 * can happen with large stack limits and large mmap()
+	 * allocations.
+	 */
+	mm->cached_hole_size = ~0UL;
+	mm->free_area_cache = TASK_UNMAPPED_BASE;
+	addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
+	/*
+	 * Restore the topdown base:
+	 */
+	mm->free_area_cache = mm->mmap_base;
+	mm->cached_hole_size = ~0UL;
+
+	return addr;
+}
+
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+	unsigned long random_factor = 0UL;
+
+	/* 8 bits of randomness in 20 address space bits */
+	if ((current->flags & PF_RANDOMIZE) &&
+	    !(current->personality & ADDR_NO_RANDOMIZE))
+		random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;
+
+	if (mmap_is_legacy()) {
+		mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
+		mm->get_unmapped_area = arch_get_unmapped_area;
+		mm->unmap_area = arch_unmap_area;
+	} else {
+		mm->mmap_base = mmap_base(random_factor);
+		mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+		mm->unmap_area = arch_unmap_area_topdown;
+	}
+}
 
 /*
  * You really shouldn't be using read() or write() on /dev/mem.  This
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 9e36e1e..04c3300 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -481,6 +481,7 @@
 	driver->feature_mask->ctrl_pkt_data_len = 4 + FEATURE_MASK_LEN_BYTES;
 	driver->feature_mask->feature_mask_len = FEATURE_MASK_LEN_BYTES;
 	memcpy(buf, driver->feature_mask, header_size);
+	feature_byte |= F_DIAG_INT_FEATURE_MASK;
 	feature_byte |= APPS_RESPOND_LOG_ON_DEMAND;
 	memcpy(buf+header_size, &feature_byte, FEATURE_MASK_LEN_BYTES);
 
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 2ebae71..7022a6f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -2071,6 +2071,7 @@
 	diagchar_cleanup();
 	diagfwd_exit();
 	diagfwd_cntl_exit();
+	diag_dci_exit();
 	diag_masks_exit();
 	diag_sdio_fn(EXIT);
 	diagfwd_bridge_fn(EXIT);
@@ -2085,6 +2086,7 @@
 	diagmem_exit(driver, POOL_TYPE_ALL);
 	diagfwd_exit();
 	diagfwd_cntl_exit();
+	diag_dci_exit();
 	diag_masks_exit();
 	diag_sdio_fn(EXIT);
 	diagfwd_bridge_fn(EXIT);
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 7cd1866..9c2c691 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -30,6 +30,9 @@
 /* Send Diag F3 mask */
 #define DIAG_CTRL_MSG_F3_MASK_V2	11
 
+/* Denotes that we support sending/receiving the feature mask */
+#define F_DIAG_INT_FEATURE_MASK	0x01
+
 struct cmd_code_range {
 	uint16_t cmd_code_lo;
 	uint16_t cmd_code_hi;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 245272b..1f16497 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -62,6 +62,7 @@
 	dma_addr_t coh_pmem;	    /* Allocated coherent physical memory */
 	int memsize;				/* Memory allocated */
 	int is_shared;				/* CE HW is shared */
+	bool support_cmd_dscr;
 
 	void __iomem *iobase;	    /* Virtual io base of CE HW  */
 	unsigned int phy_iobase;    /* Physical io base of CE HW    */
@@ -84,6 +85,7 @@
 	int dir;
 	void *areq;
 	enum qce_cipher_mode_enum mode;
+	struct qce_ce_cfg_reg_setting reg;
 	struct ce_sps_data ce_sps;
 };
 
@@ -494,25 +496,17 @@
 		for (i = 0; i < noncelen32; i++, pce++)
 			pce->data = nonce32[i];
 
-		/* TBD  NEW FEATURE partial AES CCM  pkt support set last bit */
-		auth_cfg |= ((1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST));
+		if (creq->authklen ==  AES128_KEY_SIZE)
+			auth_cfg = pce_dev->reg.auth_cfg_aes_ccm_128;
+		else {
+			if (creq->authklen ==  AES256_KEY_SIZE)
+				auth_cfg = pce_dev->reg.auth_cfg_aes_ccm_256;
+		}
 		if (creq->dir == QCE_ENCRYPT)
 			auth_cfg |= (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
 		else
 			auth_cfg |= (CRYPTO_AUTH_POS_AFTER << CRYPTO_AUTH_POS);
 		auth_cfg |= ((creq->authsize - 1) << CRYPTO_AUTH_SIZE);
-		auth_cfg |= (CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE);
-		if (creq->authklen ==  AES128_KEY_SIZE)
-			auth_cfg |= (CRYPTO_AUTH_KEY_SZ_AES128 <<
-						CRYPTO_AUTH_KEY_SIZE);
-		else {
-			if (creq->authklen ==  AES256_KEY_SIZE)
-				auth_cfg |= (CRYPTO_AUTH_KEY_SZ_AES256 <<
-							CRYPTO_AUTH_KEY_SIZE);
-		}
-		auth_cfg |= (CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG);
-		auth_cfg |= ((MAX_NONCE/sizeof(uint32_t)) <<
-						CRYPTO_AUTH_NONCE_NUM_WORDS);
 
 		if (use_hw_key == true)	{
 			auth_cfg |= (1 << CRYPTO_USE_HW_KEY_AUTH);
@@ -542,21 +536,37 @@
 	}
 	switch (creq->mode) {
 	case QCE_MODE_ECB:
-		encr_cfg |= (CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ecb_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ecb_256;
 		break;
 	case QCE_MODE_CBC:
-		encr_cfg |= (CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_cbc_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_cbc_256;
 		break;
 	case QCE_MODE_XTS:
-		encr_cfg |= (CRYPTO_ENCR_MODE_XTS << CRYPTO_ENCR_MODE);
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_xts_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_xts_256;
 		break;
 	case QCE_MODE_CCM:
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ccm_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ccm_256;
 		encr_cfg |= (CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE) |
 				(CRYPTO_LAST_CCM_XFR << CRYPTO_LAST_CCM);
 		break;
 	case QCE_MODE_CTR:
 	default:
-		encr_cfg |= (CRYPTO_ENCR_MODE_CTR << CRYPTO_ENCR_MODE);
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_256;
 		break;
 	}
 	pce_dev->mode = creq->mode;
@@ -600,13 +610,15 @@
 			uint32_t xtsklen =
 					creq->encklen/(2 * sizeof(uint32_t));
 
-			_byte_stream_to_net_words(xtskey32, (creq->enckey +
-					creq->encklen/2), creq->encklen/2);
-			/* write xts encr key */
-			pce = cmdlistinfo->encr_xts_key;
-			for (i = 0; i < xtsklen; i++, pce++)
-				pce->data = xtskey32[i];
-
+			if ((use_hw_key == false) && (use_pipe_key == false)) {
+				_byte_stream_to_net_words(xtskey32,
+					(creq->enckey + creq->encklen/2),
+							creq->encklen/2);
+				/* write xts encr key */
+				pce = cmdlistinfo->encr_xts_key;
+				for (i = 0; i < xtsklen; i++, pce++)
+					pce->data = xtskey32[i];
+			}
 			/* write xts du size */
 			pce = cmdlistinfo->encr_xts_du_size;
 			if (use_pipe_key == true)
@@ -642,26 +654,13 @@
 		if (creq->op == QCE_REQ_ABLK_CIPHER_NO_KEY) {
 				encr_cfg |= (CRYPTO_ENCR_KEY_SZ_AES128 <<
 						CRYPTO_ENCR_KEY_SZ);
-			encr_cfg |= CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG;
 		} else {
 			if (use_hw_key == false) {
 				/* write encr key */
 				pce = cmdlistinfo->encr_key;
 				for (i = 0; i < enck_size_in_word; i++, pce++)
 					pce->data = enckey32[i];
-				switch (key_size) {
-				case AES128_KEY_SIZE:
-					encr_cfg |= (CRYPTO_ENCR_KEY_SZ_AES128
-							 << CRYPTO_ENCR_KEY_SZ);
-					break;
-				case AES256_KEY_SIZE:
-				default:
-					encr_cfg |= (CRYPTO_ENCR_KEY_SZ_AES256
-							 << CRYPTO_ENCR_KEY_SZ);
-				break;
-				} /* end of switch (creq->encklen) */
 			}
-			encr_cfg |= CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG;
 		} /* else of if (creq->op == QCE_REQ_ABLK_CIPHER_NO_KEY) */
 		break;
 	} /* end of switch (creq->mode)  */
@@ -706,10 +705,499 @@
 	return 0;
 };
 
+static int _ce_setup_hash_direct(struct qce_device *pce_dev,
+				struct qce_sha_req *sreq)
+{
+	uint32_t auth32[SHA256_DIGEST_SIZE / sizeof(uint32_t)];
+	uint32_t diglen;
+	bool use_hw_key = false;
+	int i;
+	uint32_t mackey32[SHA_HMAC_KEY_SIZE/sizeof(uint32_t)] = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	bool sha1 = false;
+	uint32_t auth_cfg = 0;
+
+	writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
+							CRYPTO_CONFIG_REG));
+	/*
+	 * Ensure previous instructions (setting the CONFIG register)
+	 * was completed before issuing starting to set other config register
+	 * This is to ensure the configurations are done in correct endian-ness
+	 * as set in the CONFIG registers
+	 */
+	mb();
+
+	if (sreq->alg == QCE_HASH_AES_CMAC) {
+		/* write seg_cfg */
+		writel_relaxed(0, pce_dev->iobase + CRYPTO_AUTH_SEG_CFG_REG);
+		/* write seg_cfg */
+		writel_relaxed(0, pce_dev->iobase + CRYPTO_ENCR_SEG_CFG_REG);
+		/* write seg_cfg */
+		writel_relaxed(0, pce_dev->iobase + CRYPTO_ENCR_SEG_SIZE_REG);
+
+		/* Clear auth_ivn, auth_keyn registers  */
+		for (i = 0; i < 16; i++) {
+			writel_relaxed(0, (pce_dev->iobase +
+				(CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t))));
+			writel_relaxed(0, (pce_dev->iobase +
+				(CRYPTO_AUTH_KEY0_REG + i*sizeof(uint32_t))));
+		}
+		/* write auth_bytecnt 0/1/2/3, start with 0 */
+		for (i = 0; i < 4; i++)
+			writel_relaxed(0, pce_dev->iobase +
+						CRYPTO_AUTH_BYTECNT0_REG +
+						i * sizeof(uint32_t));
+
+		if (sreq->authklen == AES128_KEY_SIZE)
+			auth_cfg = pce_dev->reg.auth_cfg_cmac_128;
+		else
+			auth_cfg = pce_dev->reg.auth_cfg_cmac_256;
+	}
+
+	if ((sreq->alg == QCE_HASH_SHA1_HMAC) ||
+			(sreq->alg == QCE_HASH_SHA256_HMAC) ||
+			(sreq->alg ==  QCE_HASH_AES_CMAC)) {
+		uint32_t authk_size_in_word = sreq->authklen/sizeof(uint32_t);
+
+		_byte_stream_to_net_words(mackey32, sreq->authkey,
+						sreq->authklen);
+
+		/* check for null key. If null, use hw key*/
+		for (i = 0; i < authk_size_in_word; i++) {
+			if (mackey32[i] != 0)
+				break;
+		}
+
+		if (i == authk_size_in_word)
+			use_hw_key = true;
+		else
+			/* Clear auth_ivn, auth_keyn registers  */
+			for (i = 0; i < authk_size_in_word; i++)
+				writel_relaxed(mackey32[i], (pce_dev->iobase +
+					(CRYPTO_AUTH_KEY0_REG +
+							i*sizeof(uint32_t))));
+	}
+
+	if (sreq->alg ==  QCE_HASH_AES_CMAC)
+		goto go_proc;
+
+	/* if not the last, the size has to be on the block boundary */
+	if (sreq->last_blk == 0 && (sreq->size % SHA256_BLOCK_SIZE))
+		return -EIO;
+
+	switch (sreq->alg) {
+	case QCE_HASH_SHA1:
+		auth_cfg = pce_dev->reg.auth_cfg_sha1;
+		diglen = SHA1_DIGEST_SIZE;
+		sha1 = true;
+		break;
+	case QCE_HASH_SHA1_HMAC:
+		auth_cfg = pce_dev->reg.auth_cfg_hmac_sha1;
+		diglen = SHA1_DIGEST_SIZE;
+		sha1 = true;
+		break;
+	case QCE_HASH_SHA256:
+		auth_cfg = pce_dev->reg.auth_cfg_sha256;
+		diglen = SHA256_DIGEST_SIZE;
+		break;
+	case QCE_HASH_SHA256_HMAC:
+		auth_cfg = pce_dev->reg.auth_cfg_hmac_sha256;
+		diglen = SHA256_DIGEST_SIZE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* write 20/32 bytes, 5/8 words into auth_iv for SHA1/SHA256 */
+	if (sreq->first_blk) {
+		if (sha1) {
+			for (i = 0; i < 5; i++)
+				auth32[i] = _std_init_vector_sha1[i];
+		} else {
+			for (i = 0; i < 8; i++)
+				auth32[i] = _std_init_vector_sha256[i];
+		}
+	} else {
+		_byte_stream_to_net_words(auth32, sreq->digest, diglen);
+	}
+
+	/* Set auth_ivn, auth_keyn registers  */
+	for (i = 0; i < 5; i++)
+		writel_relaxed(auth32[i], (pce_dev->iobase +
+			(CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t))));
+
+	if ((sreq->alg == QCE_HASH_SHA256) ||
+			(sreq->alg == QCE_HASH_SHA256_HMAC)) {
+		for (i = 5; i < 8; i++)
+			writel_relaxed(auth32[i], (pce_dev->iobase +
+				(CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t))));
+	}
+
+
+	/* write auth_bytecnt 0/1/2/3, start with 0 */
+	for (i = 0; i < 2; i++)
+		writel_relaxed(sreq->auth_data[i], pce_dev->iobase +
+					CRYPTO_AUTH_BYTECNT0_REG +
+						i * sizeof(uint32_t));
+
+	/* Set/reset  last bit in CFG register  */
+	if (sreq->last_blk)
+		auth_cfg |= 1 << CRYPTO_LAST;
+	else
+		auth_cfg &= ~(1 << CRYPTO_LAST);
+	if (sreq->first_blk)
+		auth_cfg |= 1 << CRYPTO_FIRST;
+	else
+		auth_cfg &= ~(1 << CRYPTO_FIRST);
+go_proc:
+	 /* write seg_cfg */
+	writel_relaxed(auth_cfg, pce_dev->iobase + CRYPTO_AUTH_SEG_CFG_REG);
+	/* write auth seg_size   */
+	writel_relaxed(sreq->size, pce_dev->iobase + CRYPTO_AUTH_SEG_SIZE_REG);
+
+	/* write auth_seg_start   */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_AUTH_SEG_START_REG);
+
+	/* reset encr seg_cfg   */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_ENCR_SEG_CFG_REG);
+
+	/* write seg_size   */
+	writel_relaxed(sreq->size, pce_dev->iobase + CRYPTO_SEG_SIZE_REG);
+
+	writel_relaxed(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
+							CRYPTO_CONFIG_REG));
+	/* issue go to crypto   */
+	if (use_hw_key == false)
+		writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+				pce_dev->iobase + CRYPTO_GOPROC_REG);
+	else
+		writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+				pce_dev->iobase + CRYPTO_GOPROC_QC_KEY_REG);
+	/*
+	 * Ensure previous instructions (setting the GO register)
+	 * was completed before issuing a DMA transfer request
+	 */
+	mb();
+	return 0;
+}
+
+static int _ce_setup_cipher_direct(struct qce_device *pce_dev,
+		struct qce_req *creq, uint32_t totallen_in, uint32_t coffset)
+{
+	uint32_t enckey32[(MAX_CIPHER_KEY_SIZE * 2)/sizeof(uint32_t)] = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	uint32_t enciv32[MAX_IV_LENGTH / sizeof(uint32_t)] = {
+			0, 0, 0, 0};
+	uint32_t enck_size_in_word = 0;
+	uint32_t key_size;
+	bool use_hw_key = false;
+	bool use_pipe_key = false;
+	uint32_t encr_cfg = 0;
+	uint32_t ivsize = creq->ivsize;
+	int i;
+
+	writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
+							CRYPTO_CONFIG_REG));
+	/*
+	 * Ensure previous instructions (setting the CONFIG register)
+	 * was completed before issuing starting to set other config register
+	 * This is to ensure the configurations are done in correct endian-ness
+	 * as set in the CONFIG registers
+	 */
+	mb();
+
+	if (creq->mode == QCE_MODE_XTS)
+		key_size = creq->encklen/2;
+	else
+		key_size = creq->encklen;
+
+	_byte_stream_to_net_words(enckey32, creq->enckey, key_size);
+
+	/* check for null key. If null, use hw key*/
+	enck_size_in_word = key_size/sizeof(uint32_t);
+	for (i = 0; i < enck_size_in_word; i++) {
+		if (enckey32[i] != 0)
+			break;
+	}
+	if (i == enck_size_in_word)
+		use_hw_key = true;
+
+	if (use_hw_key == false) {
+		for (i = 0; i < enck_size_in_word; i++) {
+			if (enckey32[i] != 0xFFFFFFFF)
+				break;
+		}
+		if (i == enck_size_in_word)
+			use_pipe_key = true;
+	}
+
+	if ((creq->op == QCE_REQ_AEAD) && (creq->mode == QCE_MODE_CCM)) {
+		uint32_t authklen32 = creq->encklen/sizeof(uint32_t);
+		uint32_t noncelen32 = MAX_NONCE/sizeof(uint32_t);
+		uint32_t nonce32[MAX_NONCE/sizeof(uint32_t)] = {0, 0, 0, 0};
+		uint32_t auth_cfg = 0;
+
+		/* Clear auth_ivn, auth_keyn registers  */
+		for (i = 0; i < 16; i++) {
+			writel_relaxed(0, (pce_dev->iobase +
+				(CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t))));
+			writel_relaxed(0, (pce_dev->iobase +
+				(CRYPTO_AUTH_KEY0_REG + i*sizeof(uint32_t))));
+		}
+		/* write auth_bytecnt 0/1/2/3, start with 0 */
+		for (i = 0; i < 4; i++)
+			writel_relaxed(0, pce_dev->iobase +
+						CRYPTO_AUTH_BYTECNT0_REG +
+						i * sizeof(uint32_t));
+		/* write nonce */
+		_byte_stream_to_net_words(nonce32, creq->nonce, MAX_NONCE);
+		for (i = 0; i < noncelen32; i++)
+			writel_relaxed(nonce32[i], pce_dev->iobase +
+				CRYPTO_AUTH_INFO_NONCE0_REG +
+					(i*sizeof(uint32_t)));
+
+		if (creq->authklen ==  AES128_KEY_SIZE)
+			auth_cfg = pce_dev->reg.auth_cfg_aes_ccm_128;
+		else {
+			if (creq->authklen ==  AES256_KEY_SIZE)
+				auth_cfg = pce_dev->reg.auth_cfg_aes_ccm_256;
+		}
+		if (creq->dir == QCE_ENCRYPT)
+			auth_cfg |= (CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+		else
+			auth_cfg |= (CRYPTO_AUTH_POS_AFTER << CRYPTO_AUTH_POS);
+		auth_cfg |= ((creq->authsize - 1) << CRYPTO_AUTH_SIZE);
+
+		if (use_hw_key == true)	{
+			auth_cfg |= (1 << CRYPTO_USE_HW_KEY_AUTH);
+		} else {
+			auth_cfg &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
+			/* write auth key */
+			for (i = 0; i < authklen32; i++)
+				writel_relaxed(enckey32[i], pce_dev->iobase +
+				CRYPTO_AUTH_KEY0_REG + (i*sizeof(uint32_t)));
+		}
+		writel_relaxed(auth_cfg, pce_dev->iobase +
+						CRYPTO_AUTH_SEG_CFG_REG);
+		if (creq->dir == QCE_ENCRYPT)
+			writel_relaxed(totallen_in, pce_dev->iobase +
+						CRYPTO_AUTH_SEG_SIZE_REG);
+		else
+			writel_relaxed((totallen_in - creq->authsize),
+				pce_dev->iobase + CRYPTO_AUTH_SEG_SIZE_REG);
+		writel_relaxed(0, pce_dev->iobase + CRYPTO_AUTH_SEG_START_REG);
+	} else {
+		if (creq->op != QCE_REQ_AEAD)
+			writel_relaxed(0, pce_dev->iobase +
+						CRYPTO_AUTH_SEG_CFG_REG);
+	}
+	/*
+	 * Ensure previous instructions (write to all AUTH registers)
+	 * was completed before accessing a register that is not in
+	 * in the same 1K range.
+	 */
+	mb();
+	switch (creq->mode) {
+	case QCE_MODE_ECB:
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ecb_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ecb_256;
+		break;
+	case QCE_MODE_CBC:
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_cbc_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_cbc_256;
+		break;
+	case QCE_MODE_XTS:
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_xts_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_xts_256;
+		break;
+	case QCE_MODE_CCM:
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ccm_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ccm_256;
+		break;
+	case QCE_MODE_CTR:
+	default:
+		if (key_size == AES128_KEY_SIZE)
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_128;
+		else
+			encr_cfg = pce_dev->reg.encr_cfg_aes_ctr_256;
+		break;
+	}
+	pce_dev->mode = creq->mode;
+
+	switch (creq->alg) {
+	case CIPHER_ALG_DES:
+		if (creq->mode !=  QCE_MODE_ECB) {
+			encr_cfg = pce_dev->reg.encr_cfg_des_cbc;
+			_byte_stream_to_net_words(enciv32, creq->iv, ivsize);
+			writel_relaxed(enciv32[0], pce_dev->iobase +
+						CRYPTO_CNTR0_IV0_REG);
+			writel_relaxed(enciv32[1], pce_dev->iobase +
+						CRYPTO_CNTR1_IV1_REG);
+		} else {
+			encr_cfg = pce_dev->reg.encr_cfg_des_ecb;
+		}
+		if (use_hw_key == false) {
+			writel_relaxed(enckey32[0], pce_dev->iobase +
+							CRYPTO_ENCR_KEY0_REG);
+			writel_relaxed(enckey32[1], pce_dev->iobase +
+							CRYPTO_ENCR_KEY1_REG);
+		}
+		break;
+	case CIPHER_ALG_3DES:
+		if (creq->mode !=  QCE_MODE_ECB) {
+			_byte_stream_to_net_words(enciv32, creq->iv, ivsize);
+			writel_relaxed(enciv32[0], pce_dev->iobase +
+						CRYPTO_CNTR0_IV0_REG);
+			writel_relaxed(enciv32[1], pce_dev->iobase +
+						CRYPTO_CNTR1_IV1_REG);
+			encr_cfg = pce_dev->reg.encr_cfg_3des_cbc;
+		} else {
+			encr_cfg = pce_dev->reg.encr_cfg_3des_ecb;
+		}
+		if (use_hw_key == false) {
+			/* write encr key */
+			for (i = 0; i < 6; i++)
+				writel_relaxed(enckey32[0], (pce_dev->iobase +
+				(CRYPTO_ENCR_KEY0_REG + i * sizeof(uint32_t))));
+		}
+		break;
+	case CIPHER_ALG_AES:
+	default:
+		if (creq->mode ==  QCE_MODE_XTS) {
+			uint32_t xtskey32[MAX_CIPHER_KEY_SIZE/sizeof(uint32_t)]
+					= {0, 0, 0, 0, 0, 0, 0, 0};
+			uint32_t xtsklen =
+					creq->encklen/(2 * sizeof(uint32_t));
+
+			if ((use_hw_key == false) && (use_pipe_key == false)) {
+				_byte_stream_to_net_words(xtskey32,
+					(creq->enckey + creq->encklen/2),
+							creq->encklen/2);
+				/* write xts encr key */
+				for (i = 0; i < xtsklen; i++)
+					writel_relaxed(xtskey32[i],
+						pce_dev->iobase +
+						CRYPTO_ENCR_XTS_KEY0_REG +
+						(i * sizeof(uint32_t)));
+			}
+			/* write xts du size */
+			if (use_pipe_key == true)
+				writel_relaxed(min((uint32_t)QCE_SECTOR_SIZE,
+						creq->cryptlen),
+						pce_dev->iobase +
+						CRYPTO_ENCR_XTS_DU_SIZE_REG);
+			else
+				writel_relaxed(creq->cryptlen ,
+						pce_dev->iobase +
+						CRYPTO_ENCR_XTS_DU_SIZE_REG);
+		}
+		if (creq->mode !=  QCE_MODE_ECB) {
+			if (creq->mode ==  QCE_MODE_XTS)
+				_byte_stream_swap_to_net_words(enciv32,
+							creq->iv, ivsize);
+			else
+				_byte_stream_to_net_words(enciv32, creq->iv,
+								ivsize);
+
+			/* write encr cntr iv */
+			for (i = 0; i <= 3; i++)
+				writel_relaxed(enciv32[i], pce_dev->iobase +
+							CRYPTO_CNTR0_IV0_REG +
+							(i * sizeof(uint32_t)));
+
+			if (creq->mode == QCE_MODE_CCM) {
+				/* write cntr iv for ccm */
+				for (i = 0; i <= 3; i++)
+					writel_relaxed(enciv32[i],
+						pce_dev->iobase +
+						CRYPTO_ENCR_CCM_INT_CNTR0_REG +
+							(i * sizeof(uint32_t)));
+				/* update cntr_iv[3] by one */
+				writel_relaxed((enciv32[3] + 1),
+							pce_dev->iobase +
+							CRYPTO_CNTR0_IV0_REG +
+							(3 * sizeof(uint32_t)));
+			}
+		}
+
+		if (creq->op == QCE_REQ_ABLK_CIPHER_NO_KEY) {
+				encr_cfg |= (CRYPTO_ENCR_KEY_SZ_AES128 <<
+						CRYPTO_ENCR_KEY_SZ);
+		} else {
+			if ((use_hw_key == false) && (use_pipe_key == false)) {
+				for (i = 0; i < enck_size_in_word; i++)
+					writel_relaxed(enckey32[i],
+						pce_dev->iobase +
+							CRYPTO_ENCR_KEY0_REG +
+							(i * sizeof(uint32_t)));
+			}
+		} /* else of if (creq->op == QCE_REQ_ABLK_CIPHER_NO_KEY) */
+		break;
+	} /* end of switch (creq->mode)  */
+
+	if (use_pipe_key)
+		encr_cfg |= (CRYPTO_USE_PIPE_KEY_ENCR_ENABLED
+					<< CRYPTO_USE_PIPE_KEY_ENCR);
+
+	/* write encr seg cfg */
+	encr_cfg |= ((creq->dir == QCE_ENCRYPT) ? 1 : 0) << CRYPTO_ENCODE;
+	if (use_hw_key == true)
+		encr_cfg |= (CRYPTO_USE_HW_KEY << CRYPTO_USE_HW_KEY_ENCR);
+	else
+		encr_cfg &= ~(CRYPTO_USE_HW_KEY << CRYPTO_USE_HW_KEY_ENCR);
+	/* write encr seg cfg */
+	writel_relaxed(encr_cfg, pce_dev->iobase + CRYPTO_ENCR_SEG_CFG_REG);
+
+	/* write encr seg size */
+	if ((creq->mode == QCE_MODE_CCM) && (creq->dir == QCE_DECRYPT))
+		writel_relaxed((creq->cryptlen + creq->authsize),
+				pce_dev->iobase + CRYPTO_ENCR_SEG_SIZE_REG);
+	else
+		writel_relaxed(creq->cryptlen,
+				pce_dev->iobase + CRYPTO_ENCR_SEG_SIZE_REG);
+
+	/* write encr seg start */
+	writel_relaxed((coffset & 0xffff),
+			pce_dev->iobase + CRYPTO_ENCR_SEG_START_REG);
+	/* write encr seg start */
+	writel_relaxed(0xffffffff,
+			pce_dev->iobase + CRYPTO_CNTR_MASK_REG);
+
+	/* write seg size  */
+	writel_relaxed(totallen_in, pce_dev->iobase + CRYPTO_SEG_SIZE_REG);
+
+	writel_relaxed(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
+							CRYPTO_CONFIG_REG));
+	/* issue go to crypto   */
+	if (use_hw_key == false)
+		writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+				pce_dev->iobase + CRYPTO_GOPROC_REG);
+	else
+		writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+				pce_dev->iobase + CRYPTO_GOPROC_QC_KEY_REG);
+	/*
+	 * Ensure previous instructions (setting the GO register)
+	 * was completed before issuing a DMA transfer request
+	 */
+	mb();
+	return 0;
+};
+
 static int _qce_unlock_other_pipes(struct qce_device *pce_dev)
 {
 	int rc = 0;
 
+	if (pce_dev->support_cmd_dscr == false)
+		return rc;
+
 	pce_dev->ce_sps.consumer.event.callback = NULL;
 	rc = sps_transfer_one(pce_dev->ce_sps.consumer.pipe,
 	GET_PHYS_ADDR(pce_dev->ce_sps.cmdlistptr.unlock_all_pipes.cmdlist),
@@ -1411,20 +1899,11 @@
 	uint32_t key_reg = 0;
 	uint32_t xts_key_reg = 0;
 	uint32_t iv_reg = 0;
-	uint32_t crypto_cfg = 0;
-	uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
-	uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
 
 	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
 					pdev->ce_sps.ce_burst_size);
 	ce_vaddr = (struct sps_command_element *)(*pvaddr);
 	ce_vaddr_start = (uint32_t)(*pvaddr);
-	crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
-			BIT(CRYPTO_MASK_DOUT_INTR) |
-			BIT(CRYPTO_MASK_DIN_INTR) |
-			BIT(CRYPTO_MASK_OP_DONE_INTR) |
-			(0 << CRYPTO_HIGH_SPD_EN_N) |
-			(pipe_pair << CRYPTO_PIPE_SET_SELECT);
 	/*
 	 * Designate chunks of the allocated memory to various
 	 * command list pointers related to AES cipher operations defined
@@ -1437,11 +1916,10 @@
 			cmdlistptr->cipher_aes_128_cbc_ctr.cmdlist =
 							(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_aes_128_cbc_ctr);
-
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES128 <<
-						CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_AES <<
-						CRYPTO_ENCR_ALG);
+			if (mode == QCE_MODE_CBC)
+				encr_cfg = pdev->reg.encr_cfg_aes_cbc_128;
+			else
+				encr_cfg = pdev->reg.encr_cfg_aes_ctr_128;
 			iv_reg = 4;
 			key_reg = 4;
 			xts_key_reg = 0;
@@ -1450,10 +1928,10 @@
 							(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_aes_256_cbc_ctr);
 
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES256 <<
-							CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_AES <<
-							CRYPTO_ENCR_ALG);
+			if (mode == QCE_MODE_CBC)
+				encr_cfg = pdev->reg.encr_cfg_aes_cbc_256;
+			else
+				encr_cfg = pdev->reg.encr_cfg_aes_ctr_256;
 			iv_reg = 4;
 			key_reg = 8;
 			xts_key_reg = 0;
@@ -1465,12 +1943,7 @@
 							(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_aes_128_ecb);
 
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES128 <<
-						CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_AES <<
-						CRYPTO_ENCR_ALG) |
-					(CRYPTO_ENCR_MODE_ECB <<
-						CRYPTO_ENCR_MODE);
+			encr_cfg = pdev->reg.encr_cfg_aes_ecb_128;
 			iv_reg = 0;
 			key_reg = 4;
 			xts_key_reg = 0;
@@ -1479,12 +1952,7 @@
 							(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_aes_256_ecb);
 
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES256 <<
-							CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_AES <<
-							CRYPTO_ENCR_ALG) |
-					(CRYPTO_ENCR_MODE_ECB <<
-						CRYPTO_ENCR_MODE);
+			encr_cfg = pdev->reg.encr_cfg_aes_ecb_256;
 			iv_reg = 0;
 			key_reg = 8;
 			xts_key_reg = 0;
@@ -1496,12 +1964,7 @@
 							(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_aes_128_xts);
 
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES128 <<
-						CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_AES <<
-						CRYPTO_ENCR_ALG) |
-					(CRYPTO_ENCR_MODE_XTS <<
-						CRYPTO_ENCR_MODE);
+			encr_cfg = pdev->reg.encr_cfg_aes_xts_128;
 			iv_reg = 4;
 			key_reg = 4;
 			xts_key_reg = 4;
@@ -1510,12 +1973,7 @@
 							(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_aes_256_xts);
 
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES256 <<
-							CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_AES <<
-							CRYPTO_ENCR_ALG) |
-					(CRYPTO_ENCR_MODE_XTS <<
-						CRYPTO_ENCR_MODE);
+			encr_cfg = pdev->reg.encr_cfg_aes_xts_256;
 			iv_reg = 4;
 			key_reg = 8;
 			xts_key_reg = 8;
@@ -1528,8 +1986,8 @@
 	break;
 	}
 
-	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG, crypto_cfg,
-						&pcl_info->crypto_cfg);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_SEG_SIZE_REG, 0,
 						&pcl_info->seg_size);
@@ -1583,7 +2041,7 @@
 						0, &pcl_info->auth_seg_size);
 	}
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-				(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK), NULL);
+			pdev->reg.crypto_cfg_le, NULL);
 
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
 			((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1608,20 +2066,11 @@
 	uint32_t encr_cfg = 0;
 	uint32_t key_reg = 0;
 	uint32_t iv_reg = 0;
-	uint32_t crypto_cfg = 0;
-	uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
-	uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
 
 	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
 					pdev->ce_sps.ce_burst_size);
 	ce_vaddr = (struct sps_command_element *)(*pvaddr);
 	ce_vaddr_start = (uint32_t)(*pvaddr);
-	crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
-			BIT(CRYPTO_MASK_DOUT_INTR) |
-			BIT(CRYPTO_MASK_DIN_INTR) |
-			BIT(CRYPTO_MASK_OP_DONE_INTR) |
-			(0 << CRYPTO_HIGH_SPD_EN_N) |
-			(pipe_pair << CRYPTO_PIPE_SET_SELECT);
 
 	/*
 	 * Designate chunks of the allocated memory to various
@@ -1635,12 +2084,8 @@
 						(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_des_cbc);
 
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_DES <<
-						CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_DES <<
-						CRYPTO_ENCR_ALG) |
-					(CRYPTO_ENCR_MODE_CBC <<
-							CRYPTO_ENCR_MODE);
+
+			encr_cfg = pdev->reg.encr_cfg_des_cbc;
 			iv_reg = 2;
 			key_reg = 2;
 		} else {
@@ -1648,12 +2093,7 @@
 						(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_des_ecb);
 
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_DES <<
-						CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_DES <<
-						CRYPTO_ENCR_ALG) |
-					(CRYPTO_ENCR_MODE_ECB <<
-						CRYPTO_ENCR_MODE);
+			encr_cfg = pdev->reg.encr_cfg_des_ecb;
 			iv_reg = 0;
 			key_reg = 2;
 		}
@@ -1664,12 +2104,7 @@
 						(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_3des_cbc);
 
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_3DES <<
-						CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_DES <<
-						CRYPTO_ENCR_ALG) |
-					(CRYPTO_ENCR_MODE_CBC <<
-							CRYPTO_ENCR_MODE);
+			encr_cfg = pdev->reg.encr_cfg_3des_cbc;
 			iv_reg = 2;
 			key_reg = 6;
 		} else {
@@ -1677,12 +2112,7 @@
 						(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->cipher_3des_ecb);
 
-			encr_cfg = (CRYPTO_ENCR_KEY_SZ_3DES <<
-						CRYPTO_ENCR_KEY_SZ) |
-					(CRYPTO_ENCR_ALG_DES <<
-						CRYPTO_ENCR_ALG) |
-					(CRYPTO_ENCR_MODE_ECB <<
-						CRYPTO_ENCR_MODE);
+			encr_cfg = pdev->reg.encr_cfg_3des_ecb;
 			iv_reg = 0;
 			key_reg = 6;
 		}
@@ -1693,8 +2123,8 @@
 	break;
 	}
 
-	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG, crypto_cfg,
-						&pcl_info->crypto_cfg);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_SEG_SIZE_REG, 0,
 						&pcl_info->seg_size);
@@ -1727,8 +2157,7 @@
 						0, &pcl_info->auth_seg_size);
 	}
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-			(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
-			NULL);
+			pdev->reg.crypto_cfg_le, NULL);
 
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
 			((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1752,20 +2181,12 @@
 	uint32_t key_reg = 0;
 	uint32_t auth_cfg = 0;
 	uint32_t iv_reg = 0;
-	uint32_t crypto_cfg = 0;
-	uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
-	uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
 
 	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
 					pdev->ce_sps.ce_burst_size);
 	ce_vaddr_start = (uint32_t)(*pvaddr);
 	ce_vaddr = (struct sps_command_element *)(*pvaddr);
-	crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
-			BIT(CRYPTO_MASK_DOUT_INTR) |
-			BIT(CRYPTO_MASK_DIN_INTR) |
-			BIT(CRYPTO_MASK_OP_DONE_INTR) |
-			(0 << CRYPTO_HIGH_SPD_EN_N) |
-			(pipe_pair << CRYPTO_PIPE_SET_SELECT);
+
 	/*
 	 * Designate chunks of the allocated memory to various
 	 * command list pointers related to authentication operations
@@ -1776,13 +2197,10 @@
 		cmdlistptr->auth_sha1.cmdlist = (uint32_t)ce_vaddr;
 		pcl_info = &(cmdlistptr->auth_sha1);
 
-		auth_cfg = (CRYPTO_AUTH_MODE_HASH << CRYPTO_AUTH_MODE)|
-				(CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
-				(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
-				(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+		auth_cfg = pdev->reg.auth_cfg_sha1;
 		iv_reg = 5;
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-					crypto_cfg, &pcl_info->crypto_cfg);
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
 							0, NULL);
 
@@ -1791,13 +2209,10 @@
 		cmdlistptr->auth_sha256.cmdlist = (uint32_t)ce_vaddr;
 		pcl_info = &(cmdlistptr->auth_sha256);
 
-		auth_cfg = (CRYPTO_AUTH_MODE_HASH << CRYPTO_AUTH_MODE)|
-				(CRYPTO_AUTH_SIZE_SHA256 << CRYPTO_AUTH_SIZE) |
-				(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
-				(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+		auth_cfg = pdev->reg.auth_cfg_sha256;
 		iv_reg = 8;
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-					crypto_cfg, &pcl_info->crypto_cfg);
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
@@ -1808,14 +2223,11 @@
 		cmdlistptr->auth_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
 		pcl_info = &(cmdlistptr->auth_sha1_hmac);
 
-		auth_cfg = (CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
-				(CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
-				(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
-				(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+		auth_cfg = pdev->reg.auth_cfg_hmac_sha1;
 		key_reg = 16;
 		iv_reg = 5;
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-					crypto_cfg, &pcl_info->crypto_cfg);
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
 							0, NULL);
 	break;
@@ -1823,16 +2235,11 @@
 		cmdlistptr->aead_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
 		pcl_info = &(cmdlistptr->aead_sha1_hmac);
 
-		auth_cfg = (CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
-				(CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
-				(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
-				(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS) |
-				(1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST);
-
+		auth_cfg = pdev->reg.auth_cfg_aead_sha1_hmac;
 		key_reg = 16;
 		iv_reg = 5;
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-					crypto_cfg, &pcl_info->crypto_cfg);
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
@@ -1843,15 +2250,12 @@
 		cmdlistptr->auth_sha256_hmac.cmdlist = (uint32_t)ce_vaddr;
 		pcl_info = &(cmdlistptr->auth_sha256_hmac);
 
-		auth_cfg = (CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
-				(CRYPTO_AUTH_SIZE_SHA256 << CRYPTO_AUTH_SIZE) |
-				(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
-				(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+		auth_cfg = pdev->reg.auth_cfg_hmac_sha256;
 		key_reg = 16;
 		iv_reg = 8;
 
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-					crypto_cfg, &pcl_info->crypto_cfg);
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
@@ -1864,32 +2268,18 @@
 						(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->auth_aes_128_cmac);
 
-			auth_cfg = (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
-				(CRYPTO_AUTH_MODE_CMAC << CRYPTO_AUTH_MODE)|
-				(CRYPTO_AUTH_SIZE_ENUM_16_BYTES <<
-							CRYPTO_AUTH_SIZE) |
-				(CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
-				(CRYPTO_AUTH_KEY_SZ_AES128 <<
-							CRYPTO_AUTH_KEY_SIZE) |
-				(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+			auth_cfg = pdev->reg.auth_cfg_cmac_128;
 			key_reg = 4;
 		} else {
 			cmdlistptr->auth_aes_256_cmac.cmdlist =
 							(uint32_t)ce_vaddr;
 			pcl_info = &(cmdlistptr->auth_aes_256_cmac);
 
-			auth_cfg = (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST)|
-				(CRYPTO_AUTH_MODE_CMAC << CRYPTO_AUTH_MODE)|
-				(CRYPTO_AUTH_SIZE_ENUM_16_BYTES <<
-							CRYPTO_AUTH_SIZE) |
-				(CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
-				(CRYPTO_AUTH_KEY_SZ_AES256 <<
-							CRYPTO_AUTH_KEY_SIZE) |
-				(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+			auth_cfg = pdev->reg.auth_cfg_cmac_256;
 			key_reg = 8;
 		}
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-					crypto_cfg, &pcl_info->crypto_cfg);
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
@@ -1946,8 +2336,7 @@
 				0, NULL);
 	}
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-			(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
-			NULL);
+					pdev->reg.crypto_cfg_le, NULL);
 
 	if (alg != QCE_AEAD_SHA1_HMAC)
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
@@ -1971,20 +2360,12 @@
 	uint32_t encr_cfg = 0;
 	uint32_t auth_cfg = 0;
 	uint32_t key_reg = 0;
-	uint32_t crypto_cfg = 0;
-	uint32_t beats = (pdev->ce_sps.ce_burst_size >> 3) - 1;
-	uint32_t pipe_pair = pdev->ce_sps.pipe_pair_index;
 
 	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
 					pdev->ce_sps.ce_burst_size);
 	ce_vaddr_start = (uint32_t)(*pvaddr);
 	ce_vaddr = (struct sps_command_element *)(*pvaddr);
-	crypto_cfg = (beats << CRYPTO_REQ_SIZE) |
-			BIT(CRYPTO_MASK_DOUT_INTR) |
-			BIT(CRYPTO_MASK_DIN_INTR) |
-			BIT(CRYPTO_MASK_OP_DONE_INTR) |
-			(0 << CRYPTO_HIGH_SPD_EN_N) |
-			(pipe_pair << CRYPTO_PIPE_SET_SELECT);
+
 	/*
 	 * Designate chunks of the allocated memory to various
 	 * command list pointers related to aead operations
@@ -1994,36 +2375,21 @@
 		cmdlistptr->aead_aes_128_ccm.cmdlist = (uint32_t)ce_vaddr;
 		pcl_info = &(cmdlistptr->aead_aes_128_ccm);
 
-		auth_cfg = (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
-			(CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE)|
-			(CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
-			(CRYPTO_AUTH_KEY_SZ_AES128 << CRYPTO_AUTH_KEY_SIZE);
-		auth_cfg &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
-		encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
-			(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
-			((CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE));
+		auth_cfg = pdev->reg.auth_cfg_aes_ccm_128;
+		encr_cfg = pdev->reg.encr_cfg_aes_ccm_128;
 		key_reg = 4;
 	} else {
 
 		cmdlistptr->aead_aes_256_ccm.cmdlist = (uint32_t)ce_vaddr;
 		pcl_info = &(cmdlistptr->aead_aes_256_ccm);
 
-		auth_cfg = (1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
-			(CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE)|
-			(CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
-			(CRYPTO_AUTH_KEY_SZ_AES256 << CRYPTO_AUTH_KEY_SIZE) |
-			((MAX_NONCE/sizeof(uint32_t)) <<
-						CRYPTO_AUTH_NONCE_NUM_WORDS);
-		auth_cfg &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
-		encr_cfg = (CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
-			(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
-			(CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE) |
-			(CRYPTO_LAST_CCM_XFR << CRYPTO_LAST_CCM);
+		auth_cfg = pdev->reg.auth_cfg_aes_ccm_256;
+		encr_cfg = pdev->reg.encr_cfg_aes_ccm_256;
 
 		key_reg = 8;
 	}
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-				crypto_cfg, &pcl_info->crypto_cfg);
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG, 0, NULL);
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, 0, NULL);
@@ -2093,8 +2459,7 @@
 			0, NULL);
 
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
-			(crypto_cfg | CRYPTO_LITTLE_ENDIAN_MASK),
-			NULL);
+					pdev->reg.crypto_cfg_le, NULL);
 
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
 			((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -2197,7 +2562,8 @@
 					(uint32_t)GET_PHYS_ADDR(vaddr);
 	vaddr += QCE_MAX_NUM_DSCR * sizeof(struct sps_iovec);
 
-	qce_setup_cmdlistptrs(pce_dev, &vaddr);
+	if (pce_dev->support_cmd_dscr)
+		qce_setup_cmdlistptrs(pce_dev, &vaddr);
 	vaddr = (unsigned char *) ALIGN(((unsigned int)vaddr),
 					pce_dev->ce_sps.ce_burst_size);
 	pce_dev->ce_sps.result_dump = (uint32_t)vaddr;
@@ -2207,6 +2573,160 @@
 	return 0;
 }
 
+static int qce_init_ce_cfg_val(struct qce_device *pce_dev)
+{
+	uint32_t beats = (pce_dev->ce_sps.ce_burst_size >> 3) - 1;
+	uint32_t pipe_pair = pce_dev->ce_sps.pipe_pair_index;
+
+	pce_dev->reg.crypto_cfg_be = (beats << CRYPTO_REQ_SIZE) |
+		BIT(CRYPTO_MASK_DOUT_INTR) | BIT(CRYPTO_MASK_DIN_INTR) |
+		BIT(CRYPTO_MASK_OP_DONE_INTR) | (0 << CRYPTO_HIGH_SPD_EN_N) |
+		(pipe_pair << CRYPTO_PIPE_SET_SELECT);
+
+	pce_dev->reg.crypto_cfg_le =
+		(pce_dev->reg.crypto_cfg_be | CRYPTO_LITTLE_ENDIAN_MASK);
+
+	/* Initialize encr_cfg register for AES alg */
+	pce_dev->reg.encr_cfg_aes_cbc_128 =
+		(CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_aes_cbc_256 =
+		(CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_aes_ctr_128 =
+		(CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_CTR << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_aes_ctr_256 =
+		(CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_CTR << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_aes_xts_128 =
+		(CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_XTS << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_aes_xts_256 =
+		(CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_XTS << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_aes_ecb_128 =
+		(CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_aes_ecb_256 =
+		(CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_aes_ccm_128 =
+		(CRYPTO_ENCR_KEY_SZ_AES128 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		((CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE));
+
+	pce_dev->reg.encr_cfg_aes_ccm_256 =
+		(CRYPTO_ENCR_KEY_SZ_AES256 << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_AES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_CCM << CRYPTO_ENCR_MODE) |
+		(CRYPTO_LAST_CCM_XFR << CRYPTO_LAST_CCM);
+
+	/* Initialize encr_cfg register for DES alg */
+	pce_dev->reg.encr_cfg_des_ecb =
+		(CRYPTO_ENCR_KEY_SZ_DES << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_DES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_des_cbc =
+		(CRYPTO_ENCR_KEY_SZ_DES << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_DES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_3des_ecb =
+		(CRYPTO_ENCR_KEY_SZ_3DES << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_DES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
+
+	pce_dev->reg.encr_cfg_3des_cbc =
+		(CRYPTO_ENCR_KEY_SZ_3DES << CRYPTO_ENCR_KEY_SZ) |
+		(CRYPTO_ENCR_ALG_DES << CRYPTO_ENCR_ALG) |
+		(CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
+
+	/* Initialize auth_cfg register for CMAC alg */
+	pce_dev->reg.auth_cfg_cmac_128 =
+		(1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
+		(CRYPTO_AUTH_MODE_CMAC << CRYPTO_AUTH_MODE)|
+		(CRYPTO_AUTH_SIZE_ENUM_16_BYTES << CRYPTO_AUTH_SIZE) |
+		(CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
+		(CRYPTO_AUTH_KEY_SZ_AES128 << CRYPTO_AUTH_KEY_SIZE);
+
+	pce_dev->reg.auth_cfg_cmac_256 =
+		(1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
+		(CRYPTO_AUTH_MODE_CMAC << CRYPTO_AUTH_MODE)|
+		(CRYPTO_AUTH_SIZE_ENUM_16_BYTES << CRYPTO_AUTH_SIZE) |
+		(CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
+		(CRYPTO_AUTH_KEY_SZ_AES256 << CRYPTO_AUTH_KEY_SIZE);
+
+	/* Initialize auth_cfg register for HMAC alg */
+	pce_dev->reg.auth_cfg_hmac_sha1 =
+		(CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
+		(CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
+		(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+		(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+
+	pce_dev->reg.auth_cfg_hmac_sha256 =
+		(CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
+		(CRYPTO_AUTH_SIZE_SHA256 << CRYPTO_AUTH_SIZE) |
+		(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+		(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+
+	/* Initialize auth_cfg register for SHA1/256 alg */
+	pce_dev->reg.auth_cfg_sha1 =
+		(CRYPTO_AUTH_MODE_HASH << CRYPTO_AUTH_MODE)|
+		(CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
+		(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+		(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+
+	pce_dev->reg.auth_cfg_sha256 =
+		(CRYPTO_AUTH_MODE_HASH << CRYPTO_AUTH_MODE)|
+		(CRYPTO_AUTH_SIZE_SHA256 << CRYPTO_AUTH_SIZE) |
+		(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+		(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS);
+
+	/* Initialize auth_cfg register for AEAD alg */
+	pce_dev->reg.auth_cfg_aead_sha1_hmac =
+		(CRYPTO_AUTH_MODE_HMAC << CRYPTO_AUTH_MODE)|
+		(CRYPTO_AUTH_SIZE_SHA1 << CRYPTO_AUTH_SIZE) |
+		(CRYPTO_AUTH_ALG_SHA << CRYPTO_AUTH_ALG) |
+		(CRYPTO_AUTH_POS_BEFORE << CRYPTO_AUTH_POS) |
+		(1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST);
+
+	pce_dev->reg.auth_cfg_aes_ccm_128 =
+		(1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
+		(CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE)|
+		(CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
+		(CRYPTO_AUTH_KEY_SZ_AES128 << CRYPTO_AUTH_KEY_SIZE) |
+		((MAX_NONCE/sizeof(uint32_t)) << CRYPTO_AUTH_NONCE_NUM_WORDS);
+	pce_dev->reg.auth_cfg_aes_ccm_128 &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
+
+	pce_dev->reg.auth_cfg_aes_ccm_256 =
+		(1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
+		(CRYPTO_AUTH_MODE_CCM << CRYPTO_AUTH_MODE)|
+		(CRYPTO_AUTH_ALG_AES << CRYPTO_AUTH_ALG) |
+		(CRYPTO_AUTH_KEY_SZ_AES256 << CRYPTO_AUTH_KEY_SIZE) |
+		((MAX_NONCE/sizeof(uint32_t)) << CRYPTO_AUTH_NONCE_NUM_WORDS);
+	pce_dev->reg.auth_cfg_aes_ccm_256 &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
+
+	return 0;
+}
+
 int qce_aead_sha1_hmac_setup(struct qce_req *creq, struct crypto_aead *aead,
 				struct qce_cmdlist_info *cmdlistinfo)
 {
@@ -2301,10 +2821,16 @@
 		pce_dev->dst_nents = pce_dev->src_nents;
 	}
 
-	_ce_get_cipher_cmdlistinfo(pce_dev, q_req, &cmdlistinfo);
-	/* set up crypto device */
-	rc = _ce_setup_cipher(pce_dev, q_req, totallen_in,
-				areq->assoclen + ivsize, cmdlistinfo);
+	if (pce_dev->support_cmd_dscr) {
+		_ce_get_cipher_cmdlistinfo(pce_dev, q_req, &cmdlistinfo);
+		/* set up crypto device */
+		rc = _ce_setup_cipher(pce_dev, q_req, totallen_in,
+					areq->assoclen + ivsize, cmdlistinfo);
+	} else {
+		/* set up crypto device */
+		rc = _ce_setup_cipher_direct(pce_dev, q_req, totallen_in,
+					areq->assoclen + ivsize);
+	}
 	if (rc < 0)
 		goto bad;
 
@@ -2334,7 +2860,8 @@
 	}
 	_qce_sps_iovec_count_init(pce_dev);
 
-	_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
+	if (pce_dev->support_cmd_dscr)
+		_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
 					&pce_dev->ce_sps.in_transfer);
 
 	if (pce_dev->ce_sps.minor_version == 0) {
@@ -2445,7 +2972,6 @@
 
 	pce_dev->src_nents = 0;
 	pce_dev->dst_nents = 0;
-	_ce_get_cipher_cmdlistinfo(pce_dev, c_req, &cmdlistinfo);
 
 	/* cipher input */
 	pce_dev->src_nents = count_sg(areq->src, areq->nbytes);
@@ -2472,7 +2998,13 @@
 	}
 
 	/* set up crypto device */
-	rc = _ce_setup_cipher(pce_dev, c_req, areq->nbytes, 0, cmdlistinfo);
+	if (pce_dev->support_cmd_dscr) {
+		_ce_get_cipher_cmdlistinfo(pce_dev, c_req, &cmdlistinfo);
+		rc = _ce_setup_cipher(pce_dev, c_req, areq->nbytes, 0,
+							cmdlistinfo);
+	} else {
+		rc = _ce_setup_cipher_direct(pce_dev, c_req, areq->nbytes, 0);
+	}
 	if (rc < 0)
 		goto bad;
 
@@ -2491,8 +3023,8 @@
 		goto bad;
 	}
 	_qce_sps_iovec_count_init(pce_dev);
-
-	_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
+	if (pce_dev->support_cmd_dscr)
+		_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
 					&pce_dev->ce_sps.in_transfer);
 	if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
 					&pce_dev->ce_sps.in_transfer))
@@ -2547,10 +3079,15 @@
 	struct qce_cmdlist_info *cmdlistinfo = NULL;
 
 	pce_dev->src_nents = count_sg(sreq->src, sreq->size);
-	_ce_get_hash_cmdlistinfo(pce_dev, sreq, &cmdlistinfo);
 	qce_dma_map_sg(pce_dev->pdev, sreq->src, pce_dev->src_nents,
 							DMA_TO_DEVICE);
-	rc = _ce_setup_hash(pce_dev, sreq, cmdlistinfo);
+
+	if (pce_dev->support_cmd_dscr) {
+		_ce_get_hash_cmdlistinfo(pce_dev, sreq, &cmdlistinfo);
+		rc = _ce_setup_hash(pce_dev, sreq, cmdlistinfo);
+	} else {
+		rc = _ce_setup_hash_direct(pce_dev, sreq);
+	}
 	if (rc < 0)
 		goto bad;
 
@@ -2568,7 +3105,8 @@
 	}
 	_qce_sps_iovec_count_init(pce_dev);
 
-	_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
+	if (pce_dev->support_cmd_dscr)
+		_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
 					&pce_dev->ce_sps.in_transfer);
 	if (_qce_sps_add_sg_data(pce_dev, areq->src, areq->nbytes,
 						 &pce_dev->ce_sps.in_transfer))
@@ -2602,7 +3140,8 @@
 
 	pce_dev->is_shared = of_property_read_bool((&pdev->dev)->of_node,
 				"qcom,ce-hw-shared");
-
+	pce_dev->support_cmd_dscr = of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,ce-hw-support-cmd-dscr");
 	if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,bam-pipe-pair",
 				&pce_dev->ce_sps.pipe_pair_index)) {
@@ -2857,6 +3396,7 @@
 		goto err;
 	}
 	*rc = 0;
+	qce_init_ce_cfg_val(pce_dev);
 	qce_setup_ce_sps_data(pce_dev);
 	qce_sps_init(pce_dev);
 
diff --git a/drivers/crypto/msm/qce50.h b/drivers/crypto/msm/qce50.h
index f5123df..38515fb 100644
--- a/drivers/crypto/msm/qce50.h
+++ b/drivers/crypto/msm/qce50.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -109,6 +109,45 @@
 	struct qce_cmdlist_info unlock_all_pipes;
 };
 
+struct qce_ce_cfg_reg_setting {
+	uint32_t crypto_cfg_be;
+	uint32_t crypto_cfg_le;
+
+	uint32_t encr_cfg_aes_cbc_128;
+	uint32_t encr_cfg_aes_cbc_256;
+
+	uint32_t encr_cfg_aes_ecb_128;
+	uint32_t encr_cfg_aes_ecb_256;
+
+	uint32_t encr_cfg_aes_xts_128;
+	uint32_t encr_cfg_aes_xts_256;
+
+	uint32_t encr_cfg_aes_ctr_128;
+	uint32_t encr_cfg_aes_ctr_256;
+
+	uint32_t encr_cfg_aes_ccm_128;
+	uint32_t encr_cfg_aes_ccm_256;
+
+	uint32_t encr_cfg_des_cbc;
+	uint32_t encr_cfg_des_ecb;
+
+	uint32_t encr_cfg_3des_cbc;
+	uint32_t encr_cfg_3des_ecb;
+
+	uint32_t auth_cfg_cmac_128;
+	uint32_t auth_cfg_cmac_256;
+
+	uint32_t auth_cfg_sha1;
+	uint32_t auth_cfg_sha256;
+
+	uint32_t auth_cfg_hmac_sha1;
+	uint32_t auth_cfg_hmac_sha256;
+
+	uint32_t auth_cfg_aes_ccm_128;
+	uint32_t auth_cfg_aes_ccm_256;
+	uint32_t auth_cfg_aead_sha1_hmac;
+
+};
 
 /* DM data structure with buffers, commandlists & commmand pointer lists */
 struct ce_sps_data {
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index e91dcaa..7666e74 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1559,34 +1559,54 @@
 static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req,
 						struct qcedev_control *podev)
 {
+
+	if (req->encklen < 0) {
+		pr_err("%s: Invalid key size: %d\n", __func__, req->encklen);
+		return -EINVAL;
+	}
 	/* if intending to use HW key make sure key fields are set
 	 * correctly and HW key is indeed supported in target
 	 */
 	if (req->encklen == 0) {
 		int i;
-		for (i = 0; i < QCEDEV_MAX_KEY_SIZE; i++)
-			if (req->enckey[i])
+		for (i = 0; i < QCEDEV_MAX_KEY_SIZE; i++) {
+			if (req->enckey[i]) {
+				pr_err("%s: Invalid key: non-zero key input\n",
+								__func__);
 				goto error;
+			}
+		}
 		if ((req->op != QCEDEV_OPER_ENC_NO_KEY) &&
 			(req->op != QCEDEV_OPER_DEC_NO_KEY))
-			if (!podev->platform_support.hw_key_support)
+			if (!podev->platform_support.hw_key_support) {
+				pr_err("%s: Invalid op %d\n", __func__,
+						(uint32_t)req->op);
 				goto error;
+			}
 	} else {
 		if (req->encklen == QCEDEV_AES_KEY_192) {
-			if (!podev->ce_support.aes_key_192)
+			if (!podev->ce_support.aes_key_192) {
+				pr_err("%s: AES-192 not supported\n", __func__);
 				goto error;
+			}
 		} else {
 			/* if not using HW key make sure key
 			 * length is valid
 			 */
 			if ((req->mode == QCEDEV_AES_MODE_XTS)) {
-				if (!((req->encklen == QCEDEV_AES_KEY_128*2) ||
-					(req->encklen == QCEDEV_AES_KEY_256*2)))
+				if ((req->encklen != QCEDEV_AES_KEY_128*2) &&
+				(req->encklen != QCEDEV_AES_KEY_256*2)) {
+					pr_err("%s: unsupported key size: %d\n",
+							__func__, req->encklen);
 					goto error;
+				}
 			} else {
-				if (!((req->encklen == QCEDEV_AES_KEY_128) ||
-					(req->encklen == QCEDEV_AES_KEY_256)))
+				if ((req->encklen != QCEDEV_AES_KEY_128) &&
+					(req->encklen != QCEDEV_AES_KEY_256)) {
+					pr_err("%s: unsupported key size %d\n",
+							__func__, req->encklen);
 					goto error;
+				}
 			}
 		}
 	}
@@ -1602,32 +1622,48 @@
 		pr_err("%s: Use of PMEM is not supported\n", __func__);
 		goto error;
 	}
-	if ((req->entries == 0) || (req->data_len == 0))
+	if ((req->entries == 0) || (req->data_len == 0) ||
+			(req->entries > QCEDEV_MAX_BUFFERS)) {
+		pr_err("%s: Invalid cipher length/entries\n", __func__);
 		goto error;
+	}
 	if ((req->alg >= QCEDEV_ALG_LAST) ||
-		(req->mode >= QCEDEV_AES_DES_MODE_LAST))
+		(req->mode >= QCEDEV_AES_DES_MODE_LAST)) {
+		pr_err("%s: Invalid algorithm %d\n", __func__,
+						(uint32_t)req->alg);
 		goto error;
-
-	if ((req->mode == QCEDEV_AES_MODE_XTS) && (!podev->ce_support.aes_xts))
-					goto error;
-
-	if (req->alg == QCEDEV_ALG_AES)
+	}
+	if ((req->mode == QCEDEV_AES_MODE_XTS) &&
+				(!podev->ce_support.aes_xts)) {
+		pr_err("%s: XTS algorithm is not supported\n", __func__);
+		goto error;
+	}
+	if (req->alg == QCEDEV_ALG_AES) {
 		if (qcedev_check_cipher_key(req, podev))
-					goto error;
+			goto error;
+
+	}
 	/* if using a byteoffset, make sure it is CTR mode using vbuf */
 	if (req->byteoffset) {
-		if (req->mode != QCEDEV_AES_MODE_CTR)
+		if (req->mode != QCEDEV_AES_MODE_CTR) {
+			pr_err("%s: Operation on byte offset not supported\n",
+								 __func__);
 			goto error;
+		}
 	}
 	/* Ensure zer ivlen for ECB  mode  */
-	if (req->ivlen != 0) {
+	if (req->ivlen > 0) {
 		if ((req->mode == QCEDEV_AES_MODE_ECB) ||
-				(req->mode == QCEDEV_DES_MODE_ECB))
+				(req->mode == QCEDEV_DES_MODE_ECB)) {
+			pr_err("%s: Expecting a zero length IV\n", __func__);
 			goto error;
+		}
 	} else {
 		if ((req->mode != QCEDEV_AES_MODE_ECB) &&
-				(req->mode != QCEDEV_DES_MODE_ECB))
+				(req->mode != QCEDEV_DES_MODE_ECB)) {
+			pr_err("%s: Expecting a non-zero ength IV\n", __func__);
 			goto error;
+		}
 	}
 
 	return 0;
@@ -1640,20 +1676,42 @@
 						struct qcedev_control *podev)
 {
 	if ((req->alg == QCEDEV_ALG_AES_CMAC) &&
-				(!podev->ce_support.cmac))
+				(!podev->ce_support.cmac)) {
+		pr_err("%s: CMAC not supported\n", __func__);
 		goto sha_error;
-
-	if ((req->entries == 0) || (req->data_len == 0))
+	}
+	if ((req->entries == 0) || (req->data_len == 0) ||
+			(req->entries > QCEDEV_MAX_BUFFERS)) {
+		pr_err("%s: Invalid data length (%d)/ num entries (%d)\n",
+				__func__, req->data_len, req->entries);
 		goto sha_error;
+	}
 
-	if (req->alg >= QCEDEV_ALG_SHA_ALG_LAST)
+	if (req->alg >= QCEDEV_ALG_SHA_ALG_LAST) {
+		pr_err("%s: Invalid algorithm (%d)\n", __func__, req->alg);
 		goto sha_error;
-
+	}
 	if ((req->alg == QCEDEV_ALG_SHA1_HMAC) ||
 			(req->alg == QCEDEV_ALG_SHA1_HMAC)) {
-		if (req->authklen == 0)
+		if (req->authkey == NULL) {
+			pr_err("%s: Invalid authkey pointer\n", __func__);
 			goto sha_error;
+		}
+		if (req->authklen <= 0) {
+			pr_err("%s: Invalid authkey length (%d)\n",
+						__func__, req->authklen);
+			goto sha_error;
+		}
 	}
+
+	if (req->alg == QCEDEV_ALG_AES_CMAC) {
+		if ((req->authklen != QCEDEV_AES_KEY_128) &&
+					(req->authklen != QCEDEV_AES_KEY_256)) {
+			pr_err("%s: unsupported key length\n", __func__);
+			goto sha_error;
+		}
+	}
+
 	return 0;
 sha_error:
 	return -EINVAL;
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 4e9f55c..a44011f 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -25,7 +25,6 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/seq_file.h>
 #include "ion_priv.h"
 #include <mach/memory.h>
 #include <asm/cacheflush.h>
@@ -33,9 +32,6 @@
 #include <linux/dma-mapping.h>
 #include <trace/events/kmem.h>
 
-static atomic_t system_heap_allocated;
-static atomic_t system_contig_heap_allocated;
-
 static unsigned int high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO |
 					    __GFP_NOWARN | __GFP_NORETRY |
 					    __GFP_NO_KSWAPD) & ~__GFP_WAIT;
@@ -212,7 +208,6 @@
 	}
 
 	buffer->priv_virt = table;
-	atomic_add(size, &system_heap_allocated);
 	return 0;
 err1:
 	kfree(table);
@@ -246,7 +241,6 @@
 				get_order(sg_dma_len(sg)));
 	sg_free_table(table);
 	kfree(table);
-	atomic_sub(buffer->size, &system_heap_allocated);
 }
 
 struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap,
@@ -261,15 +255,6 @@
 	return;
 }
 
-static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s,
-				  const struct rb_root *unused)
-{
-	seq_printf(s, "total bytes currently allocated: %lx\n",
-			(unsigned long) atomic_read(&system_heap_allocated));
-
-	return 0;
-}
-
 static struct ion_heap_ops system_heap_ops = {
 	.allocate = ion_system_heap_allocate,
 	.free = ion_system_heap_free,
@@ -278,7 +263,6 @@
 	.map_kernel = ion_heap_map_kernel,
 	.unmap_kernel = ion_heap_unmap_kernel,
 	.map_user = ion_heap_map_user,
-	.print_debug = ion_system_print_debug,
 };
 
 struct ion_heap *ion_system_heap_create(struct ion_platform_heap *pheap)
@@ -340,14 +324,12 @@
 	buffer->priv_virt = kzalloc(len, GFP_KERNEL);
 	if (!buffer->priv_virt)
 		return -ENOMEM;
-	atomic_add(len, &system_contig_heap_allocated);
 	return 0;
 }
 
 void ion_system_contig_heap_free(struct ion_buffer *buffer)
 {
 	kfree(buffer->priv_virt);
-	atomic_sub(buffer->size, &system_contig_heap_allocated);
 }
 
 static int ion_system_contig_heap_phys(struct ion_heap *heap,
@@ -385,44 +367,6 @@
 	kfree(buffer->sg_table);
 }
 
-int ion_system_contig_heap_map_user(struct ion_heap *heap,
-				    struct ion_buffer *buffer,
-				    struct vm_area_struct *vma)
-{
-	unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt));
-
-	if (ION_IS_CACHED(buffer->flags))
-		return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
-			       vma->vm_end - vma->vm_start,
-			       vma->vm_page_prot);
-	else {
-		pr_err("%s: cannot map system heap uncached\n", __func__);
-		return -EINVAL;
-	}
-}
-
-static int ion_system_contig_print_debug(struct ion_heap *heap,
-					 struct seq_file *s,
-					 const struct rb_root *unused)
-{
-	seq_printf(s, "total bytes currently allocated: %lx\n",
-		(unsigned long) atomic_read(&system_contig_heap_allocated));
-
-	return 0;
-}
-
-void *ion_system_contig_heap_map_kernel(struct ion_heap *heap,
-	struct ion_buffer *buffer)
-{
-	return buffer->priv_virt;
-}
-
-void ion_system_contig_heap_unmap_kernel(struct ion_heap *heap,
-	struct ion_buffer *buffer)
-{
-	return;
-}
-
 static struct ion_heap_ops kmalloc_ops = {
 	.allocate = ion_system_contig_heap_allocate,
 	.free = ion_system_contig_heap_free,
@@ -431,8 +375,7 @@
 	.unmap_dma = ion_system_contig_heap_unmap_dma,
 	.map_kernel = ion_heap_map_kernel,
 	.unmap_kernel = ion_heap_unmap_kernel,
-	.map_user = ion_system_contig_heap_map_user,
-	.print_debug = ion_system_contig_print_debug,
+	.map_user = ion_heap_map_user,
 };
 
 struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *pheap)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 60bab32..08791a3 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -810,8 +810,10 @@
 	int num_iommu_units;
 	struct kgsl_context *context;
 	struct adreno_context *adreno_ctx = NULL;
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 
-	if (!adreno_dev->drawctxt_active) {
+	if (!adreno_dev->drawctxt_active ||
+		KGSL_STATE_ACTIVE != device->state) {
 		kgsl_mmu_device_setstate(&device->mmu, flags);
 		return;
 	}
@@ -863,12 +865,9 @@
 	 */
 	adreno_ringbuffer_issuecmds(device, adreno_ctx, KGSL_CMD_FLAGS_PMODE,
 			&link[0], sizedwords);
-	/* timestamp based clock gating is currently unstable on iommuv1 */
-	if (msm_soc_version_supports_iommu_v0()) {
-		struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
-		kgsl_mmu_disable_clk_on_ts(&device->mmu,
-			rb->timestamp[KGSL_MEMSTORE_GLOBAL], true);
-	}
+
+	kgsl_mmu_disable_clk_on_ts(&device->mmu,
+		rb->timestamp[KGSL_MEMSTORE_GLOBAL], true);
 
 	kgsl_context_put(context);
 }
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index a76ed87..967e4ab 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -785,13 +785,13 @@
 
 			struct kgsl_memdesc *memdesc =
 				adreno_find_ctxtmem(device, ptbase, ibaddr,
-					ibsize);
+					ibsize << 2);
 
 			/* IOMMU uses a NOP IB placed in setsate memory */
 			if (NULL == memdesc)
 				if (kgsl_gpuaddr_in_memdesc(
 						&device->mmu.setstate_memory,
-						ibaddr, ibsize))
+						ibaddr, ibsize << 2))
 					memdesc = &device->mmu.setstate_memory;
 			/*
 			 * The IB from CP_IB1_BASE and the IBs for legacy
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index 6dc2ccc..ef2a19a 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -363,9 +363,11 @@
 
 	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
 		kgsl_cffdump_memory_base(device->id,
-			kgsl_mmu_get_base_addr(&device->mmu),
-			kgsl_mmu_get_ptsize(&device->mmu) +
-			KGSL_IOMMU_GLOBAL_MEM_SIZE, adreno_dev->gmem_size);
+			KGSL_PAGETABLE_BASE,
+			KGSL_IOMMU_GLOBAL_MEM_BASE +
+			KGSL_IOMMU_GLOBAL_MEM_SIZE -
+			KGSL_PAGETABLE_BASE,
+			adreno_dev->gmem_size);
 	} else {
 		kgsl_cffdump_memory_base(device->id,
 			kgsl_mmu_get_base_addr(&device->mmu),
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 15f35c9..869ab25 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -46,7 +46,7 @@
 	{ 0x03C, 1 },			/* TLBLKCR */
 	{ 0x818, 1 },			/* V2PUR */
 	{ 0x2C, 1 },			/* FSYNR0 */
-	{ 0x2C, 1 },			/* FSYNR0 */
+	{ 0x30, 1 },			/* FSYNR1 */
 	{ 0, 0 },			/* TLBSYNC, not in v0 */
 	{ 0, 0 },			/* TLBSTATUS, not in v0 */
 	{ 0, 0 }			/* IMPLDEF_MICRO_MMU_CRTL, not in v0 */
@@ -390,18 +390,20 @@
 	kgsl_sharedmem_readl(&device->memstore, &curr_context_id,
 		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context));
 	context = idr_find(&device->context_idr, curr_context_id);
-	if (context != NULL)
+	if (context != NULL) {
 			curr_context = context->devctxt;
 
-	kgsl_sharedmem_readl(&device->memstore, &curr_global_ts,
-		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, eoptimestamp));
+		kgsl_sharedmem_readl(&device->memstore, &curr_global_ts,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp));
 
-	/*
-	 * Store pagefault's timestamp in adreno context,
-	 * this information will be used in GFT
-	 */
-	curr_context->pagefault = 1;
-	curr_context->pagefault_ts = curr_global_ts;
+		/*
+		 * Store pagefault's timestamp in adreno context,
+		 * this information will be used in GFT
+		 */
+		curr_context->pagefault = 1;
+		curr_context->pagefault_ts = curr_global_ts;
+	}
 
 	trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
 			kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
@@ -624,8 +626,10 @@
 {
 	struct kgsl_iommu_pt *iommu_pt = pt->priv;
 	if (iommu_pt->domain)
-		iommu_domain_free(iommu_pt->domain);
+		msm_unregister_domain(iommu_pt->domain);
+
 	kfree(iommu_pt);
+	iommu_pt = NULL;
 }
 
 /*
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index b3b5643..0fab4d1 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -373,7 +373,7 @@
 {
 	struct qpnp_vadc_linear_graph btm_param;
 	int64_t low_output = 0, high_output = 0;
-	int rc = 0;
+	int rc = 0, sign = 0;
 
 	rc = qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_ABSOLUTE);
 	if (rc < 0) {
@@ -384,19 +384,36 @@
 	/* Convert to Kelvin and account for voltage to be written as 2mV/K */
 	low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
 	/* Convert to voltage threshold */
-	low_output *= btm_param.dy;
-	do_div(low_output, btm_param.adc_vref);
+	low_output = (low_output - QPNP_ADC_625_UV) * btm_param.dy;
+	if (low_output < 0) {
+		sign = 1;
+		low_output = -low_output;
+	}
+	do_div(low_output, QPNP_ADC_625_UV);
+	if (sign)
+		low_output = -low_output;
 	low_output += btm_param.adc_gnd;
 
+	sign = 0;
 	/* Convert to Kelvin and account for voltage to be written as 2mV/K */
 	high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
 	/* Convert to voltage threshold */
-	high_output *= btm_param.dy;
-	do_div(high_output, btm_param.adc_vref);
+	high_output = (high_output - QPNP_ADC_625_UV) * btm_param.dy;
+	if (high_output < 0) {
+		sign = 1;
+		high_output = -high_output;
+	}
+	do_div(high_output, QPNP_ADC_625_UV);
+	if (sign)
+		high_output = -high_output;
 	high_output += btm_param.adc_gnd;
 
-	*low_threshold = low_output;
-	*high_threshold = high_output;
+	*low_threshold = (uint32_t) low_output;
+	*high_threshold = (uint32_t) high_output;
+	pr_debug("high_temp:%d, low_temp:%d\n", param->high_temp,
+				param->low_temp);
+	pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
+				*low_threshold);
 
 	return 0;
 }
@@ -637,7 +654,7 @@
 		uint32_t *low_threshold, uint32_t *high_threshold)
 {
 	struct qpnp_vadc_linear_graph vbatt_param;
-	int rc = 0;
+	int rc = 0, sign = 0;
 	int64_t low_thr = 0, high_thr = 0;
 
 	rc = qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
@@ -646,12 +663,25 @@
 
 	low_thr = (((param->low_thr/3) - QPNP_ADC_625_UV) *
 				vbatt_param.dy);
+	if (low_thr < 0) {
+		sign = 1;
+		low_thr = -low_thr;
+	}
 	do_div(low_thr, QPNP_ADC_625_UV);
+	if (sign)
+		low_thr = -low_thr;
 	*low_threshold = low_thr + vbatt_param.adc_gnd;
 
+	sign = 0;
 	high_thr = (((param->high_thr/3) - QPNP_ADC_625_UV) *
 				vbatt_param.dy);
+	if (high_thr < 0) {
+		sign = 1;
+		high_thr = -high_thr;
+	}
 	do_div(high_thr, QPNP_ADC_625_UV);
+	if (sign)
+		high_thr = -high_thr;
 	*high_threshold = high_thr + vbatt_param.adc_gnd;
 
 	pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
@@ -877,8 +907,6 @@
 
 	init_completion(&adc_qpnp->adc_rslt_completion);
 
-	mutex_init(&adc_qpnp->adc_lock);
-
 	return 0;
 }
 EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 66811bf..275291f 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -830,6 +830,8 @@
 		goto fail;
 	}
 
+	mutex_init(&iadc->adc->adc_lock);
+
 	rc = of_property_read_u32(node, "qcom,rsense",
 			&iadc->rsense);
 	if (rc)
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index d296a47..68cff09 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -982,6 +982,7 @@
 		dev_err(&spmi->dev, "failed to read device tree\n");
 		goto fail;
 	}
+	mutex_init(&vadc->adc->adc_lock);
 
 	rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
 				qpnp_vadc_isr, IRQF_TRIGGER_RISING,
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 4e2b1a4..4a021e1 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -103,6 +103,10 @@
 
 static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data);
 
+#ifdef CONFIG_PM
+static int synaptics_rmi4_suspend(struct device *dev);
+
+static int synaptics_rmi4_resume(struct device *dev);
 #ifdef CONFIG_HAS_EARLYSUSPEND
 static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
 		struct device_attribute *attr, char *buf);
@@ -113,10 +117,7 @@
 static void synaptics_rmi4_early_suspend(struct early_suspend *h);
 
 static void synaptics_rmi4_late_resume(struct early_suspend *h);
-
-static int synaptics_rmi4_suspend(struct device *dev);
-
-static int synaptics_rmi4_resume(struct device *dev);
+#endif
 #endif
 
 static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
@@ -1838,7 +1839,7 @@
 				RMI4_VTG_MIN_UV, RMI4_VTG_MAX_UV);
 			if (retval) {
 				dev_err(&rmi4_data->i2c_client->dev,
-					"regulator set_vtg failed retval=%d\n",
+					"regulator set_vtg failed retval =%d\n",
 					retval);
 				goto err_set_vtg_vdd;
 			}
@@ -1861,7 +1862,7 @@
 				RMI4_I2C_VTG_MIN_UV, RMI4_I2C_VTG_MAX_UV);
 			if (retval) {
 				dev_err(&rmi4_data->i2c_client->dev,
-					"reg set i2c vtg failed retval=%d\n",
+					"reg set i2c vtg failed retval =%d\n",
 					retval);
 			goto err_set_vtg_i2c;
 			}
@@ -2492,6 +2493,75 @@
 }
 #endif
 
+static int synaptics_rmi4_regulator_lpm(struct synaptics_rmi4_data *rmi4_data,
+						bool on)
+{
+	int retval;
+
+	if (on == false)
+		goto regulator_hpm;
+
+	retval = reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
+	if (retval < 0) {
+		dev_err(&rmi4_data->i2c_client->dev,
+			"Regulator vcc_ana set_opt failed rc=%d\n",
+			retval);
+		goto fail_regulator_lpm;
+	}
+
+	if (rmi4_data->board->i2c_pull_up) {
+		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+			RMI4_I2C_LOAD_UA);
+		if (retval < 0) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"Regulator vcc_i2c set_opt failed rc=%d\n",
+				retval);
+			goto fail_regulator_lpm;
+		}
+	}
+
+	return 0;
+
+regulator_hpm:
+
+	retval = reg_set_optimum_mode_check(rmi4_data->vdd,
+				RMI4_ACTIVE_LOAD_UA);
+	if (retval < 0) {
+		dev_err(&rmi4_data->i2c_client->dev,
+			"Regulator vcc_ana set_opt failed rc=%d\n",
+			retval);
+		goto fail_regulator_hpm;
+	}
+
+	if (rmi4_data->board->i2c_pull_up) {
+		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+			RMI4_I2C_LOAD_UA);
+		if (retval < 0) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"Regulator vcc_i2c set_opt failed rc=%d\n",
+				retval);
+			goto fail_regulator_hpm;
+		}
+	}
+
+	return 0;
+
+fail_regulator_lpm:
+	reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_ACTIVE_LOAD_UA);
+	if (rmi4_data->board->i2c_pull_up)
+		reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+						RMI4_I2C_LOAD_UA);
+
+	return retval;
+
+fail_regulator_hpm:
+	reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
+	if (rmi4_data->board->i2c_pull_up)
+		reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+						RMI4_I2C_LPM_LOAD_UA);
+	return retval;
+}
+
  /**
  * synaptics_rmi4_suspend()
  *
@@ -2505,6 +2575,7 @@
 static int synaptics_rmi4_suspend(struct device *dev)
 {
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+	int retval;
 
 	if (!rmi4_data->sensor_sleep) {
 		rmi4_data->touch_stopped = true;
@@ -2513,6 +2584,12 @@
 		synaptics_rmi4_sensor_sleep(rmi4_data);
 	}
 
+	retval = synaptics_rmi4_regulator_lpm(rmi4_data, true);
+	if (retval < 0) {
+		dev_err(dev, "failed to enter low power mode\n");
+		return retval;
+	}
+
 	return 0;
 }
 
@@ -2529,6 +2606,13 @@
 static int synaptics_rmi4_resume(struct device *dev)
 {
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+	int retval;
+
+	retval = synaptics_rmi4_regulator_lpm(rmi4_data, false);
+	if (retval < 0) {
+		dev_err(dev, "failed to enter active power mode\n");
+		return retval;
+	}
 
 	synaptics_rmi4_sensor_wake(rmi4_data);
 	rmi4_data->touch_stopped = false;
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 8a26003..8e68beb 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -804,6 +804,19 @@
 	ctx_drvdata = dev_get_drvdata(&pdev->dev);
 	BUG_ON(!ctx_drvdata);
 
+	if (!drvdata->ctx_attach_count) {
+		pr_err("Unexpected IOMMU page fault!\n");
+		pr_err("name = %s\n", drvdata->name);
+		pr_err("Power is OFF. Unable to read page fault information\n");
+		/*
+		 * We cannot determine which context bank caused the issue so
+		 * we just return handled here to ensure IRQ handler code is
+		 * happy
+		 */
+		ret = IRQ_HANDLED;
+		goto fail;
+	}
+
 	ret = __enable_clocks(drvdata);
 	if (ret) {
 		ret = IRQ_NONE;
diff --git a/drivers/iommu/msm_iommu_pagetable.c b/drivers/iommu/msm_iommu_pagetable.c
index 9614692..b871a5a 100644
--- a/drivers/iommu/msm_iommu_pagetable.c
+++ b/drivers/iommu/msm_iommu_pagetable.c
@@ -21,6 +21,7 @@
 
 #include <mach/iommu.h>
 #include <mach/msm_iommu_priv.h>
+#include <trace/events/kmem.h>
 #include "msm_iommu_pagetable.h"
 
 /* Sharability attributes of MSM IOMMU mappings */
@@ -471,6 +472,8 @@
 			chunk_size = SZ_1M;
 		/* 64k or 4k determined later */
 
+		trace_iommu_map_range(va, pa, sg->length, chunk_size);
+
 		/* for 1M and 16M, only first level entries are required */
 		if (chunk_size >= SZ_1M) {
 			if (chunk_size == SZ_16M) {
@@ -529,6 +532,9 @@
 			else
 				chunk_size = SZ_4K;
 
+			trace_iommu_map_range(va, pa, sg->length,
+							chunk_size);
+
 			if (chunk_size == SZ_4K) {
 				sl_4k(&sl_table[sl_offset], pa, pgprot4k);
 				sl_offset++;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 3667296..5d5ff43 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -180,6 +180,20 @@
 #define LED_MPP_EN_DISABLE		0x00
 
 #define MPP_SOURCE_DTEST1		0x08
+
+#define KPDBL_MAX_LEVEL			LED_FULL
+#define KPDBL_ROW_SRC_SEL(base)		(base + 0x40)
+#define KPDBL_ENABLE(base)		(base + 0x46)
+#define KPDBL_ROW_SRC(base)		(base + 0xE5)
+
+#define KPDBL_ROW_SRC_SEL_VAL_MASK	0x0F
+#define KPDBL_ROW_SCAN_EN_MASK		0x80
+#define KPDBL_ROW_SCAN_VAL_MASK		0x0F
+#define KPDBL_ROW_SCAN_EN_SHIFT		7
+#define KPDBL_MODULE_EN			0x80
+#define KPDBL_MODULE_DIS		0x00
+#define KPDBL_MODULE_EN_MASK		0x80
+
 /**
  * enum qpnp_leds - QPNP supported led ids
  * @QPNP_ID_WLED - White led backlight
@@ -192,6 +206,7 @@
 	QPNP_ID_RGB_GREEN,
 	QPNP_ID_RGB_BLUE,
 	QPNP_ID_LED_MPP,
+	QPNP_ID_KPDBL,
 	QPNP_ID_MAX,
 };
 
@@ -237,9 +252,9 @@
 	DELAY_128us,
 };
 
-enum rgb_mode {
-	RGB_MODE_PWM = 0,
-	RGB_MODE_LPG,
+enum led_mode {
+	PWM_MODE = 0,
+	LPG_MODE,
 };
 
 static u8 wled_debug_regs[] = {
@@ -267,6 +282,10 @@
 	0x40, 0x41, 0x42, 0x45, 0x46, 0x4c,
 };
 
+static u8 kpdbl_debug_regs[] = {
+	0x40, 0x46, 0xb1, 0xb3, 0xb4, 0xe5,
+};
+
 /**
  *  wled_config_data - wled configuration data
  *  @num_strings - number of wled strings supported
@@ -331,6 +350,25 @@
 };
 
 /**
+ *  kpdbl_config_data - kpdbl configuration data
+ *  @pwm_device - pwm device
+ *  @pwm_channel - pwm channel to be configured for led
+ *  @pwm_period_us - period for pwm, in us
+ *  @row_src_sel_val - select source, 0 for vph_pwr and 1 for vbst
+ *  @row_scan_en - enable row scan
+ *  @row_scan_val - map to enable needed rows
+ */
+struct kpdbl_config_data {
+	struct pwm_device	*pwm_dev;
+	int	pwm_channel;
+	u32	pwm_period_us;
+	u32	row_src_sel_val;
+	u32	row_scan_en;
+	u32	row_scan_val;
+	u8	mode;
+};
+
+/**
  *  rgb_config_data - rgb configuration data
  *  @lut_params - lut parameters to be used by pwm driver
  *  @pwm_device - pwm device
@@ -372,6 +410,7 @@
 	spinlock_t		lock;
 	struct wled_config_data *wled_cfg;
 	struct flash_config_data	*flash_cfg;
+	struct kpdbl_config_data	*kpdbl_cfg;
 	struct rgb_config_data	*rgb_cfg;
 	struct mpp_config_data	*mpp_cfg;
 	int			max_current;
@@ -414,7 +453,8 @@
 					led->spmi_dev->sid,
 					led->base + regs[i],
 					&val, sizeof(val));
-		pr_debug("0x%x = 0x%x\n", led->base + regs[i], val);
+		pr_debug("%s: 0x%x = 0x%x\n", led->cdev.name,
+					led->base + regs[i], val);
 	}
 	pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
 }
@@ -770,20 +810,57 @@
 	return 0;
 }
 
+static int qpnp_kpdbl_set(struct qpnp_led_data *led)
+{
+	int duty_us;
+	int rc;
+
+	if (led->cdev.brightness) {
+		rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
+				KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
+		duty_us = (led->kpdbl_cfg->pwm_period_us *
+			led->cdev.brightness) / KPDBL_MAX_LEVEL;
+		rc = pwm_config(led->kpdbl_cfg->pwm_dev, duty_us,
+				led->kpdbl_cfg->pwm_period_us);
+		if (rc < 0) {
+			dev_err(&led->spmi_dev->dev, "pwm config failed\n");
+			return rc;
+		}
+		rc = pwm_enable(led->kpdbl_cfg->pwm_dev);
+		if (rc < 0) {
+			dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
+			return rc;
+		}
+	} else {
+		pwm_disable(led->kpdbl_cfg->pwm_dev);
+		rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
+				KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Failed to write led enable reg\n");
+			return rc;
+		}
+	}
+
+	qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
+
+	return 0;
+}
+
 static int qpnp_rgb_set(struct qpnp_led_data *led)
 {
 	int duty_us;
 	int rc;
 
 	if (led->cdev.brightness) {
-		if (led->rgb_cfg->mode == RGB_MODE_PWM) {
+		if (led->rgb_cfg->mode == PWM_MODE) {
 			duty_us = (led->rgb_cfg->pwm_period_us *
 				led->cdev.brightness) / LED_FULL;
 			rc = pwm_config(led->rgb_cfg->pwm_dev, duty_us,
 					led->rgb_cfg->pwm_period_us);
 			if (rc < 0) {
-				dev_err(&led->spmi_dev->dev, "Failed to " \
-					"configure pwm for new values\n");
+				dev_err(&led->spmi_dev->dev,
+					"pwm config failed\n");
 				return rc;
 			}
 		}
@@ -796,6 +873,10 @@
 			return rc;
 		}
 		rc = pwm_enable(led->rgb_cfg->pwm_dev);
+		if (rc < 0) {
+			dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
+			return rc;
+		}
 	} else {
 		pwm_disable(led->rgb_cfg->pwm_dev);
 		rc = qpnp_led_masked_write(led,
@@ -855,6 +936,11 @@
 		if (rc < 0)
 			dev_err(&led->spmi_dev->dev,
 					"MPP set brightness failed (%d)\n", rc);
+	case QPNP_ID_KPDBL:
+		rc = qpnp_kpdbl_set(led);
+		if (rc < 0)
+			dev_err(&led->spmi_dev->dev,
+				"KPDBL set brightness failed (%d)\n", rc);
 		break;
 	default:
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
@@ -881,6 +967,9 @@
 	case QPNP_ID_LED_MPP:
 		led->cdev.max_brightness = MPP_MAX_LEVEL;
 		break;
+	case QPNP_ID_KPDBL:
+		led->cdev.max_brightness = KPDBL_MAX_LEVEL;
+		break;
 	default:
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
 		return -EINVAL;
@@ -1226,6 +1315,81 @@
 	return 0;
 }
 
+static int __devinit qpnp_kpdbl_init(struct qpnp_led_data *led)
+{
+	int rc;
+	u8 val;
+
+	/* enable row source selct */
+	rc = qpnp_led_masked_write(led, KPDBL_ROW_SRC_SEL(led->base),
+		KPDBL_ROW_SRC_SEL_VAL_MASK, led->kpdbl_cfg->row_src_sel_val);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Enable row src sel write failed(%d)\n", rc);
+		return rc;
+	}
+
+	/* row source */
+	rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+				KPDBL_ROW_SRC(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Unable to read from addr=%x, rc(%d)\n",
+			KPDBL_ROW_SRC(led->base), rc);
+		return rc;
+	}
+
+	val &= ~KPDBL_ROW_SCAN_VAL_MASK;
+	val |= led->kpdbl_cfg->row_scan_val;
+
+	led->kpdbl_cfg->row_scan_en <<= KPDBL_ROW_SCAN_EN_SHIFT;
+	val &= ~KPDBL_ROW_SCAN_EN_MASK;
+	val |= led->kpdbl_cfg->row_scan_en;
+
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		KPDBL_ROW_SRC(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Unable to write to addr=%x, rc(%d)\n",
+			KPDBL_ROW_SRC(led->base), rc);
+		return rc;
+	}
+
+	/* enable module */
+	rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
+		KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Enable module write failed(%d)\n", rc);
+		return rc;
+	}
+
+	if (led->kpdbl_cfg->pwm_channel != -1) {
+		led->kpdbl_cfg->pwm_dev =
+			pwm_request(led->kpdbl_cfg->pwm_channel,
+						led->cdev.name);
+
+		if (IS_ERR_OR_NULL(led->kpdbl_cfg->pwm_dev)) {
+			dev_err(&led->spmi_dev->dev,
+				"could not acquire PWM Channel %d, " \
+				"error %ld\n",
+				led->kpdbl_cfg->pwm_channel,
+				PTR_ERR(led->kpdbl_cfg->pwm_dev));
+			led->kpdbl_cfg->pwm_dev = NULL;
+			return -ENODEV;
+		}
+	} else {
+		dev_err(&led->spmi_dev->dev,
+			"Invalid PWM channel\n");
+		return -EINVAL;
+	}
+
+	/* dump kpdbl registers */
+	qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
+
+	return 0;
+}
+
 static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
 {
 	int rc, start_idx, idx_len;
@@ -1253,7 +1417,7 @@
 			return -ENODEV;
 		}
 
-		if (led->rgb_cfg->mode == RGB_MODE_LPG) {
+		if (led->rgb_cfg->mode == LPG_MODE) {
 			start_idx =
 			led->rgb_cfg->duty_cycles->start_idx;
 			idx_len =
@@ -1296,7 +1460,7 @@
 
 static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
 {
-	int rc;
+	int rc = 0;
 
 	switch (led->id) {
 	case QPNP_ID_WLED:
@@ -1322,12 +1486,18 @@
 		break;
 	case QPNP_ID_LED_MPP:
 		break;
+	case QPNP_ID_KPDBL:
+		rc = qpnp_kpdbl_init(led);
+		if (rc)
+			dev_err(&led->spmi_dev->dev,
+				"KPDBL initialize failed(%d)\n", rc);
+		break;
 	default:
 		dev_err(&led->spmi_dev->dev, "Invalid LED(%d)\n", led->id);
 		return -EINVAL;
 	}
 
-	return 0;
+	return rc;
 }
 
 static int __devinit qpnp_get_common_configs(struct qpnp_led_data *led,
@@ -1512,6 +1682,63 @@
 	return 0;
 }
 
+static int __devinit qpnp_get_config_kpdbl(struct qpnp_led_data *led,
+				struct device_node *node)
+{
+	int rc;
+	u32 val;
+
+	led->kpdbl_cfg = devm_kzalloc(&led->spmi_dev->dev,
+				sizeof(struct kpdbl_config_data), GFP_KERNEL);
+	if (!led->kpdbl_cfg) {
+		dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32(node, "qcom,mode", &val);
+	if (!rc)
+		led->kpdbl_cfg->mode = (u8) val;
+	else
+		return rc;
+
+	if (led->kpdbl_cfg->mode == LPG_MODE) {
+		dev_err(&led->spmi_dev->dev, "LPG mode not supported\n");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
+	if (!rc)
+		led->kpdbl_cfg->pwm_channel = (u8) val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,pwm-us", &val);
+	if (!rc)
+		led->kpdbl_cfg->pwm_period_us = val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,row-src-sel-val", &val);
+	if (!rc)
+		led->kpdbl_cfg->row_src_sel_val = val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,row-scan-val", &val);
+	if (!rc)
+		led->kpdbl_cfg->row_scan_val = val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,row-scan-en", &val);
+	if (!rc)
+		led->kpdbl_cfg->row_scan_en = val;
+	else
+		return rc;
+
+	return 0;
+}
+
 static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
 				struct device_node *node)
 {
@@ -1548,7 +1775,7 @@
 	else
 		return rc;
 
-	if (led->rgb_cfg->mode == RGB_MODE_PWM) {
+	if (led->rgb_cfg->mode == PWM_MODE) {
 		rc = of_property_read_u32(node, "qcom,pwm-us", &val);
 		if (!rc)
 			led->rgb_cfg->pwm_period_us = val;
@@ -1556,7 +1783,7 @@
 			return rc;
 	}
 
-	if (led->rgb_cfg->mode == RGB_MODE_LPG) {
+	if (led->rgb_cfg->mode == LPG_MODE) {
 		led->rgb_cfg->duty_cycles =
 			devm_kzalloc(&led->spmi_dev->dev,
 			sizeof(struct pwm_duty_cycles), GFP_KERNEL);
@@ -1791,6 +2018,12 @@
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
 						"Unable to read mpp config data\n");
+			}
+		} else if (strncmp(led_label, "kpdbl", sizeof("kpdbl")) == 0) {
+			rc = qpnp_get_config_kpdbl(led, temp);
+			if (rc < 0) {
+				dev_err(&led->spmi_dev->dev,
+					"Unable to read kpdbl config data\n");
 				goto fail_id_check;
 			}
 		} else {
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 71087d9..4579cee 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -595,13 +595,18 @@
 	struct v4l2_event event;
 	struct msm_video_device *pvdev = video_drvdata(filep);
 	struct camera_v4l2_private *sp = fh_to_private(filep->private_data);
-
 	BUG_ON(!pvdev);
 
 	atomic_sub_return(1, &pvdev->opened);
 
 	if (atomic_read(&pvdev->opened) == 0) {
 
+		camera_pack_event(filep, MSM_CAMERA_SET_PARM,
+			MSM_CAMERA_PRIV_DEL_STREAM, -1, &event);
+
+		/* Donot wait, imaging server may have crashed */
+		msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
+
 		camera_pack_event(filep, MSM_CAMERA_DEL_SESSION, 0, -1, &event);
 
 		/* Donot wait, imaging server may have crashed */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 04afec0..8ea1a00 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -287,13 +287,15 @@
 					bufq->buf_client_count)
 					list_del_init(
 					&temp_buf_info->share_list);
-				if (temp_buf_info->buf_reuse_flag)
+				if (temp_buf_info->buf_reuse_flag) {
 					kfree(temp_buf_info);
-				else
+				} else {
 					*buf_info = temp_buf_info;
+					rc = 0;
+				}
 				spin_unlock_irqrestore(
 					&bufq->bufq_lock, flags);
-				return 0;
+				return rc;
 			}
 		}
 	}
@@ -342,6 +344,7 @@
 			(*buf_info)->buf_used[id] = 1;
 			(*buf_info)->buf_get_count = 1;
 			(*buf_info)->buf_put_count = 0;
+			(*buf_info)->buf_reuse_flag = 0;
 			list_add_tail(&(*buf_info)->share_list,
 						  &bufq->share_head);
 		}
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 9f1c81a..be9f613 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -661,6 +661,7 @@
 			rc = -ETIMEDOUT;
 		}
 		if (rc < 0) {
+			pr_err("%s: rc = %d\n", __func__, rc);
 			mutex_unlock(&session->lock);
 			return rc;
 		}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
index 7dbbc03..e30e798 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
@@ -122,7 +122,7 @@
 				rc = PTR_ERR(clk_ptr[i]);
 				goto cam_clk_get_err;
 			}
-			if (clk_info[i].clk_rate >= 0) {
+			if (clk_info[i].clk_rate > 0) {
 				rc = clk_set_rate(clk_ptr[i],
 							clk_info[i].clk_rate);
 				if (rc < 0) {
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index f458a0a..1611a09 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1143,6 +1143,11 @@
 			goto exit;
 		}
 		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		/* Clients rely on this event for joining poll thread.
+		 * This event should be returned even if firmware has
+		 * failed to respond */
+		dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 		break;
 	default:
 		dprintk(VIDC_ERR, "Unknown Decoder Command\n");
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 5f47ae1..66a3b6e 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -20,6 +20,7 @@
 
 #define MSM_VENC_DVC_NAME "msm_venc_8974"
 #define MIN_NUM_OUTPUT_BUFFERS 4
+#define MIN_NUM_CAPTURE_BUFFERS 4
 #define MIN_BIT_RATE 64000
 #define MAX_BIT_RATE 160000000
 #define DEFAULT_BIT_RATE 64000
@@ -777,16 +778,21 @@
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		*num_planes = 1;
 		buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
-		*num_buffers = buff_req->buffer_count_actual =
+		if (buff_req) {
+			*num_buffers = buff_req->buffer_count_actual =
 			max(*num_buffers, buff_req->buffer_count_actual);
-			if (*num_buffers > VIDEO_MAX_FRAME) {
-				dprintk(VIDC_ERR,
+		}
+		if (*num_buffers < MIN_NUM_CAPTURE_BUFFERS)
+			*num_buffers = MIN_NUM_CAPTURE_BUFFERS;
+
+		if (*num_buffers > VIDEO_MAX_FRAME) {
+			dprintk(VIDC_ERR,
 					"Failed : No of slices requested = %d"\
 					" Max supported slices = %d",
 					*num_buffers, VIDEO_MAX_FRAME);
-				rc = -EINVAL;
-				break;
-			}
+			rc = -EINVAL;
+			break;
+		}
 		ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
 				V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
 		if (ctrl)
@@ -1899,6 +1905,11 @@
 			dprintk(VIDC_ERR, "Failed to release persist buf:%d\n",
 				rc);
 		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		/* Clients rely on this event for joining poll thread.
+		 * This event should be returned even if firmware has
+		 * failed to respond */
+		dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 		break;
 	}
 	if (rc)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 1ee9c67..feb239e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -582,7 +582,6 @@
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
-		queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_CLOSE_DONE);
 		inst->session = NULL;
 		show_stats(inst);
 	} else {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index ed4f317..b96a6dc 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -219,6 +219,9 @@
 	}
 	queue->qhdr_write_idx = new_write_idx;
 	*rx_req_is_set = (1 == queue->qhdr_rx_req) ? 1 : 0;
+	/*Memory barrier to make sure data is written before an
+	 * interupt is raised on venus.*/
+	mb();
 	dprintk(VIDC_DBG, "Out : ");
 	return 0;
 }
@@ -282,6 +285,7 @@
 	u32 packet_size_in_words, new_read_idx;
 	u32 *read_ptr;
 	struct vidc_iface_q_info *qinfo;
+	int rc = 0;
 
 	if (!info || !packet || !pb_tx_req_is_set) {
 		dprintk(VIDC_ERR, "Invalid Params");
@@ -293,6 +297,9 @@
 		dprintk(VIDC_WARN, "Queues have already been freed\n");
 		return -EINVAL;
 	}
+	/*Memory barrier to make sure data is valid before
+	 *reading it*/
+	mb();
 	queue = (struct hfi_queue_header *) qinfo->q_hdr;
 
 	if (!queue) {
@@ -317,17 +324,27 @@
 
 	new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
 	dprintk(VIDC_DBG, "Read Ptr: %d", (u32) new_read_idx);
-	if (new_read_idx < queue->qhdr_q_size) {
-		memcpy(packet, read_ptr,
-			packet_size_in_words << 2);
-	} else {
-		new_read_idx -= queue->qhdr_q_size;
-		memcpy(packet, read_ptr,
+	if (((packet_size_in_words << 2) <= VIDC_IFACEQ_MED_PKT_SIZE)
+			&& queue->qhdr_read_idx <= queue->qhdr_q_size) {
+		if (new_read_idx < queue->qhdr_q_size) {
+			memcpy(packet, read_ptr,
+					packet_size_in_words << 2);
+		} else {
+			new_read_idx -= queue->qhdr_q_size;
+			memcpy(packet, read_ptr,
 			(packet_size_in_words - new_read_idx) << 2);
-		memcpy(packet + ((packet_size_in_words -
-			new_read_idx) << 2),
-			(u8 *)qinfo->q_array.align_virtual_addr,
-			new_read_idx << 2);
+			memcpy(packet + ((packet_size_in_words -
+					new_read_idx) << 2),
+					(u8 *)qinfo->q_array.align_virtual_addr,
+					new_read_idx << 2);
+		}
+	} else {
+		dprintk(VIDC_WARN,
+			"BAD packet received, read_idx: 0x%x, pkt_size: %d\n",
+			queue->qhdr_read_idx, packet_size_in_words << 2);
+		dprintk(VIDC_WARN, "Dropping this packet\n");
+		new_read_idx = queue->qhdr_write_idx;
+		rc = -ENODATA;
 	}
 
 	queue->qhdr_read_idx = new_read_idx;
@@ -340,7 +357,7 @@
 	*pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
 	venus_hfi_hal_sim_modify_msg_packet(packet);
 	dprintk(VIDC_DBG, "Out : ");
-	return 0;
+	return rc;
 }
 
 static int venus_hfi_alloc(void *mem, void *clnt, u32 size, u32 align,
@@ -1072,7 +1089,6 @@
 		if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
 			disable_irq_nosync(dev->hal_data->irq);
 		dev->intr_status = 0;
-		venus_hfi_interface_queues_release(dev);
 		mutex_unlock(&dev->clock_lock);
 	}
 	dprintk(VIDC_INFO, "HAL exited\n");
@@ -2783,6 +2799,7 @@
 		flush_workqueue(device->vidc_workq);
 		venus_hfi_disable_clks(device);
 		subsystem_put(device->resources.fw.cookie);
+		venus_hfi_interface_queues_release(dev);
 		venus_hfi_iommu_detach(device);
 		device->resources.fw.cookie = NULL;
 	}
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 111131a..5efd905 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -304,9 +304,11 @@
 			pr_warn("%s: status1 : %s\n", __func__, linebuf);
 		}
 
-		memset(status, 0, num_irq_regs);
-		wcd9xxx_bulk_write(wcd9xxx, WCD9XXX_A_INTR_STATUS0,
+		memset(status, 0xff, num_irq_regs);
+		wcd9xxx_bulk_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0,
 				   num_irq_regs, status);
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
 	}
 	wcd9xxx_unlock_sleep(wcd9xxx);
 
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index cb036dd..15e36a8 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -38,6 +38,7 @@
 #include <linux/dma-mapping.h>
 #include <mach/gpio.h>
 #include <mach/msm_bus.h>
+#include <linux/iopoll.h>
 
 #include "sdhci-pltfm.h"
 
@@ -81,6 +82,31 @@
 #define CORE_CLK_PWRSAVE	(1 << 1)
 #define CORE_IO_PAD_PWR_SWITCH	(1 << 16)
 
+#define CORE_MCI_DATA_CTRL	0x2C
+#define CORE_MCI_DPSM_ENABLE	(1 << 0)
+
+#define CORE_TESTBUS_CONFIG	0x0CC
+#define CORE_TESTBUS_ENA	(1 << 3)
+#define CORE_TESTBUS_SEL2	(1 << 4)
+
+/*
+ * Waiting until end of potential AHB access for data:
+ * 16 AHB cycles (160ns for 100MHz and 320ns for 50MHz) +
+ * delay on AHB (2us) = maximum 2.32us
+ * Taking x10 times margin
+ */
+#define CORE_AHB_DATA_DELAY_US  23
+/* Waiting until end of potential AHB access for descriptor:
+ * Single (1 AHB cycle) + delay on AHB bus = max 2us
+ * INCR4 (4 AHB cycles) + delay on AHB bus = max 2us
+ * Single (1 AHB cycle) + delay on AHB bus = max 2us
+ * Total 8 us delay with margin
+ */
+#define CORE_AHB_DESC_DELAY_US  8
+
+#define CORE_SDCC_DEBUG_REG	0x124
+#define CORE_DEBUG_REG_AHB_HTRANS       (3 << 12)
+
 /* 8KB descriptors */
 #define SDHCI_MSM_MAX_SEGMENTS  (1 << 13)
 #define SDHCI_MSM_MMC_CLK_GATE_DELAY	200 /* msecs */
@@ -2044,6 +2070,51 @@
 	return 0;
 }
 
+/*
+ * sdhci_msm_disable_data_xfer - disable undergoing AHB bus data transfer
+ *
+ * Write 0 to bit 0 in MCI_DATA_CTL (offset 0x2C) - clearing TxActive bit by
+ * access to legacy registers. It will stop current burst and prevent start of
+ * the next on.
+ *
+ * Polling CORE_AHB_DATA_DELAY_US timeout, by reading bit 13:12 until they are 0
+ * in CORE_SDCC_DEBUG_REG (offset 0x124) will validate that AHB burst was
+ * completed and a new one didn't start.
+ *
+ * Waiting for 4us while AHB finishes descriptors fetch.
+ */
+static void sdhci_msm_disable_data_xfer(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	u32 value;
+	int ret;
+
+	value = readl_relaxed(msm_host->core_mem + CORE_MCI_DATA_CTRL);
+	value &= ~(u32)CORE_MCI_DPSM_ENABLE;
+	writel_relaxed(value, msm_host->core_mem + CORE_MCI_DATA_CTRL);
+
+	/* Enable the test bus for device slot */
+	writel_relaxed(CORE_TESTBUS_ENA | CORE_TESTBUS_SEL2,
+			msm_host->core_mem + CORE_TESTBUS_CONFIG);
+
+	ret = readl_poll_timeout_noirq(msm_host->core_mem
+			+ CORE_SDCC_DEBUG_REG, value,
+			!(value & CORE_DEBUG_REG_AHB_HTRANS),
+			CORE_AHB_DATA_DELAY_US, 1);
+	if (ret) {
+		pr_err("%s: %s: can't stop ongoing AHB bus access by ADMA\n",
+				mmc_hostname(host->mmc), __func__);
+		BUG();
+	}
+	/* Disable the test bus for device slot */
+	value = readl_relaxed(msm_host->core_mem + CORE_TESTBUS_CONFIG);
+	value &= ~CORE_TESTBUS_ENA;
+	writel_relaxed(value, msm_host->core_mem + CORE_TESTBUS_CONFIG);
+
+	udelay(CORE_AHB_DESC_DELAY_US);
+}
+
 static struct sdhci_ops sdhci_msm_ops = {
 	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
 	.check_power_status = sdhci_msm_check_power_status,
@@ -2054,6 +2125,7 @@
 	.platform_bus_voting = sdhci_msm_bus_voting,
 	.get_min_clock = sdhci_msm_get_min_clock,
 	.get_max_clock = sdhci_msm_get_max_clock,
+	.disable_data_xfer = sdhci_msm_disable_data_xfer,
 };
 
 static int __devinit sdhci_msm_probe(struct platform_device *pdev)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0549b4a..3efea77 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2126,7 +2126,49 @@
 
 static int sdhci_stop_request(struct mmc_host *mmc)
 {
-	return -ENOSYS;
+	struct sdhci_host *host = mmc_priv(mmc);
+	unsigned long flags;
+	struct mmc_data *data;
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (!host->mrq || !host->data)
+		goto out;
+
+	data = host->data;
+
+	if (host->ops->disable_data_xfer)
+		host->ops->disable_data_xfer(host);
+
+	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+	if (host->flags & SDHCI_REQ_USE_DMA) {
+		if (host->flags & SDHCI_USE_ADMA) {
+			sdhci_adma_table_post(host, data);
+		} else {
+			if (!data->host_cookie)
+				dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+					     data->sg_len,
+					     (data->flags & MMC_DATA_READ) ?
+					     DMA_FROM_DEVICE : DMA_TO_DEVICE);
+		}
+	}
+	del_timer(&host->timer);
+	host->mrq = NULL;
+	host->cmd = NULL;
+	host->data = NULL;
+out:
+	spin_unlock_irqrestore(&host->lock, flags);
+	return 0;
+}
+
+static unsigned int sdhci_get_xfer_remain(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	u32 present_state = 0;
+
+	present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+
+	return present_state & SDHCI_DOING_WRITE;
 }
 
 static const struct mmc_host_ops sdhci_ops = {
@@ -2143,6 +2185,7 @@
 	.enable		= sdhci_enable,
 	.disable	= sdhci_disable,
 	.stop_request = sdhci_stop_request,
+	.get_xfer_remain = sdhci_get_xfer_remain,
 };
 
 /*****************************************************************************\
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c6bef8a..a3d8442 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -286,6 +286,7 @@
 	void	(*toggle_cdr)(struct sdhci_host *host, bool enable);
 	unsigned int	(*get_max_segments)(void);
 	void	(*platform_bus_voting)(struct sdhci_host *host, u32 enable);
+	void    (*disable_data_xfer)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 570c257..0b04bbf 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -691,9 +691,9 @@
 
 	/* Lookup the 'APPS' partition's first page address */
 	for (i = 0; i < FLASH_PTABLE_MAX_PARTS_V4; i++) {
-		if (!strncmp("apps", ptable.part_entry[i].name,
-				strlen(ptable.part_entry[i].name))) {
-			page_address = ptable.part_entry[i].offset << 6;
+		if (!strncmp("apps", mtd_part[i].name,
+				strlen(mtd_part[i].name))) {
+			page_address = mtd_part[i].offset << 6;
 			break;
 		}
 	}
@@ -1458,7 +1458,7 @@
 	int ret;
 	struct mtd_oob_ops ops;
 
-	ops.mode = MTD_OPS_PLACE_OOB;
+	ops.mode = MTD_OPS_AUTO_OOB;
 	ops.len = len;
 	ops.retlen = 0;
 	ops.ooblen = 0;
@@ -1643,7 +1643,7 @@
 	int ret;
 	struct mtd_oob_ops ops;
 
-	ops.mode = MTD_OPS_PLACE_OOB;
+	ops.mode = MTD_OPS_AUTO_OOB;
 	ops.len = len;
 	ops.retlen = 0;
 	ops.ooblen = 0;
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 891ff5b..8f90ddc 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -195,6 +195,8 @@
 	NULL_CHECK(ecm_ipa_rx_dp_notify);
 	NULL_CHECK(ecm_ipa_tx_dp_notify);
 	NULL_CHECK(priv);
+	pr_debug("rx_cb=0x%p, tx_cb=0x%p priv=0x%p\n",
+			ecm_ipa_rx_dp_notify, ecm_ipa_tx_dp_notify, *priv);
 	net = alloc_etherdev(sizeof(struct ecm_ipa_dev));
 	if (!net) {
 		ret = -ENOMEM;
@@ -416,8 +418,8 @@
 	NULL_CHECK(dev);
 	net = dev->net;
 	NULL_CHECK(net);
-	pr_debug("host_ethaddr=%pM device_ethaddr=%pM\n",
-					host_ethaddr, device_ethaddr);
+	pr_debug("priv=0x%p, host_ethaddr=%pM device_ethaddr=%pM\n",
+					priv, host_ethaddr, device_ethaddr);
 	result = ecm_ipa_create_rm_resource(dev);
 	if (result) {
 		ECM_IPA_ERROR("fail on RM create\n");
@@ -468,8 +470,8 @@
 	struct ecm_ipa_dev *dev = priv;
 	ECM_IPA_LOG_ENTRY();
 	NULL_CHECK(priv);
-	pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d\n",
-					usb_to_ipa_hdl, ipa_to_usb_hdl);
+	pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d, priv=0x%p\n",
+					usb_to_ipa_hdl, ipa_to_usb_hdl, priv);
 	if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
 		ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
 				usb_to_ipa_hdl);
@@ -498,6 +500,7 @@
 	struct ecm_ipa_dev *dev = priv;
 	ECM_IPA_LOG_ENTRY();
 	NULL_CHECK(dev);
+	pr_debug("priv=0x%p\n", priv);
 	netif_carrier_off(dev->net);
 	ECM_IPA_LOG_EXIT();
 	return 0;
@@ -618,6 +621,7 @@
 {
 	struct ecm_ipa_dev *dev = priv;
 	ECM_IPA_LOG_ENTRY();
+	pr_debug("priv=0x%p\n", priv);
 	if (!dev) {
 		ECM_IPA_ERROR("dev NULL pointer\n");
 		return;
@@ -626,10 +630,9 @@
 	ecm_ipa_destory_rm_resource(dev);
 	ecm_ipa_debugfs_destroy(dev);
 
-	if (!dev->net) {
-		unregister_netdev(dev->net);
-		free_netdev(dev->net);
-	}
+	unregister_netdev(dev->net);
+	free_netdev(dev->net);
+
 	pr_debug("cleanup done\n");
 	ecm_ipa_ctx = NULL;
 	ECM_IPA_LOG_EXIT();
@@ -694,9 +697,6 @@
 		goto resource_busy;
 	}
 
-	pr_debug("Before sending packet the outstanding packets counter is %d\n",
-				atomic_read(&dev->outstanding_pkts));
-
 	if (atomic_read(&dev->outstanding_pkts) >= dev->outstanding_high) {
 		pr_debug("Outstanding high boundary reached (%d)- stopping queue\n",
 				dev->outstanding_high);
@@ -795,8 +795,6 @@
 				dev->outstanding_low);
 		netif_wake_queue(dev->net);
 	}
-	pr_debug("After Tx-complete the outstanding packets counter is %d\n",
-				atomic_read(&dev->outstanding_pkts));
 
 	dev_kfree_skb_any(skb);
 	return;
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 0970505..5f0ba94 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -214,7 +214,7 @@
 #if defined(CONFIG_MICROBLAZE)
 	dev->archdata.dma_mask = 0xffffffffUL;
 #endif
-	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	dev->dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
 	dev->dev.bus = &platform_bus_type;
 	dev->dev.platform_data = platform_data;
 
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 52c523e..442d18f 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -319,6 +319,7 @@
 #define QPNP_ENABLE_LUT_CONTROL		qpnp_set_control(0, 0, 0, 0, 1)
 #define QPNP_ENABLE_PWM_CONTROL		qpnp_set_control(0, 0, 0, 1, 0)
 #define QPNP_ENABLE_PWM_MODE		qpnp_set_control(1, 1, 1, 1, 0)
+#define QPNP_ENABLE_PWM_MODE_GPLED_CHANNEL	qpnp_set_control(1, 1, 1, 1, 1)
 #define QPNP_ENABLE_LPG_MODE		qpnp_set_control(1, 1, 1, 0, 1)
 #define QPNP_DISABLE_PWM_MODE		qpnp_set_control(0, 0, 0, 1, 0)
 #define QPNP_DISABLE_LPG_MODE		qpnp_set_control(0, 0, 0, 0, 1)
@@ -908,6 +909,17 @@
 
 }
 
+#define QPNP_GPLED_LPG_CHANNEL_RANGE_START 8
+#define QPNP_GPLED_LPG_CHANNEL_RANGE_END 11
+
+static inline int qpnp_enable_pwm_mode(struct qpnp_pwm_config *pwm_conf)
+{
+	if (pwm_conf->channel_id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START ||
+		pwm_conf->channel_id <= QPNP_GPLED_LPG_CHANNEL_RANGE_END)
+		return QPNP_ENABLE_PWM_MODE_GPLED_CHANNEL;
+	return QPNP_ENABLE_PWM_MODE;
+}
+
 static int qpnp_lpg_configure_pwm_state(struct pwm_device *pwm,
 					enum qpnp_pwm_state state)
 {
@@ -917,7 +929,7 @@
 	int			rc;
 
 	if (state == QPNP_PWM_ENABLE)
-		value = QPNP_ENABLE_PWM_MODE;
+		value = qpnp_enable_pwm_mode(&pwm->pwm_config);
 	else
 		value = QPNP_DISABLE_PWM_MODE;
 
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 1d0fb5d..2d1b763 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -27,9 +27,11 @@
 #include <linux/workqueue.h>
 #include <linux/dma-mapping.h>
 #include <mach/msm_smsm.h>
+#include <linux/pm_runtime.h>
 
 #define USB_THRESHOLD 512
 #define USB_BAM_MAX_STR_LEN 50
+#define USB_BAM_TIMEOUT (10*HZ)
 
 enum usb_bam_sm {
 	USB_BAM_SM_INIT = 0,
@@ -73,6 +75,11 @@
 *	handle/device of the sps driver.
 * @pipes_enabled_per_bam: This array stores for each BAM
 *	("ssusb", "hsusb" or "hsic") the number of pipes currently enabled.
+* @inactivity_timer_ms: The timeout configuration per each bam for inactivity
+*	timer feature.
+* @is_bam_inactivity: Is there no activity on all pipes belongs to a
+*	specific bam. (no activity = no data is pulled or pushed
+*	from/into ones of the pipes).
 */
 struct usb_bam_ctx_type {
 	struct usb_bam_sps_type usb_bam_sps;
@@ -85,19 +92,61 @@
 	char qdss_core_name[USB_BAM_MAX_STR_LEN];
 	u32 h_bam[MAX_BAMS];
 	u8 pipes_enabled_per_bam[MAX_BAMS];
+	u32 inactivity_timer_ms[MAX_BAMS];
+	bool is_bam_inactivity[MAX_BAMS];
 };
 
-static char *bam_enable_strings[3] = {
+static char *bam_enable_strings[MAX_BAMS] = {
 	[SSUSB_BAM] = "ssusb",
 	[HSUSB_BAM] = "hsusb",
 	[HSIC_BAM]  = "hsic",
 };
 
-static spinlock_t usb_bam_lock;
+static enum usb_bam ipa_rm_bams[] = {HSUSB_BAM, HSIC_BAM};
+
+static enum ipa_client_type ipa_rm_resource_prod[MAX_BAMS] = {
+	[HSUSB_BAM] = IPA_RM_RESOURCE_USB_PROD,
+	[HSIC_BAM]  = IPA_RM_RESOURCE_HSIC_PROD,
+};
+
+static enum ipa_client_type ipa_rm_resource_cons[MAX_BAMS] = {
+	[HSUSB_BAM] = IPA_RM_RESOURCE_USB_CONS,
+	[HSIC_BAM]  = IPA_RM_RESOURCE_HSIC_CONS,
+};
+
+static int usb_cons_request_resource(void);
+static int usb_cons_release_resource(void);
+static int hsic_cons_request_resource(void);
+static int hsic_cons_release_resource(void);
+
+static int (*request_resource_cb[MAX_BAMS])(void) = {
+	[HSUSB_BAM] = usb_cons_request_resource,
+	[HSIC_BAM]  = hsic_cons_request_resource,
+};
+
+static int (*release_resource_cb[MAX_BAMS])(void)  = {
+	[HSUSB_BAM] = usb_cons_release_resource,
+	[HSIC_BAM]  = hsic_cons_release_resource,
+};
+
+static enum ipa_rm_event cur_prod_state[MAX_BAMS];
+static enum ipa_rm_event cur_cons_state[MAX_BAMS];
+static int sched_lpm;
+static int lpm_wait_handshake;
+static struct completion prod_avail[MAX_BAMS];
+static struct completion cons_avail[MAX_BAMS];
+static struct completion cons_released[MAX_BAMS];
+static struct completion prod_released[MAX_BAMS];
+
+static spinlock_t usb_bam_peer_handshake_info_lock;
 static struct usb_bam_peer_handshake_info peer_handshake_info;
+static spinlock_t usb_bam_lock; /* Protect ctx and usb_bam_connections */
 static struct usb_bam_pipe_connect *usb_bam_connections;
 static struct usb_bam_ctx_type ctx;
 
+static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
+	void *param, bool trigger_cb_per_pipe);
+
 static int get_bam_type_from_core_name(const char *name)
 {
 	if (strnstr(name, bam_enable_strings[SSUSB_BAM],
@@ -128,6 +177,42 @@
 	return false;
 }
 
+static void usb_bam_set_inactivity_timer(enum usb_bam bam)
+{
+	struct sps_timer_ctrl timer_ctrl;
+	struct usb_bam_pipe_connect *pipe_connect;
+	struct sps_pipe *pipe = NULL;
+	int i;
+
+	/*
+	 * Since we configure global incativity timer for all pipes
+	 * and not per each pipe, it is enough to use some pipe
+	 * handle associated with this bam, so just find the first one.
+	 * This pipe handle is required due to SPS driver API we use below.
+	 */
+	for (i = 0; i < ctx.max_connections; i++) {
+		pipe_connect = &usb_bam_connections[i];
+		if (pipe_connect->bam_type == bam) {
+			pipe = ctx.usb_bam_sps.sps_pipes[i];
+			break;
+		}
+	}
+
+	if (!pipe) {
+		pr_err("%s: Bam %s has no pipes\n", __func__,
+			bam_enable_strings[bam]);
+		return;
+	}
+
+	timer_ctrl.op = SPS_TIMER_OP_CONFIG;
+	timer_ctrl.mode = SPS_TIMER_MODE_ONESHOT;
+	timer_ctrl.timeout_msec = ctx.inactivity_timer_ms[bam];
+	sps_timer_ctrl(pipe, &timer_ctrl, NULL);
+
+	timer_ctrl.op = SPS_TIMER_OP_RESET;
+	sps_timer_ctrl(pipe, &timer_ctrl, NULL);
+}
+
 static int connect_pipe(u8 idx, u32 *usb_pipe_idx)
 {
 	int ret, ram1_value;
@@ -281,6 +366,7 @@
 		pr_err("%s: sps_connect failed %d\n", __func__, ret);
 		goto error;
 	}
+
 	return 0;
 
 error:
@@ -323,6 +409,10 @@
 		return ret;
 	}
 
+	pipe_connect->activity_notify = ipa_params->activity_notify;
+	pipe_connect->inactivity_notify = ipa_params->inactivity_notify;
+	pipe_connect->priv = ipa_params->priv;
+
 	/* IPA input parameters */
 	ipa_in_params.client_bam_hdl = usb_handle;
 	ipa_in_params.desc_fifo_sz = pipe_connect->desc_fifo_size;
@@ -395,6 +485,7 @@
 			__func__,
 			pipe_connect->src_pipe_index,
 			pipe_connect->dst_pipe_index);
+		sps_connection->options = SPS_O_NO_DISABLE;
 	} else {
 		/* IPA src, USB dest */
 		sps_connection->mode = SPS_MODE_DEST;
@@ -409,12 +500,13 @@
 			__func__,
 			pipe_connect->src_pipe_index,
 			pipe_connect->dst_pipe_index);
+		sps_connection->options = 0;
 	}
 
 	sps_connection->data = sps_out_params.data;
 	sps_connection->desc = sps_out_params.desc;
 	sps_connection->event_thresh = 16;
-	sps_connection->options = SPS_O_AUTO_ENABLE;
+	sps_connection->options |= SPS_O_AUTO_ENABLE;
 
 	ret = sps_connect(*pipe, sps_connection);
 	if (ret < 0) {
@@ -422,6 +514,16 @@
 		goto error;
 	}
 
+	spin_lock(&usb_bam_lock);
+
+	/* Set global inactivity timer upon first pipe connection */
+	if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0 &&
+		ctx.inactivity_timer_ms[pipe_connect->bam_type] &&
+		pipe_connect->inactivity_notify)
+		usb_bam_set_inactivity_timer(pipe_connect->bam_type);
+
+	spin_unlock(&usb_bam_lock);
+
 	return 0;
 
 error:
@@ -505,6 +607,8 @@
 		return -EINVAL;
 	}
 
+	spin_lock(&usb_bam_lock);
+
 	/* Check if BAM requires RESET before connect and reset of first pipe */
 	if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
 	    (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
@@ -513,24 +617,34 @@
 	ret = connect_pipe(idx, bam_pipe_idx);
 	if (ret) {
 		pr_err("%s: pipe connection[%d] failure\n", __func__, idx);
+		spin_unlock(&usb_bam_lock);
 		return ret;
 	}
 
 	pipe_connect->enabled = 1;
 	ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
 
+	spin_unlock(&usb_bam_lock);
 	return 0;
 }
 
 static void usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
 	unsigned long data)
 {
+	enum usb_bam *cur_bam = (void *)user_data;
+
 	switch (event) {
 	case IPA_RM_RESOURCE_GRANTED:
-		pr_debug("USB_PROD resource granted\n");
+		pr_debug("%s: %s_PROD resource granted\n",
+			__func__, bam_enable_strings[*cur_bam]);
+		cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
+		complete_all(&prod_avail[*cur_bam]);
 		break;
 	case IPA_RM_RESOURCE_RELEASED:
-		pr_debug("USB_PROD resource released\n");
+		pr_debug("%s: %s_PROD resource released\n",
+			__func__, bam_enable_strings[*cur_bam]);
+		cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
+		complete_all(&prod_released[*cur_bam]);
 		break;
 	default:
 		break;
@@ -538,50 +652,130 @@
 	return;
 }
 
+static int cons_request_resource(enum usb_bam cur_bam)
+{
+	pr_debug("%s: Request %s_CONS resource\n",
+			__func__, bam_enable_strings[cur_bam]);
+
+	cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+	complete_all(&cons_avail[cur_bam]);
+
+	if (ctx.pipes_enabled_per_bam[cur_bam])
+		return 0;
+
+	return -EINPROGRESS;
+}
+
 static int usb_cons_request_resource(void)
 {
-	pr_debug(": Requesting USB_CONS resource\n");
-	return 0;
+	return cons_request_resource(HSUSB_BAM);
+}
+
+static int hsic_cons_request_resource(void)
+{
+	return cons_request_resource(HSIC_BAM);
+}
+
+static int cons_release_resource(enum usb_bam cur_bam)
+{
+	pr_debug("%s: Release %s_CONS resource\n",
+			__func__, bam_enable_strings[cur_bam]);
+
+	cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+	complete_all(&cons_released[cur_bam]);
+
+	if (!ctx.pipes_enabled_per_bam[cur_bam])
+		return 0;
+
+	return -EINPROGRESS;
+}
+
+static int hsic_cons_release_resource(void)
+{
+	return cons_release_resource(HSIC_BAM);
 }
 
 static int usb_cons_release_resource(void)
 {
-	pr_debug(": Releasing USB_CONS resource\n");
-	return 0;
+	return cons_release_resource(HSUSB_BAM);
 }
 
 static void usb_bam_ipa_create_resources(void)
 {
 	struct ipa_rm_create_params usb_prod_create_params;
 	struct ipa_rm_create_params usb_cons_create_params;
+	enum usb_bam cur_bam;
+	int ret, i;
+
+	for (i = 0; i < ARRAY_SIZE(ipa_rm_bams); i++) {
+		/* Create USB/HSIC_PROD entity */
+		cur_bam = ipa_rm_bams[i];
+
+		memset(&usb_prod_create_params, 0,
+					sizeof(usb_prod_create_params));
+		usb_prod_create_params.name = ipa_rm_resource_prod[cur_bam];
+		usb_prod_create_params.reg_params.notify_cb =
+							usb_prod_notify_cb;
+		usb_prod_create_params.reg_params.user_data = &ipa_rm_bams[i];
+		ret = ipa_rm_create_resource(&usb_prod_create_params);
+		if (ret) {
+			pr_err("%s: Failed to create USB_PROD resource\n",
+								__func__);
+			return;
+		}
+
+		/* Create USB_CONS entity */
+		memset(&usb_cons_create_params, 0,
+					sizeof(usb_cons_create_params));
+		usb_cons_create_params.name = ipa_rm_resource_cons[cur_bam];
+		usb_cons_create_params.request_resource =
+						request_resource_cb[cur_bam];
+		usb_cons_create_params.release_resource =
+						release_resource_cb[cur_bam];
+		ret = ipa_rm_create_resource(&usb_cons_create_params);
+		if (ret) {
+			pr_err("%s: Failed to create USB_CONS resource\n",
+								__func__);
+			return ;
+		}
+	}
+}
+
+static void wait_for_prod_granted(enum usb_bam cur_bam)
+{
 	int ret;
 
-	/* Create USB_PROD entity */
-	memset(&usb_prod_create_params, 0, sizeof(usb_prod_create_params));
-	usb_prod_create_params.name = IPA_RM_RESOURCE_USB_PROD;
-	usb_prod_create_params.reg_params.notify_cb = usb_prod_notify_cb;
-	usb_prod_create_params.reg_params.user_data = NULL;
-	ret = ipa_rm_create_resource(&usb_prod_create_params);
-	if (ret) {
-		pr_err("%s: Failed to create USB_PROD resource\n", __func__);
-		return;
-	}
+	pr_debug("%s Request %s_PROD_RES\n", __func__,
+		bam_enable_strings[cur_bam]);
+	if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+		pr_debug("%s: CONS already granted for some reason\n",
+			__func__);
+	if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+		pr_debug("%s: PROD already granted for some reason\n",
+			__func__);
 
-	/* Create USB_CONS entity */
-	memset(&usb_cons_create_params, 0, sizeof(usb_cons_create_params));
-	usb_cons_create_params.name = IPA_RM_RESOURCE_USB_CONS;
-	usb_cons_create_params.request_resource = usb_cons_request_resource;
-	usb_cons_create_params.release_resource = usb_cons_release_resource;
-	ret = ipa_rm_create_resource(&usb_cons_create_params);
-	if (ret) {
-		pr_err("%s: Failed to create USB_CONS resource\n", __func__);
-		return ;
-	}
+	init_completion(&prod_avail[cur_bam]);
+	init_completion(&cons_avail[cur_bam]);
+
+	ret = ipa_rm_request_resource(ipa_rm_resource_prod[cur_bam]);
+	if (!ret) {
+		cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+		complete_all(&prod_avail[cur_bam]);
+		pr_debug("%s: PROD_GRANTED without wait\n", __func__);
+	} else if (ret == -EINPROGRESS) {
+		pr_debug("%s: Waiting for PROD_GRANTED\n", __func__);
+		if (!wait_for_completion_timeout(&prod_avail[cur_bam],
+			USB_BAM_TIMEOUT))
+			pr_err("%s: Timeout wainting for PROD_GRANTED\n",
+				__func__);
+	} else
+		pr_err("%s: ipa_rm_request_resource ret =%d\n", __func__, ret);
 }
 
 int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
 {
 	u8 idx;
+	enum usb_bam cur_bam;
 	struct usb_bam_pipe_connect *pipe_connect;
 	int ret;
 	struct msm_usb_bam_platform_data *pdata =
@@ -604,6 +798,14 @@
 		return -EINVAL;
 	}
 	pipe_connect = &usb_bam_connections[idx];
+	cur_bam = pipe_connect->bam_type;
+
+	if (cur_bam == HSUSB_BAM) {
+		spin_lock(&usb_bam_lock);
+		sched_lpm = 0;
+		lpm_wait_handshake = 1;
+		spin_unlock(&usb_bam_lock);
+	}
 
 	if (pipe_connect->enabled) {
 		pr_debug("%s: connection %d was already established\n",
@@ -611,21 +813,40 @@
 		return 0;
 	}
 
-	/* Check if BAM requires RESET before connect and reset of first pipe */
-	if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
-	    (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
-		sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
+	spin_lock(&usb_bam_lock);
+
+	 /* Check if BAM requires RESET before connect and reset first pipe */
+	 if ((pdata->reset_on_connect[cur_bam] == true) &&
+		 (ctx.pipes_enabled_per_bam[cur_bam] == 0))
+			sps_device_reset(ctx.h_bam[cur_bam]);
+
+	spin_unlock(&usb_bam_lock);
+
+	if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
+		pr_debug("%s: Starting connect sequence\n", __func__);
+		wait_for_prod_granted(cur_bam);
+	}
 
 	ret = connect_pipe_ipa(idx, ipa_params);
-	ipa_rm_request_resource(IPA_RM_RESOURCE_USB_PROD);
-
 	if (ret) {
-		pr_err("%s: dst pipe connection failure\n", __func__);
+		pr_err("%s: pipe connection failure\n", __func__);
 		return ret;
 	}
 
+	spin_lock(&usb_bam_lock);
+
 	pipe_connect->enabled = 1;
-	ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
+	ctx.pipes_enabled_per_bam[cur_bam] += 1;
+
+	if (ipa_params->dir == PEER_PERIPHERAL_TO_USB &&
+		cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED) {
+		pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+		ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+					 ipa_rm_resource_cons[cur_bam]);
+		pr_debug("%s: Ended connect sequence\n", __func__);
+	}
+
+	spin_unlock(&usb_bam_lock);
 
 	return 0;
 }
@@ -633,22 +854,22 @@
 
 int usb_bam_client_ready(bool ready)
 {
-	spin_lock(&usb_bam_lock);
+	spin_lock(&usb_bam_peer_handshake_info_lock);
 	if (peer_handshake_info.client_ready == ready) {
 		pr_debug("%s: client state is already %d\n",
 			__func__, ready);
-		spin_unlock(&usb_bam_lock);
+		spin_unlock(&usb_bam_peer_handshake_info_lock);
 		return 0;
 	}
 
 	peer_handshake_info.client_ready = ready;
 
-	spin_unlock(&usb_bam_lock);
+	spin_unlock(&usb_bam_peer_handshake_info_lock);
 	if (!queue_work(ctx.usb_bam_wq,
 			&peer_handshake_info.reset_event.event_w)) {
-		spin_lock(&usb_bam_lock);
+		spin_lock(&usb_bam_peer_handshake_info_lock);
 		peer_handshake_info.pending_work++;
-		spin_unlock(&usb_bam_lock);
+		spin_unlock(&usb_bam_peer_handshake_info_lock);
 	}
 
 	return 0;
@@ -656,18 +877,108 @@
 
 static void usb_bam_work(struct work_struct *w)
 {
+	int i;
 	struct usb_bam_event_info *event_info =
 		container_of(w, struct usb_bam_event_info, event_w);
+	struct usb_bam_pipe_connect *pipe_connect =
+		container_of(event_info, struct usb_bam_pipe_connect, event);
+	struct usb_bam_pipe_connect *pipe_connect_iter;
+	int (*callback)(void *priv);
+	void *param = NULL;
 
-	event_info->callback(event_info->param);
+	switch (event_info->type) {
+	case USB_BAM_EVENT_WAKEUP:
+	case USB_BAM_EVENT_WAKEUP_PIPE:
+
+		pr_debug("%s recieved USB_BAM_EVENT_WAKEUP\n", __func__);
+
+		/* Notify about wakeup / activity of the bam */
+		event_info->callback(event_info->param);
+
+		/*
+		 * Reset inactivity timer counter if this pipe's bam
+		 * has inactivity timeout.
+		 */
+		spin_lock(&usb_bam_lock);
+		if (ctx.inactivity_timer_ms[pipe_connect->bam_type])
+			usb_bam_set_inactivity_timer(pipe_connect->bam_type);
+		spin_unlock(&usb_bam_lock);
+
+		break;
+
+	case USB_BAM_EVENT_INACTIVITY:
+
+		pr_debug("%s recieved USB_BAM_EVENT_INACTIVITY\n", __func__);
+
+		/*
+		 * Since event info is one structure per pipe, it might be
+		 * overriden when we will register the wakeup events below,
+		 * and still we want ot register the wakeup events before we
+		 * notify on the inactivity in order to identify the next
+		 * activity as soon as possible.
+		 */
+		callback = event_info->callback;
+		param = event_info->param;
+
+		/*
+		 * Upon inactivity, configure wakeup irq for all pipes
+		 * that are into the usb bam.
+		 */
+		spin_lock(&usb_bam_lock);
+		for (i = 0; i < ctx.max_connections; i++) {
+			pipe_connect_iter = &usb_bam_connections[i];
+			if (pipe_connect_iter->bam_type ==
+				pipe_connect->bam_type &&
+			    pipe_connect_iter->dir ==
+				PEER_PERIPHERAL_TO_USB &&
+				pipe_connect_iter->enabled) {
+				__usb_bam_register_wake_cb(i,
+					pipe_connect_iter->activity_notify,
+					pipe_connect_iter->priv,
+					false);
+			}
+		}
+		spin_unlock(&usb_bam_lock);
+
+		/* Notify about the inactivity */
+		if (callback)
+			callback(param);
+
+		break;
+	default:
+		pr_err("%s: unknown usb bam event type %d\n", __func__,
+			event_info->type);
+	}
 }
 
 static void usb_bam_wake_cb(struct sps_event_notify *notify)
 {
-	struct usb_bam_event_info *wake_event_info =
+	struct usb_bam_event_info *event_info =
 		(struct usb_bam_event_info *)notify->user;
+	struct usb_bam_pipe_connect *pipe_connect =
+		container_of(event_info,
+			     struct usb_bam_pipe_connect,
+			     event);
 
-	queue_work(ctx.usb_bam_wq, &wake_event_info->event_w);
+	spin_lock(&usb_bam_lock);
+
+	if (event_info->type == USB_BAM_EVENT_WAKEUP_PIPE)
+		queue_work(ctx.usb_bam_wq, &event_info->event_w);
+	else if (event_info->type == USB_BAM_EVENT_WAKEUP &&
+			ctx.is_bam_inactivity[pipe_connect->bam_type]) {
+
+		/*
+		 * Sps wake event is per pipe, so usb_bam_wake_cb is
+		 * called per pipe. However, we want to filter the wake
+		 * event to be wake event per all the pipes.
+		 * Therefore, the first pipe that awaked will be considered
+		 * as global bam wake event.
+		 */
+		ctx.is_bam_inactivity[pipe_connect->bam_type] = false;
+		queue_work(ctx.usb_bam_wq, &event_info->event_w);
+	}
+
+	spin_unlock(&usb_bam_lock);
 }
 
 static void usb_bam_sm_work(struct work_struct *w)
@@ -675,15 +986,15 @@
 	pr_debug("%s: current state: %d\n", __func__,
 		peer_handshake_info.state);
 
-	spin_lock(&usb_bam_lock);
+	spin_lock(&usb_bam_peer_handshake_info_lock);
 
 	switch (peer_handshake_info.state) {
 	case USB_BAM_SM_INIT:
 		if (peer_handshake_info.client_ready) {
-			spin_unlock(&usb_bam_lock);
+			spin_unlock(&usb_bam_peer_handshake_info_lock);
 			smsm_change_state(SMSM_APPS_STATE, 0,
 				SMSM_USB_PLUG_UNPLUG);
-			spin_lock(&usb_bam_lock);
+			spin_lock(&usb_bam_peer_handshake_info_lock);
 			peer_handshake_info.state = USB_BAM_SM_PLUG_NOTIFIED;
 		}
 		break;
@@ -695,19 +1006,19 @@
 		break;
 	case USB_BAM_SM_PLUG_ACKED:
 		if (!peer_handshake_info.client_ready) {
-			spin_unlock(&usb_bam_lock);
+			spin_unlock(&usb_bam_peer_handshake_info_lock);
 			smsm_change_state(SMSM_APPS_STATE,
 				SMSM_USB_PLUG_UNPLUG, 0);
-			spin_lock(&usb_bam_lock);
+			spin_lock(&usb_bam_peer_handshake_info_lock);
 			peer_handshake_info.state = USB_BAM_SM_UNPLUG_NOTIFIED;
 		}
 		break;
 	case USB_BAM_SM_UNPLUG_NOTIFIED:
 		if (peer_handshake_info.ack_received) {
-			spin_unlock(&usb_bam_lock);
+			spin_unlock(&usb_bam_peer_handshake_info_lock);
 			peer_handshake_info.reset_event.
 				callback(peer_handshake_info.reset_event.param);
-			spin_lock(&usb_bam_lock);
+			spin_lock(&usb_bam_peer_handshake_info_lock);
 			peer_handshake_info.state = USB_BAM_SM_INIT;
 			peer_handshake_info.ack_received = 0;
 		}
@@ -716,12 +1027,12 @@
 
 	if (peer_handshake_info.pending_work) {
 		peer_handshake_info.pending_work--;
-		spin_unlock(&usb_bam_lock);
+		spin_unlock(&usb_bam_peer_handshake_info_lock);
 		queue_work(ctx.usb_bam_wq,
 			&peer_handshake_info.reset_event.event_w);
-		spin_lock(&usb_bam_lock);
+		spin_lock(&usb_bam_peer_handshake_info_lock);
 	}
-	spin_unlock(&usb_bam_lock);
+	spin_unlock(&usb_bam_peer_handshake_info_lock);
 }
 
 static void usb_bam_ack_toggle_cb(void *priv,
@@ -730,29 +1041,29 @@
 	static int last_processed_state;
 	int current_state;
 
-	spin_lock(&usb_bam_lock);
+	spin_lock(&usb_bam_peer_handshake_info_lock);
 
 	current_state = new_state & SMSM_USB_PLUG_UNPLUG;
 
 	if (current_state == last_processed_state) {
-		spin_unlock(&usb_bam_lock);
+		spin_unlock(&usb_bam_peer_handshake_info_lock);
 		return;
 	}
 
 	last_processed_state = current_state;
 	peer_handshake_info.ack_received = true;
 
-	spin_unlock(&usb_bam_lock);
+	spin_unlock(&usb_bam_peer_handshake_info_lock);
 	if (!queue_work(ctx.usb_bam_wq,
 			&peer_handshake_info.reset_event.event_w)) {
-		spin_lock(&usb_bam_lock);
+		spin_lock(&usb_bam_peer_handshake_info_lock);
 		peer_handshake_info.pending_work++;
-		spin_unlock(&usb_bam_lock);
+		spin_unlock(&usb_bam_peer_handshake_info_lock);
 	}
 }
 
-int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
-	void *param)
+static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
+	void *param, bool trigger_cb_per_pipe)
 {
 	struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx];
 	struct sps_connect *sps_connection;
@@ -767,8 +1078,11 @@
 	pipe = ctx.usb_bam_sps.sps_pipes[idx];
 	sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
 	pipe_connect = &usb_bam_connections[idx];
-	wake_event_info = &pipe_connect->wake_event;
+	wake_event_info = &pipe_connect->event;
 
+	wake_event_info->type = (trigger_cb_per_pipe ?
+				USB_BAM_EVENT_WAKEUP_PIPE :
+				USB_BAM_EVENT_WAKEUP);
 	wake_event_info->param = param;
 	wake_event_info->callback = callback;
 	wake_event_info->event.mode = SPS_TRIGGER_CALLBACK;
@@ -794,6 +1108,12 @@
 	return 0;
 }
 
+int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
+	void *param)
+{
+	return __usb_bam_register_wake_cb(idx, callback, param, true);
+}
+
 int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param)
 {
 	u32 ret = 0;
@@ -831,44 +1151,121 @@
 	pipe_connect = &usb_bam_connections[idx];
 
 	if (!pipe_connect->enabled) {
-		pr_debug("%s: connection %d isn't enabled\n",
+		pr_err("%s: connection %d isn't enabled\n",
 			__func__, idx);
 		return 0;
 	}
 
+	spin_lock(&usb_bam_lock);
+
 	ret = disconnect_pipe(idx);
 	if (ret) {
-		pr_err("%s: src pipe connection failure\n", __func__);
+		pr_err("%s: src pipe disconnection failure\n", __func__);
+		spin_unlock(&usb_bam_lock);
 		return ret;
 	}
 
 	pipe_connect->enabled = 0;
+
 	if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0)
 		pr_err("%s: wrong pipes enabled counter for bam_type=%d\n",
 			__func__, pipe_connect->bam_type);
 	else
 		ctx.pipes_enabled_per_bam[pipe_connect->bam_type] -= 1;
 
+	spin_unlock(&usb_bam_lock);
+
 	return 0;
 }
 
+static void usb_bam_start_lpm(void)
+{
+	struct usb_phy *trans = usb_get_transceiver();
+	BUG_ON(trans == NULL);
+	spin_lock(&usb_bam_lock);
+	lpm_wait_handshake = 0;
+	if (sched_lpm) {
+		pr_debug("%s: Going to LPM\n", __func__);
+		spin_unlock(&usb_bam_lock);
+		pm_runtime_resume(trans->dev);
+		pm_runtime_put_noidle(trans->dev);
+		pm_runtime_suspend(trans->dev);
+		return;
+	}
+	spin_unlock(&usb_bam_lock);
+}
+
+static void wait_for_prod_release(enum usb_bam cur_bam)
+{
+	int ret;
+
+	if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+		pr_debug("%s consumer already released\n", __func__);
+	 if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+		pr_debug("%s producer already released\n", __func__);
+
+	init_completion(&prod_released[cur_bam]);
+	init_completion(&cons_released[cur_bam]);
+	pr_debug("%s: Releasing %s_PROD\n", __func__,
+				bam_enable_strings[cur_bam]);
+	ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
+	if (!ret) {
+		pr_debug("%s: Released without waiting\n", __func__);
+		cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+		complete_all(&prod_released[cur_bam]);
+	} else if (ret == -EINPROGRESS) {
+		pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
+		if (!wait_for_completion_timeout(&prod_released[cur_bam],
+						USB_BAM_TIMEOUT))
+			pr_err("%s: Timeout waiting for PROD_RELEASED\n",
+			__func__);
+	} else
+		pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
+}
+
+static void wait_for_cons_release(enum usb_bam cur_bam)
+{
+	 pr_debug("%s: Waiting for CONS release\n", __func__);
+	 if (cur_prod_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
+		if (!wait_for_completion_timeout(&cons_released[cur_bam],
+						  USB_BAM_TIMEOUT))
+			pr_err("%s: Timeout wainting for CONS_RELEASE\n",
+				__func__);
+	 } else
+		pr_debug("%s Didn't need to wait for CONS release\n",
+		     __func__);
+}
+
 int usb_bam_disconnect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
 {
 	int ret;
 	u8 idx;
 	struct usb_bam_pipe_connect *pipe_connect;
 	struct sps_connect *sps_connection;
+	enum usb_bam cur_bam;
 
+
+	if (!ipa_params->prod_clnt_hdl && !ipa_params->cons_clnt_hdl) {
+		pr_err("%s: Both of the handles is missing\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: Starting disconnect sequence\n", __func__);
+	/* Delay USB core to go into lpm before we finish our handshake */
 	if (ipa_params->prod_clnt_hdl) {
-		/* close USB -> IPA pipe */
 		idx = ipa_params->dst_idx;
+		pipe_connect = &usb_bam_connections[idx];
+
+		/* Do the release handshake with the A2 via RM */
+		cur_bam = pipe_connect->bam_type;
+		wait_for_prod_release(cur_bam);
+		/* close USB -> IPA pipe */
 		ret = ipa_disconnect(ipa_params->prod_clnt_hdl);
 		if (ret) {
 			pr_err("%s: dst pipe disconnection failure\n",
 				__func__);
 			return ret;
 		}
-		pipe_connect = &usb_bam_connections[idx];
 		sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
 		sps_connection->data.phys_base = 0;
 		sps_connection->desc.phys_base = 0;
@@ -880,16 +1277,20 @@
 			return ret;
 		}
 	}
+
 	if (ipa_params->cons_clnt_hdl) {
-		/* close IPA -> USB pipe */
 		idx = ipa_params->src_idx;
+		pipe_connect = &usb_bam_connections[idx];
+		cur_bam = pipe_connect->bam_type;
+		wait_for_cons_release(cur_bam);
+		/* close IPA -> USB pipe */
 		ret = ipa_disconnect(ipa_params->cons_clnt_hdl);
 		if (ret) {
 			pr_err("%s: src pipe disconnection failure\n",
 				__func__);
 			return ret;
 		}
-		pipe_connect = &usb_bam_connections[idx];
+
 		sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
 		sps_connection->data.phys_base = 0;
 		sps_connection->desc.phys_base = 0;
@@ -900,9 +1301,15 @@
 				__func__, idx);
 			return ret;
 		}
+		pr_debug("%s: Notify CONS release\n", __func__);
+
+		if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+			ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+				ipa_rm_resource_cons[cur_bam]);
+		pr_debug("%s Ended disconnect sequence\n", __func__);
+		usb_bam_start_lpm();
 	}
 
-	ipa_rm_release_resource(IPA_RM_RESOURCE_USB_PROD);
 	return 0;
 }
 EXPORT_SYMBOL(usb_bam_disconnect_ipa);
@@ -965,6 +1372,53 @@
 	return ret;
 }
 
+static void usb_bam_sps_events(enum sps_callback_case sps_cb_case, void *user)
+{
+	int i;
+	enum usb_bam bam;
+	struct usb_bam_pipe_connect *pipe_connect;
+	struct usb_bam_event_info *event_info;
+
+	switch (sps_cb_case) {
+	case SPS_CALLBACK_BAM_TIMER_IRQ:
+
+		pr_debug("%s:recieved SPS_CALLBACK_BAM_TIMER_IRQ\n", __func__);
+
+		spin_lock(&usb_bam_lock);
+
+		bam = get_bam_type_from_core_name((char *)user);
+		ctx.is_bam_inactivity[bam] = true;
+		pr_debug("%s: Incativity happened on bam=%s,%d\n", __func__,
+			(char *)user, bam);
+
+		for (i = 0; i < ctx.max_connections; i++) {
+			pipe_connect = &usb_bam_connections[i];
+
+			/*
+			 * Notify inactivity once, Since it is global
+			 * for all pipes on bam.
+			 */
+			if (pipe_connect->bam_type == bam) {
+				event_info = &pipe_connect->event;
+				event_info->type = USB_BAM_EVENT_INACTIVITY;
+				event_info->param = pipe_connect->priv;
+				event_info->callback =
+					pipe_connect->inactivity_notify;
+				queue_work(ctx.usb_bam_wq,
+						&event_info->event_w);
+				break;
+			}
+		}
+
+		spin_unlock(&usb_bam_lock);
+
+		break;
+	default:
+		pr_debug("%s:received sps_cb_case=%d\n", __func__,
+			(int)sps_cb_case);
+	}
+}
+
 static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
 	struct platform_device *pdev)
 {
@@ -1174,6 +1628,9 @@
 	props.summing_threshold = USB_THRESHOLD;
 	props.event_threshold = USB_THRESHOLD;
 	props.num_pipes = pdata->usb_bam_num_pipes;
+	props.callback = usb_bam_sps_events;
+	props.user = bam_enable_strings[bam_idx];
+
 	/*
 	* HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
 	* Hence, let BAM to ignore acknowledge from USB while resetting PIPE
@@ -1234,6 +1691,76 @@
 	return 0;
 }
 
+static ssize_t
+usb_bam_show_inactivity_timer(struct device *dev, struct device_attribute *attr,
+		    char *buf)
+{
+	char *buff = buf;
+	int i;
+
+	spin_lock(&usb_bam_lock);
+
+	for (i = 0; i < ARRAY_SIZE(bam_enable_strings); i++) {
+		buff += snprintf(buff, PAGE_SIZE, "%s: %dms\n",
+					bam_enable_strings[i],
+					ctx.inactivity_timer_ms[i]);
+	}
+
+	spin_unlock(&usb_bam_lock);
+
+	return buff - buf;
+}
+
+static ssize_t usb_bam_store_inactivity_timer(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buff, size_t count)
+{
+	char buf[USB_BAM_MAX_STR_LEN];
+	char *trimmed_buf, *bam_str, *bam_name, *timer;
+	int timer_d;
+	enum usb_bam bam;
+
+	if (strnstr(buff, "help", USB_BAM_MAX_STR_LEN)) {
+		pr_info("Usage: <bam_name> <ms>,<bam_name> <ms>,...\n");
+		pr_info("\tbam_name: [%s, %s, %s]\n",
+			bam_enable_strings[SSUSB_BAM],
+			bam_enable_strings[HSUSB_BAM],
+			bam_enable_strings[HSIC_BAM]);
+		pr_info("\tms: time in ms. Use 0 to disable timer\n");
+		return count;
+	}
+
+	strlcpy(buf, buff, sizeof(buf));
+	trimmed_buf = strim(buf);
+
+	while (trimmed_buf) {
+		bam_str = strsep(&trimmed_buf, ",");
+		if (bam_str) {
+			bam_name = strsep(&bam_str, " ");
+			bam = get_bam_type_from_core_name(bam_name);
+
+			timer = strsep(&bam_str, " ");
+			sscanf(timer, "%d", &timer_d);
+
+			spin_lock(&usb_bam_lock);
+
+			ctx.inactivity_timer_ms[bam] = timer_d;
+			/* Apply new timer setting if bam has running pipes */
+			if (ctx.pipes_enabled_per_bam[bam] > 0)
+				usb_bam_set_inactivity_timer(bam);
+
+			spin_unlock(&usb_bam_lock);
+		}
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(inactivity_timer, S_IWUSR | S_IRUSR,
+		   usb_bam_show_inactivity_timer,
+		   usb_bam_store_inactivity_timer);
+
+
 static int usb_bam_probe(struct platform_device *pdev)
 {
 	int ret, i;
@@ -1241,10 +1768,14 @@
 
 	dev_dbg(&pdev->dev, "usb_bam_probe\n");
 
+	ret = device_create_file(&pdev->dev, &dev_attr_inactivity_timer);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to create fs node\n");
+		return ret;
+	}
+
 	ctx.mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
 	if (IS_ERR(ctx.mem_clk))
-
-
 		dev_dbg(&pdev->dev, "failed to get mem_clock\n");
 
 	ctx.mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
@@ -1269,14 +1800,27 @@
 
 	for (i = 0; i < ctx.max_connections; i++) {
 		usb_bam_connections[i].enabled = 0;
-		INIT_WORK(&usb_bam_connections[i].wake_event.event_w,
+		INIT_WORK(&usb_bam_connections[i].event.event_w,
 			usb_bam_work);
 	}
 
-	for (i = 0; i < MAX_BAMS; i++)
+	for (i = 0; i < MAX_BAMS; i++) {
 		ctx.pipes_enabled_per_bam[i] = 0;
+		ctx.inactivity_timer_ms[i] = 0;
+		ctx.is_bam_inactivity[i] = false;
+		init_completion(&prod_avail[i]);
+		complete(&prod_avail[i]);
+		init_completion(&cons_avail[i]);
+		complete(&cons_avail[i]);
+		init_completion(&cons_released[i]);
+		complete(&cons_released[i]);
+		init_completion(&prod_released[i]);
+		complete(&prod_released[i]);
+		cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
+		cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
+	}
 
-	spin_lock_init(&usb_bam_lock);
+	spin_lock_init(&usb_bam_peer_handshake_info_lock);
 	INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
 
 	ctx.usb_bam_wq = alloc_workqueue("usb_bam_wq",
@@ -1293,6 +1837,8 @@
 	}
 	usb_bam_ipa_create_resources();
 
+	spin_lock_init(&usb_bam_lock);
+
 	return ret;
 }
 
@@ -1361,6 +1907,22 @@
 }
 EXPORT_SYMBOL(usb_bam_get_connection_idx);
 
+bool msm_bam_lpm_ok(void)
+{
+	spin_lock(&usb_bam_lock);
+	if (lpm_wait_handshake) {
+		sched_lpm = 1;
+		spin_unlock(&usb_bam_lock);
+		pr_err("%s: Scheduling LPM for later\n", __func__);
+		return 0;
+	} else {
+		spin_unlock(&usb_bam_lock);
+		pr_err("%s: Going to LPM now\n", __func__);
+		return 1;
+	}
+}
+EXPORT_SYMBOL(msm_bam_lpm_ok);
+
 static int usb_bam_remove(struct platform_device *pdev)
 {
 	destroy_workqueue(ctx.usb_bam_wq);
diff --git a/drivers/power/bq28400_battery.c b/drivers/power/bq28400_battery.c
index beab4e2..79ed2b1 100644
--- a/drivers/power/bq28400_battery.c
+++ b/drivers/power/bq28400_battery.c
@@ -164,6 +164,9 @@
 	u16	subcmd;
 };
 
+static int fake_battery = -EINVAL;
+module_param(fake_battery, int, 0644);
+
 #define BQ28400_DEBUG_REG(x) {#x, SBS_##x, 0}
 #define BQ28400_DEBUG_SUBREG(x, y) {#y, SBS_##x, SUBCMD_##y}
 
@@ -403,6 +406,11 @@
 {
 	int percentage = 0;
 
+	if (fake_battery != -EINVAL) {
+		pr_debug("Reporting Fake SOC = %d\n", fake_battery);
+		return fake_battery;
+	}
+
 	/* This register is only 1 byte */
 	percentage = i2c_smbus_read_byte_data(client, SBS_RSOC);
 
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 6a2ce8d..8207cd6 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1564,9 +1564,9 @@
 
 			rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
 				qpnp_chg_chgr_chg_failed_irq_handler,
-				IRQF_TRIGGER_RISING, "chg_failed", chip);
+				IRQF_TRIGGER_RISING, "chg-failed", chip);
 			if (rc < 0) {
-				pr_err("Can't request %d chg_failed chg: %d\n",
+				pr_err("Can't request %d chg-failed: %d\n",
 						chip->chg_failed_irq, rc);
 				return rc;
 			}
@@ -1584,7 +1584,7 @@
 			rc |= devm_request_irq(chip->dev, chip->chg_trklchg_irq,
 				qpnp_chg_chgr_chg_trklchg_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-				"fast-chg-on", chip);
+				"trkl-chg-on", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d trkl-chg-on: %d\n",
 						chip->chg_trklchg_irq, rc);
@@ -1607,7 +1607,7 @@
 			rc = devm_request_irq(chip->dev, chip->batt_pres_irq,
 				qpnp_chg_bat_if_batt_pres_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-				"bat_if_batt_pres", chip);
+				"batt-pres", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d batt-pres irq: %d\n",
 						chip->batt_pres_irq, rc);
@@ -1628,9 +1628,9 @@
 			rc = devm_request_irq(chip->dev, chip->usbin_valid_irq,
 				qpnp_chg_usb_usbin_valid_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-					"chg_usbin_valid", chip);
+					"usbin-valid", chip);
 			if (rc < 0) {
-				pr_err("Can't request %d usbinvalid: %d\n",
+				pr_err("Can't request %d usbin-valid: %d\n",
 						chip->usbin_valid_irq, rc);
 				return rc;
 			}
@@ -1644,9 +1644,9 @@
 			rc = devm_request_irq(chip->dev, chip->chg_gone_irq,
 				qpnp_chg_usb_chg_gone_irq_handler,
 				IRQF_TRIGGER_RISING,
-					"chg_gone_irq", chip);
+					"chg-gone", chip);
 			if (rc < 0) {
-				pr_err("Can't request %d chg_gone: %d\n",
+				pr_err("Can't request %d chg-gone: %d\n",
 						chip->chg_gone_irq, rc);
 				return rc;
 			}
@@ -1663,9 +1663,9 @@
 			rc = devm_request_irq(chip->dev, chip->dcin_valid_irq,
 				qpnp_chg_dc_dcin_valid_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-				"chg_dcin_valid", chip);
+				"dcin-valid", chip);
 			if (rc < 0) {
-				pr_err("Can't request %d dcinvalid: %d\n",
+				pr_err("Can't request %d dcin-valid: %d\n",
 						chip->dcin_valid_irq, rc);
 				return rc;
 			}
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 139bc06..086ff03 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -36,10 +36,20 @@
 #ifndef _UFS_H
 #define _UFS_H
 
+#include <linux/mutex.h>
+#include <linux/types.h>
+
 #define MAX_CDB_SIZE	16
+#define GENERAL_UPIU_REQUEST_SIZE 32
+#define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE	((ALIGNED_UPIU_SIZE) - \
+					(GENERAL_UPIU_REQUEST_SIZE))
+#define QUERY_OSF_SIZE			((GENERAL_UPIU_REQUEST_SIZE) - \
+					(sizeof(struct utp_upiu_header)))
+#define UFS_QUERY_RESERVED_SCSI_CMD 0xCC
+#define UFS_QUERY_CMD_SIZE 10
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
-			((byte3 << 24) | (byte2 << 16) |\
+			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
 			 (byte1 << 8) | (byte0))
 
 /*
@@ -62,7 +72,7 @@
 	UPIU_TRANSACTION_COMMAND	= 0x01,
 	UPIU_TRANSACTION_DATA_OUT	= 0x02,
 	UPIU_TRANSACTION_TASK_REQ	= 0x04,
-	UPIU_TRANSACTION_QUERY_REQ	= 0x26,
+	UPIU_TRANSACTION_QUERY_REQ	= 0x16,
 };
 
 /* UTP UPIU Transaction Codes Target to Initiator */
@@ -73,6 +83,7 @@
 	UPIU_TRANSACTION_TASK_RSP	= 0x24,
 	UPIU_TRANSACTION_READY_XFER	= 0x31,
 	UPIU_TRANSACTION_QUERY_RSP	= 0x36,
+	UPIU_TRANSACTION_REJECT_UPIU	= 0x3F,
 };
 
 /* UPIU Read/Write flags */
@@ -90,6 +101,12 @@
 	UPIU_TASK_ATTR_ACA	= 0x03,
 };
 
+/* UPIU Query request function */
+enum {
+	UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
+	UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
+};
+
 /* UTP QUERY Transaction Specific Fields OpCode */
 enum {
 	UPIU_QUERY_OPCODE_NOP		= 0x0,
@@ -103,6 +120,21 @@
 	UPIU_QUERY_OPCODE_TOGGLE_FLAG	= 0x8,
 };
 
+/* Query response result code */
+enum {
+	QUERY_RESULT_SUCCESS			= 0x00,
+	QUERY_RESULT_NOT_READABLE		= 0xF6,
+	QUERY_RESULT_NOT_WRITEABLE		= 0xF7,
+	QUERY_RESULT_ALREADY_WRITTEN		= 0xF8,
+	QUERY_RESULT_INVALID_LENGTH		= 0xF9,
+	QUERY_RESULT_INVALID_VALUE		= 0xFA,
+	QUERY_RESULT_INVALID_SELECTOR		= 0xFB,
+	QUERY_RESULT_INVALID_INDEX		= 0xFC,
+	QUERY_RESULT_INVALID_IDN		= 0xFD,
+	QUERY_RESULT_INVALID_OPCODE		= 0xFE,
+	QUERY_RESULT_GENERAL_FAILURE		= 0xFF,
+};
+
 /* UTP Transfer Request Command Type (CT) */
 enum {
 	UPIU_COMMAND_SET_TYPE_SCSI	= 0x0,
@@ -110,10 +142,17 @@
 	UPIU_COMMAND_SET_TYPE_QUERY	= 0x2,
 };
 
+/* UTP Transfer Request Command Offset */
+#define UPIU_COMMAND_TYPE_OFFSET	28
+
+/* Offset of the response code in the UPIU header */
+#define UPIU_RSP_CODE_OFFSET		8
+
 enum {
 	MASK_SCSI_STATUS	= 0xFF,
 	MASK_TASK_RESPONSE	= 0xFF00,
 	MASK_RSP_UPIU_RESULT	= 0xFFFF,
+	MASK_QUERY_DATA_SEG_LEN	= 0xFFFF,
 };
 
 /* Task management service response */
@@ -138,26 +177,59 @@
 
 /**
  * struct utp_upiu_cmd - Command UPIU structure
- * @header: UPIU header structure DW-0 to DW-2
  * @data_transfer_len: Data Transfer Length DW-3
  * @cdb: Command Descriptor Block CDB DW-4 to DW-7
  */
 struct utp_upiu_cmd {
-	struct utp_upiu_header header;
 	u32 exp_data_transfer_len;
 	u8 cdb[MAX_CDB_SIZE];
 };
 
 /**
- * struct utp_upiu_rsp - Response UPIU structure
- * @header: UPIU header DW-0 to DW-2
+ * struct utp_upiu_query - upiu request buffer structure for
+ * query request.
+ * @opcode: command to perform B-0
+ * @idn: a value that indicates the particular type of data B-1
+ * @index: Index to further identify data B-2
+ * @selector: Index to further identify data B-3
+ * @reserved_osf: spec reserved field B-4,5
+ * @length: number of descriptor bytes to read/write B-6,7
+ * @value: Attribute value to be written DW-6
+ * @reserved: spec reserved DW-7,8
+ */
+struct utp_upiu_query {
+	u8 opcode;
+	u8 idn;
+	u8 index;
+	u8 selector;
+	u16 reserved_osf;
+	u16 length;
+	u32 value;
+	u32 reserved[2];
+};
+
+/**
+ * struct utp_upiu_req - general upiu request structure
+ * @header:UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
+ */
+struct utp_upiu_req {
+	struct utp_upiu_header header;
+	union {
+		struct utp_upiu_cmd sc;
+		struct utp_upiu_query qr;
+	};
+};
+
+/**
+ * struct utp_cmd_rsp - Response UPIU structure
  * @residual_transfer_count: Residual transfer count DW-3
  * @reserved: Reserved double words DW-4 to DW-7
  * @sense_data_len: Sense data length DW-8 U16
  * @sense_data: Sense data field DW-8 to DW-12
  */
-struct utp_upiu_rsp {
-	struct utp_upiu_header header;
+struct utp_cmd_rsp {
 	u32 residual_transfer_count;
 	u32 reserved[4];
 	u16 sense_data_len;
@@ -165,6 +237,20 @@
 };
 
 /**
+ * struct utp_upiu_rsp - general upiu response structure
+ * @header: UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
+ */
+struct utp_upiu_rsp {
+	struct utp_upiu_header header;
+	union {
+		struct utp_cmd_rsp sc;
+		struct utp_upiu_query qr;
+	};
+};
+
+/**
  * struct utp_upiu_task_req - Task request UPIU structure
  * @header - UPIU header structure DW0 to DW-2
  * @input_param1: Input parameter 1 DW-3
@@ -194,4 +280,24 @@
 	u32 reserved[3];
 };
 
+/**
+ * struct ufs_query_req - parameters for building a query request
+ * @query_func: UPIU header query function
+ * @upiu_req: the query request data
+ */
+struct ufs_query_req {
+	u8 query_func;
+	struct utp_upiu_query upiu_req;
+};
+
+/**
+ * struct ufs_query_resp - UPIU QUERY
+ * @response: device response code
+ * @upiu_res: query response data
+ */
+struct ufs_query_res {
+	u8 response;
+	struct utp_upiu_query upiu_res;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c32a478..e12b9b4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -202,18 +202,13 @@
 }
 
 /**
- * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
+ * ufshcd_get_req_rsp - returns the TR response
  * @ucd_rsp_ptr: pointer to response UPIU
- *
- * This function checks the response UPIU for valid transaction type in
- * response field
- * Returns 0 on success, non-zero on failure
  */
 static inline int
-ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
 {
-	return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
-		 UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
+	return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
 }
 
 /**
@@ -316,14 +311,71 @@
 {
 	int len;
 	if (lrbp->sense_buffer) {
-		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
+		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sc.sense_data_len);
 		memcpy(lrbp->sense_buffer,
-			lrbp->ucd_rsp_ptr->sense_data,
+			lrbp->ucd_rsp_ptr->sc.sense_data,
 			min_t(int, len, SCSI_SENSE_BUFFERSIZE));
 	}
 }
 
 /**
+ * ufshcd_query_to_cpu() - formats the received buffer in to the native cpu
+ * endian
+ * @response: upiu query response to convert
+ */
+static inline void ufshcd_query_to_cpu(struct utp_upiu_query *response)
+{
+	response->length = be16_to_cpu(response->length);
+	response->value = be32_to_cpu(response->value);
+}
+
+/**
+ * ufshcd_query_to_be() - formats the buffer before sending in to big endian
+ * @response: upiu query request to convert
+ */
+static inline void ufshcd_query_to_be(struct utp_upiu_query *request)
+{
+	request->length = cpu_to_be16(request->length);
+	request->value = cpu_to_be32(request->value);
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy Query Response and descriptor
+ * @lrb - pointer to local reference block
+ * @query_res - pointer to the query result
+ */
+static
+void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	struct ufs_query_res *query_res = hba->query.response;
+
+	/* Get the UPIU response */
+	if (query_res) {
+		query_res->response = ufshcd_get_rsp_upiu_result(
+			lrbp->ucd_rsp_ptr) >> UPIU_RSP_CODE_OFFSET;
+
+		memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr,
+			QUERY_OSF_SIZE);
+		ufshcd_query_to_cpu(&query_res->upiu_res);
+	}
+
+	/* Get the descriptor */
+	if (hba->query.descriptor && lrbp->ucd_rsp_ptr->qr.opcode ==
+			UPIU_QUERY_OPCODE_READ_DESC) {
+		u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr +
+				GENERAL_UPIU_REQUEST_SIZE;
+		u16 len;
+
+		/* data segment length */
+		len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) &
+						MASK_QUERY_DATA_SEG_LEN;
+
+		memcpy(hba->query.descriptor, descp,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+}
+
+/**
  * ufshcd_hba_capabilities - Read controller capabilities
  * @hba: per adapter instance
  */
@@ -423,76 +475,159 @@
 }
 
 /**
+ * ufshcd_prepare_req_desc - Fills the requests header
+ * descriptor according to request
+ * lrbp: pointer to local reference block
+ * upiu_flags: flags required in the header
+ */
+static void ufshcd_prepare_req_desc(struct ufshcd_lrb *lrbp, u32 *upiu_flags)
+{
+	struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
+	enum dma_data_direction cmd_dir =
+		lrbp->cmd->sc_data_direction;
+	u32 data_direction;
+	u32 dword_0;
+
+	if (cmd_dir == DMA_FROM_DEVICE) {
+		data_direction = UTP_DEVICE_TO_HOST;
+		*upiu_flags = UPIU_CMD_FLAGS_READ;
+	} else if (cmd_dir == DMA_TO_DEVICE) {
+		data_direction = UTP_HOST_TO_DEVICE;
+		*upiu_flags = UPIU_CMD_FLAGS_WRITE;
+	} else {
+		data_direction = UTP_NO_DATA_TRANSFER;
+		*upiu_flags = UPIU_CMD_FLAGS_NONE;
+	}
+
+	dword_0 = data_direction | (lrbp->command_type
+				<< UPIU_COMMAND_TYPE_OFFSET);
+
+	/* Transfer request descriptor header fields */
+	req_desc->header.dword_0 = cpu_to_le32(dword_0);
+
+	/*
+	 * assigning invalid value for command status. Controller
+	 * updates OCS on command completion, with the command
+	 * status
+	 */
+	req_desc->header.dword_2 =
+		cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+}
+
+static inline bool ufshcd_is_query_req(struct ufshcd_lrb *lrbp)
+{
+	return lrbp->cmd ? lrbp->cmd->cmnd[0] == UFS_QUERY_RESERVED_SCSI_CMD :
+		false;
+}
+
+/**
+ * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
+ * for scsi commands
+ * @lrbp - local reference block pointer
+ * @upiu_flags - flags
+ */
+static
+void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+	/* command descriptor fields */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+				UPIU_TRANSACTION_COMMAND, upiu_flags,
+				lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+				UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
+
+	/* Total EHS length and Data segment length will be zero */
+	ucd_req_ptr->header.dword_2 = 0;
+
+	ucd_req_ptr->sc.exp_data_transfer_len =
+		cpu_to_be32(lrbp->cmd->sdb.length);
+
+	memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
+		(min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
+}
+
+/**
+ * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
+ * for query requsts
+ * @hba: UFS hba
+ * @lrbp: local reference block pointer
+ * @upiu_flags: flags
+ */
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+					struct ufshcd_lrb *lrbp,
+					u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+	u16 len = hba->query.request->upiu_req.length;
+	u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
+
+	/* Query request header */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+			UPIU_TRANSACTION_QUERY_REQ, upiu_flags,
+			lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+			0, hba->query.request->query_func, 0, 0);
+
+	/* Data segment length */
+	ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD(
+			0, 0, len >> 8, (u8)len);
+
+	/* Copy the Query Request buffer as is */
+	memcpy(&lrbp->ucd_req_ptr->qr, &hba->query.request->upiu_req,
+			QUERY_OSF_SIZE);
+	ufshcd_query_to_be(&lrbp->ucd_req_ptr->qr);
+
+	/* Copy the Descriptor */
+	if (hba->query.descriptor != NULL && len > 0 &&
+		(hba->query.request->upiu_req.opcode ==
+					UPIU_QUERY_OPCODE_WRITE_DESC)) {
+		memcpy(descp, hba->query.descriptor,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+
+}
+
+/**
  * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
+ * @hba - UFS hba
  * @lrb - pointer to local reference block
  */
-static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
+static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 {
-	struct utp_transfer_req_desc *req_desc;
-	struct utp_upiu_cmd *ucd_cmd_ptr;
-	u32 data_direction;
 	u32 upiu_flags;
-
-	ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
-	req_desc = lrbp->utr_descriptor_ptr;
+	int ret = 0;
 
 	switch (lrbp->command_type) {
 	case UTP_CMD_TYPE_SCSI:
-		if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
-			data_direction = UTP_DEVICE_TO_HOST;
-			upiu_flags = UPIU_CMD_FLAGS_READ;
-		} else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
-			data_direction = UTP_HOST_TO_DEVICE;
-			upiu_flags = UPIU_CMD_FLAGS_WRITE;
-		} else {
-			data_direction = UTP_NO_DATA_TRANSFER;
-			upiu_flags = UPIU_CMD_FLAGS_NONE;
-		}
-
-		/* Transfer request descriptor header fields */
-		req_desc->header.dword_0 =
-			cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
-
-		/*
-		 * assigning invalid value for command status. Controller
-		 * updates OCS on command completion, with the command
-		 * status
-		 */
-		req_desc->header.dword_2 =
-			cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
-
-		/* command descriptor fields */
-		ucd_cmd_ptr->header.dword_0 =
-			cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
-						      upiu_flags,
-						      lrbp->lun,
-						      lrbp->task_tag));
-		ucd_cmd_ptr->header.dword_1 =
-			cpu_to_be32(
-				UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
-						  0,
-						  0,
-						  0));
-
-		/* Total EHS length and Data segment length will be zero */
-		ucd_cmd_ptr->header.dword_2 = 0;
-
-		ucd_cmd_ptr->exp_data_transfer_len =
-			cpu_to_be32(lrbp->cmd->sdb.length);
-
-		memcpy(ucd_cmd_ptr->cdb,
-		       lrbp->cmd->cmnd,
-		       (min_t(unsigned short,
-			      lrbp->cmd->cmd_len,
-			      MAX_CDB_SIZE)));
-		break;
 	case UTP_CMD_TYPE_DEV_MANAGE:
-		/* For query function implementation */
+		ufshcd_prepare_req_desc(lrbp, &upiu_flags);
+		if (lrbp->cmd && lrbp->command_type == UTP_CMD_TYPE_SCSI)
+			ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
+		else if (lrbp->cmd)
+			ufshcd_prepare_utp_query_req_upiu(hba, lrbp,
+								upiu_flags);
+		else {
+			dev_err(hba->dev, "%s: Invalid UPIU request\n",
+				__func__);
+			ret = -EINVAL;
+		}
 		break;
 	case UTP_CMD_TYPE_UFS:
 		/* For UFS native command implementation */
+		dev_err(hba->dev, "%s: UFS native command are not supported\n",
+			__func__);
+		ret = -ENOTSUPP;
+		break;
+	default:
+		ret = -ENOTSUPP;
+		dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
+				__func__, lrbp->command_type);
 		break;
 	} /* end of switch */
+
+	return ret;
 }
 
 /**
@@ -527,10 +662,13 @@
 	lrbp->task_tag = tag;
 	lrbp->lun = cmd->device->lun;
 
-	lrbp->command_type = UTP_CMD_TYPE_SCSI;
+	if (ufshcd_is_query_req(lrbp))
+		lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+	else
+		lrbp->command_type = UTP_CMD_TYPE_SCSI;
 
 	/* form UPIU before issuing the command */
-	ufshcd_compose_upiu(lrbp);
+	ufshcd_compose_upiu(hba, lrbp);
 	err = ufshcd_map_sg(lrbp);
 	if (err)
 		goto out;
@@ -544,6 +682,110 @@
 }
 
 /**
+ *  ufshcd_query_request() - Entry point for issuing query request to a
+ *  ufs device.
+ *  @hba: ufs driver context
+ *  @query: params for query request
+ *  @descriptor: buffer for sending/receiving descriptor
+ *  @response: pointer to a buffer that will contain the response code and
+ *           response upiu
+ *  @timeout: time limit for the command in seconds
+ *  @retries: number of times to try executing the command
+ *
+ *  The query request is submitted to the same request queue as the rest of
+ *  the scsi commands passed to the UFS controller. In order to use this
+ *  queue, we need to receive a tag, same as all other commands. The tags
+ *  are issued from the block layer. To simulate a request from the block
+ *  layer, we use the same interface as the SCSI layer does when it issues
+ *  commands not generated by users. To distinguish a query request from
+ *  the SCSI commands, we use a vendor specific unused SCSI command
+ *  op-code. This op-code is not part of the SCSI command subset used in
+ *  UFS. In such way it is easy to check the command in the driver and
+ *  handle it appropriately.
+ *
+ *  All necessary fields for issuing a query and receiving its response are
+ *  stored in the UFS hba struct. We can use this method since we know
+ *  there is only one active query request at all times.
+ *
+ *  The request that will pass to the device is stored in "query" argument
+ *  passed to this function, while the "response" argument (which is output
+ *  field) will hold the query response from the device along with the
+ *  response code.
+ */
+int ufshcd_query_request(struct ufs_hba *hba,
+			struct ufs_query_req *query,
+			u8 *descriptor,
+			struct ufs_query_res *response,
+			int timeout,
+			int retries)
+{
+	struct scsi_device *sdev;
+	u8 cmd[UFS_QUERY_CMD_SIZE] = {0};
+	int result;
+	bool sdev_lookup = true;
+
+	if (!hba || !query || !response) {
+		dev_err(hba->dev,
+			"%s: NULL pointer hba = %p, query = %p response = %p\n",
+			__func__, hba, query, response);
+		return -EINVAL;
+	}
+
+	/*
+	 * A SCSI command structure is composed from opcode at the
+	 * begining and 0 at the end.
+	 */
+	cmd[0] = UFS_QUERY_RESERVED_SCSI_CMD;
+
+	/* extracting the SCSI Device */
+	sdev = scsi_device_lookup(hba->host, 0, 0, 0);
+	if (!sdev) {
+		/**
+		 * There are some Query Requests that are sent during device
+		 * initialization, this happens before the scsi device was
+		 * initialized. If there is no scsi device, we generate a
+		 * temporary device to allow the Query Request flow.
+		 */
+		sdev_lookup = false;
+		sdev = scsi_get_host_dev(hba->host);
+	}
+
+	if (!sdev) {
+		dev_err(hba->dev, "%s: Could not fetch scsi device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&hba->query.lock_ufs_query);
+	hba->query.request = query;
+	hba->query.descriptor = descriptor;
+	hba->query.response = response;
+
+	/* wait until request is completed */
+	result = scsi_execute(sdev, cmd, DMA_NONE, NULL, 0, NULL,
+				timeout, retries, 0, NULL);
+	if (result) {
+		dev_err(hba->dev,
+			"%s: Query with opcode 0x%x, failed with result %d\n",
+			__func__, query->upiu_req.opcode, result);
+		result = -EIO;
+	}
+
+	hba->query.request = NULL;
+	hba->query.descriptor = NULL;
+	hba->query.response = NULL;
+	mutex_unlock(&hba->query.lock_ufs_query);
+
+	/* Releasing scsi device resource */
+	if (sdev_lookup)
+		scsi_device_put(sdev);
+	else
+		scsi_free_host_dev(sdev);
+
+	return result;
+}
+
+/**
  * ufshcd_memory_alloc - allocate memory for host memory space data structures
  * @hba: per adapter instance
  *
@@ -677,8 +919,8 @@
 				cpu_to_le16(ALIGNED_UPIU_SIZE);
 
 		hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
-		hba->lrb[i].ucd_cmd_ptr =
-			(struct utp_upiu_cmd *)(cmd_descp + i);
+		hba->lrb[i].ucd_req_ptr =
+			(struct utp_upiu_req *)(cmd_descp + i);
 		hba->lrb[i].ucd_rsp_ptr =
 			(struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
 		hba->lrb[i].ucd_prdt_ptr =
@@ -1101,7 +1343,9 @@
  * @hba: per adapter instance
  * @lrb: pointer to local reference block of completed command
  *
- * Returns result of the command to notify SCSI midlayer
+ * Returns result of the command to notify SCSI midlayer. In
+ * case of query request specific result, returns DID_OK, and
+ * the error will be handled by the dispatcher.
  */
 static inline int
 ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
@@ -1115,27 +1359,46 @@
 
 	switch (ocs) {
 	case OCS_SUCCESS:
-
 		/* check if the returned transfer response is valid */
-		result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
-		if (result) {
-			dev_err(hba->dev,
-				"Invalid response = %x\n", result);
+		result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
+
+		switch (result) {
+		case UPIU_TRANSACTION_RESPONSE:
+			/*
+			 * get the response UPIU result to extract
+			 * the SCSI command status
+			 */
+			result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+			/*
+			 * get the result based on SCSI status response
+			 * to notify the SCSI midlayer of the command status
+			 */
+			scsi_status = result & MASK_SCSI_STATUS;
+			result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
 			break;
+		case UPIU_TRANSACTION_QUERY_RSP:
+			/*
+			 *  Return result = ok, since SCSI layer wouldn't
+			 *  know how to handle errors from query requests.
+			 *  The result is saved with the response so that
+			 *  the ufs_core layer will handle it.
+			 */
+			result |= DID_OK << 16;
+			ufshcd_copy_query_response(hba, lrbp);
+			break;
+		case UPIU_TRANSACTION_REJECT_UPIU:
+			/* TODO: handle Reject UPIU Response */
+			result |= DID_ERROR << 16;
+			dev_err(hba->dev,
+				"Reject UPIU not fully implemented\n");
+			break;
+		default:
+			result |= DID_ERROR << 16;
+			dev_err(hba->dev,
+				"Unexpected request response code = %x\n",
+				result);
 		}
-
-		/*
-		 * get the response UPIU result to extract
-		 * the SCSI command status
-		 */
-		result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
-
-		/*
-		 * get the result based on SCSI status response
-		 * to notify the SCSI midlayer of the command status
-		 */
-		scsi_status = result & MASK_SCSI_STATUS;
-		result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
 		break;
 	case OCS_ABORTED:
 		result |= DID_ABORT << 16;
@@ -1364,10 +1627,10 @@
 	task_req_upiup =
 		(struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
 	task_req_upiup->header.dword_0 =
-		cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
-					      lrbp->lun, lrbp->task_tag));
+		UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
+					      lrbp->lun, lrbp->task_tag);
 	task_req_upiup->header.dword_1 =
-	cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
+		UPIU_HEADER_DWORD(0, tm_function, 0, 0);
 
 	task_req_upiup->input_param1 = lrbp->lun;
 	task_req_upiup->input_param1 =
@@ -1670,6 +1933,9 @@
 	INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
 	INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
 
+	/* Initialize mutex for query requests */
+	mutex_init(&hba->query.lock_ufs_query);
+
 	/* IRQ registration */
 	err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
 	if (err) {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 6b99a42..336980b 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -60,6 +60,7 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
 
 #include "ufs.h"
 #include "ufshci.h"
@@ -88,7 +89,7 @@
 /**
  * struct ufshcd_lrb - local reference block
  * @utr_descriptor_ptr: UTRD address of the command
- * @ucd_cmd_ptr: UCD address of the command
+ * @ucd_req_ptr: UCD address of the command
  * @ucd_rsp_ptr: Response UPIU address for this command
  * @ucd_prdt_ptr: PRDT address of the command
  * @cmd: pointer to SCSI command
@@ -101,7 +102,7 @@
  */
 struct ufshcd_lrb {
 	struct utp_transfer_req_desc *utr_descriptor_ptr;
-	struct utp_upiu_cmd *ucd_cmd_ptr;
+	struct utp_upiu_req *ucd_req_ptr;
 	struct utp_upiu_rsp *ucd_rsp_ptr;
 	struct ufshcd_sg_entry *ucd_prdt_ptr;
 
@@ -115,6 +116,19 @@
 	unsigned int lun;
 };
 
+/**
+ * struct ufs_query - keeps the query request information
+ * @request: request upiu and function
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: response upiu and response
+ * @mutex: lock to allow one query at a time
+ */
+struct ufs_query {
+	struct ufs_query_req *request;
+	u8 *descriptor;
+	struct ufs_query_res *response;
+	struct mutex lock_ufs_query;
+};
 
 /**
  * struct ufs_hba - per adapter private structure
@@ -143,6 +157,7 @@
  * @uic_workq: Work queue for UIC completion handling
  * @feh_workq: Work queue for fatal controller error handling
  * @errors: HBA errors
+ * @query: query request information
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -184,6 +199,9 @@
 
 	/* HBA Errors */
 	u32 errors;
+
+	/* Query Request */
+	struct ufs_query query;
 };
 
 int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 0c16484..4a86247 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,7 +39,7 @@
 enum {
 	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
 	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
-	ALIGNED_UPIU_SIZE		= 128,
+	ALIGNED_UPIU_SIZE		= 512,
 };
 
 /* UFSHCI Registers */
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 6cd30f1..3abc3b9 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -2525,14 +2525,38 @@
 			struct binder_transaction *t;
 
 			t = container_of(w, struct binder_transaction, work);
-			if (t->buffer->target_node && !(t->flags & TF_ONE_WAY))
+			if (t->buffer->target_node &&
+			    !(t->flags & TF_ONE_WAY)) {
 				binder_send_failed_reply(t, BR_DEAD_REPLY);
+			} else {
+				binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
+					"binder: undelivered transaction %d\n",
+					t->debug_id);
+				t->buffer->transaction = NULL;
+				kfree(t);
+				binder_stats_deleted(BINDER_STAT_TRANSACTION);
+			}
 		} break;
 		case BINDER_WORK_TRANSACTION_COMPLETE: {
+			binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
+				"binder: undelivered TRANSACTION_COMPLETE\n");
 			kfree(w);
 			binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
 		} break;
+		case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
+		case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
+			struct binder_ref_death *death;
+
+			death = container_of(w, struct binder_ref_death, work);
+			binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
+				"binder: undelivered death notification, %p\n",
+				death->cookie);
+			kfree(death);
+			binder_stats_deleted(BINDER_STAT_DEATH);
+		} break;
 		default:
+			pr_err("binder: unexpected work type, %d, not freed\n",
+			       w->type);
 			break;
 		}
 	}
@@ -3009,6 +3033,7 @@
 		nodes++;
 		rb_erase(&node->rb_node, &proc->nodes);
 		list_del_init(&node->work.entry);
+		binder_release_work(&node->async_todo);
 		if (hlist_empty(&node->refs)) {
 			kfree(node);
 			binder_stats_deleted(BINDER_STAT_NODE);
@@ -3047,6 +3072,7 @@
 		binder_delete_ref(ref);
 	}
 	binder_release_work(&proc->todo);
+	binder_release_work(&proc->delivered_death);
 	buffers = 0;
 
 	while ((n = rb_first(&proc->allocated_buffers))) {
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 12ac3bc..42119aa 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -103,6 +103,7 @@
 	ko_attr.attr.mode = 444; \
 	ko_attr.show = vdd_rstr_reg_##_name##_show; \
 	ko_attr.store = NULL; \
+	sysfs_attr_init(&ko_attr.attr); \
 	_rail.attr_gp.attrs[j] = &ko_attr.attr;
 
 #define VDD_RES_RW_ATTRIB(_rail, ko_attr, j, _name) \
@@ -110,6 +111,7 @@
 	ko_attr.attr.mode = 644; \
 	ko_attr.show = vdd_rstr_reg_##_name##_show; \
 	ko_attr.store = vdd_rstr_reg_##_name##_store; \
+	sysfs_attr_init(&ko_attr.attr); \
 	_rail.attr_gp.attrs[j] = &ko_attr.attr;
 
 #define VDD_RSTR_ENABLE_FROM_ATTRIBS(attr) \
@@ -126,6 +128,7 @@
 	ko_attr.attr.mode = 644; \
 	ko_attr.show = psm_reg_##_name##_show; \
 	ko_attr.store = psm_reg_##_name##_store; \
+	sysfs_attr_init(&ko_attr.attr); \
 	_rail.attr_gp.attrs[j] = &ko_attr.attr;
 
 #define PSM_REG_MODE_FROM_ATTRIBS(attr) \
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index d848a18..26a12d0 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1200,22 +1200,28 @@
 		}
 	}
 
-	rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
-		sensor_mask, false);
-	if (rc < 0) {
-		pr_err("multi meas disable for channel failed\n");
-		goto fail;
-	}
+	if (adc_tm_high_enable || adc_tm_low_enable) {
+		rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+			sensor_mask, false);
+		if (rc < 0) {
+			pr_err("multi meas disable for channel failed\n");
+			goto fail;
+		}
 
-	rc = qpnp_adc_tm_enable_if_channel_meas();
-	if (rc < 0) {
-		pr_err("re-enabling measurement failed\n");
-		return rc;
-	}
+		rc = qpnp_adc_tm_enable_if_channel_meas();
+		if (rc < 0) {
+			pr_err("re-enabling measurement failed\n");
+			return rc;
+		}
+	} else
+		pr_debug("No threshold status enable %d for high/low??\n",
+								sensor_mask);
+
 fail:
 	mutex_unlock(&adc_tm->adc->adc_lock);
 
-	schedule_work(&adc_tm->sensor[sensor_num].work);
+	if (adc_tm_high_enable || adc_tm_low_enable)
+		schedule_work(&adc_tm->sensor[sensor_num].work);
 
 	return rc;
 }
@@ -1528,6 +1534,7 @@
 		dev_err(&spmi->dev, "failed to read device tree\n");
 		goto fail;
 	}
+	mutex_init(&adc_tm->adc->adc_lock);
 
 	/* Register the ADC peripheral interrupt */
 	adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index ad7c702..f695870 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -2340,9 +2340,7 @@
 	msm_hs_start_rx_locked(uport);
 
 	spin_unlock_irqrestore(&uport->lock, flags);
-	ret = pm_runtime_set_active(uport->dev);
-	if (ret)
-		dev_err(uport->dev, "set active error:%d\n", ret);
+
 	pm_runtime_enable(uport->dev);
 
 	return 0;
@@ -3180,7 +3178,6 @@
 	cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work);
 	flush_workqueue(msm_uport->hsuart_wq);
 	pm_runtime_disable(uport->dev);
-	pm_runtime_set_suspended(uport->dev);
 
 	/* Disable the transmitter */
 	msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 7aa14de..d520253 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -364,6 +364,22 @@
 	return msm_hsl_port->uart.line;
 }
 
+static int bus_vote(uint32_t client, int vector)
+{
+	int ret = 0;
+
+	if (!client)
+		return ret;
+
+	pr_debug("Voting for bus scaling:%d\n", vector);
+
+	ret = msm_bus_scale_client_update_request(client, vector);
+	if (ret)
+		pr_err("Failed to request bus bw vector %d\n", vector);
+
+	return ret;
+}
+
 static int clk_en(struct uart_port *port, int enable)
 {
 	struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
@@ -372,9 +388,13 @@
 	if (enable) {
 
 		msm_hsl_port->clk_enable_count++;
-		ret = clk_prepare_enable(msm_hsl_port->clk);
+		ret = bus_vote(msm_hsl_port->bus_perf_client,
+				!!msm_hsl_port->clk_enable_count);
 		if (ret)
 			goto err;
+		ret = clk_prepare_enable(msm_hsl_port->clk);
+		if (ret)
+			goto err_bus;
 		if (msm_hsl_port->pclk) {
 			ret = clk_prepare_enable(msm_hsl_port->pclk);
 			if (ret)
@@ -386,23 +406,17 @@
 		clk_disable_unprepare(msm_hsl_port->clk);
 		if (msm_hsl_port->pclk)
 			clk_disable_unprepare(msm_hsl_port->pclk);
-	}
-
-	if (msm_hsl_port->bus_perf_client) {
-			pr_debug("Voting for bus scaling:%d\n",
-					!!msm_hsl_port->clk_enable_count);
-			ret = msm_bus_scale_client_update_request(
-				msm_hsl_port->bus_perf_client,
+		ret = bus_vote(msm_hsl_port->bus_perf_client,
 				!!msm_hsl_port->clk_enable_count);
-			if (ret)
-				pr_err("Failed to request bus bw vector %d\n",
-					!!msm_hsl_port->clk_enable_count);
 	}
 
 	return ret;
 
 err_clk_disable:
 	clk_disable_unprepare(msm_hsl_port->clk);
+err_bus:
+	bus_vote(msm_hsl_port->bus_perf_client,
+			!!(msm_hsl_port->clk_enable_count - 1));
 err:
 	msm_hsl_port->clk_enable_count--;
 	return ret;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 924e8f4..a27eb09 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1309,8 +1309,14 @@
 	data |= (0x7F | (1 << 14));
 	dwc3_msm_ssusb_write_phycreg(msm->base, 0x1002, data);
 
-	/* Set LOS_BIAS to 0x5 */
-	dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1, 0x07, 0x5);
+	/*
+	 * Set the QSCRATCH SS_PHY_PARAM_CTRL1 parameters as follows
+	 * TX_FULL_SWING [26:20] amplitude to 127
+	 * TX_DEEMPH_3_5DB [13:8] to 22
+	 * LOS_BIAS [2:0] to 0x5
+	 */
+	dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1,
+				0x07f03f07, 0x07f01605);
 }
 
 /* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
@@ -2433,6 +2439,8 @@
 	msm->charger.charging_disabled = of_property_read_bool(node,
 				"qcom,charging-disabled");
 
+	msm->charger.skip_chg_detect = of_property_read_bool(node,
+				"qcom,skip-charger-detection");
 	/*
 	 * DWC3 has separate IRQ line for OTG events (ID/BSV) and for
 	 * DP and DM linestate transitions during low power mode.
@@ -2606,12 +2614,17 @@
 	msm->otg_xceiv = usb_get_transceiver();
 	/* Register with OTG if present, ignore USB2 OTG using other PHY */
 	if (msm->otg_xceiv && !(msm->otg_xceiv->flags & ENABLE_SECONDARY_PHY)) {
-		msm->charger.start_detection = dwc3_start_chg_det;
-		ret = dwc3_set_charger(msm->otg_xceiv->otg, &msm->charger);
-		if (ret || !msm->charger.notify_detection_complete) {
-			dev_err(&pdev->dev, "failed to register charger: %d\n",
-									ret);
-			goto put_xcvr;
+		/* Skip charger detection for simulator targets */
+		if (!msm->charger.skip_chg_detect) {
+			msm->charger.start_detection = dwc3_start_chg_det;
+			ret = dwc3_set_charger(msm->otg_xceiv->otg,
+					&msm->charger);
+			if (ret || !msm->charger.notify_detection_complete) {
+				dev_err(&pdev->dev,
+					"failed to register charger: %d\n",
+					ret);
+				goto put_xcvr;
+			}
 		}
 
 		if (msm->ext_xceiv.otg_capability)
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index c2fab53..90e26cf 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -77,6 +77,8 @@
 	unsigned		max_power;
 	bool			charging_disabled;
 
+	bool			skip_chg_detect;
+
 	/* start/stop charger detection, provided by external charger module */
 	void	(*start_detection)(struct dwc3_charger *charger, bool start);
 
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 8d2ec97..bb0b2fb 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -751,6 +751,9 @@
 	dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
 
 	r = next_request(&ep0->request_list);
+	if (r == NULL)
+		return;
+
 	ur = &r->request;
 	if ((epnum & 1) && ur->zero &&
 		(ur->length % ep0->endpoint.maxpacket == 0)) {
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 705600d..147e3db 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -2689,6 +2689,8 @@
 		of_property_read_u32(pdev->dev.of_node,
 				"qcom,android-usb-swfi-latency",
 				&pdata->swfi_latency);
+		pdata->cdrom = of_property_read_bool(pdev->dev.of_node,
+				"qcom,android-usb-cdrom");
 	} else {
 		pdata = pdev->dev.platform_data;
 	}
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index d0ebda1..01d8be1 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2268,8 +2268,8 @@
 	gadget->otg_srp_reqd = 0;
 
 	udc->driver->disconnect(gadget);
-	usb_ep_fifo_flush(&udc->ep0out.ep);
-	usb_ep_fifo_flush(&udc->ep0in.ep);
+	_ep_nuke(&udc->ep0out);
+	_ep_nuke(&udc->ep0in);
 
 	if (udc->ep0in.last_zptr) {
 		dma_pool_free(udc->ep0in.td_pool, udc->ep0in.last_zptr,
@@ -3023,21 +3023,24 @@
 
 	trace("%p, %p, %X", ep, req, gfp_flags);
 
-	if (ep == NULL || req == NULL || mEp->desc == NULL)
-		return -EINVAL;
-
-	if (!udc->softconnect)
-		return -ENODEV;
-
 	spin_lock_irqsave(mEp->lock, flags);
+	if (ep == NULL || req == NULL || mEp->desc == NULL) {
+		retval = -EINVAL;
+		goto done;
+	}
+
+	if (!udc->softconnect) {
+		retval = -ENODEV;
+		goto done;
+	}
 
 	if (!udc->configured && mEp->type !=
 		USB_ENDPOINT_XFER_CONTROL) {
-		spin_unlock_irqrestore(mEp->lock, flags);
 		trace("usb is not configured"
 			"ept #%d, ept name#%s\n",
 			mEp->num, mEp->ep.name);
-		return -ESHUTDOWN;
+		retval = -ESHUTDOWN;
+		goto done;
 	}
 
 	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
@@ -3117,12 +3120,19 @@
 
 	trace("%p, %p", ep, req);
 
+	spin_lock_irqsave(mEp->lock, flags);
+	/*
+	 * Only ep0 IN is exposed to composite.  When a req is dequeued
+	 * on ep0, check both ep0 IN and ep0 OUT queues.
+	 */
 	if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
 		mEp->desc == NULL || list_empty(&mReq->queue) ||
-		list_empty(&mEp->qh.queue))
+		(list_empty(&mEp->qh.queue) && ((mEp->type !=
+			USB_ENDPOINT_XFER_CONTROL) ||
+			list_empty(&_udc->ep0out.qh.queue)))) {
+		spin_unlock_irqrestore(mEp->lock, flags);
 		return -EINVAL;
-
-	spin_lock_irqsave(mEp->lock, flags);
+	}
 
 	dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
 
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index bac8b68..87a3fd5 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2510,7 +2510,8 @@
 		goto reset_bulk_int;
 	fsg->bulk_out->driver_data = common;
 	fsg->bulk_out_enabled = 1;
-	common->bulk_out_maxpacket = le16_to_cpu(fsg->bulk_in->desc->wMaxPacketSize);
+	common->bulk_out_maxpacket =
+			le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
 	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 	csw_hack_sent = 0;
 	write_error_after_csw_sent = 0;
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index f3c6481..1017900 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -25,11 +25,6 @@
 #include "u_ether.h"
 #include "rndis.h"
 
-static bool rndis_multipacket_dl_disable;
-module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(rndis_multipacket_dl_disable,
-	"Disable RNDIS Multi-packet support in DownLink");
-
 /*
  * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
  * been promoted instead of the standard CDC Ethernet.  The published RNDIS
@@ -71,6 +66,16 @@
  *   - MS-Windows drivers sometimes emit undocumented requests.
  */
 
+static bool rndis_multipacket_dl_disable;
+module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(rndis_multipacket_dl_disable,
+	"Disable RNDIS Multi-packet support in DownLink");
+
+static unsigned int rndis_ul_max_pkt_per_xfer = 1;
+module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
+	"Disable RNDIS Multi-packet support in DownLink");
+
 struct f_rndis {
 	struct gether			port;
 	u8				ctrl_id, data_id;
@@ -799,6 +804,7 @@
 
 	rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0);
 	rndis_set_host_mac(rndis->config, rndis->ethaddr);
+	rndis_set_max_pkt_xfer(rndis->config, rndis_ul_max_pkt_per_xfer);
 
 	if (rndis->manufacturer && rndis->vendorID &&
 			rndis_set_param_vendor(rndis->config, rndis->vendorID,
@@ -945,6 +951,7 @@
 	rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
 	rndis->port.wrap = rndis_add_header;
 	rndis->port.unwrap = rndis_rm_hdr;
+	rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
 
 	rndis->port.func.name = "rndis";
 	rndis->port.func.strings = rndis_strings;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 7ac5b64..07f4d26 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -59,6 +59,16 @@
 
 #define RNDIS_MAX_CONFIGS	1
 
+int rndis_ul_max_pkt_per_xfer_rcvd;
+module_param(rndis_ul_max_pkt_per_xfer_rcvd, int, S_IRUGO);
+MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer_rcvd,
+	"Max num of REMOTE_NDIS_PACKET_MSGs received in a single transfer");
+
+int rndis_ul_max_xfer_size_rcvd;
+module_param(rndis_ul_max_xfer_size_rcvd, int, S_IRUGO);
+MODULE_PARM_DESC(rndis_ul_max_xfer_size_rcvd,
+	"Max size of bus transfer received");
+
 
 static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
 
@@ -590,7 +600,6 @@
 		(params->dev->mtu
 		+ sizeof(struct ethhdr)
 		+ sizeof(struct rndis_packet_msg_type)
-
 		+ 22));
 	resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor);
 	resp->AFListOffset = cpu_to_le32(0);
@@ -1051,25 +1060,77 @@
 			struct sk_buff *skb,
 			struct sk_buff_head *list)
 {
-	/* tmp points to a struct rndis_packet_msg_type */
-	__le32 *tmp = (void *)skb->data;
+	int num_pkts = 1;
 
-	/* MessageType, MessageLength */
-	if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
-			!= get_unaligned(tmp++)) {
-		dev_kfree_skb_any(skb);
-		return -EINVAL;
-	}
-	tmp++;
+	if (skb->len > rndis_ul_max_xfer_size_rcvd)
+		rndis_ul_max_xfer_size_rcvd = skb->len;
 
-	/* DataOffset, DataLength */
-	if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
-		dev_kfree_skb_any(skb);
-		return -EOVERFLOW;
+	while (skb->len) {
+		struct rndis_packet_msg_type *hdr;
+		struct sk_buff		*skb2;
+		u32		msg_len, data_offset, data_len;
+
+		/* some rndis hosts send extra byte to avoid zlp, ignore it */
+		if (skb->len == 1) {
+			dev_kfree_skb_any(skb);
+			return 0;
+		}
+
+		if (skb->len < sizeof *hdr) {
+			pr_err("invalid rndis pkt: skblen:%u hdr_len:%u",
+					skb->len, sizeof *hdr);
+			dev_kfree_skb_any(skb);
+			return -EINVAL;
+		}
+
+		hdr = (void *)skb->data;
+		msg_len = le32_to_cpu(hdr->MessageLength);
+		data_offset = le32_to_cpu(hdr->DataOffset);
+		data_len = le32_to_cpu(hdr->DataLength);
+
+		if (skb->len < msg_len ||
+			((data_offset + data_len + 8) > msg_len)) {
+			pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
+				le32_to_cpu(hdr->MessageType),
+				msg_len, data_offset, data_len, skb->len);
+			dev_kfree_skb_any(skb);
+			return -EOVERFLOW;
+		}
+
+		if (le32_to_cpu(hdr->MessageType) != REMOTE_NDIS_PACKET_MSG) {
+			pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
+				le32_to_cpu(hdr->MessageType),
+				msg_len, data_offset, data_len, skb->len);
+			dev_kfree_skb_any(skb);
+			return -EINVAL;
+		}
+
+		skb_pull(skb, data_offset + 8);
+
+		if (msg_len == skb->len) {
+			skb_trim(skb, data_len);
+			break;
+		}
+
+		skb2 = skb_clone(skb, GFP_ATOMIC);
+		if (!skb2) {
+			pr_err("%s:skb clone failed\n", __func__);
+			dev_kfree_skb_any(skb);
+			return -ENOMEM;
+		}
+
+		skb_pull(skb, msg_len - sizeof *hdr);
+		skb_trim(skb2, data_len);
+		skb_queue_tail(list, skb2);
+
+		num_pkts++;
 	}
-	skb_trim(skb, get_unaligned_le32(tmp++));
+
+	if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
+		rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;
 
 	skb_queue_tail(list, skb);
+
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 8a6a630..d00f81f 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -252,6 +252,7 @@
 int  rndis_set_param_vendor (u8 configNr, u32 vendorID,
 			    const char *vendorDescr);
 int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
+void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer);
 void rndis_add_hdr (struct sk_buff *skb);
 int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
 			struct sk_buff_head *list);
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index c601000..c05f683 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -667,11 +667,11 @@
 	int ret;
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		teth_bridge_disconnect();
 		ret = usb_bam_disconnect_ipa(&d->ipa_params);
 		if (ret)
 			pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
 				__func__, ret);
-		teth_bridge_disconnect();
 	}
 }
 
@@ -742,8 +742,8 @@
 		d->ipa_params.priv = priv;
 		d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
 
-		d->ipa_params.client = IPA_CLIENT_USB_CONS;
-		d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
+		d->ipa_params.client = IPA_CLIENT_USB_PROD;
+		d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
 		ret = usb_bam_connect_ipa(&d->ipa_params);
 		if (ret) {
 			pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
@@ -751,8 +751,8 @@
 			return;
 		}
 
-		d->ipa_params.client = IPA_CLIENT_USB_PROD;
-		d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
+		d->ipa_params.client = IPA_CLIENT_USB_CONS;
+		d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
 		ret = usb_bam_connect_ipa(&d->ipa_params);
 		if (ret) {
 			pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index eec9e37..2abe2ef 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -219,10 +219,10 @@
 			d->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
 		}
 
-		d->ipa_params.client = IPA_CLIENT_USB_CONS;
-		d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
+		d->ipa_params.client = IPA_CLIENT_USB_PROD;
+		d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
 		if (d->func_type == USB_FUNC_ECM) {
-			d->ipa_params.notify = ecm_qc_get_ipa_tx_cb();
+			d->ipa_params.notify = ecm_qc_get_ipa_rx_cb();
 			d->ipa_params.priv = ecm_qc_get_ipa_priv();
 		}
 		ret = usb_bam_connect_ipa(&d->ipa_params);
@@ -232,10 +232,10 @@
 			return;
 		}
 
-		d->ipa_params.client = IPA_CLIENT_USB_PROD;
-		d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
+		d->ipa_params.client = IPA_CLIENT_USB_CONS;
+		d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
 		if (d->func_type == USB_FUNC_ECM) {
-			d->ipa_params.notify = ecm_qc_get_ipa_rx_cb();
+			d->ipa_params.notify = ecm_qc_get_ipa_tx_cb();
 			d->ipa_params.priv = ecm_qc_get_ipa_priv();
 		}
 		ret = usb_bam_connect_ipa(&d->ipa_params);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 2d974ab..d4c21dd 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -70,6 +70,7 @@
 	struct sk_buff_head	rx_frames;
 
 	unsigned		header_len;
+	unsigned		ul_max_pkts_per_xfer;
 	struct sk_buff		*(*wrap)(struct gether *, struct sk_buff *skb);
 	int			(*unwrap)(struct gether *,
 						struct sk_buff *skb,
@@ -233,9 +234,13 @@
 	size += out->maxpacket - 1;
 	size -= size % out->maxpacket;
 
+	if (dev->ul_max_pkts_per_xfer)
+		size *= dev->ul_max_pkts_per_xfer;
+
 	if (dev->port_usb->is_fixed)
 		size = max_t(size_t, size, dev->port_usb->fixed_out_len);
 
+	pr_debug("%s: size: %d", __func__, size);
 	skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
 	if (skb == NULL) {
 		DBG(dev, "no rx skb\n");
@@ -1076,6 +1081,7 @@
 		dev->header_len = link->header_len;
 		dev->unwrap = link->unwrap;
 		dev->wrap = link->wrap;
+		dev->ul_max_pkts_per_xfer = link->ul_max_pkts_per_xfer;
 
 		spin_lock(&dev->lock);
 		dev->tx_skb_hold_count = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index faa9a3b..7040ab0 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -53,6 +53,8 @@
 	bool				is_fixed;
 	u32				fixed_out_len;
 	u32				fixed_in_len;
+
+	unsigned			ul_max_pkts_per_xfer;
 /* Max number of SKB packets to be used to create Multi Packet RNDIS */
 #define TX_SKB_HOLD_THRESHOLD		3
 	bool				multi_pkt_xfer;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4865b03..d4d7ee9 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -869,6 +869,9 @@
 	if (atomic_read(&motg->in_lpm))
 		return 0;
 
+	if (motg->pdata->delay_lpm_hndshk_on_disconnect && !msm_bam_lpm_ok())
+		return 0;
+
 	disable_irq(motg->irq);
 	host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
 		!test_bit(ID, &motg->inputs);
@@ -3802,6 +3805,8 @@
 				"qcom,hsusb-otg-clk-always-on-workaround");
 	pdata->delay_lpm_on_disconnect = of_property_read_bool(node,
 				"qcom,hsusb-otg-delay-lpm");
+	pdata->delay_lpm_hndshk_on_disconnect = of_property_read_bool(node,
+				"qcom,hsusb-otg-delay-lpm-hndshk-on-disconnect");
 	pdata->dp_manual_pullup = of_property_read_bool(node,
 				"qcom,dp-manual-pullup");
 	pdata->enable_sec_phy = of_property_read_bool(node,
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 5be0173..3bb4bdc 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -110,6 +110,10 @@
 	void *video_intf;
 	u32 nintf;
 
+	struct mdss_ad_info *ad_cfgs;
+	u32 nad_cfgs;
+	struct workqueue_struct *ad_calc_wq;
+
 	struct ion_client *iclient;
 	int iommu_attached;
 	struct mdss_iommu_map_type *iommu_map;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index acac6b9..5d56df4 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -414,6 +414,8 @@
 	/* disable DSI controller */
 	mdss_dsi_controller_cfg(0, pdata);
 
+	/* disable DSI phy */
+	mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
 	ret = mdss_dsi_panel_power_on(pdata, 0);
 	if (ret) {
 		pr_err("%s: Panel power off failed\n", __func__);
@@ -1078,12 +1080,12 @@
 	cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
 			"qcom,cont-splash-enabled");
 	if (!cont_splash_enabled) {
-		pr_info("%s:%d Continous splash flag not found.\n",
+		pr_info("%s:%d Continuous splash flag not found.\n",
 				__func__, __LINE__);
 		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
 		ctrl_pdata->panel_data.panel_info.panel_power_on = 0;
 	} else {
-		pr_info("%s:%d Continous splash flag enabled.\n",
+		pr_info("%s:%d Continuous splash flag enabled.\n",
 				__func__, __LINE__);
 
 		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 1a64be4..3c0dfc2 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -52,6 +52,8 @@
 
 void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl)
 {
+	int ret;
+
 	if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
 		mdss_dsi0_hw.ptr = (void *)(ctrl);
 		ctrl->mdss_hw = &mdss_dsi0_hw;
@@ -60,7 +62,8 @@
 		ctrl->mdss_hw = &mdss_dsi1_hw;
 	}
 
-	if (!mdss_register_irq(ctrl->mdss_hw))
+	ret = mdss_register_irq(ctrl->mdss_hw);
+	if (ret)
 		pr_err("%s: mdss_register_irq failed.\n", __func__);
 }
 
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index a7ea948..97a07ed 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -143,9 +143,9 @@
 	if (!bl_lvl && value)
 		bl_lvl = 1;
 
-	mutex_lock(&mfd->lock);
+	mutex_lock(&mfd->bl_lock);
 	mdss_fb_set_backlight(mfd, bl_lvl);
-	mutex_unlock(&mfd->lock);
+	mutex_unlock(&mfd->bl_lock);
 }
 
 static struct led_classdev backlight_led = {
@@ -263,6 +263,7 @@
 	mfd->mdp = *mdp_instance;
 
 	mutex_init(&mfd->lock);
+	mutex_init(&mfd->bl_lock);
 
 	fbi_list[fbi_list_index++] = fbi;
 
@@ -524,7 +525,7 @@
 	(*bl_lvl) = temp;
 }
 
-/* must call this function from within mfd->lock */
+/* must call this function from within mfd->bl_lock */
 void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
 {
 	struct mdss_panel_data *pdata;
@@ -566,11 +567,11 @@
 	if (unset_bl_level && !bl_updated) {
 		pdata = dev_get_platdata(&mfd->pdev->dev);
 		if ((pdata) && (pdata->set_backlight)) {
-			mutex_lock(&mfd->lock);
+			mutex_lock(&mfd->bl_lock);
 			mfd->bl_level = unset_bl_level;
 			pdata->set_backlight(pdata, mfd->bl_level);
 			bl_level_old = unset_bl_level;
-			mutex_unlock(&mfd->lock);
+			mutex_unlock(&mfd->bl_lock);
 			bl_updated = 1;
 		}
 	}
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index fdbbea9..6f6f490 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -102,6 +102,7 @@
 	u32 bl_level;
 	u32 bl_scale;
 	u32 bl_min_lvl;
+	struct mutex bl_lock;
 	struct mutex lock;
 
 	struct platform_device *pdev;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 1ff8acf..dc51b1b 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -84,6 +84,8 @@
 static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
 static irqreturn_t hdmi_tx_isr(int irq, void *data);
 static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
+static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
+	enum hdmi_tx_power_module_type module, int enable);
 
 struct mdss_hw hdmi_tx_hw = {
 	.hw_ndx = MDSS_HW_HDMI,
@@ -93,12 +95,15 @@
 
 struct dss_gpio hpd_gpio_config[] = {
 	{0, 1, COMPATIBLE_NAME "-hpd"},
-	{0, 1, COMPATIBLE_NAME "-ddc-clk"},
-	{0, 1, COMPATIBLE_NAME "-ddc-data"},
 	{0, 1, COMPATIBLE_NAME "-mux-en"},
 	{0, 0, COMPATIBLE_NAME "-mux-sel"}
 };
 
+struct dss_gpio ddc_gpio_config[] = {
+	{0, 1, COMPATIBLE_NAME "-ddc-clk"},
+	{0, 1, COMPATIBLE_NAME "-ddc-data"}
+};
+
 struct dss_gpio core_gpio_config[] = {
 };
 
@@ -110,6 +115,7 @@
 {
 	switch (module) {
 	case HDMI_TX_HPD_PM:	return "HDMI_TX_HPD_PM";
+	case HDMI_TX_DDC_PM:	return "HDMI_TX_DDC_PM";
 	case HDMI_TX_CORE_PM:	return "HDMI_TX_CORE_PM";
 	case HDMI_TX_CEC_PM:	return "HDMI_TX_CEC_PM";
 	default: return "???";
@@ -187,6 +193,7 @@
 {
 	switch (module) {
 	case HDMI_TX_HPD_PM:	return "HDMI_TX_HPD_PM";
+	case HDMI_TX_DDC_PM:	return "HDMI_TX_DDC_PM";
 	case HDMI_TX_CORE_PM:	return "HDMI_TX_CORE_PM";
 	case HDMI_TX_CEC_PM:	return "HDMI_TX_CEC_PM";
 	default: return "???";
@@ -810,11 +817,19 @@
 	DEV_DBG("%s: Got HPD interrupt\n", __func__);
 
 	if (hdmi_ctrl->hpd_state) {
+		if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true)) {
+			DEV_ERR("%s: Failed to enable ddc power\n", __func__);
+			return;
+		}
+
 		hdmi_tx_read_sink_info(hdmi_ctrl);
 		hdmi_tx_send_cable_notification(hdmi_ctrl, 1);
 		DEV_INFO("%s: sense cable CONNECTED: state switch to %d\n",
 			__func__, hdmi_ctrl->sdev.state);
 	} else {
+		if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false))
+			DEV_WARN("%s: Failed to disable ddc power\n", __func__);
+
 		hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
 		DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
 			__func__, hdmi_ctrl->sdev.state);
@@ -2323,6 +2338,13 @@
 
 	hdmi_tx_set_mode(hdmi_ctrl, false);
 
+	if (hdmi_ctrl->hpd_state) {
+		rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, 0);
+		if (rc)
+			DEV_INFO("%s: Failed to disable ddc power. Error=%d\n",
+				__func__, rc);
+	}
+
 	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
 	if (rc)
 		DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
@@ -2884,6 +2906,7 @@
 		mp->clk_config[1].rate = 0;
 		break;
 
+	case HDMI_TX_DDC_PM:
 	case HDMI_TX_CEC_PM:
 		mp->num_clk = 0;
 		DEV_DBG("%s: no clk\n", __func__);
@@ -2943,6 +2966,9 @@
 	case HDMI_TX_HPD_PM:
 		mod_name = "hpd";
 		break;
+	case HDMI_TX_DDC_PM:
+		mod_name = "ddc";
+		break;
 	case HDMI_TX_CORE_PM:
 		mod_name = "core";
 		break;
@@ -3139,6 +3165,10 @@
 		gpio_list_size = ARRAY_SIZE(hpd_gpio_config);
 		gpio_list = hpd_gpio_config;
 		break;
+	case HDMI_TX_DDC_PM:
+		gpio_list_size = ARRAY_SIZE(ddc_gpio_config);
+		gpio_list = ddc_gpio_config;
+		break;
 	case HDMI_TX_CORE_PM:
 		gpio_list_size = ARRAY_SIZE(core_gpio_config);
 		gpio_list = core_gpio_config;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 8d9a477..ce3c00c 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -25,6 +25,7 @@
 
 enum hdmi_tx_power_module_type {
 	HDMI_TX_HPD_PM,
+	HDMI_TX_DDC_PM,
 	HDMI_TX_CORE_PM,
 	HDMI_TX_CEC_PM,
 	HDMI_TX_MAX_PM
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 2f09fee..22de7e4 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -134,6 +134,7 @@
 				       char *prop_name);
 static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_misc(struct platform_device *pdev);
+static int mdss_mdp_parse_dt_ad_cfg(struct platform_device *pdev);
 
 int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd)
 {
@@ -1161,6 +1162,12 @@
 		return rc;
 	}
 
+	rc = mdss_mdp_parse_dt_ad_cfg(pdev);
+	if (rc) {
+		pr_err("Error in device tree : ad\n");
+		return rc;
+	}
+
 	return 0;
 }
 
@@ -1483,6 +1490,41 @@
 	return 0;
 }
 
+static int mdss_mdp_parse_dt_ad_cfg(struct platform_device *pdev)
+{
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+	u32 *ad_offsets = NULL;
+	int rc;
+
+	mdata->nad_cfgs = mdss_mdp_parse_dt_prop_len(pdev, "qcom,mdss-ad-off");
+
+	if (mdata->nad_cfgs == 0) {
+		mdata->ad_cfgs = NULL;
+		return 0;
+	}
+	if (mdata->nad_cfgs > mdata->nmixers_intf)
+		return -EINVAL;
+
+	ad_offsets = kzalloc(sizeof(u32) * mdata->nad_cfgs, GFP_KERNEL);
+	if (!ad_offsets) {
+		pr_err("no mem assigned: kzalloc fail\n");
+		return -ENOMEM;
+	}
+
+	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-ad-off", ad_offsets,
+					mdata->nad_cfgs);
+	if (rc)
+		goto parse_done;
+
+	rc = mdss_mdp_ad_addr_setup(mdata, ad_offsets);
+	if (rc)
+		pr_err("unable to setup assertive display\n");
+
+parse_done:
+	kfree(ad_offsets);
+	return rc;
+}
+
 static int mdss_mdp_parse_dt_handler(struct platform_device *pdev,
 		char *prop_name, u32 *offsets, int len)
 {
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 6018e6f..6be2b73 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -109,6 +109,12 @@
 struct mdss_mdp_ctl;
 typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
 
+struct mdss_mdp_vsync_handler {
+	mdp_vsync_handler_t vsync_handler;
+	u32 ref_cnt;
+	struct list_head list;
+};
+
 struct mdss_mdp_ctl {
 	u32 num;
 	char __iomem *base;
@@ -144,14 +150,18 @@
 	struct mutex lock;
 
 	struct mdss_panel_data *panel_data;
+	struct mdss_mdp_vsync_handler vsync_handler;
 
 	int (*start_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
 	int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
 	int (*wait_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
-	int (*set_vsync_handler) (struct mdss_mdp_ctl *, mdp_vsync_handler_t);
 	u32 (*read_line_cnt_fnc) (struct mdss_mdp_ctl *);
+	int (*add_vsync_handler) (struct mdss_mdp_ctl *,
+					struct mdss_mdp_vsync_handler *);
+	int (*remove_vsync_handler) (struct mdss_mdp_ctl *,
+					struct mdss_mdp_vsync_handler *);
 
 	void *priv_data;
 };
@@ -237,6 +247,25 @@
 	spinlock_t hist_lock;
 };
 
+struct mdss_ad_info {
+	char __iomem *base;
+	u8 num;
+	u32 sts;
+	u32 state;
+	u32 ad_data;
+	u32 ad_data_mode;
+	struct mdss_ad_init init;
+	struct mdss_ad_cfg cfg;
+	struct mutex lock;
+	struct work_struct calc_work;
+	struct msm_fb_data_type *mfd;
+	struct mdss_mdp_vsync_handler handle;
+	struct completion comp;
+	u32 last_str;
+	u32 last_bl;
+	u32 calc_itr;
+};
+
 struct pp_sts_type {
 	u32 pa_sts;
 	u32 pcc_sts;
@@ -413,7 +442,7 @@
 int mdss_mdp_pp_init(struct device *dev);
 void mdss_mdp_pp_term(struct device *dev);
 
-int mdss_mdp_pp_resume(u32 mixer_num);
+int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 mixer_num);
 
 int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl);
@@ -453,6 +482,13 @@
 				struct mdp_histogram_data *hist);
 void mdss_mdp_hist_intr_done(u32 isr);
 
+int mdss_ad_init_checks(struct msm_fb_data_type *mfd);
+int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
+				struct mdss_ad_init_cfg *init_cfg);
+int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
+				struct mdss_ad_input *input);
+int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off);
+
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
 					  u32 type);
 struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 6c9cce2..568fc37 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -300,8 +300,9 @@
 	ctl->prepare_fnc = NULL;
 	ctl->display_fnc = NULL;
 	ctl->wait_fnc = NULL;
-	ctl->set_vsync_handler = NULL;
 	ctl->read_line_cnt_fnc = NULL;
+	ctl->add_vsync_handler = NULL;
+	ctl->remove_vsync_handler = NULL;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
@@ -890,7 +891,7 @@
 		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), 0);
 
 	mixer = ctl->mixer_left;
-	mdss_mdp_pp_resume(mixer->num);
+	mdss_mdp_pp_resume(ctl, mixer->num);
 	mixer->params_changed++;
 
 	temp = MDSS_MDP_REG_READ(MDSS_MDP_REG_DISP_INTF_SEL);
@@ -937,7 +938,7 @@
 	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_RESET, NULL);
 	if (ret) {
 		pr_err("panel power on failed ctl=%d\n", ctl->num);
-		return ret;
+		goto error;
 	}
 
 	ret = mdss_mdp_ctl_start_sub(ctl);
@@ -950,7 +951,7 @@
 			struct mdss_mdp_mixer *mixer = ctl->mixer_right;
 			u32 out, off;
 
-			mdss_mdp_pp_resume(mixer->num);
+			mdss_mdp_pp_resume(ctl, mixer->num);
 			mixer->params_changed++;
 			out = (mixer->height << 16) | mixer->width;
 			off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
@@ -960,6 +961,7 @@
 	}
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+error:
 	mutex_unlock(&ctl->lock);
 
 	return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index a59560e..6ec5b63 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -351,6 +351,41 @@
 #define MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS		0x2B0
 
 
+#define MDSS_MDP_REG_AD_BYPASS				0x000
+#define MDSS_MDP_REG_AD_CTRL_0				0x004
+#define MDSS_MDP_REG_AD_CTRL_1				0x008
+#define MDSS_MDP_REG_AD_FRAME_SIZE			0x00C
+#define MDSS_MDP_REG_AD_CON_CTRL_0			0x010
+#define MDSS_MDP_REG_AD_CON_CTRL_1			0x014
+#define MDSS_MDP_REG_AD_STR_MAN				0x018
+#define MDSS_MDP_REG_AD_VAR				0x01C
+#define MDSS_MDP_REG_AD_DITH				0x020
+#define MDSS_MDP_REG_AD_DITH_CTRL			0x024
+#define MDSS_MDP_REG_AD_AMP_LIM				0x028
+#define MDSS_MDP_REG_AD_SLOPE				0x02C
+#define MDSS_MDP_REG_AD_BW_LVL				0x030
+#define MDSS_MDP_REG_AD_LOGO_POS			0x034
+#define MDSS_MDP_REG_AD_LUT_FI				0x038
+#define MDSS_MDP_REG_AD_LUT_CC				0x07C
+#define MDSS_MDP_REG_AD_STR_LIM				0x0C8
+#define MDSS_MDP_REG_AD_CALIB_AB			0x0CC
+#define MDSS_MDP_REG_AD_CALIB_CD			0x0D0
+#define MDSS_MDP_REG_AD_MODE_SEL			0x0D4
+#define MDSS_MDP_REG_AD_TFILT_CTRL			0x0D8
+#define MDSS_MDP_REG_AD_BL_MINMAX			0x0DC
+#define MDSS_MDP_REG_AD_BL				0x0E0
+#define MDSS_MDP_REG_AD_BL_MAX				0x0E8
+#define MDSS_MDP_REG_AD_AL				0x0EC
+#define MDSS_MDP_REG_AD_AL_MIN				0x0F0
+#define MDSS_MDP_REG_AD_AL_FILT				0x0F4
+#define MDSS_MDP_REG_AD_CFG_BUF				0x0F8
+#define MDSS_MDP_REG_AD_LUT_AL				0x100
+#define MDSS_MDP_REG_AD_TARG_STR			0x144
+#define MDSS_MDP_REG_AD_START_CALC			0x148
+#define MDSS_MDP_REG_AD_STR_OUT				0x14C
+#define MDSS_MDP_REG_AD_BL_OUT				0x154
+#define MDSS_MDP_REG_AD_CALC_DONE			0x158
+
 enum mdss_mdp_dspp_index {
 	MDSS_MDP_DSPP0,
 	MDSS_MDP_DSPP1,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index fff8a6e..eb2bd21 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -44,13 +44,21 @@
 
 	/* te config */
 	u8 tear_check;
-	u16 total_lcd_lines;
-	u16 v_porch;	/* vertical porches */
-	u32 vsync_cnt;
+	u16 height;	/* panel height */
+	u16 vporch;	/* vertical porches */
+	u32 vclk_line;	/* vsync clock per line */
 };
 
 struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
 
+/*
+ * TE configuration:
+ * dsi byte clock calculated base on 70 fps
+ * around 14 ms to complete a kickoff cycle if te disabled
+ * vclk_line base on 60 fps
+ * write is faster than read
+ * init == start == rdptr
+ */
 static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
 			struct mdss_mdp_cmd_ctx *ctx, int enable)
 {
@@ -59,15 +67,21 @@
 	cfg = BIT(19); /* VSYNC_COUNTER_EN */
 	if (ctx->tear_check)
 		cfg |= BIT(20);	/* VSYNC_IN_EN */
-	cfg |= ctx->vsync_cnt;
+	cfg |= ctx->vclk_line;
 
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg);
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT,
 				0xfff0); /* set to verh height */
-	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL, 0);
-	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_RD_PTR_IRQ, 0);
 
-	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_START_POS, ctx->v_porch);
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_VSYNC_INIT_VAL,
+						ctx->height);
+
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_RD_PTR_IRQ,
+						ctx->height + 1);
+
+	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_START_POS,
+						ctx->height);
+
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
 			   (CONTINUE_TRESHOLD << 16) | (START_THRESHOLD));
 
@@ -85,7 +99,6 @@
 
 	if (pinfo->mipi.vsync_enable && enable) {
 		u32 mdp_vsync_clk_speed_hz, total_lines;
-		u32 vsync_cnt_cfg_dem;
 
 		mdss_mdp_vsync_clk_enable(1);
 
@@ -100,21 +113,18 @@
 		}
 
 		ctx->tear_check = pinfo->mipi.hw_vsync_mode;
-
-		total_lines = pinfo->lcdc.v_back_porch +
-				    pinfo->lcdc.v_front_porch +
-				    pinfo->lcdc.v_pulse_width + pinfo->yres;
-
-		vsync_cnt_cfg_dem =
-			mult_frac(pinfo->mipi.frame_rate * total_lines,
-						1, 100);
-
-		ctx->vsync_cnt = mdp_vsync_clk_speed_hz / vsync_cnt_cfg_dem;
-
-		ctx->v_porch = pinfo->lcdc.v_back_porch +
+		ctx->height = pinfo->yres;
+		ctx->vporch = pinfo->lcdc.v_back_porch +
 				    pinfo->lcdc.v_front_porch +
 				    pinfo->lcdc.v_pulse_width;
-		ctx->total_lcd_lines = total_lines;
+
+		total_lines = ctx->height + ctx->vporch;
+		total_lines *= pinfo->mipi.frame_rate;
+		ctx->vclk_line = mdp_vsync_clk_speed_hz / total_lines;
+
+		pr_debug("%s: fr=%d tline=%d vcnt=%d vrate=%d\n",
+			__func__, pinfo->mipi.frame_rate, total_lines,
+				ctx->vclk_line, mdp_vsync_clk_speed_hz);
 	} else {
 		enable = 0;
 	}
@@ -225,7 +235,7 @@
 }
 
 static int mdss_mdp_cmd_vsync_ctrl(struct mdss_mdp_ctl *ctl,
-		mdp_vsync_handler_t send_vsync)
+		struct mdss_mdp_vsync_handler *handler)
 {
 	struct mdss_mdp_cmd_ctx *ctx;
 	unsigned long flags;
@@ -237,7 +247,7 @@
 		return -ENODEV;
 	}
 
-	enable = (send_vsync != NULL);
+	enable = (handler->vsync_handler != NULL);
 
 	pr_debug("%s: ctx=%p ctx=%d enabled=%d %d clk_enabled=%d clk_ctrl=%d\n",
 			__func__, ctx, ctx->pp_num, ctx->vsync_enabled, enable,
@@ -253,7 +263,7 @@
 		spin_lock_irqsave(&ctx->clk_lock, flags);
 		ctx->clk_control = 0;
 		ctx->expire = 0;
-		ctx->send_vsync = send_vsync;
+		ctx->send_vsync = handler->vsync_handler;
 		spin_unlock_irqrestore(&ctx->clk_lock, flags);
 		if (ctx->clk_enabled == 0) {
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
@@ -366,6 +376,7 @@
 {
 	struct mdss_mdp_cmd_ctx *ctx;
 	int need_wait = 0;
+	struct mdss_mdp_vsync_handler null_handle;
 	int ret;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
@@ -389,7 +400,8 @@
 
 	ctx->panel_on = 0;
 
-	mdss_mdp_cmd_vsync_ctrl(ctl, NULL);
+	null_handle.vsync_handler = NULL;
+	mdss_mdp_cmd_vsync_ctrl(ctl, &null_handle);
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctl->intf_num,
 				   NULL, NULL);
@@ -468,7 +480,8 @@
 	ctl->stop_fnc = mdss_mdp_cmd_stop;
 	ctl->display_fnc = mdss_mdp_cmd_kickoff;
 	ctl->wait_fnc = mdss_mdp_cmd_wait4comp;
-	ctl->set_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
+	ctl->add_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
+	ctl->remove_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
 
 	pr_debug("%s:-\n", __func__);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 94ae710..d68a3d4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -13,11 +13,16 @@
 
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
+#include <linux/iopoll.h>
+
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
-/* wait for at most 2 vsync for lowest refresh rate (24hz) */
-#define VSYNC_TIMEOUT msecs_to_jiffies(84)
+/* wait for at least 2 vsyncs for lowest refresh rate (24hz) */
+#define VSYNC_TIMEOUT_US 100000
+
+#define MDP_INTR_MASK_INTF_VSYNC(intf_num) \
+	(1 << (2 * (intf_num - MDSS_MDP_INTF0) + MDSS_MDP_IRQ_INTF_VSYNC))
 
 /* intf timing settings */
 struct intf_timing_params {
@@ -45,12 +50,14 @@
 	u8 ref_cnt;
 
 	u8 timegen_en;
+	bool polling_en;
+	u32 poll_cnt;
 	struct completion vsync_comp;
 	int wait_pending;
 
 	atomic_t vsync_ref;
 	spinlock_t vsync_lock;
-	mdp_vsync_handler_t vsync_handler;
+	struct list_head vsync_handlers;
 };
 
 static inline void mdp_video_write(struct mdss_mdp_video_ctx *ctx,
@@ -92,6 +99,7 @@
 				offsets[i], head[i].base);
 		head[i].ref_cnt = 0;
 		head[i].intf_num = i + MDSS_MDP_INTF0;
+		INIT_LIST_HEAD(&head[i].vsync_handlers);
 	}
 
 	mdata->video_intf = head;
@@ -212,12 +220,54 @@
 		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
 }
 
-static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
-		mdp_vsync_handler_t vsync_handler)
+static int mdss_mdp_video_add_vsync_handler(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_vsync_handler *handle)
 {
 	struct mdss_mdp_video_ctx *ctx;
 	unsigned long flags;
-	int need_update;
+	struct mdss_mdp_vsync_handler *tmp;
+	bool exist = false;
+	int ret = 0;
+
+	if (!handle || !(handle->vsync_handler)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		ret = -ENODEV;
+		goto exit;
+	}
+
+	spin_lock_irqsave(&ctx->vsync_lock, flags);
+	list_for_each_entry(tmp, &(ctx->vsync_handlers), list) {
+		if (tmp->vsync_handler == handle->vsync_handler) {
+			exist = true;
+			tmp->ref_cnt++;
+		}
+	}
+	if (!exist) {
+		handle->ref_cnt = 1;
+		list_add(&handle->list, &ctx->vsync_handlers);
+	}
+
+	video_vsync_irq_enable(ctl);
+	spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+exit:
+	return ret;
+}
+
+/* passing NULL as handle or vsync_handler will clear all handlers */
+static int mdss_mdp_video_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_vsync_handler *handle)
+{
+	struct mdss_mdp_video_ctx *ctx;
+	unsigned long flags;
+	struct mdss_mdp_vsync_handler *tmp, *q;
+	bool exist = true;
+	bool used = false;
 
 	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
 	if (!ctx) {
@@ -226,18 +276,20 @@
 	}
 
 	spin_lock_irqsave(&ctx->vsync_lock, flags);
-	need_update = (!ctx->vsync_handler && vsync_handler) ||
-			(ctx->vsync_handler && !vsync_handler);
-	ctx->vsync_handler = vsync_handler;
-	spin_unlock_irqrestore(&ctx->vsync_lock, flags);
-
-	if (need_update) {
-		if (vsync_handler)
-			video_vsync_irq_enable(ctl);
-		else
-			video_vsync_irq_disable(ctl);
+	list_for_each_entry_safe(tmp, q, &ctx->vsync_handlers, list) {
+		if (handle && handle->vsync_handler)
+			exist = (tmp->vsync_handler == handle->vsync_handler);
+		if (exist) {
+			tmp->ref_cnt--;
+			if (handle && handle->vsync_handler)
+				used = (tmp->ref_cnt != 0);
+			if (!used) {
+				video_vsync_irq_disable(ctl);
+				list_del_init(&tmp->list);
+			}
+		}
 	}
-
+	spin_unlock_irqrestore(&ctx->vsync_lock, flags);
 	return 0;
 }
 
@@ -274,7 +326,7 @@
 			ctl->intf_num);
 	}
 
-	mdss_mdp_video_set_vsync_handler(ctl, NULL);
+	mdss_mdp_video_remove_vsync_handler(ctl, NULL);
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
 				   NULL, NULL);
@@ -291,6 +343,7 @@
 {
 	struct mdss_mdp_ctl *ctl = arg;
 	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+	struct mdss_mdp_vsync_handler *tmp;
 	ktime_t vsync_time;
 
 	if (!ctx) {
@@ -304,13 +357,53 @@
 	pr_debug("intr ctl=%d vsync cnt=%u vsync_time=%d\n",
 		 ctl->num, ctl->vsync_cnt, (int)ktime_to_ms(vsync_time));
 
+	ctx->polling_en = false;
 	complete_all(&ctx->vsync_comp);
 	spin_lock(&ctx->vsync_lock);
-	if (ctx->vsync_handler)
-		ctx->vsync_handler(ctl, vsync_time);
+	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+		tmp->vsync_handler(ctl, vsync_time);
+	}
 	spin_unlock(&ctx->vsync_lock);
 }
 
+static int mdss_mdp_video_pollwait(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+	u32 mask, status;
+	int rc;
+
+	mask = MDP_INTR_MASK_INTF_VSYNC(ctl->intf_num);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	rc = readl_poll_timeout(ctl->mdata->mdp_base + MDSS_MDP_REG_INTR_STATUS,
+		status,
+		(status & mask) || try_wait_for_completion(&ctx->vsync_comp),
+		1000,
+		VSYNC_TIMEOUT_US);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	if (rc == 0) {
+		pr_debug("vsync poll successful! rc=%d status=0x%x\n",
+				rc, status);
+		ctx->poll_cnt++;
+		if (status) {
+			struct mdss_mdp_vsync_handler *tmp;
+			unsigned long flags;
+			ktime_t vsync_time = ktime_get();
+
+			spin_lock_irqsave(&ctx->vsync_lock, flags);
+			list_for_each_entry(tmp, &ctx->vsync_handlers, list)
+				tmp->vsync_handler(ctl, vsync_time);
+			spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+		}
+	} else {
+		pr_warn("vsync poll timed out! rc=%d status=0x%x mask=0x%x\n",
+				rc, status, mask);
+	}
+
+	return rc;
+}
+
 static int mdss_mdp_video_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_video_ctx *ctx;
@@ -324,9 +417,20 @@
 
 	WARN(!ctx->wait_pending, "waiting without commit! ctl=%d", ctl->num);
 
-	rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
-			VSYNC_TIMEOUT);
-	WARN(rc <= 0, "vsync timed out (%d) ctl=%d\n", rc, ctl->num);
+	if (ctx->polling_en) {
+		rc = mdss_mdp_video_pollwait(ctl);
+	} else {
+		rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+				usecs_to_jiffies(VSYNC_TIMEOUT_US));
+		if (rc < 0) {
+			pr_warn("vsync wait interrupted ctl=%d\n", ctl->num);
+		} else if (rc == 0) {
+			pr_warn("vsync wait timeout %d, fallback to poll mode\n",
+					ctl->num);
+			ctx->polling_en++;
+			rc = mdss_mdp_video_pollwait(ctl);
+		}
+	}
 
 	if (ctx->wait_pending) {
 		ctx->wait_pending = 0;
@@ -343,7 +447,7 @@
 		return;
 
 	ctl->underrun_cnt++;
-	pr_warn("display underrun detected for ctl=%d count=%d\n", ctl->num,
+	pr_debug("display underrun detected for ctl=%d count=%d\n", ctl->num,
 			ctl->underrun_cnt);
 }
 
@@ -381,7 +485,7 @@
 		wmb();
 
 		rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
-				VSYNC_TIMEOUT);
+				usecs_to_jiffies(VSYNC_TIMEOUT_US));
 		WARN(rc <= 0, "timeout (%d) enabling timegen on ctl=%d\n",
 				rc, ctl->num);
 
@@ -471,8 +575,9 @@
 	ctl->stop_fnc = mdss_mdp_video_stop;
 	ctl->display_fnc = mdss_mdp_video_display;
 	ctl->wait_fnc = mdss_mdp_video_wait4comp;
-	ctl->set_vsync_handler = mdss_mdp_video_set_vsync_handler;
 	ctl->read_line_cnt_fnc = mdss_mdp_video_line_count;
+	ctl->add_vsync_handler = mdss_mdp_video_add_vsync_handler;
+	ctl->remove_vsync_handler = mdss_mdp_video_remove_vsync_handler;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 6c90794..fed13e6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -179,6 +179,14 @@
 			       req->src_rect.h, req->dst_rect.h);
 			return -EINVAL;
 		}
+
+		if (req->flags & MDP_BWC_EN) {
+			if ((req->src.width != req->src_rect.w) ||
+			    (req->src.height != req->src_rect.h)) {
+				pr_err("BWC: unequal src img and rect w,h\n");
+				return -EINVAL;
+			}
+		}
 	}
 
 	if (fmt->is_yuv) {
@@ -189,6 +197,13 @@
 		}
 	}
 
+	if (req->flags & MDP_DEINTERLACE) {
+		if ((req->src.width % 4 != 0) || (req->src.height % 4 != 0)) {
+			pr_err("interlaced fmt w,h need to be even post div\n");
+			return -EINVAL;
+		}
+	}
+
 	return 0;
 }
 
@@ -1302,7 +1317,7 @@
 
 	if (!ctl)
 		return -ENODEV;
-	if (!ctl->set_vsync_handler)
+	if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
 		return -ENOTSUPP;
 
 	rc = mutex_lock_interruptible(&ctl->lock);
@@ -1325,9 +1340,9 @@
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (en)
-		rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
+		rc = ctl->add_vsync_handler(ctl, &ctl->vsync_handler);
 	else
-		rc = ctl->set_vsync_handler(ctl, NULL);
+		rc = ctl->remove_vsync_handler(ctl, &ctl->vsync_handler);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
 	mutex_unlock(&ctl->lock);
@@ -1517,7 +1532,7 @@
 {
 	int ret = 0;
 	int curr_bl;
-	mutex_lock(&mfd->lock);
+	mutex_lock(&mfd->bl_lock);
 	curr_bl = mfd->bl_level;
 	mfd->bl_scale = data->scale;
 	mfd->bl_min_lvl = data->min_lvl;
@@ -1526,7 +1541,7 @@
 
 	/* update current backlight to use new scaling*/
 	mdss_fb_set_backlight(mfd, curr_bl);
-	mutex_unlock(&mfd->lock);
+	mutex_unlock(&mfd->bl_lock);
 	return ret;
 }
 
@@ -1600,6 +1615,16 @@
 		ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
 						&mdp_pp.data.bl_scale_data);
 		break;
+	case mdp_op_ad_cfg:
+		ret = mdss_mdp_ad_config(mfd, &mdp_pp.data.ad_init_cfg);
+		break;
+	case mdp_op_ad_input:
+		ret = mdss_mdp_ad_input(mfd, &mdp_pp.data.ad_input);
+		if (ret > 0) {
+			ret = 0;
+			copyback = 1;
+		}
+		break;
 	default:
 		pr_err("Unsupported request to MDP_PP IOCTL.\n");
 		ret = -EINVAL;
@@ -1865,6 +1890,8 @@
 				mfd->index);
 			return PTR_ERR(ctl);
 		}
+		ctl->vsync_handler.vsync_handler =
+						mdss_mdp_overlay_handle_vsync;
 
 		if (mfd->split_display && pdata->next) {
 			/* enable split display */
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 8bd5674..12ff943 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -119,6 +119,39 @@
 #define PP_STS_ENABLE	0x1
 #define PP_STS_GAMUT_FIRST	0x2
 
+#define PP_AD_STATE_INIT	0x2
+#define PP_AD_STATE_CFG		0x4
+#define PP_AD_STATE_DATA	0x8
+#define PP_AD_STATE_RUN		0x10
+#define PP_AD_STATE_VSYNC	0x20
+
+#define PP_AD_STATE_IS_INITCFG(st)	(((st) & PP_AD_STATE_INIT) &&\
+						((st) & PP_AD_STATE_CFG))
+
+#define PP_AD_STATE_IS_READY(st)	(((st) & PP_AD_STATE_INIT) &&\
+						((st) & PP_AD_STATE_CFG) &&\
+						((st) & PP_AD_STATE_DATA))
+
+#define PP_AD_STS_DIRTY_INIT	0x2
+#define PP_AD_STS_DIRTY_CFG	0x4
+#define PP_AD_STS_DIRTY_DATA	0x8
+#define PP_AD_STS_DIRTY_VSYNC	0x10
+
+#define PP_AD_STS_IS_DIRTY(sts) (((sts) & PP_AD_STS_DIRTY_INIT) ||\
+					((sts) & PP_AD_STS_DIRTY_CFG))
+
+/* Bits 0 and 1 */
+#define MDSS_AD_INPUT_AMBIENT	(0x03)
+/* Bits 3 and 7 */
+#define MDSS_AD_INPUT_STRENGTH	(0x88)
+/*
+ * Check data by shifting by mode to see if it matches to the
+ * MDSS_AD_INPUT_* bitfields
+ */
+#define MDSS_AD_MODE_DATA_MATCH(mode, data) ((1 << (mode)) & (data))
+#define MDSS_AD_RUNNING_AUTO_BL(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
+				((ad)->cfg.mode == MDSS_AD_MODE_AUTO_BL))
+
 #define SHARP_STRENGTH_DEFAULT	32
 #define SHARP_EDGE_THR_DEFAULT	112
 #define SHARP_SMOOTH_THR_DEFAULT	8
@@ -187,7 +220,14 @@
 static void pp_sharp_config(char __iomem *offset,
 				struct pp_sts_type *pp_sts,
 				struct mdp_sharp_cfg *sharp_config);
+static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t);
+static void pp_ad_cfg_write(struct mdss_ad_info *ad);
+static void pp_ad_init_write(struct mdss_ad_info *ad);
+static void pp_ad_input_write(struct mdss_ad_info *ad, u32 bl_lvl);
+static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
+static void pp_ad_cfg_lut(char __iomem *offset, u32 *data);
 
+static u32 last_sts, last_state;
 
 int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
 				   struct mdp_csc_cfg *data)
@@ -906,8 +946,11 @@
 	u32 data;
 	char __iomem *basel;
 	int i, ret = 0;
+	struct mdss_data_type *mdata;
 
-	if (!mixer || !ctl)
+	mdata = ctl->mdata;
+
+	if (!mixer || !ctl || !mdata)
 		return -EINVAL;
 
 	dspp_num = mixer->num;
@@ -929,9 +972,15 @@
 	else
 		flags = 0;
 
+	if (dspp_num < mdata->nad_cfgs) {
+		ret = mdss_mdp_ad_setup(ctl->mfd);
+		if (ret < 0)
+			pr_warn("ad_setup(dspp%d) returns %d", dspp_num, ret);
+	}
 	/* nothing to update */
-	if ((!flags) && (!(opmode)))
+	if ((!flags) && (!(opmode)) && (ret <= 0))
 		goto dspp_exit;
+	ret = 0;
 
 	pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
 
@@ -1077,16 +1126,30 @@
  * Set dirty and write bits on features that were enabled so they will be
  * reconfigured
  */
-int mdss_mdp_pp_resume(u32 mixer_num)
+int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 mixer_num)
 {
 	u32 flags = 0;
 	struct pp_sts_type pp_sts;
-
+	struct mdss_ad_info *ad;
+	struct mdss_data_type *mdata = ctl->mdata;
 	if (mixer_num >= MDSS_MDP_MAX_DSPP) {
 		pr_warn("invalid mixer_num");
 		return -EINVAL;
 	}
 
+	if (mixer_num < mdata->nad_cfgs) {
+		ad = &mdata->ad_cfgs[mixer_num];
+
+		if (PP_AD_STATE_CFG & ad->state)
+			pp_ad_cfg_write(ad);
+		if (PP_AD_STATE_INIT & ad->state)
+			pp_ad_init_write(ad);
+		if (PP_AD_STATE_DATA & ad->state)
+			pp_ad_input_write(ad, ctl->mfd->bl_level);
+		if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
+			ctl->add_vsync_handler(ctl, &ad->handle);
+	}
+
 	pp_sts = mdss_pp_res->pp_dspp_sts[mixer_num];
 
 	if (pp_sts.pa_sts & PP_STS_ENABLE) {
@@ -2519,3 +2582,472 @@
 		}
 	};
 }
+
+#define MDSS_AD_MAX_MIXERS 1
+int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
+{
+	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+	u32 mixer_num;
+	u32 ret = -EINVAL;
+	int i = 0;
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+
+	if (!mfd || !mdata)
+		return ret;
+
+	if (mdata->nad_cfgs == 0) {
+		pr_debug("Assertive Display not supported by device");
+		return -ENODEV;
+	}
+
+	if (mfd->panel_info->type == MIPI_CMD_PANEL) {
+		pr_debug("Command panel not supported");
+		return -EINVAL;
+	}
+
+	mixer_num = mdss_mdp_get_ctl_mixers(mfd->index, mixer_id);
+	if (!mixer_num || mixer_num > MDSS_AD_MAX_MIXERS) {
+		pr_err("invalid mixer_num, %d", mixer_num);
+		return ret;
+	}
+
+	do {
+		if (mixer_id[i] >= mdata->nad_cfgs) {
+			pr_err("invalid mixer input, %d", mixer_id[i]);
+			return ret;
+		}
+		i++;
+	} while (i < mixer_num);
+
+	return mixer_id[0];
+}
+
+int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
+			struct mdss_ad_init_cfg *init_cfg)
+{
+	int ad_num;
+	struct mdss_ad_info *ad;
+	struct mdss_data_type *mdata;
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	ctl = mdp5_data->ctl;
+
+	ad_num = mdss_ad_init_checks(mfd);
+	if (ad_num < 0)
+		return ad_num;
+
+	mdata = mdss_mdp_get_mdata();
+	ad = &mdata->ad_cfgs[ad_num];
+
+	mutex_lock(&ad->lock);
+	if (init_cfg->ops & MDP_PP_AD_INIT) {
+		memcpy(&ad->init, &init_cfg->params.init,
+				sizeof(struct mdss_ad_init));
+		ad->sts |= PP_AD_STS_DIRTY_INIT;
+	} else if (init_cfg->ops & MDP_PP_AD_CFG) {
+		memcpy(&ad->cfg, &init_cfg->params.cfg,
+				sizeof(struct mdss_ad_cfg));
+		/*
+		 * TODO: specify panel independent range of input from cfg,
+		 * scale input backlight_scale to panel bl_max's range
+		 */
+		ad->cfg.backlight_scale = mfd->panel_info->bl_max;
+		ad->sts |= PP_AD_STS_DIRTY_CFG;
+	}
+
+	if (init_cfg->ops & MDP_PP_OPS_DISABLE) {
+		ad->sts &= ~PP_STS_ENABLE;
+		ad->mfd = NULL;
+	} else if (init_cfg->ops & MDP_PP_OPS_ENABLE) {
+		ad->sts |= PP_STS_ENABLE;
+		ad->mfd = mfd;
+	}
+	mutex_unlock(&ad->lock);
+	mdss_mdp_pp_setup(ctl);
+	return 0;
+}
+
+int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
+			struct mdss_ad_input *input) {
+	int ad_num, ret = 0;
+	struct mdss_ad_info *ad;
+	struct mdss_data_type *mdata;
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	ctl = mdp5_data->ctl;
+
+	ad_num = mdss_ad_init_checks(mfd);
+	if (ad_num < 0)
+		return ad_num;
+
+	mdata = mdss_mdp_get_mdata();
+	ad = &mdata->ad_cfgs[ad_num];
+
+	mutex_lock(&ad->lock);
+	if (!PP_AD_STATE_IS_INITCFG(ad->state) &&
+			!PP_AD_STS_IS_DIRTY(ad->sts)) {
+		pr_warn("AD not initialized or configured.");
+		ret = -EPERM;
+		goto error;
+	}
+	switch (input->mode) {
+	case MDSS_AD_MODE_AUTO_BL:
+	case MDSS_AD_MODE_AUTO_STR:
+		if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode,
+				MDSS_AD_INPUT_AMBIENT)) {
+			ret = -EINVAL;
+			goto error;
+		}
+		ad->ad_data_mode = MDSS_AD_INPUT_AMBIENT;
+
+		ad->ad_data = input->in.amb_light;
+		ad->calc_itr = ad->cfg.stab_itr;
+		ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+		ad->sts |= PP_AD_STS_DIRTY_DATA;
+		break;
+	case MDSS_AD_MODE_TARG_STR:
+	case MDSS_AD_MODE_MAN_STR:
+		if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode,
+				MDSS_AD_INPUT_STRENGTH)) {
+			ret = -EINVAL;
+			goto error;
+		}
+		ad->ad_data_mode = MDSS_AD_INPUT_STRENGTH;
+		ad->ad_data = input->in.strength;
+		ad->calc_itr = ad->cfg.stab_itr;
+		ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+		ad->sts |= PP_AD_STS_DIRTY_DATA;
+		break;
+	default:
+		pr_warn("invalid default %d", input->mode);
+		ret = -EINVAL;
+		goto error;
+	}
+error:
+	mutex_unlock(&ad->lock);
+	if (!ret) {
+		mutex_lock(&ad->lock);
+		init_completion(&ad->comp);
+		mutex_unlock(&ad->lock);
+		mdss_mdp_pp_setup(ctl);
+		ret = wait_for_completion_interruptible_timeout(&ad->comp,
+							HIST_WAIT_TIMEOUT(1));
+		if (ret == 0)
+			ret = -ETIMEDOUT;
+		else if (ret > 0)
+			input->output = ad->last_str;
+	}
+	return ret;
+}
+
+static void pp_ad_input_write(struct mdss_ad_info *ad, u32 bl_lvl)
+{
+	char __iomem *base = ad->base;
+	switch (ad->cfg.mode) {
+	case MDSS_AD_MODE_AUTO_BL:
+		writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
+		break;
+	case MDSS_AD_MODE_AUTO_STR:
+		writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+		writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
+		break;
+	case MDSS_AD_MODE_TARG_STR:
+		writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+		writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_TARG_STR);
+		break;
+	case MDSS_AD_MODE_MAN_STR:
+		writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+		writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_STR_MAN);
+		break;
+	default:
+		pr_warn("Invalid mode! %d", ad->cfg.mode);
+		break;
+	}
+}
+
+static void pp_ad_init_write(struct mdss_ad_info *ad)
+{
+	u32 temp;
+	char __iomem *base = ad->base;
+	writel_relaxed(ad->init.i_control[0] & 0x1F,
+				base + MDSS_MDP_REG_AD_CON_CTRL_0);
+	writel_relaxed(ad->init.i_control[1] << 8,
+				base + MDSS_MDP_REG_AD_CON_CTRL_1);
+
+	temp = ad->init.white_lvl << 16;
+	temp |= ad->init.black_lvl & 0xFFFF;
+	writel_relaxed(temp, base + MDSS_MDP_REG_AD_BW_LVL);
+
+	writel_relaxed(ad->init.var, base + MDSS_MDP_REG_AD_VAR);
+
+	writel_relaxed(ad->init.limit_ampl, base + MDSS_MDP_REG_AD_AMP_LIM);
+
+	writel_relaxed(ad->init.i_dither, base + MDSS_MDP_REG_AD_DITH);
+
+	temp = ad->init.slope_max << 8;
+	temp |= ad->init.slope_min & 0xFF;
+	writel_relaxed(temp, base + MDSS_MDP_REG_AD_SLOPE);
+
+	writel_relaxed(ad->init.dither_ctl, base + MDSS_MDP_REG_AD_DITH_CTRL);
+
+	writel_relaxed(ad->init.format, base + MDSS_MDP_REG_AD_CTRL_0);
+	writel_relaxed(ad->init.auto_size, base + MDSS_MDP_REG_AD_CTRL_1);
+
+	temp = ad->init.frame_w << 16;
+	temp |= ad->init.frame_h & 0xFFFF;
+	writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
+
+	temp = ad->init.logo_v << 8;
+	temp |= ad->init.logo_h & 0xFF;
+	writel_relaxed(temp, base + MDSS_MDP_REG_AD_LOGO_POS);
+
+	pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_FI, ad->init.asym_lut);
+	pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut);
+}
+
+#define MDSS_PP_AD_DEF_CALIB 0x6E
+static void pp_ad_cfg_write(struct mdss_ad_info *ad)
+{
+	char __iomem *base = ad->base;
+	u32 temp, temp_calib = MDSS_PP_AD_DEF_CALIB;
+	switch (ad->cfg.mode) {
+	case MDSS_AD_MODE_AUTO_BL:
+		temp = ad->cfg.backlight_max << 16;
+		temp |= ad->cfg.backlight_min & 0xFFFF;
+		writel_relaxed(temp, base + MDSS_MDP_REG_AD_BL_MINMAX);
+		writel_relaxed(ad->cfg.amb_light_min,
+				base + MDSS_MDP_REG_AD_AL_MIN);
+		temp = ad->cfg.filter[1] << 16;
+		temp |= ad->cfg.filter[0] & 0xFFFF;
+		writel_relaxed(temp, base + MDSS_MDP_REG_AD_AL_FILT);
+	case MDSS_AD_MODE_AUTO_STR:
+		pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_AL,
+				ad->cfg.al_calib_lut);
+		writel_relaxed(ad->cfg.strength_limit,
+				base + MDSS_MDP_REG_AD_STR_LIM);
+		temp = ad->cfg.calib[3] << 16;
+		temp |= ad->cfg.calib[2] & 0xFFFF;
+		writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_CD);
+		writel_relaxed(ad->cfg.t_filter_recursion,
+				base + MDSS_MDP_REG_AD_TFILT_CTRL);
+		temp_calib = ad->cfg.calib[0] & 0xFFFF;
+	case MDSS_AD_MODE_TARG_STR:
+		temp = ad->cfg.calib[1] << 16;
+		temp |= temp_calib;
+		writel_relaxed(temp, base + MDSS_MDP_REG_AD_CALIB_AB);
+	case MDSS_AD_MODE_MAN_STR:
+		writel_relaxed(ad->cfg.backlight_scale,
+				base + MDSS_MDP_REG_AD_BL_MAX);
+		writel_relaxed(ad->cfg.mode, base + MDSS_MDP_REG_AD_MODE_SEL);
+		pr_debug("stab_itr = %d", ad->cfg.stab_itr);
+		break;
+	default:
+		break;
+	}
+}
+
+static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t)
+{
+	struct mdss_data_type *mdata = ctl->mdata;
+	struct mdss_ad_info *ad;
+
+	if (ctl->mixer_left && ctl->mixer_left->num < mdata->nad_cfgs) {
+		ad = &mdata->ad_cfgs[ctl->mixer_left->num];
+		queue_work(mdata->ad_calc_wq, &ad->calc_work);
+	}
+}
+
+#define MDSS_PP_AD_BYPASS_DEF 0x101
+static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
+{
+	int ad_num, ret = 0;
+	struct mdss_ad_info *ad;
+	struct mdss_data_type *mdata;
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+	char __iomem *base;
+	u32 bypass = MDSS_PP_AD_BYPASS_DEF;
+
+	ad_num = mdss_ad_init_checks(mfd);
+	if (ad_num < 0)
+		return ad_num;
+
+	mdata = mdss_mdp_get_mdata();
+	ad = &mdata->ad_cfgs[ad_num];
+	base = ad->base;
+
+	mutex_lock(&ad->lock);
+	if (ad->sts != last_sts || ad->state != last_state) {
+		last_sts = ad->sts;
+		last_state = ad->state;
+		pr_debug("begining: ad->sts = 0x%08x, state = 0x%08x", ad->sts,
+								ad->state);
+	}
+	if (!PP_AD_STS_IS_DIRTY(ad->sts) &&
+		(ad->sts & PP_AD_STS_DIRTY_DATA ||
+			(ad->state & PP_AD_STATE_RUN &&
+				(ad->cfg.mode == MDSS_AD_MODE_AUTO_STR)))) {
+		/*
+		 * Write inputs to regs when the data has been updated or
+		 * Assertive Display is up and running as long as there are
+		 * no updates to AD init or cfg
+		 */
+		ad->sts &= ~PP_AD_STS_DIRTY_DATA;
+		ad->state |= PP_AD_STATE_DATA;
+		if (mfd->bl_level != ad->last_bl) {
+			ad->last_bl = mfd->bl_level;
+			ad->calc_itr = ad->cfg.stab_itr;
+			ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+		}
+		pp_ad_input_write(ad, mfd->bl_level);
+	}
+
+	if (ad->sts & PP_AD_STS_DIRTY_CFG) {
+		ad->sts &= ~PP_AD_STS_DIRTY_CFG;
+		ad->state |= PP_AD_STATE_CFG;
+
+		pp_ad_cfg_write(ad);
+
+		if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, ad->ad_data_mode)) {
+			ad->sts &= ~PP_AD_STS_DIRTY_DATA;
+			ad->state &= ~PP_AD_STATE_DATA;
+			pr_debug("Mode switched, data invalidated!");
+		}
+	}
+	if (ad->sts & PP_AD_STS_DIRTY_INIT) {
+		ad->sts &= ~PP_AD_STS_DIRTY_INIT;
+		ad->state |= PP_AD_STATE_INIT;
+		pp_ad_init_write(ad);
+	}
+
+	if ((ad->sts & PP_STS_ENABLE) && PP_AD_STATE_IS_READY(ad->state)) {
+		bypass = 0;
+		ret = 1;
+		ad->state |= PP_AD_STATE_RUN;
+	} else {
+		if (ad->state & PP_AD_STATE_RUN) {
+			ret = 1;
+			ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+		}
+		ad->state &= ~PP_AD_STATE_RUN;
+	}
+	writel_relaxed(bypass, base);
+
+	if (PP_AD_STS_DIRTY_VSYNC & ad->sts) {
+		pr_debug("dirty vsync, calc_itr = %d", ad->calc_itr);
+		ad->sts &= ~PP_AD_STS_DIRTY_VSYNC;
+		if (!(PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr) {
+			ctl->add_vsync_handler(ctl, &ad->handle);
+			ad->state |= PP_AD_STATE_VSYNC;
+		} else if ((PP_AD_STATE_VSYNC & ad->state) &&
+			(!ad->calc_itr || !(PP_AD_STATE_RUN & ad->state))) {
+			ctl->remove_vsync_handler(ctl, &ad->handle);
+			ad->state &= ~PP_AD_STATE_VSYNC;
+		}
+	}
+
+	if (ad->sts != last_sts || ad->state != last_state) {
+		last_sts = ad->sts;
+		last_state = ad->state;
+		pr_debug("end: ad->sts = 0x%08x, state = 0x%08x", ad->sts,
+								ad->state);
+	}
+	mutex_unlock(&ad->lock);
+	return ret;
+}
+
+#define MDSS_PP_AD_SLEEP 10
+static void pp_ad_calc_worker(struct work_struct *work)
+{
+	struct mdss_ad_info *ad;
+	struct mdss_mdp_ctl *ctl;
+	u32 bl, calc_done = 0;
+	ad = container_of(work, struct mdss_ad_info, calc_work);
+	ctl = mfd_to_ctl(ad->mfd);
+
+	mutex_lock(&ad->lock);
+	if (PP_AD_STATE_RUN & ad->state) {
+		/* Kick off calculation */
+		ad->calc_itr--;
+		writel_relaxed(1, ad->base + MDSS_MDP_REG_AD_START_CALC);
+	}
+	if (ad->state & PP_AD_STATE_RUN) {
+		do {
+			calc_done = readl_relaxed(ad->base +
+				MDSS_MDP_REG_AD_CALC_DONE);
+			if (!calc_done)
+				usleep(MDSS_PP_AD_SLEEP);
+		} while (!calc_done && (ad->state & PP_AD_STATE_RUN));
+		if (calc_done) {
+			ad->last_str = 0xFF & readl_relaxed(ad->base +
+						MDSS_MDP_REG_AD_STR_OUT);
+			if (MDSS_AD_RUNNING_AUTO_BL(ad)) {
+				bl = 0xFFFF & readl_relaxed(ad->base +
+						MDSS_MDP_REG_AD_BL_OUT);
+				pr_debug("calc bl = %d", bl);
+				ad->last_str |= bl << 16;
+				mutex_lock(&ad->mfd->bl_lock);
+				mdss_fb_set_backlight(ad->mfd, bl);
+				mutex_unlock(&ad->mfd->bl_lock);
+			}
+			pr_debug("calc_str = %d, calc_itr %d",
+							ad->last_str & 0xFF,
+							ad->calc_itr);
+		} else {
+			ad->last_str = 0xFFFFFFFF;
+		}
+	}
+	complete(&ad->comp);
+
+	if (!ad->calc_itr) {
+		ad->state &= ~PP_AD_STATE_VSYNC;
+		ctl->remove_vsync_handler(ctl, &ad->handle);
+	}
+	mutex_unlock(&ad->lock);
+	mutex_lock(&ad->mfd->lock);
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + ad->num));
+	mutex_unlock(&ad->mfd->lock);
+}
+
+#define PP_AD_LUT_LEN 33
+static void pp_ad_cfg_lut(char __iomem *offset, u32 *data)
+{
+	int i;
+	u32 temp;
+
+	for (i = 0; i < PP_AD_LUT_LEN - 1; i += 2) {
+		temp = data[i+1] << 16;
+		temp |= (data[i] & 0xFFFF);
+		writel_relaxed(temp, offset + (i*2));
+	}
+	writel_relaxed(data[PP_AD_LUT_LEN - 1] << 16,
+			offset + ((PP_AD_LUT_LEN - 1) * 2));
+}
+
+int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off)
+{
+	u32 i;
+	int rc = 0;
+
+	mdata->ad_cfgs = devm_kzalloc(&mdata->pdev->dev,
+				sizeof(struct mdss_ad_info) * mdata->nad_cfgs,
+				GFP_KERNEL);
+
+	if (!mdata->ad_cfgs) {
+		pr_err("unable to setup assertive display:devm_kzalloc fail\n");
+		return -ENOMEM;
+	}
+
+	mdata->ad_calc_wq = create_singlethread_workqueue("ad_calc_wq");
+	for (i = 0; i < mdata->nad_cfgs; i++) {
+		mdata->ad_cfgs[i].base = mdata->mdp_base + ad_off[i];
+		mdata->ad_cfgs[i].num = i;
+		mdata->ad_cfgs[i].calc_itr = 0;
+		mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
+		mutex_init(&mdata->ad_cfgs[i].lock);
+		mdata->ad_cfgs[i].handle.vsync_handler = pp_ad_vsync_handler;
+		INIT_WORK(&mdata->ad_cfgs[i].calc_work, pp_ad_calc_worker);
+	}
+	return rc;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 016c973..5d9396a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -367,6 +367,7 @@
 
 int mdss_mdp_rotator_release(u32 ndx)
 {
+	int rc = 0;
 	struct mdss_mdp_rotator_session *rot;
 	mutex_lock(&rotator_lock);
 	rot = mdss_mdp_rotator_session_get(ndx);
@@ -374,11 +375,11 @@
 		mdss_mdp_rotator_finish(rot);
 	} else {
 		pr_warn("unknown session id=%x\n", ndx);
-		return -ENOENT;
+		rc = -ENOENT;
 	}
 	mutex_unlock(&rotator_lock);
 
-	return 0;
+	return rc;
 }
 
 int mdss_mdp_rotator_release_all(void)
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 7ccf1b9..1f8244d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -194,6 +194,7 @@
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+	int rc = 0;
 
 	mutex_lock(&mdss_mdp_wb_buf_lock);
 	if (wb == NULL) {
@@ -202,7 +203,8 @@
 		mdp5_data->wb = wb;
 	} else if (mfd->index != wb->fb_ndx) {
 		pr_err("only one writeback intf supported at a time\n");
-		return -EMLINK;
+		rc = -EMLINK;
+		goto error;
 	} else {
 		pr_debug("writeback already initialized\n");
 	}
@@ -217,8 +219,9 @@
 	init_waitqueue_head(&wb->wait_q);
 
 	mdp5_data->wb = wb;
+error:
 	mutex_unlock(&mdss_mdp_wb_buf_lock);
-	return 0;
+	return rc;
 }
 
 static int mdss_mdp_wb_terminate(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index 96e8b67..08d0693 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -169,6 +169,7 @@
 	cmd_env = vmalloc(sizeof(struct msc_cmd_envelope));
 	if (!cmd_env) {
 		pr_err("%s: out of memory!\n", __func__);
+		mutex_unlock(&msc_send_workqueue_mutex);
 		return -ENOMEM;
 	}
 
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 2b07e43..5564ceb 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -275,8 +275,8 @@
 
 	} else {
 		MIPI_OUTP(ctrl_base + 0x0220, 0x006);
-		usleep(10);
 		MIPI_OUTP(ctrl_base + 0x0470, 0x000);
+		MIPI_OUTP(ctrl_base + 0x0598, 0x000);
 		wmb();
 	}
 }
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index f9e483c..61e9cb1 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -613,6 +613,7 @@
 	uint16_t calib[4];
 	uint8_t strength_limit;
 	uint8_t t_filter_recursion;
+	uint16_t stab_itr;
 };
 
 /* ops uses standard MDP_PP_* flags */
@@ -631,6 +632,7 @@
 		uint32_t amb_light;
 		uint32_t strength;
 	} in;
+	uint32_t output;
 };
 
 enum {
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 3622616..4ae3b79 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -222,6 +222,7 @@
 	bool enable_lpm_on_dev_suspend;
 	bool core_clk_always_on_workaround;
 	bool delay_lpm_on_disconnect;
+	bool delay_lpm_hndshk_on_disconnect;
 	bool dp_manual_pullup;
 	bool enable_sec_phy;
 	struct msm_bus_scale_pdata *bus_scale_table;
@@ -462,10 +463,13 @@
 	int (*notify)(void *, int, void (*)(int online));
 	void *ctxt;
 };
-
+#ifdef CONFIG_USB_BAM
+bool msm_bam_lpm_ok(void);
+#else
+static inline bool msm_bam_lpm_ok(void) { return true; }
+#endif
 #ifdef CONFIG_USB_CI13XXX_MSM
 void msm_hw_bam_disable(bool bam_disable);
-
 #else
 static inline void msm_hw_bam_disable(bool bam_disable)
 {
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 42c8823..35c57c0 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+   Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -1145,6 +1145,11 @@
 	__le16   opcode;
 } __packed;
 
+#define HCI_EV_HARDWARE_ERROR		0x10
+struct hci_ev_hardware_error {
+	__u8   hw_err_code;
+} __packed;
+
 #define HCI_EV_ROLE_CHANGE		0x12
 struct hci_ev_role_change {
 	__u8     status;
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index fa4dedc..87730b1 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -634,8 +634,6 @@
  *	when a new port is added here. */
 #define PRIMARY_I2S_RX 0		/* index = 0 */
 #define PRIMARY_I2S_TX 1		/* index = 1 */
-#define PCM_RX 2			/* index = 2 */
-#define PCM_TX 3			/* index = 3 */
 #define SECONDARY_I2S_RX 4		/* index = 4 */
 #define SECONDARY_I2S_TX 5		/* index = 5 */
 #define MI2S_RX 6			/* index = 6 */
@@ -784,26 +782,6 @@
 #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX      0x4008
 /* SLIMbus Tx port on channel 4. */
 #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX      0x4009
-/* SLIMbus Rx port on channel 0. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX      0x4000
-/* SLIMbus Tx port on channel 0. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX      0x4001
-/* SLIMbus Rx port on channel 1. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX      0x4002
-/* SLIMbus Tx port on channel 1. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX      0x4003
-/* SLIMbus Rx port on channel 2. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX      0x4004
-/* SLIMbus Tx port on channel 2. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX      0x4005
-/* SLIMbus Rx port on channel 3. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX      0x4006
-/* SLIMbus Tx port on channel 3. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX      0x4007
-/* SLIMbus Rx port on channel 4. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX      0x4008
-/* SLIMbus Tx port on channel 4. */
-#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX      0x4009
 /* SLIMbus Rx port on channel 5. */
 #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX      0x400a
 /* SLIMbus Tx port on channel 5. */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 40b0e1e..81636a3 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1453,6 +1453,23 @@
 	u32                read_format;
 } __attribute__((packed));
 
+#define ASM_STREAM_CMD_OPEN_LOOPBACK	0x00010D6E
+struct asm_stream_cmd_open_loopback {
+	struct apr_hdr         hdr;
+	u32                    mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+	u16                    src_endpointype;
+	/* Endpoint type. 0 = Tx Matrix */
+	u16                    sink_endpointype;
+	/* Endpoint type. 0 = Rx Matrix */
+	u32                    postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+} __packed;
+
 #define ADM_CMD_CONNECT_AFE_PORT 0x00010320
 #define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
 
@@ -1909,5 +1926,4 @@
 
 int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
 /* SRS Studio Sound 3D end */
-
 #endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 2a740f4..1389b2a 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -41,8 +41,8 @@
 enum {
 	IDX_PRIMARY_I2S_RX = 0,
 	IDX_PRIMARY_I2S_TX = 1,
-	IDX_PCM_RX = 2,
-	IDX_PCM_TX = 3,
+	IDX_AFE_PORT_ID_PRIMARY_PCM_RX = 2,
+	IDX_AFE_PORT_ID_PRIMARY_PCM_TX = 3,
 	IDX_SECONDARY_I2S_RX = 4,
 	IDX_SECONDARY_I2S_TX = 5,
 	IDX_MI2S_RX = 6,
@@ -166,7 +166,7 @@
 int afe_port_start(u16 port_id, union afe_port_config *afe_config,
 	u32 rate);
 int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
-	int l_ch, int r_ch);
+	int l_ch, int r_ch, u32 enable);
 int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib);
 int afe_port_stop_nowait(int port_id);
 int afe_apply_gain(u16 port_id, u16 gain);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 406407d..41f875b 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -207,6 +207,8 @@
 			uint32_t rd_format,
 			uint32_t wr_format);
 
+int q6asm_open_loopack(struct audio_client *ac);
+
 int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
 				uint32_t lsw_ts, uint32_t flags);
 int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h
index e76e822..909e1b9 100644
--- a/include/trace/events/kmem.h
+++ b/include/trace/events/kmem.h
@@ -557,6 +557,46 @@
 		unsigned int order),
 
 	TP_ARGS(gfp_flags, order)
+
+	);
+
+DECLARE_EVENT_CLASS(smmu_map,
+
+	TP_PROTO(unsigned int va,
+		phys_addr_t pa,
+		unsigned int chunk_size,
+		size_t len),
+
+	TP_ARGS(va, pa, chunk_size, len),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, va)
+		__field(phys_addr_t, pa)
+		__field(unsigned int, chunk_size)
+		__field(size_t, len)
+		),
+
+	TP_fast_assign(
+		__entry->va = va;
+		__entry->pa = pa;
+		__entry->chunk_size = chunk_size;
+		__entry->len = len;
+		),
+
+	TP_printk("v_addr=%p p_addr=%pa chunk_size=0x%x len=%zu",
+		(void *)__entry->va,
+		&__entry->pa,
+		__entry->chunk_size,
+		__entry->len)
+	);
+
+DEFINE_EVENT(smmu_map, iommu_map_range,
+	TP_PROTO(unsigned int va,
+		phys_addr_t pa,
+		unsigned int chunk_size,
+		size_t len),
+
+	TP_ARGS(va, pa, chunk_size, len)
 	);
 
 #endif /* _TRACE_KMEM_H */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d243646..2dba071 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2426,6 +2426,21 @@
 	}
 }
 
+static inline void hci_hardware_error_evt(struct hci_dev *hdev,
+					struct sk_buff *skb)
+{
+	struct hci_ev_hardware_error *ev = (void *) skb->data;
+
+	BT_ERR("hdev=%p, hw_err_code = %u", hdev, ev->hw_err_code);
+
+	if (hdev && hdev->dev_type == HCI_BREDR) {
+		hci_dev_lock_bh(hdev);
+		mgmt_powered(hdev->id, 1);
+		hci_dev_unlock_bh(hdev);
+	}
+
+}
+
 static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_role_change *ev = (void *) skb->data;
@@ -3555,6 +3570,10 @@
 		hci_cmd_status_evt(hdev, skb);
 		break;
 
+	case HCI_EV_HARDWARE_ERROR:
+		hci_hardware_error_evt(hdev, skb);
+		break;
+
 	case HCI_EV_ROLE_CHANGE:
 		hci_role_change_evt(hdev, skb);
 		break;
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index ebde90b..7ab4811 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -55,8 +55,7 @@
 # for MSM 8960 sound card driver
 
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-loopback.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
 obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o msm-pcm-host-voice.o
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 8db13f6..ffb0f3b 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -236,6 +236,17 @@
 			.rate_min =	8000,
 			.rate_max = 192000,
 		},
+		.capture = {
+			.stream_name = "MultiMedia6 Capture",
+			.aif_name = "MM_UL6",
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia6",
 	},
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
new file mode 100644
index 0000000..84ea9c6
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-loopback.c
@@ -0,0 +1,362 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/apr_audio.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm-routing.h"
+
+struct msm_pcm_loopback {
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	int instance;
+
+	struct mutex lock;
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+
+	int playback_start;
+	int capture_start;
+	int session_id;
+	struct audio_client *audio_client;
+};
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+	.formats                = 0xffffffff,
+	.channels_min           = 1,
+	.channels_max           = UINT_MAX,
+
+	/* Random values to keep userspace happy when checking constraints */
+	.info                   = SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.buffer_bytes_max       = 128*1024,
+	.period_bytes_min       = 1024,
+	.period_bytes_max       = 1024*2,
+	.periods_min            = 2,
+	.periods_max            = 128,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+					void *priv_data)
+{
+	struct msm_pcm_loopback *pcm = priv_data;
+
+	BUG_ON(!pcm);
+
+	pr_debug("%s: event %x\n", __func__, event);
+
+	switch (event) {
+	case MSM_PCM_RT_EVT_DEVSWITCH:
+		q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+		q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+		q6asm_run(pcm->audio_client, 0, 0, 0);
+	default:
+		break;
+	}
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+			break;
+		default:
+			break;
+		}
+	}
+	break;
+	default:
+		pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct msm_pcm_loopback *pcm;
+	int ret = 0;
+	struct msm_pcm_routing_evt event;
+
+	pcm = dev_get_drvdata(rtd->platform->dev);
+	mutex_lock(&pcm->lock);
+
+	snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_substream = substream;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_substream = substream;
+
+	pcm->instance++;
+	dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+			pcm->instance, substream->stream);
+	if (pcm->instance == 2) {
+		struct snd_soc_pcm_runtime *soc_pcm_rx =
+				pcm->playback_substream->private_data;
+		struct snd_soc_pcm_runtime *soc_pcm_tx =
+				pcm->capture_substream->private_data;
+		if (pcm->audio_client != NULL)
+			stop_pcm(pcm);
+
+		pcm->audio_client = q6asm_audio_client_alloc(
+				(app_cb)msm_pcm_loopback_event_handler, pcm);
+		if (!pcm->audio_client) {
+			dev_err(rtd->platform->dev,
+				"%s: Could not allocate memory\n", __func__);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		pcm->session_id = pcm->audio_client->session;
+		pcm->audio_client->perf_mode = false;
+		ret = q6asm_open_loopack(pcm->audio_client);
+		if (ret < 0) {
+			dev_err(rtd->platform->dev,
+				"%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(pcm->audio_client);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		event.event_func = msm_pcm_route_event_handler;
+		event.priv_data = (void *) pcm;
+		msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->capture_substream->stream);
+		msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->playback_substream->stream,
+			event);
+	}
+	dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+			__func__ , pcm->instance, substream->pcm->id);
+	runtime->private_data = pcm;
+
+	mutex_unlock(&pcm->lock);
+
+	return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+	struct snd_soc_pcm_runtime *soc_pcm_rx =
+		pcm->playback_substream->private_data;
+	struct snd_soc_pcm_runtime *soc_pcm_tx =
+		pcm->capture_substream->private_data;
+
+	if (pcm->audio_client == NULL)
+		return;
+	q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_audio_client_free(pcm->audio_client);
+	pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	int ret = 0;
+
+	mutex_lock(&pcm->lock);
+
+	dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+		__func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_start = 0;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_start = 0;
+
+	pcm->instance--;
+	if (!pcm->playback_start || !pcm->capture_start) {
+		dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+		stop_pcm(pcm);
+	}
+
+	mutex_unlock(&pcm->lock);
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	mutex_lock(&pcm->lock);
+
+	dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+		__func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!pcm->playback_start)
+			pcm->playback_start = 1;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (!pcm->capture_start)
+			pcm->capture_start = 1;
+	}
+	mutex_unlock(&pcm->lock);
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dev_dbg(rtd->platform->dev,
+			"%s: playback_start:%d,capture_start:%d\n", __func__,
+			pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		dev_dbg(rtd->platform->dev,
+			"%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+			__func__, pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
+
+	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+		params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.hw_params	= msm_pcm_hw_params,
+	.hw_free	= msm_pcm_hw_free,
+	.close          = msm_pcm_close,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+};
+
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	struct msm_pcm_loopback *pcm;
+
+	dev_dbg(&pdev->dev, "%s: dev name %s\n",
+		__func__, dev_name(&pdev->dev));
+
+	pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+	if (!pcm) {
+		dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
+			__func__);
+		return -ENOMEM;
+	} else {
+		mutex_init(&pcm->lock);
+		dev_set_drvdata(&pdev->dev, pcm);
+	}
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	struct msm_pcm_loopback *pcm;
+
+	pcm = dev_get_drvdata(&pdev->dev);
+	mutex_destroy(&pcm->lock);
+
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-loopback",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index e74a0dd..2c3c6df 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -658,6 +658,11 @@
 				msm_bedais[reg].sample_rate, channels,
 				DEFAULT_COPP_TOPOLOGY);
 
+			if (session_type == SESSION_TYPE_RX &&
+				fdai->event_info.event_func)
+					fdai->event_info.event_func(
+						MSM_PCM_RT_EVT_DEVSWITCH,
+						fdai->event_info.priv_data);
 
 			msm_pcm_routing_build_matrix(val,
 				fdai->strm_id, path_type);
@@ -976,10 +981,8 @@
 static int msm_routing_set_fm_vol_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	afe_loopback_gain(INT_FM_TX , ucontrol->value.integer.value[0]);
-
+	afe_loopback_gain(INT_FM_TX, ucontrol->value.integer.value[0]);
 	msm_route_fm_vol_control = ucontrol->value.integer.value[0];
-
 	return 0;
 }
 
@@ -1660,6 +1663,9 @@
 	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1696,6 +1702,9 @@
 	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1714,6 +1723,9 @@
 	SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1810,6 +1822,12 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -2715,6 +2733,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2828,6 +2847,8 @@
 	mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3008,6 +3029,7 @@
 	{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -3026,6 +3048,7 @@
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
 
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3040,12 +3063,14 @@
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
 
 	{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -3054,12 +3079,14 @@
 	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
 	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
 	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
+	{"MM_UL6", NULL, "MultiMedia6 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+	{"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
 
 	{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index c42e155..e25a44a 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -117,6 +117,7 @@
 
 enum msm_pcm_routing_event {
 	MSM_PCM_RT_EVT_BUF_RECFG,
+	MSM_PCM_RT_EVT_DEVSWITCH,
 	MSM_PCM_RT_EVT_MAX,
 };
 /* dai_id: front-end ID,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 737317c..dd92e34 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1143,6 +1143,22 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
 	},
+	{
+		.name = "MSM8960 FM",
+		.stream_name = "MultiMedia6",
+		.cpu_dai_name	= "MultiMedia6",
+		.platform_name  = "msm-pcm-loopback",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 7acb294..a458713 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -75,6 +75,11 @@
 #define EXT_CLASS_D_DIS_DELAY 3000
 #define EXT_CLASS_D_DELAY_DELTA 2000
 
+/* It takes about 13ms for Class-AB PAs to ramp-up */
+#define EXT_CLASS_AB_EN_DELAY 10000
+#define EXT_CLASS_AB_DIS_DELAY 1000
+#define EXT_CLASS_AB_DELAY_DELTA 1000
+
 #define NUM_OF_AUXPCM_GPIOS 4
 
 static inline int param_is_mask(int p)
@@ -184,6 +189,8 @@
 static struct platform_device *spdev;
 static struct regulator *ext_spk_amp_regulator;
 static int ext_spk_amp_gpio = -1;
+static int ext_ult_spk_amp_gpio = -1;
+static int ext_ult_lo_amp_gpio = -1;
 static int msm8974_spk_control = 1;
 static int msm8974_ext_spk_pamp;
 static int msm_slim_0_rx_ch = 1;
@@ -231,9 +238,43 @@
 		}
 	}
 
+	ext_ult_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+		"qcom,ext-ult-spk-amp-gpio", 0);
+
+	if (ext_ult_spk_amp_gpio >= 0) {
+		ret = gpio_request(ext_ult_spk_amp_gpio,
+						   "ext_ult_spk_amp_gpio");
+		if (ret) {
+			pr_err("%s: gpio_request failed for ext-ult_spk-amp-gpio.\n",
+				__func__);
+			return -EINVAL;
+		}
+		gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+	}
+
 	return 0;
 }
 
+static void msm8974_liquid_ext_ult_spk_power_amp_enable(u32 on)
+{
+	if (on) {
+		regulator_enable(ext_spk_amp_regulator);
+		gpio_direction_output(ext_ult_spk_amp_gpio, 1);
+		/* time takes enable the external power class AB amplifier */
+		usleep_range(EXT_CLASS_AB_EN_DELAY,
+			     EXT_CLASS_AB_EN_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+	} else {
+		gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+		regulator_disable(ext_spk_amp_regulator);
+		/* time takes disable the external power class AB amplifier */
+		usleep_range(EXT_CLASS_AB_DIS_DELAY,
+			     EXT_CLASS_AB_DIS_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+	}
+
+	pr_debug("%s: %s external ultrasound SPKR_DRV PAs.\n", __func__,
+			on ? "Enable" : "Disable");
+}
+
 static void msm8974_liquid_ext_spk_power_amp_enable(u32 on)
 {
 	if (on) {
@@ -287,7 +328,6 @@
 
 }
 
-
 static irqreturn_t msm8974_liquid_docking_irq_handler(int irq, void *dev)
 {
 	struct msm8974_liquid_dock_dev *dock_dev = dev;
@@ -351,41 +391,82 @@
 	return 0;
 }
 
-
-
-
-static void msm8974_ext_spk_power_amp_on(u32 spk)
+static int msm8974_liquid_ext_spk_power_amp_on(u32 spk)
 {
-	if (spk & (LO_1_SPK_AMP |
-		   LO_3_SPK_AMP |
-		   LO_2_SPK_AMP |
-		   LO_4_SPK_AMP)) {
+	int rc;
 
-		pr_debug("%s() External Left/Right Speakers already turned on. spk = 0x%08x\n",
-						__func__, spk);
+	if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP | LO_2_SPK_AMP | LO_4_SPK_AMP)) {
+		pr_debug("%s: External speakers are already on. spk = 0x%x\n",
+			 __func__, spk);
 
 		msm8974_ext_spk_pamp |= spk;
-
 		if ((msm8974_ext_spk_pamp & LO_1_SPK_AMP) &&
-			(msm8974_ext_spk_pamp & LO_3_SPK_AMP) &&
-			(msm8974_ext_spk_pamp & LO_2_SPK_AMP) &&
-			(msm8974_ext_spk_pamp & LO_4_SPK_AMP)) {
-
+		    (msm8974_ext_spk_pamp & LO_3_SPK_AMP) &&
+		    (msm8974_ext_spk_pamp & LO_2_SPK_AMP) &&
+		    (msm8974_ext_spk_pamp & LO_4_SPK_AMP))
 			if (ext_spk_amp_gpio >= 0 &&
-				msm8974_liquid_dock_dev != NULL &&
-				msm8974_liquid_dock_dev->dock_plug_det == 0)
+			    msm8974_liquid_dock_dev &&
+			    msm8974_liquid_dock_dev->dock_plug_det == 0)
 				msm8974_liquid_ext_spk_power_amp_enable(1);
-		}
+		rc = 0;
 	} else  {
+		pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
+		       __func__, spk);
+		rc = -EINVAL;
+	}
 
-		pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+	return rc;
+}
+
+static void msm8974_fluid_ext_us_amp_on(u32 spk)
+{
+	if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
+		pr_err("%s: ext_ult_lo_amp_gpio isn't configured\n", __func__);
+	} else if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP)) {
+		pr_debug("%s: External US amp is already on. spk = 0x%x\n",
+			 __func__, spk);
+		msm8974_ext_spk_pamp |= spk;
+		if ((msm8974_ext_spk_pamp & LO_1_SPK_AMP) &&
+		    (msm8974_ext_spk_pamp & LO_3_SPK_AMP))
+			pr_debug("%s: Turn on US amp. spk = 0x%x\n",
+				 __func__, spk);
+			gpio_direction_output(ext_ult_lo_amp_gpio, 1);
+
+	} else  {
+		pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
 			__func__, spk);
-		return;
 	}
 }
 
-static void msm8974_ext_spk_power_amp_off(u32 spk)
+static void msm8974_fluid_ext_us_amp_off(u32 spk)
 {
+	if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
+		pr_err("%s: ext_ult_lo_amp_gpio isn't configured\n", __func__);
+	} else if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP)) {
+		pr_debug("%s LO1 and LO3. spk = 0x%x", __func__, spk);
+		if (!msm8974_ext_spk_pamp) {
+			pr_debug("%s: Turn off US amp. spk = 0x%x\n",
+				 __func__, spk);
+			gpio_direction_output(ext_ult_lo_amp_gpio, 0);
+			msm8974_ext_spk_pamp = 0;
+		}
+	} else  {
+		pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
+			__func__, spk);
+	}
+}
+
+static void msm8974_ext_spk_power_amp_on(u32 spk)
+{
+	if (gpio_is_valid(ext_spk_amp_gpio))
+		msm8974_liquid_ext_spk_power_amp_on(spk);
+	else if (gpio_is_valid(ext_ult_lo_amp_gpio))
+		msm8974_fluid_ext_us_amp_on(spk);
+}
+
+static void msm8974_liquid_ext_spk_power_amp_off(u32 spk)
+{
+
 	if (spk & (LO_1_SPK_AMP |
 		   LO_3_SPK_AMP |
 		   LO_2_SPK_AMP |
@@ -410,6 +491,14 @@
 	}
 }
 
+static void msm8974_ext_spk_power_amp_off(u32 spk)
+{
+	if (gpio_is_valid(ext_spk_amp_gpio))
+		msm8974_liquid_ext_spk_power_amp_off(spk);
+	else if (gpio_is_valid(ext_ult_lo_amp_gpio))
+		msm8974_fluid_ext_us_amp_off(spk);
+}
+
 static void msm8974_ext_control(struct snd_soc_codec *codec)
 {
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
@@ -495,6 +584,33 @@
 
 }
 
+static int msm_ext_spkramp_ultrasound_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *k, int event)
+{
+
+	pr_debug("%s()\n", __func__);
+
+	if (!strncmp(w->name, "SPK_ultrasound amp", 19)) {
+		if (!gpio_is_valid(ext_ult_spk_amp_gpio)) {
+			pr_err("%s: ext_ult_spk_amp_gpio isn't configured\n",
+				__func__);
+			return -EINVAL;
+		}
+
+		if (SND_SOC_DAPM_EVENT_ON(event))
+			msm8974_liquid_ext_ult_spk_power_amp_enable(1);
+		else
+			msm8974_liquid_ext_ult_spk_power_amp_enable(0);
+
+	} else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
 					bool dapm)
 {
@@ -567,6 +683,8 @@
 
 	SND_SOC_DAPM_SPK("Lineout_2 amp", msm_ext_spkramp_event),
 	SND_SOC_DAPM_SPK("Lineout_4 amp", msm_ext_spkramp_event),
+	SND_SOC_DAPM_SPK("SPK_ultrasound amp",
+					 msm_ext_spkramp_ultrasound_event),
 
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -2272,6 +2390,7 @@
 	struct msm8974_asoc_mach_data *pdata;
 	int ret;
 	const char *auxpcm_pri_gpio_set = NULL;
+	const char *prop_name_ult_lo_gpio = "qcom,ext-ult-lo-amp-gpio";
 
 	if (!pdev->dev.of_node) {
 		dev_err(&pdev->dev, "No platform supplied from device tree\n");
@@ -2343,9 +2462,26 @@
 		goto err;
 	}
 
+	ext_ult_lo_amp_gpio = of_get_named_gpio(pdev->dev.of_node,
+						prop_name_ult_lo_gpio, 0);
+	if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
+		dev_dbg(&pdev->dev,
+			"Couldn't find %s property in node %s, %d\n",
+			prop_name_ult_lo_gpio, pdev->dev.of_node->full_name,
+			ext_ult_lo_amp_gpio);
+	} else {
+		ret = gpio_request(ext_ult_lo_amp_gpio, "US_AMP_GPIO");
+		if (ret) {
+			dev_err(card->dev,
+				"%s: Failed to request US amp gpio %d\n",
+				__func__, ext_ult_lo_amp_gpio);
+			goto err;
+		}
+	}
+
 	ret = msm8974_prepare_codec_mclk(card);
 	if (ret)
-		goto err;
+		goto err1;
 
 	if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) {
 		dev_info(&pdev->dev, "%s(): hdmi audio support present\n",
@@ -2394,7 +2530,7 @@
 	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
 			ret);
-		goto err;
+		goto err1;
 	}
 
 	ret = of_property_read_string(pdev->dev.of_node,
@@ -2403,7 +2539,7 @@
 		dev_err(&pdev->dev, "Looking up %s property in node %s failed",
 			"qcom,prim-auxpcm-gpio-set",
 			pdev->dev.of_node->full_name);
-		goto err;
+		goto err1;
 	}
 	if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
 		lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
@@ -2413,20 +2549,24 @@
 		dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
 			auxpcm_pri_gpio_set);
 		ret = -EINVAL;
-		goto err;
+		goto err1;
 	}
 	if (lpaif_pri_muxsel_virt_addr == NULL) {
 		pr_err("%s Pri muxsel virt addr is null\n", __func__);
 		ret = -EINVAL;
-		goto err;
+		goto err1;
 	}
 	lpaif_sec_muxsel_virt_addr = ioremap(LPAIF_SEC_MODE_MUXSEL, 4);
 	if (lpaif_sec_muxsel_virt_addr == NULL) {
 		pr_err("%s Sec muxsel virt addr is null\n", __func__);
 		ret = -EINVAL;
-		goto err;
+		goto err1;
 	}
 	return 0;
+
+err1:
+	gpio_free(ext_ult_lo_amp_gpio);
+	ext_ult_lo_amp_gpio = -1;
 err:
 	if (pdata->mclk_gpio > 0) {
 		dev_dbg(&pdev->dev, "%s free gpio %d\n",
@@ -2452,9 +2592,15 @@
 	if (ext_spk_amp_regulator)
 		regulator_put(ext_spk_amp_regulator);
 
+	if (gpio_is_valid(ext_ult_spk_amp_gpio))
+		gpio_free(ext_ult_spk_amp_gpio);
+
+	if (gpio_is_valid(ext_ult_lo_amp_gpio))
+		gpio_free(ext_ult_lo_amp_gpio);
+
 	gpio_free(pdata->mclk_gpio);
 	gpio_free(pdata->us_euro_gpio);
-	if (ext_spk_amp_gpio >= 0)
+	if (gpio_is_valid(ext_spk_amp_gpio))
 		gpio_free(ext_spk_amp_gpio);
 
 	if (msm8974_liquid_dock_dev != NULL) {
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index f15f4d1..659d5a2 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -912,6 +912,7 @@
 		case ASM_STREAM_CMD_OPEN_WRITE:
 		case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
 		case ASM_STREAM_CMD_OPEN_READWRITE:
+		case ASM_STREAM_CMD_OPEN_LOOPBACK:
 		case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
@@ -1852,6 +1853,45 @@
 	return -EINVAL;
 }
 
+int q6asm_open_loopack(struct audio_client *ac)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_loopback open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d]", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK;
+
+	open.mode_flags = 0;
+	open.src_endpointype = 0;
+	open.sink_endpointype = 0;
+	/* source endpoint : matrix */
+	open.postprocopo_id = get_asm_topology();
+	if (open.postprocopo_id == 0)
+		open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("open failed op[0x%x]rc[%d]\n", \
+						open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout. waited for OPEN_WRITE rc[%d]\n", rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
 int q6asm_run(struct audio_client *ac, uint32_t flags,
 		uint32_t msw_ts, uint32_t lsw_ts)
 {
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 8bb3eaf..7d9cc16 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -190,8 +190,8 @@
 
 	if (dai->id == AFE_PORT_ID_PRIMARY_PCM_RX
 			|| dai->id == AFE_PORT_ID_PRIMARY_PCM_TX) {
-		rx_port = PCM_RX;
-		tx_port = PCM_TX;
+		rx_port = AFE_PORT_ID_PRIMARY_PCM_RX;
+		tx_port = AFE_PORT_ID_PRIMARY_PCM_TX;
 	} else if (dai->id == AFE_PORT_ID_SECONDARY_PCM_RX
 			|| dai->id == AFE_PORT_ID_SECONDARY_PCM_TX) {
 		rx_port = AFE_PORT_ID_SECONDARY_PCM_RX;
@@ -295,8 +295,8 @@
 
 	if (dai->id == AFE_PORT_ID_PRIMARY_PCM_RX ||
 			dai->id == AFE_PORT_ID_PRIMARY_PCM_TX) {
-		rx_port = PCM_RX;
-		tx_port = PCM_TX;
+		rx_port = AFE_PORT_ID_PRIMARY_PCM_RX;
+		tx_port = AFE_PORT_ID_PRIMARY_PCM_TX;
 	} else if (dai->id == AFE_PORT_ID_SECONDARY_PCM_RX ||
 			dai->id == AFE_PORT_ID_SECONDARY_PCM_TX) {
 		rx_port = AFE_PORT_ID_SECONDARY_PCM_RX;
@@ -420,8 +420,8 @@
 
 	if (dai->id == AFE_PORT_ID_PRIMARY_PCM_RX ||
 			dai->id == AFE_PORT_ID_PRIMARY_PCM_TX) {
-		rx_port = PCM_RX;
-		tx_port = PCM_TX;
+		rx_port = AFE_PORT_ID_PRIMARY_PCM_RX;
+		tx_port = AFE_PORT_ID_PRIMARY_PCM_TX;
 	} else if (dai->id == AFE_PORT_ID_SECONDARY_PCM_RX ||
 			dai->id == AFE_PORT_ID_SECONDARY_PCM_TX) {
 		rx_port = AFE_PORT_ID_SECONDARY_PCM_RX;
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index f77ec0f..e6934f6 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -437,7 +437,8 @@
 	if (device == DEVICE_OUT_ALL) {
 		port_id = PRIMARY_I2S_RX | SLIMBUS_0_RX | HDMI_RX |
 				INT_BT_SCO_RX | INT_FM_RX |
-				RT_PROXY_PORT_001_RX | PCM_RX |
+				RT_PROXY_PORT_001_RX |
+				AFE_PORT_ID_PRIMARY_PCM_RX |
 				MI2S_RX | SECONDARY_I2S_RX |
 				SLIMBUS_1_RX | SLIMBUS_4_RX | SLIMBUS_3_RX |
 				AFE_PORT_ID_SECONDARY_MI2S_RX;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index c651ec7..e7c4a8a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -213,8 +213,8 @@
 	{ INT_FM_TX, 0, 0, 0, 0, 0},
 	{ RT_PROXY_PORT_001_RX, 0, 0, 0, 0, 0},
 	{ RT_PROXY_PORT_001_TX, 0, 0, 0, 0, 0},
-	{ PCM_RX, 0, 0, 0, 0, 0},
-	{ PCM_TX, 0, 0, 0, 0, 0},
+	{ AFE_PORT_ID_PRIMARY_PCM_RX, 0, 0, 0, 0, 0},
+	{ AFE_PORT_ID_PRIMARY_PCM_TX, 0, 0, 0, 0, 0},
 	{ VOICE_PLAYBACK_TX, 0, 0, 0, 0, 0},
 	{ VOICE_RECORD_RX, 0, 0, 0, 0, 0},
 	{ VOICE_RECORD_TX, 0, 0, 0, 0, 0},
@@ -2426,15 +2426,21 @@
 			__func__, e->shift_l , e->values[item]);
 		if (e->shift_l < MSM_BACKEND_DAI_MAX &&
 			e->values[item] < MSM_BACKEND_DAI_MAX)
+			/* Enable feedback TX path */
 			ret = afe_spk_prot_feed_back_cfg(
 			   msm_bedais[e->values[item]].port_id,
-			   msm_bedais[e->shift_l].port_id, 1, 0);
+			   msm_bedais[e->shift_l].port_id, 1, 0, 1);
 		else {
-			pr_err("%s values are out of range\n", __func__);
-			ret = -EINVAL;
+			pr_debug("%s values are out of range item %d\n",
+			__func__, e->values[item]);
+			/* Disable feedback TX path */
+			if (e->values[item] == MSM_BACKEND_DAI_MAX)
+				ret = afe_spk_prot_feed_back_cfg(0, 0, 0, 0, 0);
+			else
+				ret = -EINVAL;
 		}
 	} else {
-		pr_err("%s item value is out of range\n", __func__);
+		pr_err("%s item value is out of range item\n", __func__);
 		ret = -EINVAL;
 	}
 	mutex_unlock(&routing_lock);
@@ -2449,11 +2455,11 @@
 }
 
 static const char * const slim0_rx_vi_fb_tx_lch_mux_text[] = {
-	"SLIM4_TX",
+	"ZERO", "SLIM4_TX"
 };
 
 static const int const slim0_rx_vi_fb_tx_lch_value[] = {
-	MSM_BACKEND_DAI_SLIMBUS_4_TX,
+	MSM_BACKEND_DAI_MAX, MSM_BACKEND_DAI_SLIMBUS_4_TX
 };
 static const struct soc_enum slim0_rx_vi_fb_lch_mux_enum =
 	SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0,
@@ -3081,6 +3087,13 @@
 	{"BE_OUT", NULL, "SLIMBUS_3_RX"},
 	{"BE_OUT", NULL, "AUX_PCM_RX"},
 	{"BE_OUT", NULL, "SEC_AUX_PCM_RX"},
+	{"BE_OUT", NULL, "INT_BT_SCO_RX"},
+	{"BE_OUT", NULL, "INT_FM_RX"},
+	{"BE_OUT", NULL, "PCM_RX"},
+	{"BE_OUT", NULL, "SLIMBUS_3_RX"},
+	{"BE_OUT", NULL, "AUX_PCM_RX"},
+	{"BE_OUT", NULL, "SEC_AUX_PCM_RX"},
+	{"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
 
 	{"PRI_I2S_TX", NULL, "BE_IN"},
 	{"MI2S_TX", NULL, "BE_IN"},
@@ -3091,20 +3104,13 @@
 	{"SLIMBUS_3_TX", NULL, "BE_IN" },
 	{"SLIMBUS_4_TX", NULL, "BE_IN" },
 	{"SLIMBUS_5_TX", NULL, "BE_IN" },
-	{"BE_OUT", NULL, "INT_BT_SCO_RX"},
 	{"INT_BT_SCO_TX", NULL, "BE_IN"},
-	{"BE_OUT", NULL, "INT_FM_RX"},
 	{"INT_FM_TX", NULL, "BE_IN"},
-	{"BE_OUT", NULL, "PCM_RX"},
 	{"PCM_TX", NULL, "BE_IN"},
-	{"BE_OUT", NULL, "SLIMBUS_3_RX"},
-	{"BE_OUT", NULL, "AUX_PCM_RX"},
 	{"AUX_PCM_TX", NULL, "BE_IN"},
-	{"BE_OUT", NULL, "SEC_AUX_PCM_RX"},
 	{"SEC_AUX_PCM_TX", NULL, "BE_IN"},
 	{"INCALL_RECORD_TX", NULL, "BE_IN"},
 	{"INCALL_RECORD_RX", NULL, "BE_IN"},
-	{"BE_OUT", NULL, "VOICE_PLAYBACK_TX"},
 	{"SLIM0_RX_VI_FB_LCH_MUX", "SLIM4_TX", "SLIMBUS_4_TX"},
 	{"SLIMBUS_0_RX", NULL, "SLIM0_RX_VI_FB_LCH_MUX"},
 };
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 2b0d155..3598977 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -217,7 +217,7 @@
 
 	switch (port_id) {
 	case PRIMARY_I2S_RX:
-	case PCM_RX:
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
 	case SECONDARY_I2S_RX:
 	case MI2S_RX:
 	case HDMI_RX:
@@ -241,7 +241,7 @@
 		break;
 
 	case PRIMARY_I2S_TX:
-	case PCM_TX:
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
 	case SECONDARY_I2S_TX:
 	case MI2S_TX:
 	case DIGI_MIC_TX:
@@ -307,8 +307,8 @@
 	case RT_PROXY_PORT_001_TX:
 		ret_size = SIZEOF_CFG_CMD(afe_param_id_rt_proxy_port_cfg);
 		break;
-	case PCM_RX:
-	case PCM_TX:
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
 	default:
@@ -1153,8 +1153,8 @@
 	case PRIMARY_I2S_TX:
 		cfg_type = AFE_PARAM_ID_PCM_CONFIG;
 		break;
-	case PCM_RX:
-	case PCM_TX:
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
 		cfg_type = AFE_PARAM_ID_PCM_CONFIG;
@@ -1250,8 +1250,10 @@
 	switch (port_id) {
 	case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
 	case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
-	case PCM_RX: return IDX_PCM_RX;
-	case PCM_TX: return IDX_PCM_TX;
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+		return IDX_AFE_PORT_ID_PRIMARY_PCM_RX;
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
+		return IDX_AFE_PORT_ID_PRIMARY_PCM_TX;
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 		return IDX_AFE_PORT_ID_SECONDARY_PCM_RX;
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
@@ -1349,8 +1351,8 @@
 	case PRIMARY_I2S_TX:
 		cfg_type = AFE_PARAM_ID_I2S_CONFIG;
 		break;
-	case PCM_RX:
-	case PCM_TX:
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
 		cfg_type = AFE_PARAM_ID_PCM_CONFIG;
@@ -2538,8 +2540,8 @@
 	switch (port_id) {
 	case PRIMARY_I2S_RX:
 	case PRIMARY_I2S_TX:
-	case PCM_RX:
-	case PCM_TX:
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
 	case SECONDARY_I2S_RX:
@@ -2965,12 +2967,18 @@
 }
 
 int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
-	int l_ch, int r_ch)
+	int l_ch, int r_ch, u32 enable)
 {
 	int ret = -EINVAL;
 	union afe_spkr_prot_config prot_config;
 	int index = 0;
 
+	if (!enable) {
+		pr_debug("%s Disable Feedback tx path", __func__);
+		this_afe.vi_tx_port = -1;
+		return 0;
+	}
+
 	if ((q6audio_validate_port(src_port) < 0) ||
 		(q6audio_validate_port(dst_port) < 0)) {
 		pr_err("%s invalid ports src %d dst %d",
@@ -3011,6 +3019,7 @@
 	this_afe.apr = NULL;
 	this_afe.dtmf_gen_rx_portid = -1;
 	this_afe.mmap_handle = 0;
+	this_afe.vi_tx_port = -1;
 	for (i = 0; i < AFE_MAX_PORTS; i++)
 		init_waitqueue_head(&this_afe.wait[i]);
 
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index faf5f35..3cb7a1f 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -24,8 +24,10 @@
 	switch (port_id) {
 	case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
 	case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
-	case PCM_RX: return IDX_PCM_RX;
-	case PCM_TX: return IDX_PCM_TX;
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+		return IDX_AFE_PORT_ID_PRIMARY_PCM_RX;
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
+		return IDX_AFE_PORT_ID_PRIMARY_PCM_TX;
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 		return IDX_AFE_PORT_ID_SECONDARY_PCM_RX;
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
@@ -76,8 +78,10 @@
 	switch (port_id) {
 	case PRIMARY_I2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX;
 	case PRIMARY_I2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX;
-	case PCM_RX: return AFE_PORT_ID_PRIMARY_PCM_RX;
-	case PCM_TX: return AFE_PORT_ID_PRIMARY_PCM_TX;
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+			return AFE_PORT_ID_PRIMARY_PCM_RX;
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
+			return AFE_PORT_ID_PRIMARY_PCM_TX;
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 			return AFE_PORT_ID_SECONDARY_PCM_RX;
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
@@ -152,8 +156,8 @@
 	switch (port_id) {
 	case PRIMARY_I2S_RX:
 	case PRIMARY_I2S_TX:
-	case PCM_RX:
-	case PCM_TX:
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
 	case SECONDARY_I2S_RX:
@@ -179,8 +183,8 @@
 	switch (port_id) {
 	case PRIMARY_I2S_RX:
 	case PRIMARY_I2S_TX:
-	case PCM_RX:
-	case PCM_TX:
+	case AFE_PORT_ID_PRIMARY_PCM_RX:
+	case AFE_PORT_ID_PRIMARY_PCM_TX:
 	case AFE_PORT_ID_SECONDARY_PCM_RX:
 	case AFE_PORT_ID_SECONDARY_PCM_TX:
 	case SECONDARY_I2S_RX: