Merge "msm: hotplug: wait for hotplug completion event from secondary core"
diff --git a/Documentation/ABI/testing/sysfs-bus-msm_subsys b/Documentation/ABI/testing/sysfs-bus-msm_subsys
index fcfb1d4..f915a46 100644
--- a/Documentation/ABI/testing/sysfs-bus-msm_subsys
+++ b/Documentation/ABI/testing/sysfs-bus-msm_subsys
@@ -16,3 +16,16 @@
 
 		This file supports poll(3) to detect when a subsystem changes
 		state. Use POLLPRI to detect state changes.
+
+What:		/sys/bus/msm_subsys/devices/.../restart_level
+Date:		December 2012
+Contact:	Stephen Boyd <sboyd@codeaurora.org>
+Description:
+		Shows the restart level of a subsystem. The level is taken into
+		account when the subsystem is restarted via
+		subsystem_restart{_dev}(). Current supported states are:
+
+			SYSTEM	- reset the entire system
+			RELATED	- reset this subsystem and the other subsystems
+				  related to this one. Having no other
+				  subsystems related to this subsystem is valid.
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index b0a5d9a..45000f0 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -158,6 +158,17 @@
 		not enabled to wake up the system from sleep states, this
 		attribute is not present.
 
+What:		/sys/devices/.../power/wakeup_prevent_sleep_time_ms
+Date:		February 2012
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute
+		contains the total time the device has been preventing
+		opportunistic transitions to sleep states from occuring.
+		This attribute is read-only.  If the device is not enabled to
+		wake up the system from sleep states, this attribute is not
+		present.
+
 What:		/sys/devices/.../power/autosuspend_delay_ms
 Date:		September 2010
 Contact:	Alan Stern <stern@rowland.harvard.edu>
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index b464d12..31725ff 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -172,3 +172,62 @@
 
 		Reading from this file will display the current value, which is
 		set to 1 MB by default.
+
+What:		/sys/power/autosleep
+Date:		April 2012
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/power/autosleep file can be written one of the strings
+		returned by reads from /sys/power/state.  If that happens, a
+		work item attempting to trigger a transition of the system to
+		the sleep state represented by that string is queued up.  This
+		attempt will only succeed if there are no active wakeup sources
+		in the system at that time.  After every execution, regardless
+		of whether or not the attempt to put the system to sleep has
+		succeeded, the work item requeues itself until user space
+		writes "off" to /sys/power/autosleep.
+
+		Reading from this file causes the last string successfully
+		written to it to be returned.
+
+What:		/sys/power/wake_lock
+Date:		February 2012
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/power/wake_lock file allows user space to create
+		wakeup source objects and activate them on demand (if one of
+		those wakeup sources is active, reads from the
+		/sys/power/wakeup_count file block or return false).  When a
+		string without white space is written to /sys/power/wake_lock,
+		it will be assumed to represent a wakeup source name.  If there
+		is a wakeup source object with that name, it will be activated
+		(unless active already).  Otherwise, a new wakeup source object
+		will be registered, assigned the given name and activated.
+		If a string written to /sys/power/wake_lock contains white
+		space, the part of the string preceding the white space will be
+		regarded as a wakeup source name and handled as descrived above.
+		The other part of the string will be regarded as a timeout (in
+		nanoseconds) such that the wakeup source will be automatically
+		deactivated after it has expired.  The timeout, if present, is
+		set regardless of the current state of the wakeup source object
+		in question.
+
+		Reads from this file return a string consisting of the names of
+		wakeup sources created with the help of it that are active at
+		the moment, separated with spaces.
+
+
+What:		/sys/power/wake_unlock
+Date:		February 2012
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/power/wake_unlock file allows user space to deactivate
+		wakeup sources created with the help of /sys/power/wake_lock.
+		When a string is written to /sys/power/wake_unlock, it will be
+		assumed to represent the name of a wakeup source to deactivate.
+		If a wakeup source object of that name exists and is active at
+		the moment, it will be deactivated.
+
+		Reads from this file return a string consisting of the names of
+		wakeup sources created with the help of /sys/power/wake_lock
+		that are inactive at the moment, separated with spaces.
diff --git a/Documentation/cgroups/cpuacct.txt b/Documentation/cgroups/cpuacct.txt
index e21a932..9d73cc0 100644
--- a/Documentation/cgroups/cpuacct.txt
+++ b/Documentation/cgroups/cpuacct.txt
@@ -39,13 +39,6 @@
 
 user and system are in USER_HZ unit.
 
-cpuacct.cpufreq file gives CPU time (in nanoseconds) spent at each CPU
-frequency. Platform hooks must be implemented inorder to properly track
-time at each CPU frequency.
-
-cpuacct.power file gives CPU power consumed (in milliWatt seconds). Platform
-must provide and implement power callback functions.
-
 cpuacct controller uses percpu_counter interface to collect user and
 system times. This has two side effects:
 
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 6d22003..195a98d 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -8,17 +8,24 @@
 lpm-level. The units for voltage are dependent on the PMIC used on the target
 and are in uV.
 
-The optional properties are:
-
-- qcom,use-qtimer: Indicates whether the target uses the synchronized QTimer.
-
 The required nodes for lpm-levels are:
 
 - compatible: "qcom,lpm-levels"
 - reg: The numeric level id
-- qcom,mode: The sleep mode of the processor
-- qcom,xo: The state of XO clock.
-- qcom,l2: The state of L2 cache.
+- qcom,mode: The sleep mode of the processor, values for the property are:
+		"wfi" - Wait for Interrupt
+		"ramp_down_and_wfi" - Ramp down and wait for interrupt
+		"standalone_pc" - Standalone power collapse
+		"pc" - Power Collapse
+		"retention" - Retention
+		"pc_suspend" - Suspended Power Collapse
+		"pc_no_xo_shutdown" - Power Collapse with no XO shutdown
+- qcom,xo: The state of XO clock. Values are "xo_on" and "xo_off"
+- qcom,l2: The state of L2 cache. Values are:
+		"l2_cache_pc" - L2 cache in power collapse
+		"l2_cache_retenetion" - L2 cache in retention
+		"l2_cache_gdhs" - L2 cache in GDHS
+		"l2_cache_active" - L2 cache in active mode
 - qcom,vdd-mem-upper-bound: The upper bound value of mem voltage in uV
 - qcom,vdd-mem-lower-bound: The lower bound value of mem voltage in uV
 - qcom,vdd-dig-upper-bound: The upper bound value of dig voltage in uV
@@ -41,6 +48,7 @@
 - qcom,gpio-detectable: The field indicates whether the GPIOs can be detected
 			by the GPIO interrupt controller during a given low
 			power mode.
+- qcom,use-qtimer: Indicates whether the target uses the synchronized QTimer.
 
 Example:
 
@@ -48,9 +56,9 @@
 	qcom,use-qtimer;
 	qcom,lpm-level@0 {
 		reg = <0>;
-		qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
-		qcom,xo = <1>;          /* ON */
-		qcom,l2 = <3>;          /* ACTIVE */
+		qcom,mode = "wfi";
+		qcom,xo = "xo_on";
+		qcom,l2 = "l2_cache_active";
 		qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 		qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 		qcom,vdd-dig-upper-bound = <5>; /* MAX */
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
index ccb3465..7b5fda3 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
@@ -20,10 +20,9 @@
 - reg: The numeric level id
 - qcom,name: The name of the low power resource represented
              as a string.
-- qcom,resource-type: The type of the LPM resource.
-   MSM_LPM_RPM_RS_TYPE    = 0
-   MSM_LPM_LOCAL_RS_TYPE  = 1
-- qcom,init-value: Initialization value of the LPM resource.
+- qcom,init-value: Initialization value of the LPM resource represented as
+			decimal value for vdd-dig and vdd-mem resources and
+			as string for pxo and l2 resources.
 
 
 Optional Nodes:
@@ -33,12 +32,13 @@
 - qcom,id: The id representing a device within a resource type.
 - qcom,key: The key is the specific attribute of the resource being
             monitored represented as a hex value.
+- qcom,local-resource-type: The property exists only for locally managed
+				resource and is represented as a bool.
 
 Example:
             qcom,lpm-resources@0 {
                         reg = <0x0>;
                         qcom,name = "vdd-dig";
-                        qcom,resource-type = <0>;
                         qcom,type = <0x62706d73>;   /* "smpb" */
                         qcom,id = <0x02>;
                         qcom,key = <0x6e726f63>;   /* "corn" */
diff --git a/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
index e62b9ec..9ac1cbd 100644
--- a/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
+++ b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
@@ -1,4 +1,4 @@
-* MSM Timetick counter (mpm-v2)
+* MSM MPM sleep counter (mpm-v2)
 
 The MPM provides a timetick that starts when the device is powered up and
 is not reset by any of the boot loaders or the HLOS. The MPM timetick counter
@@ -6,12 +6,14 @@
 
 The required nodes for the MPM timetick counter driver are:
 
-- compatible: "qcom,mpm-counter"
+- compatible: "qcom,mpm2-sleep-counter"
 - reg: Specifies the physical address of the timetick count register.
+- clock-frequency: the physical counter frequency.
 
 Example:
-	qcom,mpm-counter@fc4a3000 {
-		compatible = "qcom,mpm-counter";
+	qcom,mpm2-sleep-counter@fc4a3000 {
+		compatible = "qcom,mpm2-sleep-counter";
 		reg = <0xfc4a3000 0x1000>;
+		clock-frequency = <32768>;
 	};
 
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index a372912..c741514 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -18,10 +18,10 @@
 - reg: physical IMEM address reserved for PC counters and the size
 - qcom,use-sync-timer: Indicates whether the target uses the synchronized QTimer.
 - qcom,pc-mode: Indicates the type of power collapse used by the target. The
-	valid values for this are:
-	0  (Power collapse terminates in TZ; integrated L2 cache controller)
-	1, (Power collapse doesn't terminate in TZ; external L2 cache controller)
-	2  (Power collapse terminates in TZ; external L2 cache controller)
+           valid values for this are:
+	"tz_l2_int"  (Power collapse terminates in TZ; integrated L2 cache controller)
+	"no_tz_l2_ext", (Power collapse doesn't terminate in TZ; external L2 cache controller)
+	"tz_l2_ext"  (Power collapse terminates in TZ; external L2 cache controller)
 - qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
 	doing power collapse and so the core need to switch to Global PLL before
 	PC.
@@ -31,6 +31,6 @@
 qcom,pm-8x60@fe800664 {
 		compatible = "qcom,pm-8x60";
 		reg = <0xfe800664 0x40>;
-		qcom,pc-mode = <0>;
+		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 	};
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-boot.txt b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
index cce9d0e..7ba8a6d 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
@@ -16,10 +16,10 @@
 
 - compatible: Must be "qcom,pm-boot"
 - qcom,mode: The mode that the target will use for booting
-	MSM_PM_BOOT_CONFIG_TZ                = 0,
-	MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
-	MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
-	MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR   = 3,
+	"tz" = MSM_PM_BOOT_CONFIG_TZ,
+	"reset_vector_phys" = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+	"reset_vector_virt" = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	"remap_boot_addr" = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
 
 Optional parameters (based on the mode chosen):
 
@@ -36,5 +36,5 @@
 
 	qcom,pm-boot {
 		compatible = "qcom,pm-boot";
-		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+		qcom,mode = "tz"; /* MSM_PM_BOOT_CONFIG_TZ */
 	};
diff --git a/Documentation/devicetree/bindings/arm/msm/pmu.txt b/Documentation/devicetree/bindings/arm/msm/pmu.txt
new file mode 100644
index 0000000..0bd5e58
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/pmu.txt
@@ -0,0 +1,40 @@
+* Qcom Performance Monitor Units
+Qcom cores have several PMUs for counting CPU side, L2 and bus side events.
+
+For the L1CC PMU:
+In most cases the L1 cache controller PMU is a per cpu unit. The irq-is-percpu
+flag becomes a requirement if this is the case.
+
+Required Properties:
+
+- compatible : Should be "qcom,krait-pmu"
+- interrupts : 1 combined interrupt or 1 per core. See the devicetree/bindings/gic.txt for more details on this format.
+
+Optional:
+
+- qcom,irq-is-percpu: 	Define this if the IRQ of the PMU is a PPI. This will tell perf to use
+			the per_cpu IRQ API for request and free.
+
+Example:
+
+ arm-pmu {
+                compatible = "qcom,krait-pmu";
+                qcom,irq-is-percpu;
+                interrupts = <1 7 0xf00>;
+        };
+
+For the L2CC PMU:
+If the L2 cache controller PMU is available, its DT bindings should be defined as
+follows.
+
+Required Properties:
+
+- compatible: Should be "qcom,l2-pmu"
+- interrupts : 1 combined interrupt.
+
+Example:
+
+  l2-pmu {
+                compatible = "qcom,l2-pmu";
+                interrupts = <0 1 0>;
+        };
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt b/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
deleted file mode 100644
index e5fd1b2..0000000
--- a/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-* Qualcomm's Watchdog Debug Image Controller
-
-The Qualcomm's Watchdog debug image controller is used for enabling/disabling of
-watchdog debug image feature.
-
-Required properties:
-- compatible : should be "qcom,msm-wdog-debug"
-- reg : base page aligned physical base address of the controller and length of
-	memory mapped region.
-
-Example:
-
-	qcom,msm-wdog-debug@fc401000 {
-		compatible = "qcom,msm-wdogi-debug";
-		reg = <0xfc401000 0x1000>;
-	};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index 7d19c03..5c426f2 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -8,22 +8,45 @@
 - cell-index:				Specifies the controller used among the two controllers.
 - reg:					offset and length of the register set for the device.
 - vdd-supply:				Phandle for vdd regulator device node.
-- vdd-io-supply:			Phandle for vdd-io regulator device node.
-- vreg-supply:				Phandle for vreg regulator device node.
+- vddio-supply:				Phandle for vdd-io regulator device node.
+- vdda-supply:				Phandle for vreg regulator device node.
 - qcom,mdss-fb-map:			pHandle that specifies the framebuffer to which the
 					interface is mapped.
 
 Optional properties:
 - label:		        	A string used to describe the controller used.
+- qcom,supply-names:			A list of strings that lists the names of the
+					regulator supplies.
+- qcom,supply-type:			A list of strings that list the type of supply(ies)
+					mentioned above. This list maps in the order of
+					the supply names listed above.
+					  regulator = supply with controlled output
+					  switch = supply without controlled output. i.e.
+					  voltage switch
+- qcom,supply-min-voltage-level:	A list that specifies minimum voltage level
+					of supply(ies) mentioned above. This list maps
+					in the order of the supply names listed above.
+- qcom,supply-max-voltage-level:	A list that specifies maximum voltage level of
+					supply(ies) mentioned above. This list maps in
+					the order of the supply names listed above.
+- qcom,supply-peak-current:		A list that specifies the peak current that will
+					be drawn from the supply(ies) mentioned above. This
+					list maps in the order of the supply names listed above.
+
 
 Example:
         mdss_dsi0: qcom,mdss_dsi@fd922800 {
-                compatible = "qcom,mdss-dsi-ctrl";
-                label = "MDSS DSI CTRL->0";
-                cell-index = <0>;
-                reg = <0xfd922800 0x600>;
-                vdd-supply = <&pm8941_l22>;
-                vdd_io-supply = <&pm8941_l12>;
-                vreg-supply = <&pm8941_l2>;
+		compatible = "qcom,mdss-dsi-ctrl";
+		label = "MDSS DSI CTRL->0";
+		cell-index = <0>;
+		reg = <0xfd922800 0x600>;
+		vdd-supply = <&pm8226_l15>;
+		vddio-supply = <&pm8226_l8>;
+		vdda-supply = <&pm8226_l4>;
+		qcom,supply-names = "vdd", "vddio", "vdda";
+		qcom,supply-type = "regulator", "regulator", "regulator";
+		qcom,supply-min-voltage-level = <2800000 1800000 1200000>;
+		qcom,supply-max-voltage-level = <2800000 1800000 1200000>;
+		qcom,supply-peak-current = <150000 100000 100000>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
         };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index a432fb5..9a7fa90 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -39,8 +39,7 @@
 Required properties:
 - compatible : should be "qcom" followed by sensor name
     - "qcom,s5k3l1yx"
-- reg : should contain i2c slave address of the camera sensor and
-    length of data field which is 0x0
+- reg : should contain i2c slave address of the device
 - qcom,slave-id : should contain i2c slave address, device id address
     and expected id read value
 - qcom,csiphy-sd-index : should contain csiphy instance that will used to
@@ -176,14 +175,14 @@
 
         actuator0: qcom,actuator@18 {
                 cell-index = <0>;
-                reg = <0x18 0x0>;
+                reg = <0x18>;
                 compatible = "qcom,actuator";
                 qcom,cci-master = <0>;
         };
 
        qcom,s5k3l1yx@6e {
                compatible = "qcom,s5k3l1yx";
-               reg = <0x6e 0x0>;
+               reg = <0x6e>;
                qcom,slave-id = <0x6e 0x0 0x3121>;
                qcom,csiphy-sd-index = <2>;
                qcom,csid-sd-index = <0>;
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index a0c7037..d5937cf 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -20,6 +20,24 @@
 Optional Properties:
 	- interrupt-names - "status_irq". This status_irq will be used for card
 			     detection.
+	- cd-gpios: specify GPIO for card detection. If this property is
+		    defined, then it means SDHC device has more than one interrupt
+		    parent and hence, it is required to define the following properties
+		    to configure interrupts from multiple parents -
+
+		    interrupt-parent - This must provide reference to the current
+				       device node.
+		    #address-cells - Should provide a value of 0.
+		    interrupts - Should be <0 1 2> and it is an index to the
+				 interrupt-map.
+		    #interrupt-cells - should provide a value of 1.
+		    #interrupt-mask - should provide a value of 0xffffffff.
+		    interrupt-map - Must create mapping for the number of interrupts
+				    that are defined in above interrupts property.
+				    For SDHC device node, it must define 3 mappings for
+				    hc_irq, pwr_irq and status_irq in the format
+				    mentioned in below example node of sdhc_2.
+
 	- qcom,bus-width - defines the bus I/O width that controller supports.
 			   Units - number of bits. The valid bus-width values are
 			   1, 4 and 8.
@@ -109,8 +127,17 @@
 		compatible = "qcom,sdhci-msm";
                 reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
                 reg-names = "hc_mem", "core_mem";
-                interrupts = <0 123 0>, <0 138 0>;
-                interrupt-names = "hc_irq", "pwr_irq";
+
+		#address-cells = <0>;
+		interrupt-parent = <&sdhc_2>;
+		interrupts = <0 1 2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 125 0
+				1 &intc 0 221 0
+				2 &msmgpio 62 0x3>;
+                interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+		cd-gpios = <&msmgpio 62 0x1>;
 
 		vdd-supply = <&pm8941_l21>;
 		vdd-io-supply = <&pm8941_l13>;
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt
new file mode 100644
index 0000000..10c1bbf
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt
@@ -0,0 +1,44 @@
+Qualcomm QPNP Coincell - coincell battery charger devices
+
+Required properties:
+- compatible:      Must be "qcom,qpnp-coincell".
+- reg:             Specifies the SPMI address and size for this coincell device.
+
+Required structure:
+- A qcom,qpnp-coincell node must be a child of an SPMI node that has specified
+	the spmi-slave-container property.
+
+Optional properties:
+- qcom,rset-ohms:	Specifies the resistance of the current limiting
+			resistor in ohms.  Four values are supported:
+			800, 1200, 1700, and 2100.
+- qcom,vset-millivolts:	Specifies the coincell charging voltage in millivolts.
+			Four values are supported: 2500, 3000, 3100, and 3200.
+- qcom,charge-enable:	Specifies if coincell charging should be enabled or not.
+			0 = disable charging, 1 = enabled charging
+
+If any of the optional properties are not specified, then the hardware default
+values for the unspecified properties will be used instead.
+
+Example:
+	qcom,spmi@fc4c0000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-controller;
+		#interrupt-cells = <3>;
+
+		qcom,pm8941@1 {
+			spmi-slave-container;
+			reg = <0x1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qcom,coincell@2800 {
+				compatible = "qcom,qpnp-coincell";
+				reg = <0x2800 0x100>;
+				qcom,rset-ohms = <800>;
+				qcom,vset-millivolts = <3100>;
+				qcom,charge-enable = <1>;
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 708ada1..5b22752 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -40,13 +40,16 @@
 			The bms will not accept new ocvs between these
 			thresholds.
 - qcom,low-soc-calculate-soc-threshold : The SoC threshold for when
-			the period calculate_soc work speeds up. This ensures
+			the periodic calculate_soc work speeds up. This ensures
 			SoC is updated in userspace constantly when we are near
 			shutdown.
+- qcom,low-voltage-threshold : The battery voltage threshold in micro-volts for
+			when the BMS tries to wake up and hold a wakelock to
+			ensure a clean shutdown.
 - qcom,low-soc-calculate-soc-ms : The time period between subsequent
-
 			SoC recalculations when the current SoC is below
-			qcom,low-soc-calculate-soc-threshold.
+			qcom,low-soc-calculate-soc-threshold or when battery
+			voltage is below qcom,low-voltage-threshold.
 - qcom,soc-calculate-soc-ms : The time period between subsequent SoC
 			recalculations when the current SoC is above or equal
 			qcom,low-soc-calculate-soc-threshold.
@@ -107,6 +110,7 @@
 	qcom,adjust-soc-low-threshold = <25>;
 	qcom,adjust-soc-high-threshold = <45>;
 	qcom,low-soc-calculate-soc-threshold = <15>;
+	qcom,low-voltage-threshold = <3420000>;
 	qcom,low-soc-calculate-soc-ms = <5000>;
 	qcom,calculate-soc-ms = <20000>;
 	qcom,chg-term-ua = <100000>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 4590227..2832693 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -26,16 +26,17 @@
 - qcom,chg-vddmax-mv:			Target voltage of battery in mV.
 - qcom,chg-vddsafe-mv:			Maximum Vdd voltage in mV.
 - qcom,chg-vinmin-mv:			Minimum input voltage in mV.
-- qcom,chg-vbatdet-mv:			Battery charging resume voltage in mV.
 - qcom,chg-ibatmax-ma:			Maximum battery charge current in mA
-- qcom,chg-ibatterm-ma:			Current at which charging is terminated.
 - qcom,chg-ibatsafe-ma:			Safety battery current setting
 - qcom,chg-thermal-mitigation:		Array of ibatmax values for different
 					system thermal mitigation level.
 
 Parent node optional properties:
+- qcom,chg-ibatterm-ma:			Current at which charging is terminated when
+					the analog end of charge option is selected.
 - qcom,chg-maxinput-usb-ma:		Maximum input current USB.
 - qcom,chg-maxinput-dc-ma:		Maximum input current DC.
+- qcom,chg-vbatdet-delta-mv:		Battery charging resume delta.
 - qcom,chg-charging-disabled:		Set this property to disable charging
 					by default. This can then be overriden
 					writing the the module parameter
@@ -44,6 +45,16 @@
 					battery temperature of 250 decidegree
 					Celsius, state of charge to be 50%
 					and disable charging.
+- qcom,chg-warm-bat-degc:		Warm battery temperature in degC.
+- qcom,chg-cool-bat-degc:		Cool battery temperature in degC.
+					Note that if both warm and cool battery
+					temperatures are set, the corresponding
+					ibatmax and bat-mv properties are
+					required to be set.
+- qcom,chg-ibatmax-cool-ma:		Maximum cool battery charge current.
+- qcom,chg-ibatmax-warm-ma:		Maximum warm battery charge current.
+- qcom,chg-warm-bat-mv:			Warm temperature battery target voltage.
+- qcom,chg-cool-bat-mv:			Cool temperature battery target voltage.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
@@ -132,11 +143,17 @@
 		qcom,chg-vddmax-mv = <4200>;
 		qcom,chg-vddsafe-mv = <4200>;
 		qcom,chg-vinmin-mv = <4200>;
-		qcom,chg-vbatdet-mv = <4200>;
 		qcom,chg-ibatmax-ma = <1500>;
 		qcom,chg-ibatterm-ma = <200>;
 		qcom,chg-ibatsafe-ma = <1500>;
 		qcom,chg-thermal-mitigation = <1500 700 600 325>;
+		qcom,chg-cool-bat-degc = <10>;
+		qcom,chg-cool-bat-mv = <4100>;
+		qcom,chg-ibatmax-warm-ma = <350>;
+		qcom,chg-warm-bat-degc = <45>;
+		qcom,chg-warm-bat-mv = <4100>;
+		qcom,chg-ibatmax-cool-ma = <350>;
+		qcom,chg-vbatdet-delta-mv = <60>;
 
 		qcom,chg-chgr@1000 {
 			reg = <0x1000 0x100>;
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 4cd9f99..a4c05d4 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -96,6 +96,12 @@
    is 8, which indicates the rx path used for audio playback
    on HDMI device.
 
+* msm-lsm-client
+
+Required properties:
+
+ - compatible : "qcom,msm-lsm-client"
+
 * msm-dai-q6
 
 [First Level Nodes]
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 67a986b..1388b7d 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -38,7 +38,11 @@
 Optional properties:
 - qcom,calibration-less-mode : If present the pre-characterized data for offsets
 		are used else it defaults to use calibration data from QFPROM.
-
+- qcom,tsens-local-init : If the flag is present the TSENS control registers are
+		initialized. If the boot configures the control register there is
+		no need to re-initialize them. The control registers are also
+		under a secure domain which can prevent them from being initialized
+		locally.
 Example:
 
 tsens@fc4a8000 {
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index ffb0c6a..9f8bbd9 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -5,14 +5,20 @@
 - regs : offset and length of the register set in the memory map
 - interrupts: IRQ lines used by this controller
 - interrupt-names : Required interrupt resource entries are:
-            HSIC EHCI expects "core_irq" and optionally "async_irq".
+	"core_irq" : Interrupt for HSIC core
 - <supply-name>-supply: handle to the regulator device tree node
   Required "supply-name" is "HSIC_VDDCX" and optionally - "HSIC_GDSC".
 
 Optional properties :
+- interrupt-names : Optional interrupt resource entries are:
+	"async_irq" : Interrupt from HSIC for asynchronous events in HSIC LPM.
+	"wakeup" : Wakeup interrupt from HSIC during suspend (or XO shutdown).
 - hsic,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
   in Documentation/devicetree/bindings/gpio/gpio.txt.
-  Optional "gpio-name" can be "strobe" and "data".
+  Optional "gpio-name" can be "strobe", "data" and "resume".
+- hsic,resume-gpio : if present then periperal connected to hsic controller
+  cannot wakeup from XO shutdown using in-band hsic resume. Use resume
+  gpio to wakeup peripheral
 - hsic,ignore-cal-pad-config : If present then HSIC CAL PAD configuration
   using TLMM is not performed.
 - hsic,strobe-pad-offset : Offset of TLMM register for configuring HSIC
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 6cf59ee..02c2871 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -114,6 +114,7 @@
 - qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
 - qcom,pool-64-bit-align: If present then the pool's memory will be aligned
   to 64 bits
+- qcom,enable_hbm: if present host bus manager is enabled.
 
 Example MSM HSUSB EHCI controller device node :
 	ehci: qcom,ehci-host@f9a55000 {
@@ -171,115 +172,90 @@
             If SSUSB_BAM is used, "ssusb" should be present.
             If HSUSB_BAM is used, "hsusb" should be present.
             If HSIC_BAM is used, "hsic" should be present.
-- qcom,usb-active-bam: active BAM type. Can be one of
-            0 - SSUSB_BAM
-            1 - HSUSB_BAM
-            2 - HSIC_BAM
-- qcom,usb-total-bam-num: total number of BAMs that are supported
 - qcom,usb-bam-num-pipes: max number of pipes that can be used
 - qcom,usb-base-address: physical base address of the BAM
 
 A number of USB BAM pipe parameters are represented as sub-nodes:
 
 Subnode Required:
-- label: a string describing the pipe's direction and BAM instance under use
-- qcom,usb-bam-type: BAM type. Can be one of
-            0 - SSUSB_BAM
-            1 - HSUSB_BAM
-            2 - HSIC_BAM
+- label: a string describing uniquely the usb bam pipe. The string can be
+  constracted as follows: <core>-<peer>-<direction>-<pipe num>.
+	core options: hsusb, ssusb/dwc3, hsic
+	peer options: qdss, ipa, a2
+	direction options: in (from peer to usb), out (from usb to peer)
+	pipe num options: 0..127
 - qcom,usb-bam-mem-type: Type of memory used by this PIPE. Can be one of
             0 - Uses SPS's dedicated pipe memory
             1 - USB's private memory residing @ 'qcom,usb-base-address'
             2 - System RAM allocated by driver
-- qcom,src-bam-physical-address: source BAM physical address
-- qcom,src-bam-pipe-index: source BAM pipe index
-- qcom,dst-bam-physical-address: destination BAM physical address
-- qcom,dst-bam-pipe-index: destination BAM pipe index
-- qcom,data-fifo-offset: data fifo offset address
+- qcom,bam-type: BAM type can be one of
+	0 - SSUSB_BAM
+	1 - HSUSB_BAM
+	2 - HSIC_BAM
+- qcom,dir: pipe direction
+	0 - from usb (out)
+	1 - to usb (in)
+- qcom,pipe-num: pipe number
+- qcom,peer-bam: peer BAM can be one of
+	0 - A2_P_BAM
+	1 - QDSS_P_BAM
+	2 - IPA_P_BAM
 - qcom,data-fifo-size: data fifo size
-- qcom,descriptor-fifo-offset: descriptor fifo offset address
 - qcom,descriptor-fifo-size: descriptor fifo size
 
 Optional Properties for Subnode:
 - qcom,reset-bam-on-connect: If present then BAM is RESET before connecting
   pipe. This may be required if BAM peripheral is also reset before connect.
+- qcom,dst-bam-physical-address: destination BAM physical address
+- qcom,dst-bam-pipe-index: destination BAM pipe index
+- qcom,src-bam-physical-address: source BAM physical address
+- qcom,src-bam-pipe-index: source BAM pipe index
+- qcom,data-fifo-offset: data fifo offset address
+- qcom,descriptor-fifo-offset: descriptor fifo offset address
 
 Optional properties :
 - qcom,ignore-core-reset-ack: If present then BAM ignores ACK from USB core
 	    while performing PIPE RESET
 - qcom,disable-clk-gating: If present then disable BAM clock gating.
 
-
 Example USB BAM controller device node:
 
-	qcom,usbbam@f9304000 {
+	qcom,usbbam@f9a44000 {
 		compatible = "qcom,usb-bam-msm";
-		reg = <0xf9304000 0x5000>,
-		      <0xf9a44000 0x11000>,
-		      <0xf92f880c 0x4>;
-		reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
-		interrupts = <0 132 0 0 135 0>;
-		interrupt-names = "ssusb", "hsusb";
-		qcom,usb-active-bam = <0>;
-		qcom,usb-total-bam-num = <2>;
+		reg = <0xf9a44000 0x11000>;
+		reg-names = "hsusb";
+		interrupts = <0 135 0>;
+		interrupt-names = "hsusb";
 		qcom,usb-bam-num-pipes = <16>;
-		qcom,usb-base-address = <0xf9200000>;
 		qcom,ignore-core-reset-ack;
+		qcom,disable-clk-gating;
 
+		qcom,pipe0 {
+			label = "hsusb-ipa-out-0";
+			qcom,usb-bam-mem-type = <0>;
+			qcom,bam-type = <1>;
+			qcom,dir = <0>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <2>;
+			qcom,src-bam-physical-address = <0xf9a44000>;
+			qcom,src-bam-pipe-index = <1>;
+			qcom,data-fifo-offset = <0x2200>;
+			qcom,data-fifo-size = <0x1e00>;
+			qcom,descriptor-fifo-offset = <0x2100>;
+			qcom,descriptor-fifo-size = <0x100>;
+		};
 		qcom,pipe1 {
-			label = "usb-to-peri-qdss-dwc3";
-			qcom,usb-bam-type = <0>;
-			qcom,usb-bam-mem-type = <1>;
-			qcom,src-bam-physical-address = <0>;
-			qcom,src-bam-pipe-index = <0>;
-			qcom,dst-bam-physical-address = <0>;
-			qcom,dst-bam-pipe-index = <0>;
-			qcom,data-fifo-offset = <0>;
-			qcom,data-fifo-size = <0>;
-			qcom,descriptor-fifo-offset = <0>;
-			qcom,descriptor-fifo-size = <0>;
-		};
-
-		qcom,pipe2 {
-			label = "peri-to-usb-qdss-dwc3";
-			qcom,usb-bam-type = <0>;
-			qcom,usb-bam-mem-type = <1>;
-			qcom,src-bam-physical-address = <0xfc37C000>;
-			qcom,src-bam-pipe-index = <0>;
-			qcom,dst-bam-physical-address = <0xf9304000>;
-			qcom,dst-bam-pipe-index = <2>;
-			qcom,data-fifo-offset = <0xf0000>;
-			qcom,data-fifo-size = <0x4000>;
-			qcom,descriptor-fifo-offset = <0xf4000>;
-			qcom,descriptor-fifo-size = <0x1400>;
-			qcom,reset-bam-on-connect;
-		};
-
-		qcom,pipe3 {
-			label = "usb-to-peri-qdss-hsusb";
-			qcom,usb-bam-type = <1>;
-			qcom,usb-bam-mem-type = <1>;
-			qcom,src-bam-physical-address = <0>;
-			qcom,src-bam-pipe-index = <0>;
-			qcom,dst-bam-physical-address = <0>;
-			qcom,dst-bam-pipe-index = <0>;
-			qcom,data-fifo-offset = <0>;
-			qcom,data-fifo-size = <0>;
-			qcom,descriptor-fifo-offset = <0>;
-			qcom,descriptor-fifo-size = <0>;
-		};
-
-		qcom,pipe4 {
-			label = "peri-to-usb-qdss-hsusb";
-			qcom,usb-bam-type = <1>;
-			qcom,usb-bam-mem-type = <1>;
-			qcom,src-bam-physical-address = <0xfc37c000>;
-			qcom,src-bam-pipe-index = <0>;
+			label = "hsusb-ipa-in-0";
+			qcom,usb-bam-mem-type = <0>;
+			qcom,bam-type = <1>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <2>;
 			qcom,dst-bam-physical-address = <0xf9a44000>;
-			qcom,dst-bam-pipe-index = <2>;
-			qcom,data-fifo-offset = <0xf4000>;
-			qcom,data-fifo-size = <0x1000>;
-			qcom,descriptor-fifo-offset = <0xf5000>;
-			qcom,descriptor-fifo-size = <0x400>;
+			qcom,dst-bam-pipe-index = <0>;
+			qcom,data-fifo-offset = <0x300>;
+			qcom,data-fifo-size = <0x1e00>;
+			qcom,descriptor-fifo-offset = <0>;
+			qcom,descriptor-fifo-size = <0x300>;
 		};
 	};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6839263..17a44b3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1830,13 +1830,6 @@
 	  Enable hardware performance counter support for perf events. If
 	  disabled, perf events will use software events only.
 
-config VMALLOC_RESERVE
-	hex "Reserved vmalloc space"
-	default 0x08000000
-	depends on MMU
-	help
-	  Reserved vmalloc space if not specified on the kernel commandline.
-
 source "mm/Kconfig"
 
 config ARCH_MEMORY_PROBE
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
new file mode 100644
index 0000000..f09a78a
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -0,0 +1,159 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,mdss_dsi_nt35590_720p_video {
+		compatible = "qcom,mdss-dsi-panel";
+		label = "nt35590 720p video mode dsi panel";
+		status = "disable";
+		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+		qcom,rst-gpio = <&msmgpio 25 0>;
+		qcom,mdss-pan-res = <720 1280>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-dest = "display_1";
+		qcom,mdss-pan-porch-values = <164 8 140 1 1 6>;
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+		qcom,mdss-pan-bl-levels = <1 255>;
+		qcom,mdss-pan-dsi-mode = <0>;
+		qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+		qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+		qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+		qcom,mdss-pan-dsi-traffic-mode = <2>;
+		qcom,mdss-pan-dsi-dst-format = <3>;
+		qcom,mdss-pan-dsi-vc = <0>;
+		qcom,mdss-pan-dsi-rgb-swap = <0>;
+		qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
+		qcom,mdss-pan-dsi-dlane-swap = <0>;
+		qcom,mdss-pan-dsi-t-clk = <0x2c 0x20>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		qcom,mdss-pan-dsi-mdp-tr = <0x0>;
+		qcom,mdss-pan-dsi-dma-tr = <0x04>;
+		qcom,mdss-pan-frame-rate = <60>;
+		qcom,panel-phy-regulatorSettings = [07 09 03 00  /* Regualotor settings */
+						    20 00 01];
+		qcom,panel-phy-timingSettings = [7d 25 1d 00 37 33
+						    22 27 1e 03 04 00];
+		qcom,panel-phy-strengthCtrl = [ff 06];
+		qcom,panel-phy-bistCtrl = [00 00 b1 ff           /* BIST Ctrl settings */
+					   00 00];
+		qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
+					     00 00 00 00 05 00 00 01 97 /* lane1 config */
+					     00 00 00 00 0a 00 00 01 97 /* lane2 config */
+					     00 00 00 00 0f 00 00 01 97 /* lane3 config */
+					     00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
+		qcom,panel-on-cmds = [29 01 00 00 00 02 FF EE
+					29 01 00 00 00 02 26 08
+					29 01 00 00 00 02 26 00
+					29 01 00 00 10 02 FF 00
+					29 01 00 00 00 02 BA 03
+					29 01 00 00 00 02 C2 03
+					29 01 00 00 00 02 FF 01
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 00 4A
+					29 01 00 00 00 02 01 33
+					29 01 00 00 00 02 02 53
+					29 01 00 00 00 02 03 55
+					29 01 00 00 00 02 04 55
+					29 01 00 00 00 02 05 33
+					29 01 00 00 00 02 06 22
+					29 01 00 00 00 02 08 56
+					29 01 00 00 00 02 09 8F
+					29 01 00 00 00 02 36 73
+					29 01 00 00 00 02 0B 9F
+					29 01 00 00 00 02 0C 9F
+					29 01 00 00 00 02 0D 2F
+					29 01 00 00 00 02 0E 24
+					29 01 00 00 00 02 11 83
+					29 01 00 00 00 02 12 03
+					29 01 00 00 00 02 71 2C
+					29 01 00 00 00 02 6F 03
+					29 01 00 00 00 02 0F 0A
+					29 01 00 00 00 02 FF 05
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 01 00
+					29 01 00 00 00 02 02 8B
+					29 01 00 00 00 02 03 82
+					29 01 00 00 00 02 04 82
+					29 01 00 00 00 02 05 30
+					29 01 00 00 00 02 06 33
+					29 01 00 00 00 02 07 01
+					29 01 00 00 00 02 08 00
+					29 01 00 00 00 02 09 46
+					29 01 00 00 00 02 0A 46
+					29 01 00 00 00 02 0D 0B
+					29 01 00 00 00 02 0E 1D
+					29 01 00 00 00 02 0F 08
+					29 01 00 00 00 02 10 53
+					29 01 00 00 00 02 11 00
+					29 01 00 00 00 02 12 00
+					29 01 00 00 00 02 14 01
+					29 01 00 00 00 02 15 00
+					29 01 00 00 00 02 16 05
+					29 01 00 00 00 02 17 00
+					29 01 00 00 00 02 19 7F
+					29 01 00 00 00 02 1A FF
+					29 01 00 00 00 02 1B 0F
+					29 01 00 00 00 02 1C 00
+					29 01 00 00 00 02 1D 00
+					29 01 00 00 00 02 1E 00
+					29 01 00 00 00 02 1F 07
+					29 01 00 00 00 02 20 00
+					29 01 00 00 00 02 21 06
+					29 01 00 00 00 02 22 55
+					29 01 00 00 00 02 23 4D
+					29 01 00 00 00 02 2D 02
+					29 01 00 00 00 02 28 01
+					29 01 00 00 00 02 2F 02
+					29 01 00 00 00 02 83 01
+					29 01 00 00 00 02 9E 58
+					29 01 00 00 00 02 9F 6A
+					29 01 00 00 00 02 A0 01
+					29 01 00 00 00 02 A2 10
+					29 01 00 00 00 02 BB 0A
+					29 01 00 00 00 02 BC 0A
+					29 01 00 00 00 02 32 08
+					29 01 00 00 00 02 33 B8
+					29 01 00 00 00 02 36 01
+					29 01 00 00 00 02 37 00
+					29 01 00 00 00 02 43 00
+					29 01 00 00 00 02 4B 21
+					29 01 00 00 00 02 4C 03
+					29 01 00 00 00 02 50 21
+					29 01 00 00 00 02 51 03
+					29 01 00 00 00 02 58 21
+					29 01 00 00 00 02 59 03
+					29 01 00 00 00 02 5D 21
+					29 01 00 00 00 02 5E 03
+					29 01 00 00 00 02 6C 00
+					29 01 00 00 00 02 6D 00
+					29 01 00 00 00 02 FF 01
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 02
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 04
+					29 01 00 00 00 02 FB 01
+					29 01 00 00 00 02 FF 00
+					29 01 00 00 64 02 11 00
+					29 01 00 00 00 02 FF EE
+					29 01 00 00 00 02 12 50
+					29 01 00 00 00 02 13 02
+					29 01 00 00 00 02 6A 60
+					29 01 00 00 00 02 FF 00
+					29 01 00 00 78 02 29 00];
+
+		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+					05 01 00 00 78 02 10 00];
+		qcom,off-cmds-dsi-state = "DSI_HS_MODE";
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 94db3ea..c488ab1 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.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,4 +15,85 @@
 	#size-cells = <0>;
 	interrupt-controller;
 	#interrupt-cells = <3>;
+
+	qcom,pm8110@0 {
+		spmi-slave-container;
+		reg = <0x0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		pm8110_vadc: vadc@3100 {
+			compatible = "qcom,qpnp-vadc";
+			reg = <0x3100 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <0x0 0x31 0x0>;
+			interrupt-names = "eoc-int-en-set";
+			qcom,adc-bit-resolution = <15>;
+			qcom,adc-vdd-reference = <1800>;
+
+			chan@8 {
+				label = "die_temp";
+				reg = <8>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <3>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@9 {
+				label = "ref_625mv";
+				reg = <9>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@a {
+				label = "ref_1250v";
+				reg = <0xa>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+		};
+
+		iadc@3600 {
+			compatible = "qcom,qpnp-iadc";
+			reg = <0x3600 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <0x0 0x36 0x0>;
+			interrupt-names = "eoc-int-en-set";
+			qcom,adc-bit-resolution = <16>;
+			qcom,adc-vdd-reference = <1800>;
+			qcom,rsense = <1500>;
+
+			chan@0 {
+				label = "internal_rsense";
+				reg = <0>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+		};
+	};
+
+	qcom,pm8110@1 {
+		spmi-slave-container;
+		reg = <0x1>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi
new file mode 100644
index 0000000..ded9494
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8226-rpm-regulator.dtsi
@@ -0,0 +1,492 @@
+/* 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.
+ */
+
+&rpm_bus {
+	rpm-regulator-smpa1 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s1 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_s1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s3 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_s3";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s4 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_s4";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa5 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <5>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s5 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_s5";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l1 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l2 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l2";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l3 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l3";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa4 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l4 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l4";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <5>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l5 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l5";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <6>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l6 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l6";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <7>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l7 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l7";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <8>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l8 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l8";
+			qcom,set = <1>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <9>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l9 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l9";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <10>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l10 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l10";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <12>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l12 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l12";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <14>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l14 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l14";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa15 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <15>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l15 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l15";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa16 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <16>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l16 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l16";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <17>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l17 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l17";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa18 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <18>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l18 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l18";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa19 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <19>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l19 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l19";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa20 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <20>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l20 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l20";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa21 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <21>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l21 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l21";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa22 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <22>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l22 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l22";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa23 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <23>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l23 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l23";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa24 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <24>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l24 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l24";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa26 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <26>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l26 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l26";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa27 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <27>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l27 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l27";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa28 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <28>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l28 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l28";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-vsa1 {
+		compatible = "qcom,rpm-regulator-smd-resource";
+		qcom,resource-name = "vsa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <2>;
+		status = "disabled";
+
+		regulator-lvs1 {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_lvs1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 28ca985..320c3e4a 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -85,6 +85,11 @@
 			qcom,sample-rate = <4>;
 		};
 
+		pm8941_coincell: qcom,coincell@2800 {
+			compatible = "qcom,qpnp-coincell";
+			reg = <0x2800 0x100>;
+		};
+
 		pm8941_bms: qcom,bms {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-bms";
@@ -106,6 +111,7 @@
 			qcom,calculate-soc-ms = <20000>;
 			qcom,chg-term-ua = <100000>;
 			qcom,batt-type = <0>;
+			qcom,low-voltage-threshold = <3420000>;
 
 			qcom,bms-iadc@3800 {
 				reg = <0x3800 0x100>;
@@ -161,11 +167,16 @@
 			qcom,chg-vddmax-mv = <4200>;
 			qcom,chg-vddsafe-mv = <4200>;
 			qcom,chg-vinmin-mv = <4200>;
-			qcom,chg-vbatdet-mv = <4100>;
 			qcom,chg-ibatmax-ma = <1500>;
-			qcom,chg-ibatterm-ma = <200>;
 			qcom,chg-ibatsafe-ma = <1500>;
 			qcom,chg-thermal-mitigation = <1500 700 600 325>;
+			qcom,chg-cool-bat-degc = <10>;
+			qcom,chg-cool-bat-mv = <4100>;
+			qcom,chg-ibatmax-warm-ma = <350>;
+			qcom,chg-warm-bat-degc = <45>;
+			qcom,chg-warm-bat-mv = <4100>;
+			qcom,chg-ibatmax-cool-ma = <350>;
+			qcom,chg-vbatdet-delta-mv = <350>;
 
 			qcom,chg-chgr@1000 {
 				status = "disabled";
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 5cb68e5..fa77c35 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -12,6 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 CDP";
@@ -22,6 +23,10 @@
 		status = "ok";
 	};
 
+	qcom,mdss_dsi_nt35590_720p_video {
+		status = "ok";
+	};
+
 	i2c@f9927000 { /* BLSP1 QUP5 */
 		synaptics@20 {
 			compatible = "synaptics,rmi4";
@@ -69,6 +74,23 @@
 			debounce-interval = <15>;
 		};
 	};
+
+	spi@f9923000 {
+		ethernet-switch@3 {
+			compatible = "micrel,ks8851";
+			reg = <3>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <0 115 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&msmgpio 114 0>;
+			vdd-io-supply = <&pm8226_lvs1>;
+			vdd-phy-supply = <&pm8226_lvs1>;
+		};
+	};
+
+	sound {
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+	};
 };
 
 &sdcc1 {
@@ -160,6 +182,14 @@
 
 &pm8226_gpios {
 	gpio@c000 { /* GPIO 1 */
+		/* XO_PMIC_CDC_MCLK enable for tapan codec */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;	/* CMOS logic */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;	/* Enable GPIO */
 	};
 
 	gpio@c100 { /* GPIO 2 */
@@ -209,3 +239,8 @@
 	mpp@a700 { /* MPP 8 */
 	};
 };
+
+&pm8226_chg {
+	qcom,chg-charging-disabled;
+	qcom,chg-use-default-batt-values;
+};
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index 8d5d23c..30d79df 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -142,12 +142,72 @@
 		coresight-child-ports = <7>;
 	};
 
+	etm0: etm@fc33c000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33c000 0x1000>;
+		reg-names = "etm0-base";
+
+		coresight-id = <10>;
+		coresight-name = "coresight-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_a7ss>;
+		coresight-child-ports = <0>;
+
+		qcom,round-robin;
+	};
+
+	etm1: etm@fc33d000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33d000 0x1000>;
+		reg-names = "etm1-base";
+
+		coresight-id = <11>;
+		coresight-name = "coresight-etm1";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_a7ss>;
+		coresight-child-ports = <1>;
+
+		qcom,round-robin;
+	};
+
+	etm2: etm@fc33e000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33e000 0x1000>;
+		reg-names = "etm2-base";
+
+		coresight-id = <12>;
+		coresight-name = "coresight-etm2";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_a7ss>;
+		coresight-child-ports = <2>;
+
+		qcom,round-robin;
+	};
+
+	etm3: etm@fc33f000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33f000 0x1000>;
+		reg-names = "etm3-base";
+
+		coresight-id = <13>;
+		coresight-name = "coresight-etm3";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_a7ss>;
+		coresight-child-ports = <3>;
+
+		qcom,round-robin;
+	};
+
 	csr: csr@fc302000 {
 		compatible = "qcom,coresight-csr";
 		reg = <0xfc302000 0x1000>;
 		reg-names = "csr-base";
 
-		coresight-id = <10>;
+		coresight-id = <14>;
 		coresight-name = "coresight-csr";
 		coresight-nr-inports = <0>;
 
diff --git a/arch/arm/boot/dts/msm8226-iommu.dtsi b/arch/arm/boot/dts/msm8226-iommu.dtsi
index bddafc9..460068b 100644
--- a/arch/arm/boot/dts/msm8226-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8226-iommu.dtsi
@@ -14,6 +14,7 @@
 
 &jpeg_iommu {
 	status = "ok";
+	qcom,iommu-enable-halt;
 
 	qcom,iommu-bfb-regs =  <0x204c
 				0x2050
@@ -50,6 +51,7 @@
 
 &mdp_iommu {
 	status = "ok";
+	qcom,iommu-enable-halt;
 
 	qcom,iommu-bfb-regs =  <0x204c
 				0x2050
@@ -92,6 +94,7 @@
 
 &venus_iommu {
 	status = "ok";
+	qcom,iommu-enable-halt;
 
 	qcom,iommu-bfb-regs =  <0x204c
 				0x2050
@@ -154,6 +157,7 @@
 
 &kgsl_iommu {
 	status = "ok";
+	qcom,iommu-enable-halt;
 
 	qcom,iommu-bfb-regs =  <0x204c
 				0x2050
@@ -184,6 +188,7 @@
 
 &vfe_iommu {
 	status = "ok";
+	qcom,iommu-enable-halt;
 
 	qcom,iommu-bfb-regs =  <0x204c
 				0x2050
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 1691743..21ed66a 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -53,6 +53,22 @@
 		};
 	};
 
+	mdss_dsi0: qcom,mdss_dsi@fd922800 {
+		compatible = "qcom,mdss-dsi-ctrl";
+		label = "MDSS DSI CTRL->0";
+		cell-index = <0>;
+		reg = <0xfd922800 0x600>;
+		vdd-supply = <&pm8226_l15>;
+		vddio-supply = <&pm8226_l8>;
+		vdda-supply = <&pm8226_l4>;
+		qcom,supply-names = "vdd", "vddio", "vdda";
+		qcom,supply-type = "regulator", "regulator", "regulator";
+		qcom,supply-min-voltage-level = <2800000 1800000 1200000>;
+		qcom,supply-max-voltage-level = <2800000 1800000 1200000>;
+		qcom,supply-peak-current = <150000 100000 100000>;
+		qcom,mdss-fb-map = <&mdss_fb0>;
+	};
+
 	qcom,mdss_wb_panel {
 		compatible = "qcom,mdss_wb";
 		qcom,mdss_pan_res = <1280 720>;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 07441d8..e747cb5 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -12,6 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 MTP";
@@ -22,6 +23,10 @@
 		status = "ok";
 	};
 
+	qcom,mdss_dsi_nt35590_720p_video {
+		status = "ok";
+	};
+
 	i2c@f9927000 { /* BLSP1 QUP5 */
 		synaptics@20 {
 			compatible = "synaptics,rmi4";
@@ -69,6 +74,23 @@
 			debounce-interval = <15>;
 		};
 	};
+
+	spi@f9923000 {
+		ethernet-switch@3 {
+			compatible = "micrel,ks8851";
+			reg = <3>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <0 115 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&msmgpio 114 0>;
+			vdd-io-supply = <&pm8226_lvs1>;
+			vdd-phy-supply = <&pm8226_lvs1>;
+		};
+	};
+
+	sound {
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+	};
 };
 
 &sdcc1 {
@@ -157,6 +179,14 @@
 
 &pm8226_gpios {
 	gpio@c000 { /* GPIO 1 */
+		/* XO_PMIC_CDC_MCLK enable for tapan codec */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;	/* CMOS logic */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;	/* Enable GPIO */
 	};
 
 	gpio@c100 { /* GPIO 2 */
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 6348f5a..34283e8 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -22,7 +22,7 @@
 		qcom,saw2-ver-reg = <0xfd0>;
 		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-spm-dly= <0x3c102800>;
-		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 2b 06 26 30 0f];
@@ -39,7 +39,7 @@
 		qcom,saw2-ver-reg = <0xfd0>;
 		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-spm-dly= <0x3c102800>;
-		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 2b 06 26 30 0f];
@@ -56,7 +56,7 @@
 		qcom,saw2-ver-reg = <0xfd0>;
 		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-spm-dly= <0x3c102800>;
-		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
 		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 2b 06 26 30 0f];
@@ -73,7 +73,7 @@
 		qcom,saw2-ver-reg = <0xfd0>;
 		qcom,saw2-cfg = <0x01>;
 		qcom,saw2-spm-dly= <0x3c102800>;
-		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
 		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 2b 06 26 30 0f];
@@ -90,7 +90,7 @@
 		qcom,saw2-ver-reg = <0xfd0>;
 		qcom,saw2-cfg = <0x14>;
 		qcom,saw2-spm-dly= <0x3c102800>;
-		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-ctl = <0x0>;
 		qcom,saw2-pmic-data0 = <0x0400009c>;
 		qcom,saw2-pmic-data1 = <0x0000001c>;
 		qcom,vctl-timeout-us = <50>;
@@ -114,9 +114,8 @@
 		qcom,lpm-resources@0 {
 			reg = <0x0>;
 			qcom,name = "vdd-dig";
-			qcom,resource-type = <0>;
-			qcom,type = <0x62706d73>;	/* "smpb" */
-			qcom,id = <0x02>;
+			qcom,type = <0x61706d73>;	/* "smpa" */
+			qcom,id = <0x01>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
 			qcom,init-value = <5>;		/* Super Turbo */
 		};
@@ -124,9 +123,8 @@
 		qcom,lpm-resources@1 {
 			reg = <0x1>;
 			qcom,name = "vdd-mem";
-			qcom,resource-type = <0>;
-			qcom,type = <0x62706d73>;	/* "smpb" */
-			qcom,id = <0x01>;
+			qcom,type = <0x616F646C>;	/* "ldoa" */
+			qcom,id = <0x03>;
 			qcom,key = <0x7675>;		/* "uv" */
 			qcom,init-value = <1050000>;	/* Super Turbo */
 		};
@@ -134,18 +132,17 @@
 		qcom,lpm-resources@2 {
 			reg = <0x2>;
 			qcom,name = "pxo";
-			qcom,resource-type = <0>;
 			qcom,type = <0x306b6c63>;	/* "clk0" */
 			qcom,id = <0x00>;
 			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = <1>;		/* On */
+			qcom,init-value = "xo_on";
 		};
 
 		qcom,lpm-resources@3 {
 			reg = <0x3>;
 			qcom,name = "l2";
-			qcom,resource-type = <1>;
-			qcom,init-value = <2>;		/* Retention */
+			qcom,local-resource-type;
+			qcom,init-value = "l2_cache_retention";
 		};
 	};
 
@@ -156,9 +153,9 @@
 
 		qcom,lpm-level@0 {
 			reg = <0x0>;
-			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "wfi";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -171,9 +168,9 @@
 
 		qcom,lpm-level@1 {
 			reg = <0x1>;
-			qcom,mode = <4>;        /* MSM_PM_SLEEP_MODE_RETENTION*/
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "retention";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -187,9 +184,9 @@
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
-			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "standalone_pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -202,9 +199,9 @@
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <1>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -217,9 +214,9 @@
 
 		qcom,lpm-level@4 {
 			reg = <0x4>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
 			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
@@ -232,9 +229,9 @@
 
 		qcom,lpm-level@5 {
 			reg = <0x5>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <1>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -247,9 +244,9 @@
 
 		qcom,lpm-level@6 {
 			reg = <0x6>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -262,9 +259,9 @@
 
 		qcom,lpm-level@7 {
 			reg = <0x7>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
 			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
@@ -277,9 +274,9 @@
 
 		qcom,lpm-level@8 {
 			reg = <0x8>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
 			qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
 			qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
@@ -293,7 +290,7 @@
 
 	qcom,pm-boot {
 		compatible = "qcom,pm-boot";
-		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+		qcom,mode = "tz";
 	};
 
 	qcom,mpm@fc4281d0 {
@@ -392,7 +389,7 @@
 	qcom,pm-8x60@fe805664 {
 		compatible = "qcom,pm-8x60";
 		reg = <0xfe805664 0x40>;
-		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 	};
 
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index cdb2680..acc4597 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -12,6 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 QRD";
@@ -22,6 +23,10 @@
 		status = "ok";
 	};
 
+	qcom,mdss_dsi_nt35590_720p_video {
+		status = "ok";
+	};
+
 	i2c@f9927000 { /* BLSP1 QUP5 */
 		synaptics@20 {
 			compatible = "synaptics,rmi4";
@@ -69,6 +74,23 @@
 			debounce-interval = <15>;
 		};
 	};
+
+	spi@f9923000 {
+		ethernet-switch@3 {
+			compatible = "micrel,ks8851";
+			reg = <3>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <0 115 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&msmgpio 114 0>;
+			vdd-io-supply = <&pm8226_lvs1>;
+			vdd-phy-supply = <&pm8226_lvs1>;
+		};
+	};
+
+	sound {
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+	};
 };
 
 &sdcc1 {
@@ -160,6 +182,14 @@
 
 &pm8226_gpios {
 	gpio@c000 { /* GPIO 1 */
+		/* XO_PMIC_CDC_MCLK enable for tapan codec */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;	/* CMOS logic */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;	/* Enable GPIO */
 	};
 
 	gpio@c100 { /* GPIO 2 */
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 8168826..c39d987 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -10,300 +10,374 @@
  * GNU General Public License for more details.
  */
 
-/* Stub Regulators */
-
-/ {
-	pm8226_s1_corner: regulator-s1-corner {
-		compatible = "qcom,stub-regulator";
-		regulator-name = "8226_s1_corner";
-		qcom,hpm-min-load = <100000>;
-		regulator-min-microvolt = <1>;
-		regulator-max-microvolt = <7>;
-		qcom,consumer-supplies = "vdd_dig", "";
-	};
-};
-
 /* QPNP controlled regulators: */
 
 &spmi_bus {
-
 	qcom,pm8226@1 {
-
-		pm8226_s1: regulator@1400 {
-			status = "okay";
-			regulator-name = "8226_s1";
-			qcom,enable-time = <500>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
-			regulator-min-microvolt = <1150000>;
-			regulator-max-microvolt = <1150000>;
-		};
-
 		pm8226_s2: regulator@1700 {
 			status = "okay";
 			regulator-name = "8226_s2";
 			qcom,enable-time = <500>;
 			qcom,system-load = <100000>;
-			regulator-always-on;
 			regulator-min-microvolt = <1050000>;
 			regulator-max-microvolt = <1150000>;
-		};
-
-		pm8226_s3: regulator@1a00 {
-			status = "okay";
-			regulator-name = "8226_s3";
-			qcom,enable-time = <500>;
-			qcom,system-load = <100000>;
 			regulator-always-on;
-			regulator-min-microvolt = <1300000>;
+		};
+	};
+};
+
+/* RPM controlled regulators: */
+
+&rpm_bus {
+	rpm-regulator-smpa1 {
+		status = "okay";
+		pm8226_s1: regulator-s1 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1275000>;
+			status = "okay";
+		};
+		pm8226_s1_corner: regulator-s1-corner {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_s1_corner";
+			qcom,set = <3>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+			qcom,consumer-supplies = "vdd_dig", "";
+		};
+		pm8226_s1_corner_ao: regulator-s1-corner-ao {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_s1_corner_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1>;
+			regulator-max-microvolt = <7>;
+			qcom,use-voltage-corner;
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		status = "okay";
+		pm8226_s3: regulator-s3 {
+			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1300000>;
-		};
-
-		pm8226_s4: regulator@1d00 {
+			qcom,init-voltage = <1200000>;
 			status = "okay";
-			regulator-name = "8226_s4";
-			qcom,enable-time = <500>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		status = "okay";
+		pm8226_s4: regulator-s4 {
 			regulator-min-microvolt = <2100000>;
 			regulator-max-microvolt = <2100000>;
-		};
-
-		pm8226_s5: regulator@2000 {
+			qcom,init-voltage = <2100000>;
 			status = "okay";
-			regulator-name = "8226_s5";
-			qcom,enable-time = <500>;
+		};
+	};
+
+	rpm-regulator-smpa5 {
+		status = "okay";
+		pm8226_s5: regulator-s5 {
 			regulator-min-microvolt = <1150000>;
 			regulator-max-microvolt = <1150000>;
-		};
-
-		pm8226_l1: regulator@4000 {
+			qcom,init-voltage = <1150000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		status = "okay";
+		pm8226_l1: regulator-l1 {
 			regulator-name = "8226_l1";
-			parent-supply = <&pm8226_s3>;
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1225000>;
 			regulator-max-microvolt = <1225000>;
-		};
-
-		pm8226_l2: regulator@4100 {
+			qcom,init-voltage = <1225000>;
 			status = "okay";
-			regulator-name = "8226_l2";
-			parent-supply = <&pm8226_s3>;
-			regulator-always-on;
-			qcom,enable-time = <200>;
-			qcom,system-load = <10000>;
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		status = "okay";
+		pm8226_l2: regulator-l2 {
 			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1200000>;
-		};
-
-		pm8226_l3: regulator@4200 {
+			qcom,init-voltage = <1200000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		status = "okay";
+		pm8226_l3: regulator-l3 {
 			regulator-name = "8226_l3";
-			parent-supply = <&pm8226_s3>;
-			qcom,system-load = <10000>;
-			regulator-always-on;
-			qcom,enable-time = <200>;
-			regulator-min-microvolt = <1150000>;
-			regulator-max-microvolt = <1150000>;
-		};
-
-		pm8226_l4: regulator@4300 {
+			regulator-min-microvolt = <750000>;
+			regulator-max-microvolt = <1275000>;
 			status = "okay";
+		};
+		pm8226_l3_ao: regulator-3-ao {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l3_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <750000>;
+			regulator-max-microvolt = <1275000>;
+			status = "okay";
+		};
+		pm8226_l3_so: regulator-l3-so {
+			compatible = "qcom,rpm-regulator-smd";
+			regulator-name = "8226_l3_so";
+			qcom,set = <2>;
+			regulator-min-microvolt = <750000>;
+			regulator-max-microvolt = <1275000>;
+			qcom,init-voltage = <750000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa4 {
+		status = "okay";
+		pm8226_l4: regulator-l4 {
 			regulator-name = "8226_l4";
-			parent-supply = <&pm8226_s3>;
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1200000>;
-		};
-
-		pm8226_l5: regulator@4400 {
+			qcom,init-voltage = <1200000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		status = "okay";
+		pm8226_l5: regulator-l5 {
 			regulator-name = "8226_l5";
-			parent-supply = <&pm8226_s3>;
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1200000>;
-		};
-
-		pm8226_l6: regulator@4500 {
+			qcom,init-voltage = <1200000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		status = "okay";
+		pm8226_l6: regulator-l6 {
 			regulator-name = "8226_l6";
-			parent-supply = <&pm8226_s4>;
-			qcom,system-load = <10000>;
-			regulator-always-on;
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
-		};
-
-		pm8226_l7: regulator@4600 {
+			qcom,init-voltage = <1800000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		status = "okay";
+		pm8226_l7: regulator-l7 {
 			regulator-name = "8226_l7";
-			parent-supply = <&pm8226_s4>;
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1850000>;
 			regulator-max-microvolt = <1850000>;
-		};
-
-		pm8226_l8: regulator@4700 {
+			qcom,init-voltage = <1850000>;
 			status = "okay";
-			regulator-name = "8226_l8";
-			parent-supply = <&pm8226_s4>;
-			qcom,enable-time = <200>;
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		status = "okay";
+		pm8226_l8: regulator-l8 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
 			qcom,consumer-supplies = "vdd_sr2_pll", "";
 		};
+	};
 
-		pm8226_l9: regulator@4800 {
-			status = "okay";
+	rpm-regulator-ldoa9 {
+		status = "okay";
+		pm8226_l9: regulator-l9 {
 			regulator-name = "8226_l9";
-			parent-supply = <&pm8226_s4>;
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <2050000>;
 			regulator-max-microvolt = <2050000>;
-		};
-
-		pm8226_l10: regulator@4900 {
+			qcom,init-voltage = <2050000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		status = "okay";
+		pm8226_l10: regulator-l10 {
 			regulator-name = "8226_l10";
-			parent-supply = <&pm8226_s4>;
-			qcom,enable-time = <200>;
-			qcom,system-load = <5000>;
-			regulator-always-on;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
-		};
-
-		pm8226_l12: regulator@4b00 {
+			qcom,init-voltage = <1800000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		status = "okay";
+		pm8226_l12: regulator-l12 {
 			regulator-name = "8226_l12";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
-		};
-
-		pm8226_l14: regulator@4d00 {
+			qcom,init-voltage = <1800000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa14 {
+		status = "okay";
+		pm8226_l14: regulator-l14 {
 			regulator-name = "8226_l14";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <2750000>;
 			regulator-max-microvolt = <2750000>;
-		};
-
-		pm8226_l15: regulator@4e00 {
+			qcom,init-voltage = <2750000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa15 {
+		status = "okay";
+		pm8226_l15: regulator-l15 {
 			regulator-name = "8226_l15";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <2800000>;
 			regulator-max-microvolt = <2800000>;
-		};
-
-		pm8226_l16: regulator@4f00 {
+			qcom,init-voltage = <2800000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa16 {
+		status = "okay";
+		pm8226_l16: regulator-l16 {
 			regulator-name = "8226_l16";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <3000000>;
 			regulator-max-microvolt = <3300000>;
-		};
-
-		pm8226_l17: regulator@5000 {
+			qcom,init-voltage = <3300000>;
 			status = "okay";
-			regulator-name = "8226_l17";
-			qcom,enable-time = <200>;
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		status = "okay";
+		pm8226_l17: regulator-l17 {
 			regulator-min-microvolt = <2950000>;
 			regulator-max-microvolt = <2950000>;
-		};
-
-		pm8226_l18: regulator@5100 {
+			qcom,init-voltage = <2950000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa18 {
+		status = "okay";
+		pm8226_l18: regulator-l18 {
 			regulator-name = "8226_l18";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <2950000>;
 			regulator-max-microvolt = <2950000>;
-		};
-
-		pm8226_l19: regulator@5200 {
+			qcom,init-voltage = <2950000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa19 {
+		status = "okay";
+		pm8226_l19: regulator-l19 {
 			regulator-name = "8226_l19";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <2850000>;
 			regulator-max-microvolt = <2850000>;
-		};
-
-		pm8226_l20: regulator@5300 {
+			qcom,init-voltage = <2850000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa20 {
+		status = "okay";
+		pm8226_l20: regulator-l20 {
 			regulator-name = "8226_l20";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <3075000>;
 			regulator-max-microvolt = <3075000>;
-		};
-
-		pm8226_l21: regulator@5400 {
+			qcom,init-voltage = <3075000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa21 {
+		status = "okay";
+		pm8226_l21: regulator-l21 {
 			regulator-name = "8226_l21";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <2950000>;
-		};
-
-		pm8226_l22: regulator@5500 {
+			qcom,init-voltage = <2950000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa22 {
+		status = "okay";
+		pm8226_l22: regulator-l22 {
 			regulator-name = "8226_l22";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <2950000>;
-		};
-
-		pm8226_l23: regulator@5600 {
+			qcom,init-voltage = <2950000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa23 {
+		status = "okay";
+		pm8226_l23: regulator-l23 {
 			regulator-name = "8226_l23";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <2950000>;
-		};
-
-		pm8226_l24: regulator@5700 {
+			qcom,init-voltage = <2950000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa24 {
+		status = "okay";
+		pm8226_l24: regulator-l24 {
 			regulator-name = "8226_l24";
-			parent-supply = <&pm8226_s3>;
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1300000>;
 			regulator-max-microvolt = <1300000>;
-		};
-
-		pm8226_l26: regulator@5900 {
+			qcom,init-voltage = <1300000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa26 {
+		status = "okay";
+		pm8226_l26: regulator-l26 {
 			regulator-name = "8226_l26";
-			parent-supply = <&pm8226_s3>;
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1225000>;
 			regulator-max-microvolt = <1225000>;
-		};
-
-		pm8226_l27: regulator@5a00 {
+			qcom,init-voltage = <1225000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa27 {
+		status = "okay";
+		pm8226_l27: regulator-l27 {
 			regulator-name = "8226_l27";
-			parent-supply = <&pm8226_s4>;
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <2050000>;
 			regulator-max-microvolt = <2050000>;
-		};
-
-		pm8226_l28: regulator@5b00 {
+			qcom,init-voltage = <2050000>;
 			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa28 {
+		status = "okay";
+		pm8226_l28: regulator-l28 {
 			regulator-name = "8226_l28";
-			qcom,enable-time = <200>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <2950000>;
-		};
-
-		pm8226_lvs1: regulator@8000 {
+			qcom,init-voltage = <2950000>;
 			status = "okay";
-			regulator-name = "8226_lvs1";
-			parent-supply = <&pm8226_l6>;
-			qcom,enable-time = <200>;
+		};
+	};
+
+	rpm-regulator-vsa1 {
+		status = "okay";
+		pm8226_lvs1: regulator-lvs1 {
+			status = "okay";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 2ceaaaa..320c577 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -201,22 +201,26 @@
 			"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";
+			"MIC BIAS3 External", "Digital Mic4";
+
 		qcom,tapan-mclk-clk-freq = <9600000>;
 	};
 
 	qcom,msm-pcm {
 		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <0>;
 	};
 
 	qcom,msm-pcm-routing {
 		compatible = "qcom,msm-pcm-routing";
 	};
 
+	qcom,msm-pcm-low-latency {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <1>;
+		qcom,msm-pcm-low-latency;
+	};
+
 	qcom,msm-pcm-lpa {
 		compatible = "qcom,msm-pcm-lpa";
 	};
@@ -418,7 +422,6 @@
 		compatible = "qcom,rpm-smd";
 		rpm-channel-name = "rpm_requests";
 		rpm-channel-type = <15>; /* SMD_APPS_RPM */
-		rpm-standalone;
 	};
 
 	sdcc1: qcom,sdcc@f9824000 {
@@ -461,7 +464,6 @@
 		/* 190,ee0_krait_hlos_spmi_periph_irq */
 		/* 187,channel_0_krait_hlos_trans_done_irq */
 		interrupts = <0 190 0>, <0 187 0>;
-		qcom,not-wakeup;
 		qcom,pmic-arb-ee = <0>;
 		qcom,pmic-arb-channel = <0>;
 	};
@@ -504,7 +506,7 @@
 		reg = <0xfdd00000 0x2000>,
 		      <0xfdd02000 0x2000>,
 		      <0xfe039000 0x400>,
-		      <0xfec00000 0x180000>;
+		      <0xfec00000 0x20000>;
 		reg-names = "ocmem_ctrl_physical", "dm_ctrl_physical", "br_ctrl_physical", "ocmem_physical";
 		interrupts = <0 76 0 0 77 0>;
 		interrupt-names = "ocmem_irq", "dm_irq";
@@ -513,12 +515,12 @@
 		qcom,resource-type = <0x706d636f>;
 		#address-cells = <1>;
 		#size-cells = <1>;
-		ranges = <0x0 0xfec00000 0x180000>;
+		ranges = <0x0 0xfec00000 0x20000>;
 
 		partition@0 {
-			reg = <0x0 0x100000>;
+			reg = <0x0 0x20000>;
 			qcom,ocmem-part-name = "graphics";
-			qcom,ocmem-part-min = <0x80000>;
+			qcom,ocmem-part-min = <0x20000>;
 		};
 	};
 
@@ -617,7 +619,7 @@
 		gpios = <&msmgpio 3 0>, /* CLK  */
 			<&msmgpio 1 0>, /* MISO */
 			<&msmgpio 0 0>; /* MOSI */
-		cs-gpios = <&msmgpio 2 0>;
+		cs-gpios = <&msmgpio 22 0>;
 
 		qcom,infinite-mode = <0>;
 		qcom,use-bam;
@@ -637,6 +639,17 @@
 		qcom,memory-reservation-type = "EBI1";
 		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
 	};
+
+	qcom,msm-rng@f9bff000 {
+                compatible = "qcom,msm-rng";
+                reg = <0xf9bff000 0x200>;
+                qcom,msm-rng-iface-clk;
+	};
+
+	qcom,tz-log@fc5b82c {
+		compatible = "qcom,tz-log";
+		reg = <0x0fc5b82c 0x1000>;
+	};
 };
 
 &gdsc_venus {
@@ -663,6 +676,7 @@
 	status = "ok";
 };
 
+/include/ "msm-pm8226-rpm-regulator.dtsi"
 /include/ "msm-pm8226.dtsi"
 /include/ "msm8226-regulator.dtsi"
 
@@ -760,9 +774,6 @@
 &pm8226_chg {
 	status = "ok";
 
-	qcom,chg-charging-disabled;
-	qcom,chg-use-default-batt-values;
-
 	qcom,chg-chgr@1000 {
 		status = "ok";
 	};
@@ -771,6 +782,10 @@
 		status = "ok";
 	};
 
+	qcom,chg-bat-if@1200 {
+		status = "ok";
+	};
+
 	qcom,chg-usb-chgpth@1300 {
 		status = "ok";
 	};
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
new file mode 100644
index 0000000..298cb68
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -0,0 +1,142 @@
+/* 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.
+ */
+
+/ {
+	tmc_etr: tmc@fc326000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0xfc326000 0x1000>,
+		      <0xfc37c000 0x3000>;
+		reg-names = "tmc-etr-base", "tmc-etr-bam-base";
+
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+
+		coresight-id = <0>;
+		coresight-name = "coresight-tmc-etr";
+		coresight-nr-inports = <1>;
+	};
+
+	tpiu: tpiu@fc320000 {
+		compatible = "arm,coresight-tpiu";
+		reg = <0xfc320000 0x1000>;
+		reg-names = "tpiu-base";
+
+		coresight-id = <1>;
+		coresight-name = "coresight-tpiu";
+		coresight-nr-inports = <1>;
+	};
+
+	replicator: replicator@fc324000 {
+		compatible = "qcom,coresight-replicator";
+		reg = <0xfc324000 0x1000>;
+		reg-names = "replicator-base";
+
+		coresight-id = <2>;
+		coresight-name = "coresight-replicator";
+		coresight-nr-inports = <1>;
+		coresight-outports = <0 1>;
+		coresight-child-list = <&tmc_etr &tpiu>;
+		coresight-child-ports = <0 0>;
+	};
+
+	tmc_etf: tmc@fc325000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0xfc325000 0x1000>;
+		reg-names = "tmc-etf-base";
+
+		coresight-id = <3>;
+		coresight-name = "coresight-tmc-etf";
+		coresight-nr-inports = <1>;
+		coresight-outports = <0>;
+		coresight-child-list = <&replicator>;
+		coresight-child-ports = <0>;
+		coresight-default-sink;
+	};
+
+	funnel_merg: funnel@fc323000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc323000 0x1000>;
+		reg-names = "funnel-merg-base";
+
+		coresight-id = <4>;
+		coresight-name = "coresight-funnel-merg";
+		coresight-nr-inports = <2>;
+		coresight-outports = <0>;
+		coresight-child-list = <&tmc_etf>;
+		coresight-child-ports = <0>;
+	};
+
+	funnel_in0: funnel@fc321000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc321000 0x1000>;
+		reg-names = "funnel-in0-base";
+
+		coresight-id = <5>;
+		coresight-name = "coresight-funnel-in0";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_merg>;
+		coresight-child-ports = <0>;
+	};
+
+	funnel_in1: funnel@fc322000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc322000 0x1000>;
+		reg-names = "funnel-in1-base";
+
+		coresight-id = <6>;
+		coresight-name = "coresight-funnel-in1";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_merg>;
+		coresight-child-ports = <1>;
+	};
+
+	funnel_a7ss: funnel@fc355000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc355000 0x1000>;
+		reg-names = "funnel-a7ss-base";
+
+		coresight-id = <7>;
+		coresight-name = "coresight-funnel-a7ss";
+		coresight-nr-inports = <4>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <5>;
+	};
+
+	stm: stm@fc302000 {
+		compatible = "arm,coresight-stm";
+		reg = <0xfc302000 0x1000>,
+		      <0xfa280000 0x180000>;
+		reg-names = "stm-base", "stm-data-base";
+
+		coresight-id = <8>;
+		coresight-name = "coresight-stm";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <7>;
+	};
+
+	csr: csr@fc301000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0xfc301000 0x1000>;
+		reg-names = "csr-base";
+
+		coresight-id = <9>;
+		coresight-name = "coresight-csr";
+		coresight-nr-inports = <0>;
+
+		qcom,blk-size = <3>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index feb3087..d6e143c 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -114,7 +114,6 @@
 		qcom,lpm-resources@0 {
 			reg = <0x0>;
 			qcom,name = "vdd-dig";
-			qcom,resource-type = <0>;
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x02>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
@@ -124,7 +123,6 @@
 		qcom,lpm-resources@1 {
 			reg = <0x1>;
 			qcom,name = "vdd-mem";
-			qcom,resource-type = <0>;
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x01>;
 			qcom,key = <0x7675>;		/* "uv" */
@@ -134,18 +132,17 @@
 		qcom,lpm-resources@2 {
 			reg = <0x2>;
 			qcom,name = "pxo";
-			qcom,resource-type = <0>;
 			qcom,type = <0x306b6c63>;	/* "clk0" */
 			qcom,id = <0x00>;
 			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = <1>;		/* On */
+			qcom,init-value = "xo_on";
 		};
 
 		qcom,lpm-resources@3 {
 			reg = <0x3>;
 			qcom,name = "l2";
-			qcom,resource-type = <1>;
-			qcom,init-value = <2>;		/* Retention */
+			qcom,local-resource-type;
+			qcom,init-value = "l2_cache_retention";
 		};
 	};
 
@@ -156,9 +153,9 @@
 
 		qcom,lpm-level@0 {
 			reg = <0x0>;
-			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "wfi";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -171,9 +168,9 @@
 
 		qcom,lpm-level@1 {
 			reg = <0x1>;
-			qcom,mode = <4>;        /* MSM_PM_SLEEP_MODE_RETENTION*/
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "retention";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -187,9 +184,9 @@
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
-			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "standalone_pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -202,9 +199,9 @@
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <1>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -217,9 +214,9 @@
 
 		qcom,lpm-level@4 {
 			reg = <0x4>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
 			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
@@ -232,9 +229,9 @@
 
 		qcom,lpm-level@5 {
 			reg = <0x5>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <1>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -247,9 +244,9 @@
 
 		qcom,lpm-level@6 {
 			reg = <0x6>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
@@ -262,9 +259,9 @@
 
 		qcom,lpm-level@7 {
 			reg = <0x7>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
 			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
@@ -277,9 +274,9 @@
 
 		qcom,lpm-level@8 {
 			reg = <0x8>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
 			qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
 			qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
@@ -293,7 +290,7 @@
 
 	qcom,pm-boot {
 		compatible = "qcom,pm-boot";
-		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+		qcom,mode = "tz";
 	};
 
 	qcom,mpm@fc4281d0 {
@@ -385,7 +382,7 @@
 	qcom,pm-8x60@fe805664 {
 		compatible = "qcom,pm-8x60";
 		reg = <0xfe805664 0x40>;
-		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 	};
 
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 2dff4c7..b78c3af 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -14,6 +14,7 @@
 /include/ "msm-iommu-v0.dtsi"
 /include/ "msm8610-ion.dtsi"
 /include/ "msm-gdsc.dtsi"
+/include/ "msm8610-coresight.dtsi"
 /include/ "msm8610-pm.dtsi"
 
 / {
@@ -235,7 +236,6 @@
 		compatible = "qcom,rpm-smd";
 		rpm-channel-name = "rpm_requests";
 		rpm-channel-type = <15>; /* SMD_APPS_RPM */
-		rpm-standalone;
 	};
 
 	qcom,msm-mem-hole {
@@ -437,6 +437,20 @@
 		vdd_cx-supply = <&pm8110_s1_corner>;
 		qcom,firmware-name = "adsp";
 	};
+
+	tsens: tsens@fc4a8000 {
+		compatible = "qcom,msm-tsens";
+		reg = <0xfc4a8000 0x2000>,
+		      <0xfc4b8000 0x1000>;
+		reg-names = "tsens_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		qcom,sensors = <2>;
+		qcom,slope = <2901 2846>;
+		qcom,calib-mode = "fuse_map2";
+		qcom,calibration-less-mode;
+		qcom,tsens-local-init;
+	};
+
 };
 
 &gdsc_vfe {
@@ -475,3 +489,95 @@
 
 /include/ "msm8610-regulator.dtsi"
 /include/ "msm-pm8110.dtsi"
+
+&pm8110_vadc {
+	chan@0 {
+		label = "usb_in";
+		reg = <0>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <4>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@2 {
+		label = "vchg_sns";
+		reg = <2>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <3>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@5 {
+		label = "vcoin";
+		reg = <5>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@6 {
+		label = "vbat_sns";
+		reg = <6>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@7 {
+		label = "vph_pwr";
+		reg = <7>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@30 {
+		label = "batt_therm";
+		reg = <0x30>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <1>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@31 {
+		label = "batt_id";
+		reg = <0x31>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@b2 {
+		label = "xo_therm_pu2";
+		reg = <0xb2>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+};
+
+
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
index fb2917c..24438f0 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
@@ -22,7 +22,7 @@
 
 	qcom,camera@6e {
 		compatible = "qcom,s5k3l1yx";
-		reg = <0x6e 0x0>;
+		reg = <0x6e>;
 		qcom,slave-id = <0x6e 0x0 0x3121>;
 		qcom,csiphy-sd-index = <0>;
 		qcom,csid-sd-index = <0>;
@@ -63,7 +63,7 @@
 
 	qcom,camera@6c {
 		compatible = "qcom,ov2720";
-		reg = <0x6c 0x0>;
+		reg = <0x6c>;
 		qcom,slave-id = <0x6c 0x300A 0x2720>;
 		qcom,csiphy-sd-index = <2>;
 		qcom,csid-sd-index = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 4fe4220..c9d1abc 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -15,7 +15,7 @@
 
 	actuator0: qcom,actuator@18 {
 		cell-index = <0>;
-		reg = <0x18 0x0>;
+		reg = <0x18>;
 		compatible = "qcom,actuator";
 		qcom,cci-master = <0>;
 	};
@@ -99,7 +99,7 @@
 
 	qcom,camera@90 {
 		compatible = "qcom,mt9m114";
-		reg = <0x90 0x0>;
+		reg = <0x90>;
 		qcom,slave-id = <0x90 0x0 0x2481>;
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index b313795..f9b89e1 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -16,14 +16,14 @@
 
 	actuator0: qcom,actuator@18 {
 		cell-index = <0>;
-		reg = <0x18 0x0>;
+		reg = <0x18>;
 		compatible = "qcom,actuator";
 		qcom,cci-master = <0>;
 	};
 
 	qcom,camera@6e {
 		compatible = "qcom,s5k3l1yx";
-		reg = <0x6e 0x0>;
+		reg = <0x6e>;
 		qcom,slave-id = <0x6e 0x0 0x3121>;
 		qcom,csiphy-sd-index = <0>;
 		qcom,csid-sd-index = <0>;
@@ -60,7 +60,7 @@
 
 	qcom,camera@6c {
 		compatible = "qcom,ov2720";
-		reg = <0x6c 0x0>;
+		reg = <0x6c>;
 		qcom,slave-id = <0x6c 0x300A 0x2720>;
 		qcom,csiphy-sd-index = <2>;
 		qcom,csid-sd-index = <0>;
@@ -95,7 +95,7 @@
 
 	qcom,camera@90 {
 		compatible = "qcom,mt9m114";
-		reg = <0x90 0x0>;
+		reg = <0x90>;
 		qcom,slave-id = <0x90 0x0 0x2481>;
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <0>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index ebb3912..95cafdb 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -179,8 +179,7 @@
 		compatible = "qcom,cci";
 		reg = <0xfda0C000 0x1000>;
                 #address-cells = <1>;
-                #size-cells = <1>;
-                ranges;
+		#size-cells = <0>;
 		reg-names = "cci";
 		interrupts = <0 50 0>;
 		interrupt-names = "cci";
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index ad26061..45cbc89 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -213,6 +213,7 @@
                 HSIC_GDSC-supply = <&gdsc_usb_hsic>;
                 hsic,strobe-gpio = <&msmgpio 144 0x00>;
                 hsic,data-gpio = <&msmgpio 145 0x00>;
+                hsic,resume-gpio = <&msmgpio 80 0x00>;
                 hsic,ignore-cal-pad-config;
                 hsic,strobe-pad-offset = <0x2050>;
                 hsic,data-pad-offset = <0x2054>;
@@ -314,6 +315,17 @@
 };
 
 &sdhc_2 {
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&msmgpio 62 0x1>;
+
 	vdd-supply = <&pm8941_l21>;
 	vdd-io-supply = <&pm8941_l13>;
 
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index dbb8958..d22c746 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -311,6 +311,17 @@
 };
 
 &sdhc_2 {
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&msmgpio 62 0x1>;
+
 	vdd-supply = <&pm8941_l21>;
 	vdd-io-supply = <&pm8941_l13>;
 
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 4dd92b98..a35b9d2 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -351,11 +351,18 @@
 		hub_int-supply = <&pm8941_l10>;
 		hub_vbus-supply = <&ext_5v>;
 
-		hsic@f9a00000 {
+		hsic_host: hsic@f9a00000 {
 			compatible = "qcom,hsic-host";
 			reg = <0xf9a00000 0x400>;
-			interrupts = <0 136 0>, <0 148 0>;
-			interrupt-names = "core_irq", "async_irq";
+			#address-cells = <0>;
+	                interrupt-parent = <&hsic_host>;
+			interrupts = <0 1 2>;
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0xffffffff>;
+			interrupt-map = <0 &intc 0 136 0
+		                1 &intc 0 148 0
+		                2 &msmgpio 144 0x8>;
+			interrupt-names = "core_irq", "async_irq", "wakeup";
 			HSIC_VDDCX-supply = <&pm8841_s2>;
 			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 			hsic,strobe-gpio = <&msmgpio 144 0x00>;
@@ -363,6 +370,14 @@
 			hsic,ignore-cal-pad-config;
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
+
+			qcom,msm-bus,name = "hsic";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,active-only = <0>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+					<85 512 0 0>,
+					<85 512 40000 160000>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index f382c3e..2f9adbb 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -75,8 +75,8 @@
 		cell-index = <0>;
 		reg = <0xfd922800 0x600>;
 		vdd-supply = <&pm8941_l22>;
-		vdd_io-supply = <&pm8941_l12>;
-		vreg-supply = <&pm8941_l2>;
+		vddio-supply = <&pm8941_l12>;
+		vdda-supply = <&pm8941_l2>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
 	};
 
@@ -86,8 +86,8 @@
 		cell-index = <1>;
 		reg = <0xfd922e00 0x600>;
 		vdd-supply = <&pm8941_l22>;
-		vdd_io-supply = <&pm8941_l12>;
-		vreg-supply = <&pm8941_l2>;
+		vddio-supply = <&pm8941_l12>;
+		vdda-supply = <&pm8941_l2>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index d3d53dd..380ec20 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -282,6 +282,17 @@
 };
 
 &sdhc_2 {
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0
+			2 &msmgpio 62 0x3>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&msmgpio 62 0x1>;
+
 	vdd-supply = <&pm8941_l21>;
 	vdd-io-supply = <&pm8941_l13>;
 
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 2de5fad..d8a1444 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -139,7 +139,6 @@
 		qcom,lpm-resources@0 {
 			reg = <0x0>;
 			qcom,name = "vdd-dig";
-			qcom,resource-type = <0>;
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x02>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
@@ -149,7 +148,6 @@
 		qcom,lpm-resources@1 {
 			reg = <0x1>;
 			qcom,name = "vdd-mem";
-			qcom,resource-type = <0>;
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x01>;
 			qcom,key = <0x7675>;		/* "uv" */
@@ -159,18 +157,17 @@
 		qcom,lpm-resources@2 {
 			reg = <0x2>;
 			qcom,name = "pxo";
-			qcom,resource-type = <0>;
 			qcom,type = <0x306b6c63>;	/* "clk0" */
 			qcom,id = <0x00>;
 			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = <1>;		/* On */
+			qcom,init-value = "xo_on";
 		};
 
 		qcom,lpm-resources@3 {
 			reg = <0x3>;
 			qcom,name = "l2";
-			qcom,resource-type = <1>;
-			qcom,init-value = <2>;		/* Retention */
+			qcom,local-resource-type;
+			qcom,init-value = "l2_cache_retention";
 		};
 	};
 
@@ -183,9 +180,9 @@
 
 		qcom,lpm-level@0 {
 			reg = <0x0>;
-			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "wfi";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -200,9 +197,9 @@
 
 		qcom,lpm-level@1 {
 			reg = <0x1>;
-			qcom,mode = <4>;        /* MSM_PM_SLEEP_MODE_RETENTION*/
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "retention";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -218,9 +215,9 @@
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
-			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "standalone_pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -235,9 +232,9 @@
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <1>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -252,9 +249,9 @@
 
 		qcom,lpm-level@4 {
 			reg = <0x4>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO  */
@@ -269,9 +266,9 @@
 
 		qcom,lpm-level@5 {
 			reg = <0x5>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <1>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -284,9 +281,9 @@
 
 		qcom,lpm-level@6 {
 			reg = <0x6>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -299,9 +296,9 @@
 
 		qcom,lpm-level@7 {
 			reg = <0x7>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode= "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
 			qcom,vdd-mem-lower-bound = <950000>;  /* SVS SOC */
 			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
@@ -314,9 +311,9 @@
 
 		qcom,lpm-level@8 {
 			reg = <0x8>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode= "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
 			qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
 			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
@@ -330,7 +327,7 @@
 
 	qcom,pm-boot {
 		compatible = "qcom,pm-boot";
-		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+		qcom,mode = "tz";
 	};
 
 	qcom,mpm@fc4281d0 {
@@ -343,7 +340,8 @@
 		qcom,ipc-bit-offset = <1>;
 
 		qcom,gic-parent = <&intc>;
-		qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+		qcom,gic-map = <47 165>, /* usb30_hs_phy_irq */
+			<50 172>, /* usb1_hs_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
@@ -416,13 +414,14 @@
 			<37  86>,
 			<38  92>,
 			<39  93>,
-			<40  95>;
+			<40  95>,
+			<41  144>;
 	};
 
 	qcom,pm-8x60@fe805664 {
 		compatible = "qcom,pm-8x60";
 		reg = <0xfe805664 0x40>;
-		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 39268a0..e020fa4 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -15,8 +15,8 @@
 / {
 	qcom,spm@f9089000 {
 		compatible = "qcom,spm-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
+	#address-cells = <1>;
+	#size-cells = <1>;
 		reg = <0xf9089000 0x1000>;
 		qcom,core-id = <0>;
 		qcom,saw2-ver-reg = <0xfd0>;
@@ -29,10 +29,10 @@
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
 		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
-				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E0 03 3B E4 5B 82 10 0B
+			30 06 26 30 0F];
 		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
-				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+			E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
 	};
 
 	qcom,spm@f9099000 {
@@ -51,8 +51,8 @@
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
 		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
-				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E0 03 3B E4 5B 82 10 0B
+			30 06 26 30 0F];
 		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
 				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
 	};
@@ -73,8 +73,8 @@
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
 		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
-				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E0 03 3B E4 5B 82 10 0B
+			30 06 26 30 0F];
 		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
 				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
 	};
@@ -95,8 +95,8 @@
 		qcom,saw2-spm-ctl = <0x1>;
 		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
 		qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
-				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E0 03 3B E4 5B 82 10 0B
+			30 06 26 30 0F];
 		qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
 				E4 5B 82 3F 50 10 0B 30 06 26 30 0F];
 	};
@@ -136,7 +136,6 @@
 		qcom,lpm-resources@0 {
 			reg = <0x0>;
 			qcom,name = "vdd-dig";
-			qcom,resource-type = <0>;
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x02>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
@@ -146,7 +145,6 @@
 		qcom,lpm-resources@1 {
 			reg = <0x1>;
 			qcom,name = "vdd-mem";
-			qcom,resource-type = <0>;
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x01>;
 			qcom,key = <0x7675>;		/* "uv" */
@@ -156,18 +154,17 @@
 		qcom,lpm-resources@2 {
 			reg = <0x2>;
 			qcom,name = "pxo";
-			qcom,resource-type = <0>;
 			qcom,type = <0x306b6c63>;	/* "clk0" */
 			qcom,id = <0x00>;
 			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = <1>;		/* On */
+			qcom,init-value = "xo_on";
 		};
 
 		qcom,lpm-resources@3 {
 			reg = <0x3>;
 			qcom,name = "l2";
-			qcom,resource-type = <1>;
-			qcom,init-value = <2>;		/* Retention */
+			qcom,local-resource-type;
+			qcom,init-value = "l2_cache_retention";
 		};
 	};
 
@@ -180,9 +177,9 @@
 
 		qcom,lpm-level@0 {
 			reg = <0x0>;
-			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "wfi";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -197,9 +194,9 @@
 
 		qcom,lpm-level@1 {
 			reg = <0x1>;
-			qcom,mode = <4>;        /* MSM_PM_SLEEP_MODE_RETENTION*/
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "retention";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -215,9 +212,9 @@
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
-			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "standalone_pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -232,9 +229,9 @@
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <1>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -249,9 +246,9 @@
 
 		qcom,lpm-level@4 {
 			reg = <0x4>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO  */
@@ -266,9 +263,9 @@
 
 		qcom,lpm-level@5 {
 			reg = <0x5>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <1>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -281,9 +278,9 @@
 
 		qcom,lpm-level@6 {
 			reg = <0x6>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -296,9 +293,9 @@
 
 		qcom,lpm-level@7 {
 			reg = <0x7>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode= "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
 			qcom,vdd-mem-lower-bound = <950000>;  /* SVS SOC */
 			qcom,vdd-dig-upper-bound = <4>;  /* NORMAL */
@@ -311,9 +308,9 @@
 
 		qcom,lpm-level@8 {
 			reg = <0x8>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode= "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
 			qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
 			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
@@ -327,7 +324,7 @@
 
 	qcom,pm-boot {
 		compatible = "qcom,pm-boot";
-		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+		qcom,mode = "tz";
 	};
 
 	qcom,mpm@fc4281d0 {
@@ -340,7 +337,8 @@
 		qcom,ipc-bit-offset = <1>;
 
 		qcom,gic-parent = <&intc>;
-		qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+		qcom,gic-map = <47 165>, /* usb30_hs_phy_irq */
+			<50 172>, /* usb1_hs_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
@@ -413,13 +411,14 @@
 			<37  86>,
 			<38  92>,
 			<39  93>,
-			<40  95>;
+			<40  95>,
+			<41  144>;
 	};
 
 	qcom,pm-8x60@fe805664 {
 		compatible = "qcom,pm-8x60";
 		reg = <0xfe805664 0x40>;
-		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
+		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 		qcom,saw-turns-off-pll;
 	};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 99886c7..ba03f79 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -36,13 +36,13 @@
 
 	memory {
 
-		secure_mem: region@0 {
+		secure_mem: secure_region {
 			linux,contiguous-region;
 			reg = <0 0x7800000>;
 			label = "secure_mem";
 		};
 
-		adsp_mem: region@0 {
+		adsp_mem: adsp_region {
 			linux,contiguous-region;
 			reg = <0 0x2000000>;
 			label = "adsp_mem";
@@ -84,9 +84,10 @@
 		clock-frequency = <19200000>;
 	};
 
-	qcom,mpm-counter@fc4a3000 {
-		compatible = "qcom,mpm-counter";
+	qcom,mpm2-sleep-counter@fc4a3000 {
+		compatible = "qcom,mpm2-sleep-counter";
 		reg = <0xfc4a3000 0x1000>;
+		clock-frequency = <32768>;
 	};
 
 	msm_vidc: qcom,vidc@fdc00000 {
@@ -589,6 +590,7 @@
 		qcom,audio-routing =
 			"RX_BIAS", "MCLK",
 			"LDO_H", "MCLK",
+			"AIF4 MAD", "MCLK",
 			"AMIC1", "MIC BIAS1 Internal1",
 			"MIC BIAS1 Internal1", "Handset Mic",
 			"AMIC2", "MIC BIAS2 External",
@@ -799,6 +801,10 @@
 		qcom,msm-dai-q6-dev-id = <8>;
 	};
 
+	qcom,msm-lsm-client {
+		compatible = "qcom,msm-lsm-client";
+	};
+
 	qcom,msm-dai-q6 {
 		compatible = "qcom,msm-dai-q6";
 		qcom,msm-dai-q6-sb-0-rx {
@@ -851,6 +857,11 @@
 			qcom,msm-dai-q6-dev-id = <16393>;
 		};
 
+		qcom,msm-dai-q6-sb-5-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <16395>;
+		};
+
 		qcom,msm-dai-q6-bt-sco-rx {
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <12288>;
@@ -1185,31 +1196,18 @@
 		reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
 		interrupts = <0 132 0 0 135 0>;
 		interrupt-names = "ssusb", "hsusb";
-		qcom,usb-active-bam = <0>;
-		qcom,usb-total-bam-num = <2>;
 		qcom,usb-bam-num-pipes = <16>;
 		qcom,usb-base-address = <0xf9200000>;
 		qcom,ignore-core-reset-ack;
 		qcom,disable-clk-gating;
 
-		qcom,pipe1 {
-			label = "usb-to-peri-qdss-dwc3";
-			qcom,usb-bam-type = <0>;
+		qcom,pipe0 {
+			label = "ssusb-qdss-in-0";
 			qcom,usb-bam-mem-type = <1>;
-			qcom,src-bam-physical-address = <0>;
-			qcom,src-bam-pipe-index = <0>;
-			qcom,dst-bam-physical-address = <0>;
-			qcom,dst-bam-pipe-index = <0>;
-			qcom,data-fifo-offset = <0>;
-			qcom,data-fifo-size = <0>;
-			qcom,descriptor-fifo-offset = <0>;
-			qcom,descriptor-fifo-size = <0>;
-		};
-
-		qcom,pipe2 {
-			label = "peri-to-usb-qdss-dwc3";
-			qcom,usb-bam-type = <0>;
-			qcom,usb-bam-mem-type = <1>;
+			qcom,bam-type = <0>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <1>;
 			qcom,src-bam-physical-address = <0xfc37C000>;
 			qcom,src-bam-pipe-index = <0>;
 			qcom,dst-bam-physical-address = <0xf9304000>;
@@ -1221,24 +1219,13 @@
 			qcom,reset-bam-on-connect;
 		};
 
-		qcom,pipe3 {
-			label = "usb-to-peri-qdss-hsusb";
-			qcom,usb-bam-type = <1>;
+		qcom,pipe1 {
+			label = "hsusb-qdss-in-0";
 			qcom,usb-bam-mem-type = <1>;
-			qcom,src-bam-physical-address = <0>;
-			qcom,src-bam-pipe-index = <0>;
-			qcom,dst-bam-physical-address = <0>;
-			qcom,dst-bam-pipe-index = <0>;
-			qcom,data-fifo-offset = <0>;
-			qcom,data-fifo-size = <0>;
-			qcom,descriptor-fifo-offset = <0>;
-			qcom,descriptor-fifo-size = <0>;
-		};
-
-		qcom,pipe4 {
-			label = "peri-to-usb-qdss-hsusb";
-			qcom,usb-bam-type = <1>;
-			qcom,usb-bam-mem-type = <1>;
+			qcom,bam-type = <1>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <1>;
 			qcom,src-bam-physical-address = <0xfc37c000>;
 			qcom,src-bam-pipe-index = <0>;
 			qcom,dst-bam-physical-address = <0xf9a44000>;
@@ -1265,10 +1252,6 @@
 		interrupts = <0 29 1>;
 	};
 
-        qcom,msm-wdog-debug@fc401000 {
-               compatible = "qcom,msm-wdog-debug";
-               reg = <0xfc401000 0x1000>;
-        };
         qcom,msm-mem-hole {
                 compatible = "qcom,msm-mem-hole";
                 qcom,memblock-remove = <0x7f00000 0x8000000>; /* Address and Size of Hole */
@@ -1373,8 +1356,8 @@
 
 	sfpb_spinlock: qcom,ipc-spinlock@fd484000 {
 		compatible = "qcom,ipc-spinlock-sfpb";
-		reg = <0xfd484000 0x1000>;
-		qcom,num-locks = <32>;
+		reg = <0xfd484000 0x400>;
+		qcom,num-locks = <8>;
 	};
 
 	ldrex_spinlock: qcom,ipc-spinlock@fa00000 {
@@ -1382,6 +1365,17 @@
 		reg = <0xfa00000 0x200000>;
 		status = "disable";
 	};
+
+	cpu-pmu {
+		compatible = "qcom,krait-pmu";
+		qcom,irq-is-percpu;
+		interrupts = <1 7 0xf00>;
+	};
+
+	l2-pmu {
+		compatible = "qcom,l2-pmu";
+		interrupts = <0 1 0>;
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index e881977..51a3faa 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -38,7 +38,6 @@
 		qcom,lpm-resources@0 {
 			reg = <0x0>;
 			qcom,name = "vdd-dig";
-			qcom,resource-type = <0>;
 			qcom,type = <0x616F646C>;       /* "ldoa" */
 			qcom,id = <0x0A>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
@@ -48,7 +47,6 @@
 		qcom,lpm-resources@1 {
 			reg = <0x1>;
 			qcom,name = "vdd-mem";
-			qcom,resource-type = <0>;
 			qcom,type = <0x616F646C>;       /* "ldoa" */
 			qcom,id = <0x0C>;
 			qcom,key =  <0x7675>;		/* "uv" */
@@ -58,11 +56,10 @@
 		qcom,lpm-resources@2 {
 			reg = <0x2>;
 			qcom,name = "pxo";
-			qcom,resource-type = <0>;
 			qcom,type = <0x306b6c63>;	/* "clk0" */
 			qcom,id = <0x00>;
 			qcom,key = <0x62616e45>;	/* "Enab" */
-			qcom,init-value = <1>;		/* On */
+			qcom,init-value = "xo_on";
 		};
 	};
 
@@ -75,9 +72,9 @@
 
 		qcom,lpm-level@0 {
 			reg = <0x0>;
-			qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "wfi";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -92,9 +89,9 @@
 
 		qcom,lpm-level@1 {
 			reg = <0x1>;
-			qcom,mode = <2>;        /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <3>;          /* ACTIVE */
+			qcom,mode = "standalone_pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_active";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -109,9 +106,9 @@
 
 		qcom,lpm-level@2 {
 			reg = <0x2>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <1>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -126,9 +123,9 @@
 
 		qcom,lpm-level@3 {
 			reg = <0x3>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <0>;          /* GDHS */
+			qcom,mode = "pc";
+			qcom,xo = "xo_on";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
 			qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
@@ -143,9 +140,9 @@
 
 		qcom,lpm-level@4 {
 			reg = <0x4>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -159,9 +156,9 @@
 
 		qcom,lpm-level@5 {
 			reg = <0x5>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
 			qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
 			qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
@@ -175,9 +172,9 @@
 
 		qcom,lpm-level@6 {
 			reg = <0x6>;
-			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <0>;          /* OFF */
-			qcom,l2 = <0>;          /* OFF */
+			qcom,mode = "pc";
+			qcom,xo = "xo_off";
+			qcom,l2 = "l2_cache_pc";
 			qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
 			qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
 			qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
@@ -191,7 +188,7 @@
 
 	qcom,pm-boot {
 		compatible = "qcom,pm-boot";
-		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+		qcom,mode = "tz";
 	};
 
 	qcom,mpm@fc4281d0 {
@@ -277,7 +274,7 @@
 
 	qcom,pm-8x60 {
 		compatible = "qcom,pm-8x60";
-		qcom,pc-mode = <2>; /*MSM_PC_TZ_L2_EXT */
+		qcom,pc-mode = "tz_l2_ext";
 		qcom,use-sync-timer;
 	};
 
diff --git a/arch/arm/boot/dts/msm9625-v2-cdp.dts b/arch/arm/boot/dts/msm9625-v2-cdp.dts
index 244556d..09a89ab 100644
--- a/arch/arm/boot/dts/msm9625-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-cdp.dts
@@ -42,7 +42,7 @@
 
 	wlan0: qca,wlan {
 		cell-index = <0>;
-		compatible = "qca,ar6004-sdio";
+		compatible = "qca,ar6004-hsic";
 		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
 		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
 		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
diff --git a/arch/arm/boot/dts/msm9625-v2-mtp.dts b/arch/arm/boot/dts/msm9625-v2-mtp.dts
index bf0f539..7949080 100644
--- a/arch/arm/boot/dts/msm9625-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-mtp.dts
@@ -42,7 +42,7 @@
 
 	wlan0: qca,wlan {
 		cell-index = <0>;
-		compatible = "qca,ar6004-sdio";
+		compatible = "qca,ar6004-hsic";
 		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
 		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
 		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index e1501ac..9172029 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -52,6 +52,12 @@
 		qcom,direct-connect-irqs = <8>;
 	};
 
+	qcom,mpm2-sleep-counter@fc4a3000 {
+		compatible = "qcom,mpm2-sleep-counter";
+		reg = <0xfc4a3000 0x1000>;
+		clock-frequency = <32768>;
+	};
+
 	timer: msm-qtimer@f9021000 {
 		compatible = "arm,armv7-timer";
 		reg = <0xF9021000 0x1000>;
@@ -117,24 +123,28 @@
 		qcom,msm-bus,vectors-KBps =
 				<85 512 0 0>,
 				<85 512 40000 640000>;
+		qcom,pool-64-bit-align;
+		qcom,enable-hbm;
 	};
 
 	qcom,usbbam@f9a44000 {
 		compatible = "qcom,usb-bam-msm";
-		reg = <0xf9a44000 0x11000>;
-		reg-names = "hsusb";
-		interrupts = <0 135 0>;
-		interrupt-names = "hsusb";
-		qcom,usb-active-bam = <1>;
-		qcom,usb-total-bam-num = <3>;
+		reg = <0xf9a44000 0x11000>,
+		      <0xf9a04000 0x11000>;
+		reg-names = "hsusb", "hsic";
+		interrupts = <0 135 0 0 255 0>;
+		interrupt-names = "hsusb", "hsic";
 		qcom,usb-bam-num-pipes = <16>;
 		qcom,ignore-core-reset-ack;
 		qcom,disable-clk-gating;
 
 		qcom,pipe0 {
-			label = "usb-to-ipa";
-			qcom,usb-bam-type = <1>;
+			label = "hsusb-ipa-out-0";
 			qcom,usb-bam-mem-type = <0>;
+			qcom,bam-type = <1>;
+			qcom,dir = <0>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <2>;
 			qcom,src-bam-physical-address = <0xf9a44000>;
 			qcom,src-bam-pipe-index = <1>;
 			qcom,data-fifo-offset = <0x2200>;
@@ -143,9 +153,12 @@
 			qcom,descriptor-fifo-size = <0x100>;
 		};
 		qcom,pipe1 {
-			label = "ipa-to-usb";
-			qcom,usb-bam-type = <1>;
+			label = "hsusb-ipa-in-0";
 			qcom,usb-bam-mem-type = <0>;
+			qcom,bam-type = <1>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <2>;
 			qcom,dst-bam-physical-address = <0xf9a44000>;
 			qcom,dst-bam-pipe-index = <0>;
 			qcom,data-fifo-offset = <0x300>;
@@ -154,22 +167,12 @@
 			qcom,descriptor-fifo-size = <0x300>;
 		};
 		qcom,pipe2 {
-			label = "usb-to-qdss-hsusb";
-			qcom,usb-bam-type = <1>;
+			label = "hsusb-qdss-in-0";
 			qcom,usb-bam-mem-type = <0>;
-			qcom,src-bam-physical-address = <0xf9a44000>;
-			qcom,src-bam-pipe-index = <0>;
-			qcom,dst-bam-physical-address = <0xfc37c000>;
-			qcom,dst-bam-pipe-index = <0>;
-			qcom,data-fifo-offset = <0>;
-			qcom,data-fifo-size = <0>;
-			qcom,descriptor-fifo-offset = <0>;
-			qcom,descriptor-fifo-size = <0>;
-		};
-		qcom,pipe3 {
-			label = "qdss-to-usb-hsusb";
-			qcom,usb-bam-type = <1>;
-			qcom,usb-bam-mem-type = <0>;
+			qcom,bam-type = <1>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <1>;
 			qcom,src-bam-physical-address = <0xfc37c000>;
 			qcom,src-bam-pipe-index = <0>;
 			qcom,dst-bam-physical-address = <0xf9a44000>;
@@ -179,6 +182,66 @@
 			qcom,descriptor-fifo-offset = <0x4000>;
 			qcom,descriptor-fifo-size = <0x400>;
 		};
+		qcom,pipe3 {
+			label = "hsic-ipa-in-0";
+			qcom,usb-bam-mem-type = <2>;
+			qcom,bam-type = <2>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <2>;
+			qcom,dst-bam-physical-address = <0xf9a04000>;
+			qcom,dst-bam-pipe-index = <3>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
+		qcom,pipe4 {
+			label = "hsic-ipa-in-1";
+			qcom,bam-type = <2>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <1>;
+			qcom,peer-bam = <2>;
+			qcom,usb-bam-mem-type = <2>;
+			qcom,dst-bam-physical-address = <0xf9a04000>;
+			qcom,dst-bam-pipe-index = <4>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
+		qcom,pipe5 {
+			label = "hsic-ipa-in-2";
+			qcom,usb-bam-mem-type = <2>;
+			qcom,bam-type = <2>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <2>;
+			qcom,peer-bam = <2>;
+			qcom,dst-bam-physical-address = <0xf9a04000>;
+			qcom,dst-bam-pipe-index = <5>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
+		qcom,pipe6 {
+			label = "hsic-ipa-in-3";
+			qcom,usb-bam-mem-type = <2>;
+			qcom,bam-type = <2>;
+			qcom,dir = <1>;
+			qcom,pipe-num = <3>;
+			qcom,peer-bam = <2>;
+			qcom,dst-bam-physical-address = <0xf9a04000>;
+			qcom,dst-bam-pipe-index = <6>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
+		qcom,pipe7 {
+			label = "hsic-ipa-out-0";
+			qcom,usb-bam-mem-type = <2>;
+			qcom,bam-type = <2>;
+			qcom,dir = <0>;
+			qcom,pipe-num = <0>;
+			qcom,peer-bam = <2>;
+			qcom,src-bam-physical-address = <0xf9a04000>;
+			qcom,src-bam-pipe-index = <7>;
+			qcom,data-fifo-size = <0xD480>;
+			qcom,descriptor-fifo-size = <0x1A80>;
+		};
 	};
 
 	qcom,nand@f9ac0000 {
@@ -721,8 +784,8 @@
 
 	sfpb_spinlock: qcom,ipc-spinlock@fd484000 {
 		compatible = "qcom,ipc-spinlock-sfpb";
-		reg = <0xfd484000 0x1000>;
-		qcom,num-locks = <32>;
+		reg = <0xfd484000 0x400>;
+		qcom,num-locks = <8>;
 	};
 
 	ldrex_spinlock: qcom,ipc-spinlock@fa00000 {
@@ -731,6 +794,17 @@
 		status = "disable";
 	};
 
+	cpu-pmu {
+                compatible = "arm,cortex-a5-pmu";
+                qcom,irq-is-percpu;
+                interrupts = <1 7 0x00>;
+        };
+
+        l2-pmu {
+                compatible = "qcom,l2-pmu";
+                interrupts = <0 1 0>;
+        };
+
 };
 
 /include/ "msm-pm8019-rpm-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msmzinc-sim.dts b/arch/arm/boot/dts/msmzinc-sim.dts
new file mode 100644
index 0000000..48d7ef1
--- /dev/null
+++ b/arch/arm/boot/dts/msmzinc-sim.dts
@@ -0,0 +1,29 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msmzinc.dtsi"
+
+/ {
+	model = "Qualcomm MSM ZINC Simulator";
+	compatible = "qcom,msmzinc-sim", "qcom,msmzinc";
+	qcom,msm-id = <178 0 0>;
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	uart0: serial@f991f000 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msmzinc.dtsi b/arch/arm/boot/dts/msmzinc.dtsi
new file mode 100644
index 0000000..8905962
--- /dev/null
+++ b/arch/arm/boot/dts/msmzinc.dtsi
@@ -0,0 +1,83 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Qualcomm MSM ZINC";
+	compatible = "qcom,msmzinc";
+	interrupt-parent = <&intc>;
+
+	intc: interrupt-controller@f9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xF9000000 0x1000>,
+		      <0xF9002000 0x1000>;
+	};
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+		ngpio = <146>;
+		interrupts = <0 208 0>;
+		qcom,direct-connect-irqs = <8>;
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <1 2 0 1 3 0>;
+		clock-frequency = <19200000>;
+	};
+
+	serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+		status = "disabled";
+	};
+
+	qcom,cache_erp {
+		compatible = "qcom,cache_erp";
+		interrupts = <1 9 0>, <0 2 0>;
+		interrupt-names = "l1_irq", "l2_irq";
+	};
+
+	qcom,cache_dump {
+		compatible = "qcom,cache_dump";
+		qcom,l1-dump-size = <0x100000>;
+		qcom,l2-dump-size = <0x500000>;
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
+	};
+
+	rpm_bus: qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+		rpm-standalone;
+	};
+
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,ion-heap@30 { /* SYSTEM HEAP */
+			reg = <30>;
+		};
+	};
+};
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 9e38eca..dc73f4d 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -58,8 +58,6 @@
 CONFIG_MSM_PIL_PRONTO=y
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_MSM_PIL_VENUS=y
-CONFIG_WCNSS_CORE=y
-CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_DLOAD_MODE=y
@@ -107,6 +105,74 @@
 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
@@ -116,6 +182,7 @@
 CONFIG_NET_CLS_FW=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_MD=y
@@ -125,6 +192,7 @@
 CONFIG_DUMMY=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
+CONFIG_KS8851=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
@@ -141,6 +209,7 @@
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB=y
 CONFIG_MSM_QPNP_INT=y
@@ -159,7 +228,6 @@
 CONFIG_HWMON=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_QPNP_CHARGER=y
-# CONFIG_HWMON is not set
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_REGULATOR=y
@@ -250,7 +318,6 @@
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_VIDEOBUF2_MSM_MEM=y
-CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -258,6 +325,7 @@
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
 CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_MSM_RTB=y
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_CORESIGHT=y
@@ -268,3 +336,8 @@
 CONFIG_CORESIGHT_STM=y
 CONFIG_CORESIGHT_EVENT=m
 CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_TZ_LOG=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 89f9d4a..a8ea31d 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -531,3 +531,7 @@
 CONFIG_CRC_CCITT=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5b9c590..9f10bc4 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -549,3 +549,7 @@
 CONFIG_CRC_CCITT=y
 CONFIG_SYNC=y
 CONFIG_SW_SYNC=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index c74262c..224df83 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -291,6 +291,7 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB=y
 CONFIG_MSM_QPNP_INT=y
+CONFIG_QPNP_REVID=y
 CONFIG_SLIMBUS_MSM_NGD=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
@@ -422,6 +423,7 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_CLKDIV=y
+CONFIG_QPNP_COINCELL=y
 CONFIG_MSM_IOMMU=y
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
@@ -468,3 +470,8 @@
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_CRC_CCITT=y
 CONFIG_MSM_EVENT_TIMER=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_BOOT_STATS=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 48ea1a4..e42aa77 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -296,6 +296,7 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB=y
 CONFIG_MSM_QPNP_INT=y
+CONFIG_QPNP_REVID=y
 CONFIG_SLIMBUS_MSM_NGD=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
@@ -430,6 +431,7 @@
 CONFIG_QPNP_PWM=y
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_CLKDIV=y
+CONFIG_QPNP_COINCELL=y
 CONFIG_MSM_IOMMU=y
 CONFIG_MSM_IOMMU_PMON=y
 CONFIG_MOBICORE_SUPPORT=m
@@ -493,3 +495,8 @@
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_CRC_CCITT=y
 CONFIG_MSM_EVENT_TIMER=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_BOOT_STATS=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 1fe528a..6e8fe3e 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -323,3 +323,6 @@
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_MSM_RTB=y
 CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_BOOT_STATS=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index aa18209..9a32239 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -324,3 +324,6 @@
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_MSM_RTB=y
 CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_PM_AUTOSLEEP=y
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_MSM_BOOT_STATS=y
diff --git a/arch/arm/configs/msmzinc_defconfig b/arch/arm/configs/msmzinc_defconfig
new file mode 100644
index 0000000..b74b204
--- /dev/null
+++ b/arch/arm/configs/msmzinc_defconfig
@@ -0,0 +1,383 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+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_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_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSMZINC=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MSM_RPM_SMD=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_RPM_REGULATOR_SMD=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
+CONFIG_MSM_L1_ERR_LOG=y
+CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_PORT_PANIC=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_ARM_LPAE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+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_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_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_CFG80211=y
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_USB_HSIC_SMSC_HUB=y
+CONFIG_TI_DRV2667=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_KS8851=m
+# CONFIG_MSM_RMNET is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_USBNET=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=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_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SMB350_CHARGER=y
+CONFIG_BATTERY_BQ28400=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_BATTERY_BCL=y
+CONFIG_SENSORS_EPM_ADC=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=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334=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_USB=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_SWITCH=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_ANDROID_LOGGER=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_CLKDIV=y
+CONFIG_MSM_IOMMU=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_PSTORE=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index d1a3e61..e1fc42f 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -52,6 +52,10 @@
 	void (*disable_irq)(int irq);
 };
 
+extern int multicore_request_irq(int irq, irq_handler_t *handle_irq);
+extern void multicore_free_irq(int irq);
+extern struct arm_pmu_platdata multicore_data;
+
 #ifdef CONFIG_CPU_HAS_PMU
 
 /**
@@ -151,9 +155,6 @@
 			    struct hw_perf_event *hwc,
 			    int idx);
 
-extern void enable_irq_callback(void *);
-extern void disable_irq_callback(void *);
-
 #endif /* CONFIG_HW_PERF_EVENTS */
 
 #endif /* __ARM_PMU_H__ */
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index dfcdb9f..c355aeb 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -110,6 +110,7 @@
 	unsigned long reboot_code_buffer_phys;
 	void *reboot_code_buffer;
 
+	arch_kexec();
 
 	page_list = image->head & PAGE_MASK;
 
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 5311d74..cef66ec 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -21,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
 #include <linux/irq.h>
+#include <linux/of.h>
 
 #include <asm/cputype.h>
 #include <asm/irq.h>
@@ -51,6 +52,8 @@
 /* Set at runtime when we know what CPU type we are. */
 static struct arm_pmu *cpu_pmu;
 
+static int per_cpu_irq;
+
 enum arm_perf_pmu_ids
 armpmu_get_pmu_id(void)
 {
@@ -381,6 +384,58 @@
 	return plat->handle_irq(irq, dev, armpmu->handle_irq);
 }
 
+static DEFINE_PER_CPU(u32, pmu_irq_cookie);
+
+void enable_irq_callback(void *info)
+{
+	int irq = *(unsigned int *)info;
+	enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
+}
+
+void disable_irq_callback(void *info)
+{
+	int irq = *(unsigned int *)info;
+	disable_percpu_irq(irq);
+}
+
+int
+multicore_request_irq(int irq, irq_handler_t *handle_irq)
+{
+	int err = 0;
+	int cpu;
+
+	err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
+			&pmu_irq_cookie);
+
+	if (!err) {
+		for_each_cpu(cpu, cpu_online_mask) {
+			smp_call_function_single(cpu,
+					enable_irq_callback, &irq, 1);
+		}
+	}
+
+	return err;
+}
+
+void
+multicore_free_irq(int irq)
+{
+	int cpu;
+
+	if (irq >= 0) {
+		for_each_cpu(cpu, cpu_online_mask) {
+			smp_call_function_single(cpu,
+					disable_irq_callback, &irq, 1);
+		}
+		free_percpu_irq(irq, &pmu_irq_cookie);
+	}
+}
+
+struct arm_pmu_platdata multicore_data = {
+	.request_pmu_irq = multicore_request_irq,
+	.free_pmu_irq = multicore_free_irq,
+};
+
 int
 armpmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
 {
@@ -689,11 +744,12 @@
 	{.compatible = "arm,cortex-a8-pmu"},
 	{.compatible = "arm,arm1136-pmu"},
 	{.compatible = "arm,arm1176-pmu"},
+	{.compatible = "qcom,krait-pmu"},
 	{},
 };
 
 static struct platform_device_id armpmu_plat_device_ids[] = {
-	{.name = "cpu-arm-pmu"},
+	{.name = "cpu-pmu"},
 	{},
 };
 
@@ -703,12 +759,16 @@
 		return -ENODEV;
 
 	cpu_pmu->plat_device = pdev;
+
+	if (per_cpu_irq == 1)
+		cpu_pmu->plat_device->dev.platform_data = &multicore_data;
+
 	return 0;
 }
 
 static struct platform_driver armpmu_driver = {
 	.driver		= {
-		.name	= "cpu-arm-pmu",
+		.name	= "cpu-pmu",
 		.of_match_table = armpmu_of_device_ids,
 	},
 	.probe		= armpmu_device_probe,
@@ -756,18 +816,6 @@
 	return 0;
 }
 
-void enable_irq_callback(void *info)
-{
-	int irq = *(unsigned int *)info;
-	enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
-}
-
-void disable_irq_callback(void *info)
-{
-	int irq = *(unsigned int *)info;
-	disable_percpu_irq(irq);
-}
-
 /*
  * PMU hardware loses all context when a CPU goes offline.
  * When a CPU is hotplugged back in, since some hardware registers are
@@ -881,6 +929,24 @@
 	.notifier_call = perf_cpu_pm_notifier,
 };
 
+#ifdef CONFIG_OF
+static inline int get_dt_irq_prop(void)
+{
+	struct device_node *np = NULL;
+	int err = -1;
+
+	np = of_find_matching_node(NULL, armpmu_of_device_ids);
+	if (np)
+		err = of_property_read_bool(np, "qcom,irq-is-percpu");
+	else
+		pr_err("Perf: can't find DT node.\n");
+
+	return err;
+}
+#else
+static inline int get_dt_irq_prop(void) {return 0; }
+#endif
+
 /*
  * CPU PMU identification and registration.
  */
@@ -956,6 +1022,8 @@
 		register_cpu_notifier(&pmu_cpu_notifier);
 		armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
 		cpu_pm_register_notifier(&perf_cpu_pm_notifier_block);
+		per_cpu_irq = get_dt_irq_prop();
+
 	} else {
 		pr_info("no hardware support available\n");
 	}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index f39046c..b65016a 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -286,6 +286,24 @@
 	select MSM_LPM_TEST
 	select MSM_RPM_LOG
 
+config ARCH_MSMZINC
+	bool "MSMZINC"
+	select ARCH_MSM_KRAITMP
+	select GPIO_MSM_V3
+	select ARM_GIC
+	select CPU_V7
+	select MSM_SCM if SMP
+	select MSM_GPIOMUX
+	select MULTI_IRQ_HANDLER
+	select MSM_NATIVE_RESTART
+	select MSM_RESTART_V2
+	select MSM_PM8X60 if PM
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+	select REGULATOR
+	select ARM_HAS_SG_CHAIN
+	select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
+
 config ARCH_MPQ8092
 	bool "MPQ8092"
 	select ARCH_MSM_KRAITMP
@@ -390,16 +408,17 @@
 	select MSM_GPIOMUX
 	select MSM_NATIVE_RESTART
 	select MSM_RESTART_V2
-	select MEMORY_HOLE_CARVEOUT
-	select DONT_MAP_HOLE_AFTER_MEMBANK
-	select QMI_ENCDEC
 	select MSM_QDSP6_APRV2
 	select MSM_QDSP6V2_CODECS
 	select MSM_AUDIO_QDSP6V2 if SND_SOC
+	select QMI_ENCDEC
 	select MSM_RPM_SMD
 	select MSM_SPM_V2
 	select MSM_L2_SPM
 	select MSM_PM8X60 if PM
+	select MEMORY_HOLE_CARVEOUT
+	select DONT_MAP_HOLE_AFTER_MEMBANK0
+	select MSM_BUS_SCALING
 	select CPU_FREQ_MSM
 	select CPU_FREQ
 	select CPU_FREQ_GOV_USERSPACE
@@ -407,6 +426,8 @@
 	select MSM_PIL
 	select MSM_RUN_QUEUE_STATS
 	select ARM_HAS_SG_CHAIN
+	select REGULATOR
+	select MSM_RPM_REGULATOR_SMD
 
 config ARCH_MSM8226
 	bool "MSM8226"
@@ -433,6 +454,12 @@
 	select MEMORY_HOLE_CARVEOUT
 	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_BUS_SCALING
+	select CPU_FREQ_MSM
+	select CPU_FREQ
+	select CPU_FREQ_GOV_USERSPACE
+	select CPU_FREQ_GOV_ONDEMAND
+	select MSM_PIL
+	select MSM_RUN_QUEUE_STATS
 	select ARM_HAS_SG_CHAIN
 	select REGULATOR
 	select MSM_RPM_REGULATOR_SMD
@@ -1034,6 +1061,7 @@
 	default "0x80200000" if ARCH_MSM8960
 	default "0x80200000" if ARCH_MSM8930
 	default "0x00000000" if ARCH_MSM8974
+	default "0x00000000" if ARCH_MSMZINC
 	default "0x00000000" if ARCH_MPQ8092
 	default "0x00000000" if ARCH_MSM8226
 	default "0x00000000" if ARCH_MSM8610
@@ -1184,6 +1212,14 @@
                 help
                   Say Y here if you want the debug print routines to direct
                   their output to the serial port on MPQ8092 devices.
+
+	config DEBUG_MSMZINC_UART
+                bool "Kernel low-level debugging messages via MSMZINC UART"
+                depends on ARCH_MSMZINC
+                select MSM_HAS_DEBUG_UART_HS_V14
+                help
+                  Say Y here if you want the debug print routines to direct
+                  their output to the serial port on MSMZINC devices.
 endchoice
 
 choice
@@ -2808,12 +2844,12 @@
 	 does not have a direct access to the PMIC.
 
 config MSM_ENABLE_WDOG_DEBUG_CONTROL
-	bool "MSM Watchdog driver to disable debug Image"
+	bool "Enable control of watchdog debug and boot partition select"
 	help
-	 This driver supports the configuration of the GCC_WDOG_DEBUG register
-	 used to control debug image.
-	 This support is currently required for MSM8974 to disable debug image
-	 on PS HOLD reset
+	  Enables support for controlling watchdog debug and boot partition
+	  select. This is currently used to bypass debug image for PS_HOLD reset
+	  by disabling watchdog debug and boot partition select. This allows
+	  for a clean MSM reset for reboot scenarios.
 
 config MSM_FIQ
 	bool "Enable FIQ for debugging"
@@ -2850,4 +2886,12 @@
 	depends on SERIAL_MSM_HS
 	help
 		Select if BLSP based UART Core v.14 or higher is present.
+
+config MSM_BOOT_STATS
+	bool "Use MSM boot stats reporting"
+	help
+	 Use this to report msm boot stats such as bootloader throughput,
+	 display init, total boot time.
+	 This figures are reported in mpm sleep clock cycles and have a
+	 resolution of 31 bits as 1 bit is used as an overflow check.
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index cb5e712..161ee3d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -29,15 +29,17 @@
 obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
 endif
 obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o acpuclock-8625q.o clock-pll.o
-obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
 obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
-obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
+ifndef CONFIG_OF
+obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o
+endif
+obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o perf_event_msm_krait_l2.o
 obj-$(CONFIG_ARCH_MSM_KRAIT) += krait-scm.o
 ifdef CONFIG_HW_PERF_EVENTS
-obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o perf_event_msm_pl310.o
-obj-$(CONFIG_ARCH_MSM9625) += pmu.o perf_event_msm_pl310.o
-obj-$(CONFIG_ARCH_MSM8625) += pmu.o perf_event_msm_pl310.o
-obj-$(CONFIG_ARCH_MSM9615) += pmu.o perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM7X27A) += perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM9625) += perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM8625) += perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM9615) += perf_event_msm_pl310.o
 obj-$(CONFIG_DEBUG_FS) += perf_debug.o
 endif
 
@@ -116,6 +118,7 @@
 ifndef CONFIG_ARCH_MSM9625
 ifndef CONFIG_ARCH_MPQ8092
 ifndef CONFIG_ARCH_MSM8610
+ifndef CONFIG_ARCH_MSMZINC
 	obj-y += nand_partitions.o
 endif
 endif
@@ -125,6 +128,7 @@
 endif
 endif
 endif
+endif
 obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
 obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
 obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -193,6 +197,7 @@
 obj-$(CONFIG_ARCH_MSM8X60) += clock-rpm.o
 obj-$(CONFIG_ARCH_MSM8X60) += saw-regulator.o
 obj-$(CONFIG_ARCH_MSM8X60) += footswitch-8x60.o
+obj-$(CONFIG_MSM_BOOT_STATS) += boot_stats.o
 
 ifdef CONFIG_MSM_RPM_REGULATOR
 obj-y += rpm-regulator.o
@@ -287,6 +292,7 @@
 obj-$(CONFIG_MACH_MPQ8064_DTV) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
 obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
+obj-$(CONFIG_ARCH_MSMZINC) += board-zinc.o board-zinc-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-8974-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
 obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o
@@ -300,7 +306,7 @@
 obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o acpuclock-8930ab.o
 obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8974.o
+obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8226.o
 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
@@ -362,6 +368,7 @@
 obj-$(CONFIG_ARCH_MPQ8092) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSMZINC) += gpiomux-v2.o gpiomux.o
 
 obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
 obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 02d0b46..e3b8d73 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -58,6 +58,11 @@
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2-liquid.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2-mtp.dtb
 
+# MSMZINC
+   zreladdr-$(CONFIG_ARCH_MSMZINC)	:= 0x00008000
+        dtb-$(CONFIG_ARCH_MSMZINC)	+= msmzinc-sim.dtb
+
+
 # MSM9615
    zreladdr-$(CONFIG_ARCH_MSM9615)	:= 0x40808000
 
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index efd0045..83c14a8 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -308,6 +308,168 @@
 	{ 0, { 0 } }
 };
 
+static struct acpu_level acpu_freq_tbl_2g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   800000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   810000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   820000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   830000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   840000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   850000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   860000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  875000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  885000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  895000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  910000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  920000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  930000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  945000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  960000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  975000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  990000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1005000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1020000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1030000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19), 1045000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19), 1060000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1075000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   785000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   795000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   805000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   815000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   825000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   835000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   845000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  855000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  865000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  875000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  890000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  900000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  910000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  925000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  940000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  955000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  970000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  980000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  995000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1005000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19), 1020000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19), 1035000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1050000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   780000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   790000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   800000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   810000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   820000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   830000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  840000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  850000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  860000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  885000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  895000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  910000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  925000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  935000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  960000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  970000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  985000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  995000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19), 1010000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1025000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   780000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   790000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   800000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   810000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   820000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  830000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  840000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  850000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  870000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  880000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  895000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  910000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  920000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  940000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  950000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  960000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  975000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19),  985000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1000000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   760000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   770000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   780000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   790000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   800000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   810000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  820000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  830000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  840000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  860000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  870000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  880000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  890000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  900000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  920000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  930000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  940000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  955000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19),  965000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  975000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   750000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   760000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   770000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   780000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   790000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   800000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  810000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  820000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  830000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  840000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  850000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  860000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  870000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  875000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  885000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  905000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  915000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  920000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  930000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19),  940000, 3200000 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 3200000 },
+	{ 0, { 0 } }
+};
+
 static struct acpu_level acpu_freq_tbl_2p3g_pvs0[] __initdata = {
 	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   800000,  400000 },
 	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   800000, 3200000 },
@@ -339,6 +501,192 @@
 	{ 0, { 0 } }
 };
 
+static struct acpu_level acpu_freq_tbl_2p3g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   800000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   800000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   800000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   800000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   800000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   810000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   820000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  830000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  840000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  850000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  860000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  875000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  885000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  895000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  910000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  920000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  930000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  945000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  960000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  975000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  990000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19), 1005000, 3200000 },
+	{ 0, { 1958400, HFPLL, 1, 102 }, L2(19), 1020000, 3200000 },
+	{ 1, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   775000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   775000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   785000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   795000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   805000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  815000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  825000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  835000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  845000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  855000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  865000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  875000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  890000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  900000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  910000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  925000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  940000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  955000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  970000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19),  980000, 3200000 },
+	{ 0, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 3200000 },
+	{ 1, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   775000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   775000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   775000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   780000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   790000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  800000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  810000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  820000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  830000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  840000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  850000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  860000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  875000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  885000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  895000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  910000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  925000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  935000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  950000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19),  960000, 3200000 },
+	{ 0, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 3200000 },
+	{ 1, { 2035200, HFPLL, 1, 106 }, L2(19),  985000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   775000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   775000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   775000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   775000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   775000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   775000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   780000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  790000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  800000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  810000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  830000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  840000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  850000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  860000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  870000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  880000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  895000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  910000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  920000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  930000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19),  940000, 3200000 },
+	{ 0, { 1958400, HFPLL, 1, 102 }, L2(19),  950000, 3200000 },
+	{ 1, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   750000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   750000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   750000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   750000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   760000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   770000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  780000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  790000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  800000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  810000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  820000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  830000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  840000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  850000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  860000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  880000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  890000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  900000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  910000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19),  920000, 3200000 },
+	{ 0, { 1958400, HFPLL, 1, 102 }, L2(19),  930000, 3200000 },
+	{ 1, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  965000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 3200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_2p3g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   750000,  400000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(3),   750000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(3),   750000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(6),   750000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(6),   750000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(7),   750000, 3200000 },
+	{ 1, {  729600, HFPLL, 1,  38 }, L2(7),   760000, 3200000 },
+	{ 0, {  806400, HFPLL, 1,  42 }, L2(10),  770000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(10),  780000, 3200000 },
+	{ 0, {  960000, HFPLL, 1,  50 }, L2(10),  790000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(12),  810000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1,  62 }, L2(12),  820000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1,  66 }, L2(12),  830000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(12),  840000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(16),  850000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1,  78 }, L2(16),  860000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16),  870000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16),  875000, 3200000 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16),  885000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(19),  895000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(19),  905000, 3200000 },
+	{ 0, { 1958400, HFPLL, 1, 102 }, L2(19),  915000, 3200000 },
+	{ 1, { 2035200, HFPLL, 1, 106 }, L2(19),  920000, 3200000 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 3200000 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 3200000 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 3200000 },
+	{ 0, { 0 } }
+};
+
 static struct pvs_table pvs_v1[NUM_SPEED_BINS][NUM_PVS] __initdata = {
 	/* 8974v1 1.7GHz Parts */
 	[0][0] = { acpu_freq_tbl_v1_pvs0, sizeof(acpu_freq_tbl_v1_pvs0) },
@@ -351,23 +699,23 @@
 static struct pvs_table pvs_v2[NUM_SPEED_BINS][NUM_PVS] __initdata = {
 	/* 8974v2 2.0GHz Parts */
 	[0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
-	[0][1] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
-	[0][2] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
-	[0][3] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
-	[0][4] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
-	[0][5] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
-	[0][6] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
-	[0][7] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
+	[0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
+	[0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
+	[0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
+	[0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
+	[0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
+	[0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
+	[0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
 
 	/* 8974v2 2.3GHz Parts */
 	[1][0] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
-	[1][1] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
-	[1][2] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
-	[1][3] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
-	[1][4] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
-	[1][5] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
-	[1][6] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
-	[1][7] = { acpu_freq_tbl_2p3g_pvs0, sizeof(acpu_freq_tbl_2p3g_pvs0) },
+	[1][1] = { acpu_freq_tbl_2p3g_pvs1, sizeof(acpu_freq_tbl_2p3g_pvs1) },
+	[1][2] = { acpu_freq_tbl_2p3g_pvs2, sizeof(acpu_freq_tbl_2p3g_pvs2) },
+	[1][3] = { acpu_freq_tbl_2p3g_pvs3, sizeof(acpu_freq_tbl_2p3g_pvs3) },
+	[1][4] = { acpu_freq_tbl_2p3g_pvs4, sizeof(acpu_freq_tbl_2p3g_pvs4) },
+	[1][5] = { acpu_freq_tbl_2p3g_pvs5, sizeof(acpu_freq_tbl_2p3g_pvs5) },
+	[1][6] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
+	[1][7] = { acpu_freq_tbl_2p3g_pvs6, sizeof(acpu_freq_tbl_2p3g_pvs6) },
 };
 
 static struct msm_bus_scale_pdata bus_scale_data __initdata = {
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 833b213..20c461d 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1577,8 +1577,6 @@
 {
 	DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled\n", __func__);
 	in_global_reset = 1;
-	if (get_restart_level() <= RESET_SOC)
-		DMUX_LOG_KERR("%s: ssrestart not enabled\n", __func__);
 	return 1;
 }
 
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index c8bdb5d..48abd35 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2388,12 +2388,6 @@
 	}
 }
 
-static void __init fsm8064_ep_pcie_init(void)
-{
-	msm_device_pcie.dev.platform_data = &ep_pcie_platform_data;
-	platform_device_register(&msm_device_pcie);
-}
-
 static struct platform_device mpq8064_device_ext_3p3v_vreg = {
 	.name			= "reg-fixed-voltage",
 	.dev			= {
@@ -2401,6 +2395,12 @@
 	},
 };
 
+static void __init fsm8064_ep_pcie_init(void)
+{
+	msm_device_pcie.dev.platform_data = &ep_pcie_platform_data;
+	platform_device_register(&msm_device_pcie);
+}
+
 static struct platform_device apq8064_device_ext_5v_vreg __devinitdata = {
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= PM8921_MPP_PM_TO_SYS(7),
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 5db52dd..e8e75df 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -17,7 +17,7 @@
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
 
-#define KS8851_IRQ_GPIO 75
+#define KS8851_IRQ_GPIO 115
 
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 static struct gpiomux_setting gpio_eth_config = {
@@ -84,6 +84,12 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting gpio_spi_cs_eth_config = {
+	.func = GPIOMUX_FUNC_4,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 static struct gpiomux_setting gpio_i2c_config = {
 	.func = GPIOMUX_FUNC_3,
 	.drv = GPIOMUX_DRV_2MA,
@@ -114,6 +120,29 @@
 	},
 };
 
+static struct gpiomux_setting lcd_rst_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting lcd_rst_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
+	{
+		.gpio = 25,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &lcd_rst_act_cfg,
+			[GPIOMUX_SUSPENDED] = &lcd_rst_sus_cfg,
+		},
+	}
+};
+
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 	{
 		.gpio      = 0,		/* BLSP1 QUP1 SPI_DATA_MOSI */
@@ -163,6 +192,12 @@
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
+	{
+		.gpio      = 22,		/* BLSP1 QUP1 SPI_CS_ETH */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_eth_config,
+		},
+	},
 };
 
 static struct msm_gpiomux_config msm_synaptics_configs[] __initdata = {
@@ -225,4 +260,6 @@
 	msm_gpiomux_install(&sd_card_det, 1);
 	msm_gpiomux_install(msm_synaptics_configs,
 			ARRAY_SIZE(msm_synaptics_configs));
+	msm_gpiomux_install_nowrite(msm_lcd_configs,
+			ARRAY_SIZE(msm_lcd_configs));
 }
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index b4f202d..2723e20 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -36,6 +36,7 @@
 #ifdef CONFIG_ION_MSM
 #include <mach/ion.h>
 #endif
+#include <linux/regulator/qpnp-regulator.h>
 #include <mach/msm_memtypes.h>
 #include <mach/socinfo.h>
 #include <mach/board.h>
@@ -96,6 +97,7 @@
 	msm_rpm_driver_init();
 	msm_lpmrs_module_init();
 	msm_spm_device_init();
+	qpnp_regulator_init();
 	msm_thermal_device_init();
 
 	if (machine_is_msm8610_rumi())
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 78e3ca6..7ef6fed 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -652,29 +652,6 @@
 #endif
 }
 
-static void ion_adjust_secure_allocation(void)
-{
-	int i;
-
-	for (i = 0; i < msm8960_ion_pdata.nr; i++) {
-		struct ion_platform_heap *heap =
-			&(msm8960_ion_pdata.heaps[i]);
-
-
-		if (heap->extra_data) {
-			switch ((int) heap->type) {
-			case ION_HEAP_TYPE_CP:
-				if (cpu_is_msm8960()) {
-					((struct ion_cp_heap_pdata *)
-					heap->extra_data)->allow_nonsecure_alloc
-						= 1;
-				}
-
-			}
-		}
-	}
-}
-
 static void __init reserve_mdp_memory(void)
 {
 	msm8960_mdp_writeback(msm8960_reserve_table);
@@ -3394,7 +3371,6 @@
 		mdm_sglte_device.dev.platform_data = &sglte_platform_data;
 		platform_device_register(&mdm_sglte_device);
 	}
-	ion_adjust_secure_allocation();
 }
 
 MACHINE_START(MSM8960_CDP, "QCT MSM8960 CDP")
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 5240f38..688c6f7 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -203,7 +203,6 @@
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_DOWN,
-	.dir = GPIOMUX_OUT_LOW,
 };
 
 static struct gpiomux_setting hsic_act_cfg = {
@@ -219,6 +218,19 @@
 	.dir = GPIOMUX_IN,
 };
 
+static struct gpiomux_setting hsic_resume_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting hsic_resume_susp_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct msm_gpiomux_config msm_hsic_configs[] = {
 	{
 		.gpio = 144,               /*HSIC_STROBE */
@@ -234,6 +246,13 @@
 			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
 		},
 	},
+	{
+		.gpio = 80,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_resume_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_resume_susp_cfg,
+		},
+	},
 };
 
 static struct msm_gpiomux_config msm_hsic_hub_configs[] = {
@@ -644,7 +663,7 @@
 	{
 		.gpio = 25, /* WEBCAM2_RESET_N */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
 			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
@@ -665,36 +684,36 @@
 	{
 		.gpio = 28, /* WEBCAM1_STANDBY */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
 			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
 	{
 		.gpio = 89, /* CAM1_STANDBY_N */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
-			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
 	{
 		.gpio = 90, /* CAM1_RST_N */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
-			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
 	{
 		.gpio = 91, /* CAM2_STANDBY_N */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
-			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
 	{
 		.gpio = 92, /* CAM2_RST_N */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
-			[GPIOMUX_SUSPENDED] = &cam_settings[1],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
 };
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index f609bbc..50f4fd7 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.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
@@ -625,8 +625,13 @@
 #define USB_BAM_PHY_BASE	0x12502000
 #define HSIC_BAM_PHY_BASE	0x12542000
 #define A2_BAM_PHY_BASE		0x124C2000
-static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][8][2] = {
-	[HSUSB_BAM][0][USB_TO_PEER_PERIPHERAL] = {
+static struct usb_bam_pipe_connect msm_usb_bam_connections[] = {
+	{
+		.name = "hsusb-a2-out-0",
+		.bam_type = HSUSB_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = USB_TO_PEER_PERIPHERAL,
+		.pipe_num = 0,
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 11,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -636,7 +641,12 @@
 		.desc_fifo_base_offset = 0x1700,
 		.desc_fifo_size = 0x300,
 	},
-	[HSUSB_BAM][0][PEER_PERIPHERAL_TO_USB] = {
+	{
+		.name = "hsusb-a2-in-0",
+		.bam_type = HSUSB_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = PEER_PERIPHERAL_TO_USB,
+		.pipe_num = 0,
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 1,
 		.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -646,7 +656,12 @@
 		.desc_fifo_base_offset = 0x1000,
 		.desc_fifo_size = 0x100,
 	},
-	[HSUSB_BAM][1][USB_TO_PEER_PERIPHERAL] = {
+	{
+		.name = "hsusb-a2-out-1",
+		.bam_type = HSUSB_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = USB_TO_PEER_PERIPHERAL,
+		.pipe_num = 1,
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 13,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -656,7 +671,12 @@
 		.desc_fifo_base_offset = 0x2700,
 		.desc_fifo_size = 0x300,
 	},
-	[HSUSB_BAM][1][PEER_PERIPHERAL_TO_USB] = {
+	{
+		.name = "hsusb-a2-in-1",
+		.bam_type = HSUSB_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = PEER_PERIPHERAL_TO_USB,
+		.pipe_num = 1,
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 3,
 		.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -666,7 +686,12 @@
 		.desc_fifo_base_offset = 0x2000,
 		.desc_fifo_size = 0x100,
 	},
-	[HSUSB_BAM][2][USB_TO_PEER_PERIPHERAL] = {
+	{
+		.name = "hsusb-a2-out-2",
+		.bam_type = HSUSB_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = USB_TO_PEER_PERIPHERAL,
+		.pipe_num = 2,
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 15,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -676,7 +701,12 @@
 		.desc_fifo_base_offset = 0x3700,
 		.desc_fifo_size = 0x300,
 	},
-	[HSUSB_BAM][2][PEER_PERIPHERAL_TO_USB] = {
+	{
+		.name = "hsusb-a2-in-2",
+		.bam_type = HSUSB_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = PEER_PERIPHERAL_TO_USB,
+		.pipe_num = 2,
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 5,
 		.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -686,7 +716,12 @@
 		.desc_fifo_base_offset = 0x3000,
 		.desc_fifo_size = 0x100,
 	},
-	[HSIC_BAM][0][USB_TO_PEER_PERIPHERAL] = {
+	{
+		.name = "hsic-a2-out-0",
+		.bam_type = HSIC_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = USB_TO_PEER_PERIPHERAL,
+		.pipe_num = 0,
 		.src_phy_addr = HSIC_BAM_PHY_BASE,
 		.src_pipe_index = 1,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -696,7 +731,12 @@
 		.desc_fifo_base_offset = 0x1700,
 		.desc_fifo_size = 0x300,
 	},
-	[HSIC_BAM][0][PEER_PERIPHERAL_TO_USB] = {
+	{
+		.name = "hsic-a2-in-0",
+		.bam_type = HSIC_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = PEER_PERIPHERAL_TO_USB,
+		.pipe_num = 0,
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 1,
 		.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -706,7 +746,12 @@
 		.desc_fifo_base_offset = 0x1000,
 		.desc_fifo_size = 0x100,
 	},
-	[HSIC_BAM][1][USB_TO_PEER_PERIPHERAL] = {
+	{
+		.name = "hsic-a2-out-1",
+		.bam_type = HSIC_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = USB_TO_PEER_PERIPHERAL,
+		.pipe_num = 1,
 		.src_phy_addr = HSIC_BAM_PHY_BASE,
 		.src_pipe_index = 3,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -716,7 +761,12 @@
 		.desc_fifo_base_offset = 0x2700,
 		.desc_fifo_size = 0x300,
 	},
-	[HSIC_BAM][1][PEER_PERIPHERAL_TO_USB] = {
+	{
+		.name = "hsic-a2-in-1",
+		.bam_type = HSIC_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = PEER_PERIPHERAL_TO_USB,
+		.pipe_num = 1,
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 3,
 		.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -726,7 +776,12 @@
 		.desc_fifo_base_offset = 0x2000,
 		.desc_fifo_size = 0x100,
 	},
-	[HSIC_BAM][2][USB_TO_PEER_PERIPHERAL] = {
+	{
+		.name = "hsic-a2-out-2",
+		.bam_type = HSIC_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = USB_TO_PEER_PERIPHERAL,
+		.pipe_num = 2,
 		.src_phy_addr = HSIC_BAM_PHY_BASE,
 		.src_pipe_index = 5,
 		.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -736,7 +791,12 @@
 		.desc_fifo_base_offset = 0x3700,
 		.desc_fifo_size = 0x300,
 	},
-	[HSIC_BAM][2][PEER_PERIPHERAL_TO_USB] = {
+	{
+		.name = "hsic-a2-in-2",
+		.bam_type = HSIC_BAM,
+		.peer_bam = A2_P_BAM,
+		.dir = PEER_PERIPHERAL_TO_USB,
+		.pipe_num = 2,
 		.src_phy_addr = A2_BAM_PHY_BASE,
 		.src_pipe_index = 5,
 		.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -749,12 +809,9 @@
 };
 
 static struct msm_usb_bam_platform_data msm_usb_bam_pdata = {
-	.connections = &msm_usb_bam_connections[0][0][0],
-#ifndef CONFIG_USB_CI13XXX_MSM_HSIC
-	.usb_active_bam = HSUSB_BAM,
-#else
-	.usb_active_bam = HSIC_BAM,
-#endif
+	.connections = &msm_usb_bam_connections[0],
+	.max_connections = sizeof(msm_usb_bam_connections) /
+		sizeof(struct usb_bam_pipe_connect),
 	.usb_bam_num_pipes = 16,
 };
 
diff --git a/arch/arm/mach-msm/board-zinc-gpiomux.c b/arch/arm/mach-msm/board-zinc-gpiomux.c
new file mode 100644
index 0000000..ac4daa8
--- /dev/null
+++ b/arch/arm/mach-msm/board-zinc-gpiomux.c
@@ -0,0 +1,29 @@
+/* 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/gpio.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+
+void __init msmzinc_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init_dt();
+	if (rc) {
+		pr_err("%s failed %d\n", __func__, rc);
+		return;
+	}
+}
diff --git a/arch/arm/mach-msm/board-zinc.c b/arch/arm/mach-msm/board-zinc.c
new file mode 100644
index 0000000..fa19e39
--- /dev/null
+++ b/arch/arm/mach-msm/board-zinc.c
@@ -0,0 +1,127 @@
+/* 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/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/memory.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_smd.h>
+#include <mach/restart.h>
+#include <mach/socinfo.h>
+#include <mach/clk-provider.h>
+#include "board-dt.h"
+#include "clock.h"
+#include "devices.h"
+#include "platsmp.h"
+
+static struct memtype_reserve msmzinc_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags  =       MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags  =       MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
+
+static int msmzinc_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+static struct reserve_info msmzinc_reserve_info __initdata = {
+	.memtype_reserve_table = msmzinc_reserve_table,
+	.paddr_to_memtype = msmzinc_paddr_to_memtype,
+};
+
+void __init msmzinc_reserve(void)
+{
+	reserve_info = &msmzinc_reserve_info;
+	of_scan_flat_dt(dt_scan_for_memory_reserve, msmzinc_reserve_table);
+	msm_reserve();
+}
+
+static void __init msmzinc_early_memory(void)
+{
+	reserve_info = &msmzinc_reserve_info;
+	of_scan_flat_dt(dt_scan_for_memory_hole, msmzinc_reserve_table);
+}
+
+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),
+};
+
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
+	.table = msm_clocks_dummy,
+	.size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msmzinc_add_drivers(void)
+{
+	msm_smd_init();
+	msm_clock_init(&msm_dummy_clock_init_data);
+}
+
+static void __init msmzinc_map_io(void)
+{
+	msm_map_zinc_io();
+}
+
+void __init msmzinc_init(void)
+{
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed\n", __func__);
+
+	msmzinc_init_gpiomux();
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+	msmzinc_add_drivers();
+}
+
+void __init msmzinc_init_very_early(void)
+{
+	msmzinc_early_memory();
+}
+
+static const char *msmzinc_dt_match[] __initconst = {
+	"qcom,msmzinc",
+	NULL
+};
+
+DT_MACHINE_START(MSMZINC_DT, "Qualcomm MSM ZINC (Flattened Device Tree)")
+	.map_io = msmzinc_map_io,
+	.init_irq = msm_dt_init_irq,
+	.init_machine = msmzinc_init,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_dt_timer,
+	.dt_compat = msmzinc_dt_match,
+	.reserve = msmzinc_reserve,
+	.init_very_early = msmzinc_init_very_early,
+	.restart = msm_restart,
+	.smp = &msm8974_smp_ops,
+MACHINE_END
diff --git a/arch/arm/mach-msm/boot_stats.c b/arch/arm/mach-msm/boot_stats.c
new file mode 100644
index 0000000..afb4374
--- /dev/null
+++ b/arch/arm/mach-msm/boot_stats.c
@@ -0,0 +1,100 @@
+/* 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/err.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/smp.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <mach/msm_iomap.h>
+
+#include "boot_stats.h"
+
+#define MSM_BOOT_STATS_IMEM_START	(MSM_IMEM_BASE+0x6b0)
+
+static void __iomem *mpm_counter_base;
+static uint32_t mpm_counter_freq;
+static struct boot_stats *boot_stats =
+				(void __iomem *)(MSM_BOOT_STATS_IMEM_START);
+
+static const struct of_device_id mpm_counter_of_match[]	= {
+	{ .compatible	= "qcom,mpm2-sleep-counter",	},
+	{},
+};
+
+static int mpm_parse_dt(void)
+{
+	struct device_node *np;
+	u32 freq;
+
+	np = of_find_matching_node(NULL, mpm_counter_of_match);
+	if (!np) {
+		pr_err("mpm_counter: can't find DT node\n");
+		return -ENODEV;
+	}
+
+	if (!of_property_read_u32(np, "clock-frequency", &freq))
+		mpm_counter_freq = freq;
+	else
+		return -ENODEV;
+
+	if (of_get_address(np, 0, NULL, NULL)) {
+		mpm_counter_base = of_iomap(np, 0);
+		if (!mpm_counter_base) {
+			pr_err("mpm_counter: cant map counter base\n");
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static void print_boot_stats(void)
+{
+	pr_info("KPI: Bootloader start count = %u\n",
+			boot_stats->bootloader_start);
+	pr_info("KPI: Bootloader end count = %u\n",
+			boot_stats->bootloader_end);
+	pr_info("KPI: Bootloader display count = %u\n",
+			boot_stats->bootloader_display);
+	pr_info("KPI: Bootloader load kernel count = %u\n",
+			boot_stats->bootloader_load_kernel);
+	pr_info("KPI: Kernel MPM timestamp = %u\n",
+			__raw_readl(mpm_counter_base));
+	pr_info("KPI: Kernel MPM Clock frequency = %u\n",
+			mpm_counter_freq);
+}
+
+int boot_stats_init(void)
+{
+	int ret;
+
+	if (!boot_stats)
+		return -ENODEV;
+
+	ret = mpm_parse_dt();
+	if (ret < 0)
+		return -ENODEV;
+
+	print_boot_stats();
+
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/boot_stats.h b/arch/arm/mach-msm/boot_stats.h
new file mode 100644
index 0000000..93e36a2
--- /dev/null
+++ b/arch/arm/mach-msm/boot_stats.h
@@ -0,0 +1,24 @@
+/* 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.
+ */
+
+struct boot_stats {
+	uint32_t bootloader_start;
+	uint32_t bootloader_end;
+	uint32_t bootloader_display;
+	uint32_t bootloader_load_kernel;
+};
+
+#ifdef CONFIG_MSM_BOOT_STATS
+int boot_stats_init(void);
+#else
+static inline int boot_stats_init(void) { return 0; }
+#endif
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 5b8ee92..2899d93 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3094,6 +3094,10 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33d000.etm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33e000.etm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33f000.etm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33c000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33d000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33e000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc33f000.jtagmm"),
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -3109,6 +3113,10 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.etm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.etm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33c000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33d000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33e000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33f000.jtagmm"),
 
 	/* HSUSB-OTG Clocks */
 	CLK_LOOKUP("xo",                          xo.c, "f9a55000.usb"),
@@ -3342,7 +3350,7 @@
 	"fdc84000.qcom,iommu"),
 	CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
-
+	CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, "f9bff000.qcom,msm-rng"),
 	CLK_LOOKUP("cam_gp0_clk", camss_gp0_clk.c, ""),
 	CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
 	CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
@@ -3350,6 +3358,15 @@
 	CLK_LOOKUP("", mmss_mmssnoc_bto_ahb_clk.c, ""),
 	CLK_LOOKUP("", mmss_mmssnoc_axi_clk.c, ""),
 	CLK_LOOKUP("", mmss_s0_axi_clk.c, ""),
+
+	/* Audio clocks */
+	CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.224"),
+	CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.4106"),
+	CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16384"),
+	CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16386"),
+	CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16390"),
+	CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16391"),
+
 };
 
 static struct clk_lookup msm_clocks_8226_rumi[] = {
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 5690730..0aee878 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -3047,35 +3047,65 @@
 	CLK_LOOKUP("mem_a_clk",	bimc_msmbus_a_clk.c,	"msm_bimc"),
 	CLK_LOOKUP("mem_clk",	bimc_acpu_a_clk.c,	""),
 
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etr"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tpiu"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-replicator"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etf"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-merg"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in0"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in1"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-kpss"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-mmss"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-stm"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm0"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm1"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm2"),
-	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm3"),
+	/* CoreSight clocks */
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc326000.tmc"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc320000.tpiu"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc324000.replicator"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc325000.tmc"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc323000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc355000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc302000.stm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34c000.etm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34d000.etm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34e000.etm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34f000.etm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc301000.csr"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc311000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc312000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc313000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc314000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc315000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc316000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc317000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc351000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc352000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc353000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc354000.cti"),
 
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etr"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tpiu"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-replicator"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etf"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-merg"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in0"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in1"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-kpss"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-mmss"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-stm"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm0"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm1"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm2"),
-	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm3"),
+
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc326000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc320000.tpiu"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc324000.replicator"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc325000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc323000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc355000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc302000.stm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34c000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34e000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34f000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc301000.csr"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc311000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc312000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc313000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc314000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc315000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc316000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc317000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc351000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc352000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc353000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc354000.cti"),
+
+
 
 	CLK_LOOKUP("core_clk_src", blsp1_qup1_spi_apps_clk_src.c, ""),
 	CLK_LOOKUP("core_clk_src", blsp1_qup2_spi_apps_clk_src.c, ""),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 78e3259..0657c21 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4851,6 +4851,7 @@
 	CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c,	  "msm_hsic_host"),
 	CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c,  "msm_hsic_host"),
 	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
+	CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16384"),
 	CLK_LOOKUP("ref_clk", div_clk2.c, "msm_smsc_hub"),
 	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c,     "msm_ehci_host"),
 	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c,   "msm_ehci_host"),
diff --git a/arch/arm/mach-msm/clock-mdss-8226.c b/arch/arm/mach-msm/clock-mdss-8226.c
new file mode 100644
index 0000000..e7eca7b
--- /dev/null
+++ b/arch/arm/mach-msm/clock-mdss-8226.c
@@ -0,0 +1,346 @@
+/* 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-mdss-8226.h"
+
+#define REG_R(addr)		readl_relaxed(addr)
+#define REG_W(data, addr)	writel_relaxed(data, addr)
+
+#define GDSC_PHYS		0xFD8C2304
+#define GDSC_SIZE		0x4
+
+#define DSI_PHY_PHYS		0xFD922800
+#define DSI_PHY_SIZE		0x00000800
+
+static unsigned char *mdss_dsi_base;
+static unsigned char *gdsc_base;
+static int pll_byte_clk_rate;
+static int pll_pclk_rate;
+static int pll_initialized;
+static struct clk *mdss_dsi_ahb_clk;
+static unsigned long dsi_pll_rate;
+
+void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
+{
+	BUG_ON(ahb_clk == NULL);
+
+	gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
+	if (!gdsc_base)
+		pr_err("%s: unable to remap gdsc base", __func__);
+
+	mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
+	if (!mdss_dsi_base)
+		pr_err("%s: unable to remap dsi base", __func__);
+
+	mdss_dsi_ahb_clk = ahb_clk;
+}
+
+#define PLL_POLL_MAX_READS 10
+#define PLL_POLL_TIMEOUT_US 50
+
+static int mdss_gdsc_enabled(void)
+{
+	if (!gdsc_base)
+		return 0;
+
+	return !!(readl_relaxed(gdsc_base) & BIT(31));
+}
+
+static int mdss_dsi_check_pll_lock(void)
+{
+	u32 status;
+
+	clk_prepare_enable(mdss_dsi_ahb_clk);
+	/* poll for PLL ready status */
+	if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
+				status,
+				((status & BIT(0)) == 1),
+				PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+		pr_err("%s: DSI PLL status=%x failed to Lock\n",
+				__func__, status);
+		pll_initialized = 0;
+	} else {
+		pll_initialized = 1;
+	}
+	clk_disable_unprepare(mdss_dsi_ahb_clk);
+
+	return pll_initialized;
+}
+
+static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
+{
+	if (pll_initialized) {
+		return pll_byte_clk_rate;
+	} else {
+		pr_err("%s: DSI PLL not configured\n", __func__);
+		return -EINVAL;
+	}
+}
+
+static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
+{
+	if (pll_initialized) {
+		return pll_pclk_rate;
+	} else {
+		pr_err("%s: Configure Byte clk first\n", __func__);
+		return -EINVAL;
+	}
+}
+
+static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
+{
+	if (pll_initialized) {
+		pll_pclk_rate = (rate * 3) / 2;
+		pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
+		return 0;
+	} else {
+		pr_err("%s: Configure Byte clk first\n", __func__);
+		return -EINVAL;
+	}
+}
+
+static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
+{
+	pr_debug("%s: rate=%ld\n", __func__, rate);
+
+	if (pll_initialized)
+		return 0;
+
+	REG_W(0x70, mdss_dsi_base + 0x0230); /* LPFC1 CFG */
+	REG_W(0x08, mdss_dsi_base + 0x022c); /* LPFR CFG */
+	REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
+	REG_W(0x00, mdss_dsi_base + 0x0204); /* postDiv1 */
+	REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
+	REG_W(0x03, mdss_dsi_base + 0x0224); /* postDiv2 */
+	REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
+	REG_W(0x0b, mdss_dsi_base + 0x023c); /* SDM CFG1 */
+	REG_W(0x00, mdss_dsi_base + 0x0240); /* SDM CFG2 */
+	REG_W(0x6c, mdss_dsi_base + 0x0244); /* SDM CFG3 */
+	REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
+	REG_W(0x31, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
+	REG_W(0x15, mdss_dsi_base + 0x0234); /* LPFC2 CFG */
+
+	REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
+	REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
+	REG_W(0x60, mdss_dsi_base + 0x028c); /* CAL CFG8 */
+	REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
+	REG_W(0xdd, mdss_dsi_base + 0x0294); /* CAL CFG10 */
+	REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
+
+	REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+	REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
+	REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
+	REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
+	REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
+	REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
+	REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
+	REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
+
+	dsi_pll_rate = rate;
+	pll_byte_clk_rate = rate;
+
+	pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
+	pll_initialized = 1;
+
+	return 0;
+}
+
+static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret;
+
+	clk_prepare_enable(mdss_dsi_ahb_clk);
+	ret = __mdss_dsi_pll_byte_set_rate(c, rate);
+	clk_disable_unprepare(mdss_dsi_ahb_clk);
+
+	return ret;
+}
+
+static void mdss_dsi_uniphy_pll_lock_detect_setting(void)
+{
+	REG_W(0x04, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
+	udelay(100);
+	REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
+	udelay(500);
+}
+
+static void mdss_dsi_uniphy_pll_sw_reset(void)
+{
+	REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
+	udelay(1);
+	REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
+	udelay(1);
+}
+
+static int __mdss_dsi_pll_enable(struct clk *c)
+{
+	u32 status;
+	u32 max_reads, timeout_us;
+	int i;
+
+	if (!pll_initialized) {
+		if (dsi_pll_rate)
+			__mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
+		else
+			pr_err("%s: Calling clk_en before set_rate\n",
+				__func__);
+	}
+
+	mdss_dsi_uniphy_pll_sw_reset();
+	/* PLL power up */
+	/* Add HW recommended delay between
+	   register writes for the update to propagate */
+	REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(20);
+	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(100);
+	REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(20);
+	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+	udelay(200);
+
+	for (i = 0; i < 3; i++) {
+		mdss_dsi_uniphy_pll_lock_detect_setting();
+		/* poll for PLL ready status */
+		max_reads = 5;
+		timeout_us = 100;
+		if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
+				   status,
+				   ((status & 0x01) == 1),
+					     max_reads, timeout_us)) {
+			pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+			       __func__, status);
+			pr_debug("%s:Trying to power UP PLL again\n",
+			       __func__);
+		} else
+			break;
+
+		mdss_dsi_uniphy_pll_sw_reset();
+		udelay(1000);
+		/* Add HW recommended delay between
+		   register writes for the update to propagate */
+		REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(20);
+		REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(100);
+		REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(20);
+		REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+		udelay(200);
+	}
+
+	if ((status & 0x01) != 1) {
+		pr_err("%s: DSI PLL status=%x failed to Lock\n",
+		       __func__, status);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: **** PLL Lock success\n", __func__);
+
+	return 0;
+}
+
+static void __mdss_dsi_pll_disable(void)
+{
+	writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
+	pr_debug("%s: **** disable pll Initialize\n", __func__);
+	pll_initialized = 0;
+}
+
+static DEFINE_SPINLOCK(dsipll_lock);
+static int dsipll_refcount;
+
+static void mdss_dsi_pll_disable(struct clk *c)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dsipll_lock, flags);
+	if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
+		goto out;
+	if (dsipll_refcount == 1)
+		__mdss_dsi_pll_disable();
+	dsipll_refcount--;
+out:
+	spin_unlock_irqrestore(&dsipll_lock, flags);
+}
+
+static int mdss_dsi_pll_enable(struct clk *c)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&dsipll_lock, flags);
+	if (dsipll_refcount == 0) {
+		ret = __mdss_dsi_pll_enable(c);
+		if (ret < 0)
+			goto out;
+	}
+	dsipll_refcount++;
+out:
+	spin_unlock_irqrestore(&dsipll_lock, flags);
+	return ret;
+}
+
+/* todo: Adjust these values appropriately */
+static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
+{
+	if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
+		c->rate = 59000000;
+		dsi_pll_rate = 59000000;
+		pll_byte_clk_rate = 59000000;
+		pll_pclk_rate = 117000000;
+		dsipll_refcount++;
+		return HANDOFF_ENABLED_CLK;
+	}
+
+	return HANDOFF_DISABLED_CLK;
+}
+
+/* todo: Adjust these values appropriately */
+static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
+{
+	if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
+		c->rate = 117000000;
+		dsipll_refcount++;
+		return HANDOFF_ENABLED_CLK;
+	}
+
+	return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_dsi_pixel_pll = {
+	.enable = mdss_dsi_pll_enable,
+	.disable = mdss_dsi_pll_disable,
+	.set_rate = mdss_dsi_pll_pixel_set_rate,
+	.round_rate = mdss_dsi_pll_pixel_round_rate,
+	.handoff = mdss_dsi_pll_pixel_handoff,
+};
+
+struct clk_ops clk_ops_dsi_byte_pll = {
+	.enable = mdss_dsi_pll_enable,
+	.disable = mdss_dsi_pll_disable,
+	.set_rate = mdss_dsi_pll_byte_set_rate,
+	.round_rate = mdss_dsi_pll_byte_round_rate,
+	.handoff = mdss_dsi_pll_byte_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/mach-msm/clock-mdss-8226.h
new file mode 100644
index 0000000..dcf4f92
--- /dev/null
+++ b/arch/arm/mach-msm/clock-mdss-8226.h
@@ -0,0 +1,22 @@
+/* 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_MDSS_8226
+#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+
+extern struct clk_ops clk_ops_dsi_byte_pll;
+extern struct clk_ops clk_ops_dsi_pixel_pll;
+
+void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
+void mdss_clk_ctrl_post_init(void);
+
+#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 91e96b7..8e7f1fa 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -192,11 +192,12 @@
 
 static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
 {
-	if (pll_initialized)
+	if (pll_initialized) {
+		pll_pclk_rate = (rate * 3) / 2;
+		pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
 		return 0;
-	else {
-		pr_err("%s: Configure Byte clk first\n",
-				__func__);
+	} else {
+		pr_err("%s: Configure Byte clk first\n", __func__);
 		return -EINVAL;
 	}
 }
@@ -256,11 +257,9 @@
 	REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
 
 	dsi_pll_rate = rate;
+	pll_byte_clk_rate = rate;
 
-	pll_byte_clk_rate = 53000000;
-	pll_pclk_rate = 105000000;
-
-	pr_debug("%s: **** PLL initialized success\n", __func__);
+	pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
 	pll_initialized = 1;
 
 	return 0;
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 46af77d..d02ab66 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -32,6 +32,17 @@
 
 #include "acpuclock.h"
 
+struct cpufreq_work_struct {
+	struct work_struct work;
+	struct cpufreq_policy *policy;
+	struct completion complete;
+	int frequency;
+	int status;
+};
+
+static DEFINE_PER_CPU(struct cpufreq_work_struct, cpufreq_work);
+static struct workqueue_struct *msm_cpufreq_wq;
+
 struct cpufreq_suspend_t {
 	struct mutex suspend_mutex;
 	int device_suspended;
@@ -99,6 +110,15 @@
 	return ret;
 }
 
+static void set_cpu_work(struct work_struct *work)
+{
+	struct cpufreq_work_struct *cpu_work =
+		container_of(work, struct cpufreq_work_struct, work);
+
+	cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
+	complete(&cpu_work->complete);
+}
+
 static int msm_cpufreq_target(struct cpufreq_policy *policy,
 				unsigned int target_freq,
 				unsigned int relation)
@@ -107,11 +127,17 @@
 	int index;
 	struct cpufreq_frequency_table *table;
 
+	struct cpufreq_work_struct *cpu_work = NULL;
+	cpumask_var_t mask;
+
 	if (!cpu_active(policy->cpu)) {
 		pr_info("cpufreq: cpu %d is not active.\n", policy->cpu);
 		return -ENODEV;
 	}
 
+	if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+		return -ENOMEM;
+
 	mutex_lock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
 
 	if (per_cpu(cpufreq_suspend, policy->cpu).device_suspended) {
@@ -133,9 +159,27 @@
 		policy->cpu, target_freq, relation,
 		policy->min, policy->max, table[index].frequency);
 
-	ret = set_cpu_freq(policy, table[index].frequency);
+	cpu_work = &per_cpu(cpufreq_work, policy->cpu);
+	cpu_work->policy = policy;
+	cpu_work->frequency = table[index].frequency;
+	cpu_work->status = -ENODEV;
+
+	cpumask_clear(mask);
+	cpumask_set_cpu(policy->cpu, mask);
+	if (cpumask_equal(mask, &current->cpus_allowed)) {
+		ret = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
+		goto done;
+	} else {
+		cancel_work_sync(&cpu_work->work);
+		INIT_COMPLETION(cpu_work->complete);
+		queue_work_on(policy->cpu, msm_cpufreq_wq, &cpu_work->work);
+		wait_for_completion(&cpu_work->complete);
+	}
+
+	ret = cpu_work->status;
 
 done:
+	free_cpumask_var(mask);
 	mutex_unlock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
 	return ret;
 }
@@ -218,6 +262,7 @@
 	int cur_freq;
 	int index;
 	struct cpufreq_frequency_table *table;
+	struct cpufreq_work_struct *cpu_work = NULL;
 
 	table = cpufreq_frequency_get_table(policy->cpu);
 	if (table == NULL)
@@ -247,7 +292,7 @@
 	    CPUFREQ_RELATION_H, &index) &&
 	    cpufreq_frequency_table_target(policy, table, cur_freq,
 	    CPUFREQ_RELATION_L, &index)) {
-		pr_info("%s: cpu%d at invalid freq: %d\n", __func__,
+		pr_info("cpufreq: cpu%d at invalid freq: %d\n",
 				policy->cpu, cur_freq);
 		return -EINVAL;
 	}
@@ -268,6 +313,10 @@
 	policy->cpuinfo.transition_latency =
 		acpuclk_get_switch_time() * NSEC_PER_USEC;
 
+	cpu_work = &per_cpu(cpufreq_work, policy->cpu);
+	INIT_WORK(&cpu_work->work, set_cpu_work);
+	init_completion(&cpu_work->complete);
+
 	return 0;
 }
 
@@ -355,6 +404,7 @@
 		per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
 	}
 
+	msm_cpufreq_wq = create_workqueue("msm-cpufreq");
 	register_hotcpu_notifier(&msm_cpufreq_cpu_notifier);
 
 	return cpufreq_register_driver(&msm_cpufreq_driver);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 327212e..3fa2d5e 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -598,6 +598,7 @@
 void msm_map_msm7x30_io(void);
 void msm_map_fsm9xxx_io(void);
 void msm_map_8974_io(void);
+void msm_map_zinc_io(void);
 void msm_map_msm8625_io(void);
 void msm_map_msm9625_io(void);
 void msm_init_irq(void);
@@ -606,6 +607,7 @@
 void msm_8974_reserve(void);
 void msm_8974_very_early(void);
 void msm_8974_init_gpiomux(void);
+void msmzinc_init_gpiomux(void);
 void msm9625_init_gpiomux(void);
 void msm_map_mpq8092_io(void);
 void mpq8092_init_gpiomux(void);
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index a104a42..d908a65 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -94,7 +94,7 @@
 
 extern int msm_iommu_map_extra(struct iommu_domain *domain,
 						unsigned long start_iova,
-						unsigned long phys_addr,
+						phys_addr_t phys_addr,
 						unsigned long size,
 						unsigned long page_size,
 						int cached);
@@ -104,7 +104,7 @@
 						unsigned long size,
 						unsigned long page_size);
 
-extern int msm_iommu_map_contig_buffer(unsigned long phys,
+extern int msm_iommu_map_contig_buffer(phys_addr_t phys,
 				unsigned int domain_no,
 				unsigned int partition_no,
 				unsigned long size,
@@ -148,7 +148,7 @@
 
 static inline int msm_iommu_map_extra(struct iommu_domain *domain,
 						unsigned long start_iova,
-						unsigned long phys_addr,
+						phys_addr_t phys_addr,
 						unsigned long size,
 						unsigned long page_size,
 						int cached)
@@ -163,7 +163,7 @@
 {
 }
 
-static inline int msm_iommu_map_contig_buffer(unsigned long phys,
+static inline int msm_iommu_map_contig_buffer(phys_addr_t phys,
 				unsigned int domain_no,
 				unsigned int partition_no,
 				unsigned long size,
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index d3574c8..fff7fa4 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/include/mach/memory.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -69,7 +69,6 @@
 #endif
 
 #ifndef __ASSEMBLY__
-void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment);
 void *allocate_contiguous_ebi(unsigned long, unsigned long, int);
 unsigned long allocate_contiguous_ebi_nomap(unsigned long, unsigned long);
 void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long);
@@ -97,11 +96,15 @@
 extern unsigned long memory_hole_offset;
 extern unsigned long memory_hole_start;
 extern unsigned long memory_hole_end;
+extern unsigned long memory_hole_align;
+extern unsigned long virtual_hole_start;
+extern unsigned long virtual_hole_end;
 #ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
 void find_memory_hole(void);
 
 #define MEM_HOLE_END_PHYS_OFFSET (memory_hole_end)
-#define MEM_HOLE_PAGE_OFFSET (PAGE_OFFSET + memory_hole_offset)
+#define MEM_HOLE_PAGE_OFFSET (PAGE_OFFSET + memory_hole_offset + \
+				memory_hole_align)
 
 #define __phys_to_virt(phys)				\
 	((MEM_HOLE_END_PHYS_OFFSET && ((phys) >= MEM_HOLE_END_PHYS_OFFSET)) ? \
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-zinc.h b/arch/arm/mach-msm/include/mach/msm_iomap-zinc.h
new file mode 100644
index 0000000..8456445
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-zinc.h
@@ -0,0 +1,45 @@
+/* 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 __ASM_ARCH_MSM_IOMAP_zinc_H
+#define __ASM_ARCH_MSM_IOMAP_zinc_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSMZINC_SHARED_RAM_PHYS     0x0FA00000
+
+#define MSMZINC_QGIC_DIST_PHYS	0xF9000000
+#define MSMZINC_QGIC_DIST_SIZE	SZ_4K
+
+#define MSMZINC_QGIC_CPU_PHYS	0xF9002000
+#define MSMZINC_QGIC_CPU_SIZE	SZ_4K
+
+#define MSMZINC_TLMM_PHYS	0xFD510000
+#define MSMZINC_TLMM_SIZE	SZ_16K
+
+#define MSMZINC_IMEM_PHYS       0xFC42B000
+#define MSMZINC_IMEM_SIZE       SZ_4K
+
+#ifdef CONFIG_DEBUG_MSMZINC_UART
+#define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS	0xF991E000
+#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 ebb096e..9cf9517 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -54,7 +54,8 @@
 	defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
 	defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
 	defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092) || \
-	defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8610)
+	defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8610) || \
+	defined(CONFIG_ARCH_MSMZINC)
 
 /* Unified iomap */
 
@@ -129,6 +130,7 @@
 #include "msm_iomap-8064.h"
 #include "msm_iomap-9615.h"
 #include "msm_iomap-8974.h"
+#include "msm_iomap-zinc.h"
 #include "msm_iomap-9625.h"
 #include "msm_iomap-8092.h"
 #include "msm_iomap-8226.h"
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 59908e6..c21f6e5 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -82,6 +82,7 @@
 #define APR_SVC_ADSP_CVS	0x0A
 #define APR_SVC_ADSP_CVP	0x0B
 #define APR_SVC_USM		0x0C
+#define APR_SVC_LSM		0x0D
 #define APR_SVC_VIDC		0x16
 #define APR_SVC_MAX		0x17
 
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 1f6ca66..67f643e 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -21,9 +21,8 @@
 struct subsys_device;
 
 enum {
-	RESET_SOC = 1,
+	RESET_SOC = 0,
 	RESET_SUBSYS_COUPLED,
-	RESET_SUBSYS_INDEPENDENT,
 	RESET_LEVEL_MAX
 };
 
@@ -60,7 +59,7 @@
 
 #if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
 
-extern int get_restart_level(void);
+extern int subsys_get_restart_level(struct subsys_device *dev);
 extern int subsystem_restart_dev(struct subsys_device *dev);
 extern int subsystem_restart(const char *name);
 extern int subsystem_crashed(const char *name);
@@ -75,7 +74,7 @@
 
 #else
 
-static inline int get_restart_level(void)
+static inline int subsys_get_restart_level(struct subsys_device *dev)
 {
 	return 0;
 }
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index b3fb8af..5a77d99 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,22 +14,36 @@
 #define _USB_BAM_H_
 #include "sps.h"
 #include <mach/ipa.h>
+#include <linux/usb/msm_hsusb.h>
 
-/**
- * SPS Pipes direction.
- *
- * USB_TO_PEER_PERIPHERAL	USB (as Producer) to other
- *                          peer peripheral.
- * PEER_PERIPHERAL_TO_USB	Other Peripheral to
- *                          USB (as consumer).
- */
+enum usb_bam {
+	SSUSB_BAM = 0,
+	HSUSB_BAM,
+	HSIC_BAM,
+	MAX_BAMS,
+};
+
+enum peer_bam {
+	A2_P_BAM = 0,
+	QDSS_P_BAM,
+	IPA_P_BAM,
+	MAX_PEER_BAMS,
+};
+
 enum usb_bam_pipe_dir {
 	USB_TO_PEER_PERIPHERAL,
 	PEER_PERIPHERAL_TO_USB,
 };
 
+enum usb_pipe_mem_type {
+	SPS_PIPE_MEM = 0,	/* Default, SPS dedicated pipe memory */
+	USB_PRIVATE_MEM,	/* USB's private memory */
+	SYSTEM_MEM,		/* System RAM, requires allocation */
+};
+
 struct usb_bam_connect_ipa_params {
-	u8 idx;
+	u8 src_idx;
+	u8 dst_idx;
 	u32 *src_pipe;
 	u32 *dst_pipe;
 	enum usb_bam_pipe_dir dir;
@@ -44,29 +58,100 @@
 			unsigned long data);
 };
 
+/**
+* struct usb_bam_event_info: suspend/resume event information.
+* @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 {
+	struct sps_register_event event;
+	int (*callback)(void *);
+	void *param;
+	struct work_struct event_w;
+};
+
+/**
+* struct usb_bam_pipe_connect: pipe connection information
+* between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+* either src BAM or dst BAM
+* @name: pipe description.
+* @mem_type: type of memory used for BAM FIFOs
+* @src_phy_addr: src bam physical address.
+* @src_pipe_index: src bam pipe index.
+* @dst_phy_addr: dst bam physical address.
+* @dst_pipe_index: dst bam pipe index.
+* @data_fifo_base_offset: data fifo offset.
+* @data_fifo_size: data fifo size.
+* @desc_fifo_base_offset: descriptor fifo offset.
+* @desc_fifo_size: descriptor fifo size.
+* @data_mem_buf: data fifo buffer.
+* @desc_mem_buf: descriptor fifo buffer.
+* @wake_event: event for wakeup.
+* @enabled: true if pipe is enabled.
+*/
+struct usb_bam_pipe_connect {
+	const char *name;
+	u32 pipe_num;
+	enum usb_pipe_mem_type mem_type;
+	enum usb_bam_pipe_dir dir;
+	enum usb_bam bam_type;
+	enum peer_bam peer_bam;
+	u32 src_phy_addr;
+	u32 src_pipe_index;
+	u32 dst_phy_addr;
+	u32 dst_pipe_index;
+	u32 data_fifo_base_offset;
+	u32 data_fifo_size;
+	u32 desc_fifo_base_offset;
+	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;
+	bool enabled;
+};
+
+/**
+ * struct msm_usb_bam_platform_data: pipe connection information
+ * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+ * either src BAM or dst BAM
+ * @connections: holds all pipe connections data.
+ * @usb_bam_num_pipes: max number of pipes to use.
+ * @active_conn_num: number of active pipe connections.
+ * @usb_base_address: BAM physical address.
+ * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
+ * @disable_clk_gating: Disable clock gating
+ */
+struct msm_usb_bam_platform_data {
+	struct usb_bam_pipe_connect *connections;
+	u8 max_connections;
+	int usb_bam_num_pipes;
+	u32 usb_base_address;
+	bool ignore_core_reset_ack;
+	bool reset_on_connect[MAX_BAMS];
+	bool disable_clk_gating;
+};
+
 #ifdef CONFIG_USB_BAM
 /**
- * Connect USB-to-Periperal SPS connection.
+ * Connect USB-to-Peripheral SPS connection.
  *
- * This function returns the allocated pipes number.
+ * This function returns the allocated pipe number.
  *
  * @idx - Connection index.
  *
- * @src_pipe_idx - allocated pipe index - USB as a
- *  source (output)
- *
- * @dst_pipe_idx - allocated pipe index - USB as a
- * destination (output)
+ * @bam_pipe_idx - allocated pipe index.
  *
  * @return 0 on success, negative value on error
  *
  */
-int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx);
+int usb_bam_connect(u8 idx, u32 *bam_pipe_idx);
 
 /**
  * Connect USB-to-IPA SPS connection.
  *
- * This function returns the allocated pipes number adn clnt handles.
+ * This function returns the allocated pipes number and clnt handles.
  *
  * @ipa_params - in/out parameters
  *
@@ -78,14 +163,12 @@
 /**
  * Disconnect USB-to-IPA SPS connection.
  *
- * @idx - Connection index.
- *
  * @ipa_params - in/out parameters
  *
  * @return 0 on success, negative value on error
  *
  */
-int usb_bam_disconnect_ipa(u8 idx,
+int usb_bam_disconnect_ipa(
 		struct usb_bam_connect_ipa_params *ipa_params);
 
 /**
@@ -99,13 +182,11 @@
  *
  */
 int usb_bam_register_wake_cb(u8 idx,
-	 int (*callback)(void *), void* param);
+	int (*callback)(void *), void *param);
 
 /**
  * Register a callback for peer BAM reset.
  *
- * @idx - Connection index.
- *
  * @callback - the callback function that will be called in USB
  *				driver upon a peer bam reset
  *
@@ -114,8 +195,7 @@
  * @return 0 on success, negative value on error
  *
  */
-int usb_bam_register_peer_reset_cb(u8 idx,
-	 int (*callback)(void *), void *param);
+int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param);
 
 /**
  * Disconnect USB-to-Periperal SPS connection.
@@ -129,9 +209,7 @@
 /**
  * Returns usb bam connection parameters.
  *
- * @conn_idx - Connection index.
- *
- * @usb_bam_pipe_dir - Usb pipe direction to/from peripheral.
+ * @idx - Connection index.
  *
  * @usb_bam_handle - Usb bam handle.
  *
@@ -143,16 +221,17 @@
  *
  * @data_fifo - Data fifo parameters.
  *
+ * @return pipe index on success, negative value on error.
  */
-void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
+int get_bam2bam_connection_info(u8 idx,
 	u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
 	struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo);
 
 /**
- * Resets the entire USB BAM.
+ * Resets the USB BAM that has A2 pipes
  *
  */
-int usb_bam_reset(void);
+int usb_bam_a2_reset(void);
 
 /**
  * Indicates if the client of the USB BAM is ready to start
@@ -162,9 +241,41 @@
  *
  */
 int usb_bam_client_ready(bool ready);
+/**
+* Returns qdss index from the connections array.
+*
+* @num - The qdss pipe number.
+*
+* @return pipe index on success, negative value on error
+*/
+int usb_bam_get_qdss_idx(u8 num);
+
+/**
+* Saves qdss core number.
+*
+* @qdss_core - The qdss core name.
+*/
+void usb_bam_set_qdss_core(const char *qdss_core);
+
+/**
+* Indicates if the client of the USB BAM is ready to start
+* sending/receiving transfers.
+*
+* @name - Core name (ssusb/hsusb/hsic).
+*
+* @client - Usb pipe peer (a2, ipa, qdss...)
+*
+* @dir - In (from peer to usb) or out (from usb to peer)
+*
+* @num - Pipe number.
+*
+* @return 0 on success, negative value on error
+*/
+int usb_bam_get_connection_idx(const char *name, enum peer_bam client,
+	enum usb_bam_pipe_dir dir, u32 num);
 
 #else
-static inline int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
+static inline int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
 {
 	return -ENODEV;
 }
@@ -175,7 +286,7 @@
 	return -ENODEV;
 }
 
-static inline int usb_bam_disconnect_ipa(u8 idx,
+static inline int usb_bam_disconnect_ipa(
 			struct usb_bam_connect_ipa_params *ipa_params)
 {
 	return -ENODEV;
@@ -187,8 +298,8 @@
 	return -ENODEV;
 }
 
-static inline int usb_bam_register_peer_reset_cb(u8 idx,
-	 int (*callback)(void *), void *param)
+static inline int usb_bam_register_peer_reset_cb(
+	int (*callback)(void *), void *param)
 {
 	return -ENODEV;
 }
@@ -198,15 +309,14 @@
 	return -ENODEV;
 }
 
-static inline void get_bam2bam_connection_info(u8 conn_idx,
-	enum usb_bam_pipe_dir pipe_dir, u32 *usb_bam_handle,
-	u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+static inline int get_bam2bam_connection_info(u8 idx,
+	u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
 	struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
 {
-	return;
+	return -ENODEV;
 }
 
-static inline int usb_bam_reset(void)
+static inline int usb_bam_a2_reset(void)
 {
 	return -ENODEV;
 }
@@ -216,5 +326,20 @@
 	return -ENODEV;
 }
 
+static inline int usb_bam_get_qdss_idx(u8 num)
+{
+	return -ENODEV;
+}
+
+static inline void usb_bam_set_qdss_core(const char *qdss_core)
+{
+	return;
+}
+
+static inline int usb_bam_get_connection_idx(const char *name,
+		enum peer_bam client, enum usb_bam_pipe_dir dir, u32 num)
+{
+	return -ENODEV;
+}
 #endif
 #endif				/* _USB_BAM_H_ */
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index fd096ec..c7b47a5 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -323,6 +323,29 @@
 }
 #endif /* CONFIG_ARCH_MSM8974 */
 
+#ifdef CONFIG_ARCH_MSMZINC
+static struct map_desc msm_zinc_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, MSMZINC),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSMZINC),
+	MSM_CHIP_DEVICE(TLMM, MSMZINC),
+	MSM_CHIP_DEVICE(IMEM, MSMZINC),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_MSMZINC_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_zinc_io(void)
+{
+	msm_shared_ram_phys = MSMZINC_SHARED_RAM_PHYS;
+	msm_map_io(msm_zinc_io_desc, ARRAY_SIZE(msm_zinc_io_desc));
+}
+#endif /* CONFIG_ARCH_MSMZINC */
+
 #ifdef CONFIG_ARCH_MSM7X30
 static struct map_desc msm7x30_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(VIC, MSM7X30),
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index f24dc87..5228abc 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -55,7 +55,7 @@
 
 int msm_iommu_map_extra(struct iommu_domain *domain,
 				unsigned long start_iova,
-				unsigned long phy_addr,
+				phys_addr_t phy_addr,
 				unsigned long size,
 				unsigned long page_size,
 				int prot)
@@ -135,7 +135,7 @@
 
 static int msm_iommu_map_iova_phys(struct iommu_domain *domain,
 				unsigned long iova,
-				unsigned long phys,
+				phys_addr_t phys,
 				unsigned long size,
 				int cached)
 {
@@ -167,7 +167,7 @@
 
 }
 
-int msm_iommu_map_contig_buffer(unsigned long phys,
+int msm_iommu_map_contig_buffer(phys_addr_t phys,
 				unsigned int domain_no,
 				unsigned int partition_no,
 				unsigned long size,
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 8fe69d9..953f941d 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -28,6 +28,7 @@
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/krait-regulator.h>
 #include <linux/debugfs.h>
+#include <linux/syscore_ops.h>
 #include <mach/msm_iomap.h>
 
 #include "spm.h"
@@ -292,27 +293,6 @@
 	return 0;
 }
 
-int krait_power_mdd_enable(int cpu_num, bool on)
-{
-	/*
-	 * Expected to be called when the cpu goes to retention mode as a part
-	 * of idle power collapse. IT is guaranteed that cpu won't be put in
-	 * retention while being hotplugged out
-	 */
-	struct krait_power_vreg *kvreg = per_cpu(krait_vregs, cpu_num);
-
-	if (!on && kvreg->mode == LDO_MODE) {
-		pr_debug("%s using LDO - cannot turn off MDD\n", kvreg->name);
-		return -EINVAL;
-	}
-
-	if (on && kvreg->mode == LDO_MODE)
-		return 0;
-
-	__krait_power_mdd_enable(kvreg, on);
-	return 0;
-}
-
 static int switch_to_using_hs(struct krait_power_vreg *kvreg)
 {
 	if (kvreg->mode == HS_MODE)
@@ -342,8 +322,6 @@
 	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
 				LDO_PWR_DWN_MASK, LDO_PWR_DWN_MASK);
 
-	/* turn off MDD since LDO is not used */
-	__krait_power_mdd_enable(kvreg, false);
 	kvreg->mode = HS_MODE;
 	pr_debug("%s using BHS\n", kvreg->name);
 	return 0;
@@ -362,9 +340,6 @@
 	if (kvreg->mode == LDO_MODE)
 		switch_to_using_hs(kvreg);
 
-	/* turn on MDD since LDO is being turned on */
-	__krait_power_mdd_enable(kvreg, true);
-
 	set_krait_ldo_uv(kvreg, kvreg->uV - kvreg->ldo_delta_uV);
 
 	/*
@@ -792,8 +767,7 @@
 	int rc;
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
-	if (kvreg->mode == LDO_MODE)
-		__krait_power_mdd_enable(kvreg, true);
+	__krait_power_mdd_enable(kvreg, true);
 	kvreg->online = true;
 	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load_uA);
 	if (rc < 0)
@@ -823,8 +797,7 @@
 		goto dis_err;
 
 	rc = _set_voltage(rdev, kvreg->uV, kvreg->uV);
-	if (kvreg->mode == LDO_MODE)
-		__krait_power_mdd_enable(kvreg, false);
+	__krait_power_mdd_enable(kvreg, false);
 dis_err:
 	mutex_unlock(&pvreg->krait_power_vregs_lock);
 	return rc;
@@ -889,6 +862,8 @@
 
 	/* setup the bandgap that configures the reference to the LDO */
 	writel_relaxed(0x00000190, kvreg->mdd_base + MDD_CONFIG_CTL);
+	/* Enable MDD */
+	writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
 	mb();
 }
 
@@ -1112,6 +1087,26 @@
 	{}
 };
 
+static int boot_cpu_mdd_off(void)
+{
+	struct krait_power_vreg *kvreg = per_cpu(krait_vregs, 0);
+
+	__krait_power_mdd_enable(kvreg, false);
+	return 0;
+}
+
+static void boot_cpu_mdd_on(void)
+{
+	struct krait_power_vreg *kvreg = per_cpu(krait_vregs, 0);
+
+	__krait_power_mdd_enable(kvreg, true);
+}
+
+static struct syscore_ops boot_cpu_mdd_ops = {
+	.suspend	= boot_cpu_mdd_off,
+	.resume		= boot_cpu_mdd_on,
+};
+
 static int __devinit krait_pdn_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -1172,6 +1167,7 @@
 	dent = debugfs_create_dir(KRAIT_REGULATOR_DRIVER_NAME, NULL);
 	debugfs_create_file("retention_uV",
 			0644, dent, the_gang, &retention_fops);
+	register_syscore_ops(&boot_cpu_mdd_ops);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 8194721..aa33f2c 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -28,6 +28,8 @@
 	MSM_LPM_LVL_DBG_IDLE_LIMITS = BIT(1),
 };
 
+#define MAX_STR_LEN 30
+
 static int msm_lpm_lvl_dbg_msk;
 
 module_param_named(
@@ -41,6 +43,48 @@
 static DEFINE_PER_CPU(int , lpm_permitted_level);
 static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
 
+static int msm_pm_get_sleep_mode_value(struct device_node *node,
+			const char *key, uint32_t *sleep_mode_val)
+{
+	int i;
+	struct lpm_lookup_table {
+		uint32_t modes;
+		const char *mode_name;
+	};
+	struct lpm_lookup_table pm_sm_lookup[] = {
+		{MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+			"wfi"},
+		{MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT,
+			"ramp_down_and_wfi"},
+		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+			"standalone_pc"},
+		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+			"pc"},
+		{MSM_PM_SLEEP_MODE_RETENTION,
+			"retention"},
+		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
+			"pc_suspend"},
+		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN,
+			"pc_no_xo_shutdown"}
+	};
+	int ret;
+	const char *mode_name;
+
+	ret = of_property_read_string(node, key, &mode_name);
+	if (!ret) {
+		ret = -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
+			if (!strncmp(mode_name, pm_sm_lookup[i].mode_name,
+				MAX_STR_LEN)) {
+				*sleep_mode_val = pm_sm_lookup[i].modes;
+				ret = 0;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
 static void msm_lpm_level_update(void)
 {
 	unsigned int lpm_level;
@@ -343,19 +387,19 @@
 		level->available = false;
 
 		key = "qcom,mode";
-		ret = of_property_read_u32(node, key, &val);
+		ret = msm_pm_get_sleep_mode_value(node, key, &val);
 		if (ret)
 			goto fail;
 		level->sleep_mode = val;
 
 		key = "qcom,xo";
-		ret = of_property_read_u32(node, key, &val);
+		ret = msm_lpm_get_xo_value(node, key, &val);
 		if (ret)
 			goto fail;
 		level->rs_limits.pxo = val;
 
 		key = "qcom,l2";
-		ret = of_property_read_u32(node, key, &val);
+		ret = msm_lpm_get_l2_cache_value(node, key, &val);
 		if (ret)
 			goto fail;
 		level->rs_limits.l2_cache = val;
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 60184b4..f0e5ebd 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -51,29 +51,39 @@
 #define MAX_RS_SIZE		(4)
 #define IS_RPM_CTL(rs) \
 	(!strncmp(rs->name, "rpm_ctl", MAX_RS_NAME))
+#define MAX_STR_LEN		30
 
 static bool msm_lpm_beyond_limits_vdd_dig(struct msm_rpmrs_limits *limits);
 static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits);
 static void msm_lpm_flush_vdd_dig(int notify_rpm);
 static void msm_lpm_notify_vdd_dig(struct msm_rpm_notifier_data
 					*rpm_notifier_cb);
+static int msm_lpm_init_value_vdd_dig(struct device_node *node,
+					char *key, uint32_t *default_value);
 
 static bool msm_lpm_beyond_limits_vdd_mem(struct msm_rpmrs_limits *limits);
 static void msm_lpm_aggregate_vdd_mem(struct msm_rpmrs_limits *limits);
 static void msm_lpm_flush_vdd_mem(int notify_rpm);
 static void msm_lpm_notify_vdd_mem(struct msm_rpm_notifier_data
 					*rpm_notifier_cb);
+static int msm_lpm_init_value_vdd_mem(struct device_node *node,
+					char *key, uint32_t *default_value);
+
 
 static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits);
 static void msm_lpm_aggregate_pxo(struct msm_rpmrs_limits *limits);
 static void msm_lpm_flush_pxo(int notify_rpm);
 static void msm_lpm_notify_pxo(struct msm_rpm_notifier_data
 					*rpm_notifier_cb);
+static int msm_lpm_init_value_pxo(struct device_node *node,
+				char *key, uint32_t *default_value);
 
 
 static bool msm_lpm_beyond_limits_l2(struct msm_rpmrs_limits *limits);
 static void msm_lpm_flush_l2(int notify_rpm);
 static void msm_lpm_aggregate_l2(struct msm_rpmrs_limits *limits);
+static int msm_lpm_init_value_l2(struct device_node *node,
+				char *key, uint32_t *default_value);
 
 static void msm_lpm_flush_rpm_ctl(int notify_rpm);
 
@@ -127,8 +137,14 @@
 	void (*flush)(int notify_rpm);
 	void (*notify)(struct msm_rpm_notifier_data *rpm_notifier_cb);
 	struct kobj_attribute ko_attr;
+	int (*init_value)(struct device_node *node,
+			char *key, uint32_t *default_value);
 };
 
+struct lpm_lookup_table {
+	uint32_t modes;
+	const char *mode_name;
+};
 
 static struct msm_lpm_resource msm_lpm_l2 = {
 	.name = "l2",
@@ -138,6 +154,7 @@
 	.notify = NULL,
 	.valid = false,
 	.ko_attr = RPMRS_ATTR(l2),
+	.init_value = msm_lpm_init_value_l2,
 };
 
 static struct msm_lpm_resource msm_lpm_vdd_dig = {
@@ -148,6 +165,7 @@
 	.notify = msm_lpm_notify_vdd_dig,
 	.valid = false,
 	.ko_attr = RPMRS_ATTR(vdd_dig),
+	.init_value = msm_lpm_init_value_vdd_dig,
 };
 
 static struct msm_lpm_resource msm_lpm_vdd_mem = {
@@ -158,6 +176,7 @@
 	.notify = msm_lpm_notify_vdd_mem,
 	.valid = false,
 	.ko_attr = RPMRS_ATTR(vdd_mem),
+	.init_value = msm_lpm_init_value_vdd_mem,
 };
 
 static struct msm_lpm_resource msm_lpm_pxo = {
@@ -168,6 +187,7 @@
 	.notify = msm_lpm_notify_pxo,
 	.valid = false,
 	.ko_attr = RPMRS_ATTR(pxo),
+	.init_value = msm_lpm_init_value_pxo,
 };
 
 static struct msm_lpm_resource *msm_lpm_resources[] = {
@@ -444,6 +464,12 @@
 				__func__, lpm);
 }
 
+static int msm_lpm_init_value_l2(struct device_node *node,
+					char *key, uint32_t *default_value)
+{
+	return msm_lpm_get_l2_cache_value(node, key, default_value);
+}
+
 static void msm_lpm_flush_l2(int notify_rpm)
 {
 	struct msm_lpm_resource *rs = &msm_lpm_l2;
@@ -451,6 +477,34 @@
 	msm_lpm_set_l2_mode(rs->sleep_value, notify_rpm);
 }
 
+int msm_lpm_get_l2_cache_value(struct device_node *node,
+			char *key, uint32_t *l2_val)
+{
+	int i;
+	struct lpm_lookup_table l2_mode_lookup[] = {
+		{MSM_LPM_L2_CACHE_HSFS_OPEN, "l2_cache_pc"},
+		{MSM_LPM_L2_CACHE_GDHS, "l2_cache_gdhs"},
+		{MSM_LPM_L2_CACHE_RETENTION, "l2_cache_retention"},
+		{MSM_LPM_L2_CACHE_ACTIVE, "l2_cache_active"}
+	};
+	const char *l2_str;
+	int ret;
+
+	ret = of_property_read_string(node, key, &l2_str);
+	if (!ret) {
+		ret = -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++) {
+			if (!strncmp(l2_str, l2_mode_lookup[i].mode_name,
+				MAX_STR_LEN)) {
+				*l2_val = l2_mode_lookup[i].modes;
+				ret = 0;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
 /* RPM CTL */
 static void msm_lpm_flush_rpm_ctl(int notify_rpm)
 {
@@ -484,6 +538,12 @@
 	return ret;
 }
 
+static int msm_lpm_init_value_vdd_dig(struct device_node *node,
+					char *key, uint32_t *default_value)
+{
+	return of_property_read_u32(node, key, default_value);
+}
+
 static void msm_lpm_aggregate_vdd_dig(struct msm_rpmrs_limits *limits)
 {
 	struct msm_lpm_resource *rs = &msm_lpm_vdd_dig;
@@ -570,6 +630,12 @@
 	msm_lpm_notify_common(rpm_notifier_cb, rs);
 }
 
+static int msm_lpm_init_value_vdd_mem(struct device_node *node,
+					char *key, uint32_t *default_value)
+{
+	return of_property_read_u32(node, key, default_value);
+}
+
 /*PXO*/
 static bool msm_lpm_beyond_limits_pxo(struct msm_rpmrs_limits *limits)
 {
@@ -628,11 +694,43 @@
 	msm_lpm_notify_common(rpm_notifier_cb, rs);
 }
 
+static int msm_lpm_init_value_pxo(struct device_node *node,
+				char *key, uint32_t *default_value)
+{
+	return msm_lpm_get_xo_value(node, key, default_value);
+}
+
 static inline bool msm_lpm_use_mpm(struct msm_rpmrs_limits *limits)
 {
 	return (limits->pxo == MSM_LPM_PXO_OFF);
 }
 
+int msm_lpm_get_xo_value(struct device_node *node,
+			char *key, uint32_t *xo_val)
+{
+	int  i;
+	struct lpm_lookup_table pxo_mode_lookup[] = {
+		{MSM_LPM_PXO_OFF, "xo_off"},
+		{MSM_LPM_PXO_ON, "xo_on"}
+	};
+	const char *xo_str;
+	int ret;
+
+	ret = of_property_read_string(node, key, &xo_str);
+	if (!ret) {
+		ret = -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(pxo_mode_lookup); i++) {
+			if (!strncmp(xo_str, pxo_mode_lookup[i].mode_name,
+				MAX_STR_LEN)) {
+				*xo_val = pxo_mode_lookup[i].modes;
+				ret = 0;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
 /* LPM levels interface */
 bool msm_lpm_level_beyond_limit(struct msm_rpmrs_limits *limits)
 {
@@ -797,7 +895,7 @@
 		struct msm_lpm_resource *rs = NULL;
 		const char *val;
 		int i;
-		uint32_t resource_type;
+		bool local_resource;
 
 		key = "qcom,name";
 		ret = of_property_read_string(node, key, &val);
@@ -822,8 +920,7 @@
 		}
 
 		key = "qcom,init-value";
-		ret = of_property_read_u32(node, key,
-				&rs->rs_data.default_value);
+		ret = rs->init_value(node, key, &rs->rs_data.default_value);
 		if (ret) {
 			pr_err("%s():Failed to read %s\n", __func__, key);
 			goto fail;
@@ -831,18 +928,13 @@
 
 		rs->rs_data.value = rs->rs_data.default_value;
 
-		key = "qcom,resource-type";
-		ret = of_property_read_u32(node, key, &resource_type);
-		if (ret) {
-			pr_err("Failed to read resource-type\n");
-			goto fail;
-		}
+		key = "qcom,local-resource-type";
+		local_resource = of_property_read_bool(node, key);
 
-		switch (resource_type) {
-		case MSM_LPM_RPM_RS_TYPE:
+		if (!local_resource) {
 			key = "qcom,type";
 			ret = of_property_read_u32(node, key,
-						&rs->rs_data.type);
+					&rs->rs_data.type);
 			if (ret) {
 				pr_err("Failed to read type\n");
 				goto fail;
@@ -873,15 +965,9 @@
 				goto fail;
 			}
 			/* fall through */
-
-		case MSM_LPM_LOCAL_RS_TYPE:
-			rs->valid = true;
-			break;
-		default:
-			pr_err("%s: Invalid resource type %d", __func__,
-					resource_type);
-			goto fail;
 		}
+
+		rs->valid = true;
 	}
 	msm_rpm_register_notifier(&msm_lpm_rpm_nblk);
 	msm_lpm_init_rpm_ctl();
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
index 1a2d72d..105cfe6 100644
--- a/arch/arm/mach-msm/lpm_resources.h
+++ b/arch/arm/mach-msm/lpm_resources.h
@@ -17,15 +17,15 @@
 #include "test-lpm.h"
 
 enum {
-	MSM_LPM_PXO_OFF = 0,
-	MSM_LPM_PXO_ON = 1,
+	MSM_LPM_PXO_OFF,
+	MSM_LPM_PXO_ON
 };
 
 enum {
-	MSM_LPM_L2_CACHE_HSFS_OPEN = 0,
-	MSM_LPM_L2_CACHE_GDHS = 1,
-	MSM_LPM_L2_CACHE_RETENTION = 2,
-	MSM_LPM_L2_CACHE_ACTIVE = 3,
+	MSM_LPM_L2_CACHE_HSFS_OPEN,
+	MSM_LPM_L2_CACHE_GDHS,
+	MSM_LPM_L2_CACHE_RETENTION,
+	MSM_LPM_L2_CACHE_ACTIVE,
 };
 
 struct msm_rpmrs_limits {
@@ -99,6 +99,24 @@
 uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
 
 /**
+ * msm_lpm_get_xo_value() - get the enum value for xo
+ * @node		pointer to the device node
+ * @key			pxo property key
+ * @xo_val		xo enum value
+ */
+int msm_lpm_get_xo_value(struct device_node *node,
+			char *key, uint32_t *xo_val);
+
+/**
+ * msm_lpm_get_l2_cache_value() - get the enum value for l2 cache
+ * @node                pointer to the device node
+ * @key                 l2 cache property key
+ * @l2_val              l2 mode enum value
+ */
+int msm_lpm_get_l2_cache_value(struct device_node *node,
+				char *key, uint32_t *l2_val);
+
+/**
  * struct msm_lpm_sleep_data - abstraction to get sleep data
  * @limits:	pointer to the msm_rpmrs_limits structure
  * @kernel_sleep:	kernel sleep time as decided by the power calculation
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index fd8c878..7474215 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -119,7 +119,7 @@
 
 	CHARM_DBG("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
 			 __func__);
-	if (get_restart_level() == RESET_SOC)
+	if (subsys_get_restart_level(charm_subsys) == RESET_SOC)
 		pm8xxx_stay_on();
 
 	charm_disable_irqs();
@@ -237,7 +237,7 @@
 static void charm_fatal_fn(struct work_struct *work)
 {
 	pr_info("Reseting the charm due to an errfatal\n");
-	if (get_restart_level() == RESET_SOC)
+	if (subsys_get_restart_level(charm_subsys) == RESET_SOC)
 		pm8xxx_stay_on();
 	subsystem_restart_dev(charm_subsys);
 }
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index f3bd34a..5f11806 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -107,34 +107,6 @@
 	outer_inv_range(pstart, pstart + length);
 }
 
-void * __init alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
-{
-	void *unused_addr = NULL;
-	unsigned long addr, tmp_size, unused_size;
-
-	/* Allocate maximum size needed, see where it ends up.
-	 * Then free it -- in this path there are no other allocators
-	 * so we can depend on getting the same address back
-	 * when we allocate a smaller piece that is aligned
-	 * at the end (if necessary) and the piece we really want,
-	 * then free the unused first piece.
-	 */
-
-	tmp_size = size + alignment - PAGE_SIZE;
-	addr = (unsigned long)alloc_bootmem(tmp_size);
-	free_bootmem(__pa(addr), tmp_size);
-
-	unused_size = alignment - (addr % alignment);
-	if (unused_size)
-		unused_addr = alloc_bootmem(unused_size);
-
-	addr = (unsigned long)alloc_bootmem(size);
-	if (unused_size)
-		free_bootmem(__pa(unused_addr), unused_size);
-
-	return (void *)addr;
-}
-
 char *memtype_name[] = {
 	"SMI_KERNEL",
 	"SMI",
diff --git a/arch/arm/mach-msm/msm_mpmctr.c b/arch/arm/mach-msm/msm_mpmctr.c
index 4ab82ab..cc0c1c3 100644
--- a/arch/arm/mach-msm/msm_mpmctr.c
+++ b/arch/arm/mach-msm/msm_mpmctr.c
@@ -54,7 +54,7 @@
 }
 
 static struct of_device_id msm_mpmctr_of_match[] = {
-	{.compatible = "qcom,mpm-counter"},
+	{.compatible = "qcom,mpm2-sleep-counter"},
 	{}
 };
 
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index d1538dd..1589623 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -31,6 +31,7 @@
 #include <linux/tick.h>
 #include <asm/smp_plat.h>
 #include "acpuclock.h"
+#include <linux/suspend.h>
 
 #define MAX_LONG_SIZE 24
 #define DEFAULT_RQ_POLL_JIFFIES 1
@@ -206,6 +207,34 @@
 	return NOTIFY_OK;
 }
 
+static int system_suspend_handler(struct notifier_block *nb,
+				unsigned long val, void *data)
+{
+	switch (val) {
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		rq_info.hotplug_disabled = 0;
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		rq_info.hotplug_disabled = 1;
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+	return NOTIFY_OK;
+}
+
+
+static ssize_t hotplug_disable_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	unsigned int val = 0;
+	val = rq_info.hotplug_disabled;
+	return snprintf(buf, MAX_LONG_SIZE, "%d\n", val);
+}
+
+static struct kobj_attribute hotplug_disabled_attr = __ATTR_RO(hotplug_disable);
+
 static void def_work_fn(struct work_struct *work)
 {
 	int64_t diff;
@@ -310,6 +339,7 @@
 	&def_timer_ms_attr.attr,
 	&run_queue_avg_attr.attr,
 	&run_queue_poll_ms_attr.attr,
+	&hotplug_disabled_attr.attr,
 	NULL,
 };
 
@@ -358,6 +388,7 @@
 	rq_info.def_timer_jiffies = DEFAULT_DEF_TIMER_JIFFIES;
 	rq_info.rq_poll_last_jiffy = 0;
 	rq_info.def_timer_last_jiffy = 0;
+	rq_info.hotplug_disabled = 0;
 	ret = init_rq_attribs();
 
 	rq_info.init = 1;
@@ -380,3 +411,16 @@
 	return ret;
 }
 late_initcall(msm_rq_stats_init);
+
+static int __init msm_rq_stats_early_init(void)
+{
+	/* Bail out if this is not an SMP Target */
+	if (!is_smp()) {
+		rq_info.init = 0;
+		return -ENOSYS;
+	}
+
+	pm_notifier(system_suspend_handler, 0);
+	return 0;
+}
+core_initcall(msm_rq_stats_early_init);
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index e797e2e..fdf39be 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -55,7 +55,7 @@
 
 struct msm_rtb_state {
 	struct msm_rtb_layout *rtb;
-	unsigned long phys;
+	phys_addr_t phys;
 	int nentries;
 	int size;
 	int enabled;
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 0579145..7f2f528 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -27,6 +27,7 @@
 	"2  Perf: Toggle PMU IRQ when CPU's are hotplugged\n"
 	"3  Perf: Correct irq for CPU hotplug detection\n"
 	"4  Perf: Check perf activity on correct CPU\n"
+	"5  Perf: Add DT support for L1 and L2 PMU\n"
 ;
 
 static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
index 34b9426..ad34457 100644
--- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -564,6 +564,14 @@
 	.pmu.attr_groups		= msm_l2_pmu_attr_grps,
 };
 
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id l2pmu_of_device_ids[] = {
+	{.compatible = "qcom,l2-pmu"},
+	{},
+};
+
 static int __devinit krait_l2_pmu_device_probe(struct platform_device *pdev)
 {
 	krait_l2_pmu.plat_device = pdev;
@@ -576,7 +584,8 @@
 
 static struct platform_driver krait_l2_pmu_driver = {
 	.driver		= {
-		.name	= "l2-arm-pmu",
+		.name	= "l2-pmu",
+		.of_match_table = l2pmu_of_device_ids,
 	},
 	.probe		= krait_l2_pmu_device_probe,
 };
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
index f78487a..efd5e21 100644
--- a/arch/arm/mach-msm/perf_event_msm_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -917,7 +917,7 @@
 
 static struct platform_driver scorpion_l2_pmu_driver = {
 	.driver		= {
-		.name	= "l2-arm-pmu",
+		.name	= "l2-pmu",
 	},
 	.probe		= scorpion_l2_pmu_device_probe,
 };
diff --git a/arch/arm/mach-msm/perf_event_msm_pl310.c b/arch/arm/mach-msm/perf_event_msm_pl310.c
index e2a580f..a0d96bf 100644
--- a/arch/arm/mach-msm/perf_event_msm_pl310.c
+++ b/arch/arm/mach-msm/perf_event_msm_pl310.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 ARM Limited
- * 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
@@ -415,9 +415,18 @@
 	return 0;
 }
 
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id l2pmu_of_device_ids[] = {
+	{.compatible = "qcom,l2-pmu"},
+	{},
+};
+
 static struct platform_driver l2x0pmu_driver = {
 	.driver		= {
-		.name	= "l2-arm-pmu",
+		.name	= "l2-pmu",
+		.of_match_table = l2pmu_of_device_ids,
 	},
 	.probe		= l2x0pmu_device_probe,
 };
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index fc9a0fa..958edaf 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -208,16 +208,24 @@
 	return ret;
 }
 
-static void pil_proxy_unvote(struct pil_desc *desc, unsigned long timeout)
+static void pil_proxy_unvote(struct pil_desc *desc, int immediate)
 {
 	struct pil_priv *priv = desc->priv;
+	unsigned long timeout;
 
-	if (proxy_timeout_ms >= 0)
+	if (proxy_timeout_ms == 0 && !immediate)
+		return;
+	else if (proxy_timeout_ms > 0)
 		timeout = proxy_timeout_ms;
+	else
+		timeout = desc->proxy_timeout;
 
-	if (timeout && desc->ops->proxy_unvote) {
+	if (desc->ops->proxy_unvote) {
 		if (WARN_ON(!try_module_get(desc->owner)))
 			return;
+
+		if (immediate)
+			timeout = 0;
 		schedule_delayed_work(&priv->proxy, msecs_to_jiffies(timeout));
 	}
 }
@@ -558,7 +566,6 @@
 	const struct elf32_hdr *ehdr;
 	struct pil_seg *seg;
 	const struct firmware *fw;
-	unsigned long proxy_timeout = desc->proxy_timeout;
 	struct pil_priv *priv = desc->priv;
 
 	/* Reinitialize for new image */
@@ -633,12 +640,11 @@
 	ret = desc->ops->auth_and_reset(desc);
 	if (ret) {
 		pil_err(desc, "Failed to bring out of reset\n");
-		proxy_timeout = 0; /* Remove proxy vote immediately on error */
 		goto err_boot;
 	}
 	pil_info(desc, "Brought out of reset\n");
 err_boot:
-	pil_proxy_unvote(desc, proxy_timeout);
+	pil_proxy_unvote(desc, ret);
 release_fw:
 	release_firmware(fw);
 out:
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index 0630e6a..65d60d6 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -142,9 +142,6 @@
 
 static void dsps_restart_handler(struct dsps_data *drv)
 {
-	pr_debug("%s: Restart lvl %d\n",
-		__func__, get_restart_level());
-
 	if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
 		pr_err("%s: DSPS already resetting. Count %d\n", __func__,
 		       atomic_read(&drv->crash_in_progress));
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index e7b4cea..bc40130 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -284,7 +284,8 @@
 	if (per_cpu(cold_boot_done, cpu) == false) {
 		if (machine_is_msm8974_sim() || machine_is_mpq8092_sim())
 			release_secondary_sim(0xf9088000, cpu);
-		else if (!machine_is_msm8974_rumi())
+		else if (!machine_is_msm8974_rumi() &&
+			 !machine_is_msmzinc_sim())
 			msm8974_release_secondary(0xf9088000, cpu);
 
 		per_cpu(cold_boot_done, cpu) = true;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 631da7d..717c057 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -131,6 +131,40 @@
 static bool msm_no_ramp_down_pc;
 static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
 
+static int msm_pm_get_pc_mode(struct device_node *node,
+		const char *key, uint32_t *pc_mode_val)
+{
+	struct pc_mode_of {
+		uint32_t mode;
+		char *mode_name;
+	};
+	int i;
+	struct pc_mode_of pc_modes[] = {
+				{MSM_PM_PC_TZ_L2_INT, "tz_l2_int"},
+				{MSM_PM_PC_NOTZ_L2_EXT, "no_tz_l2_ext"},
+				{MSM_PM_PC_TZ_L2_EXT , "tz_l2_ext"} };
+	int ret;
+	const char *pc_mode_str;
+
+	ret = of_property_read_string(node, key, &pc_mode_str);
+	if (ret) {
+		pr_debug("%s: Cannot read %s,defaulting to 0", __func__, key);
+		pc_mode_val = MSM_PM_PC_TZ_L2_INT;
+		ret = 0;
+	} else {
+		ret = -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(pc_modes); i++) {
+			if (!strncmp(pc_mode_str, pc_modes[i].mode_name,
+				strlen(pc_modes[i].mode_name))) {
+				*pc_mode_val = pc_modes[i].mode;
+				ret = 0;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
 /*
  * Write out the attribute.
  */
@@ -363,12 +397,10 @@
 
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
 	WARN_ON(ret);
-	krait_power_mdd_enable(smp_processor_id(), false);
 }
 
 static void msm_pm_config_hw_before_retention(void)
 {
-	krait_power_mdd_enable(smp_processor_id(), true);
 	return;
 }
 
@@ -622,7 +654,7 @@
 	int64_t time = 0;
 
 	if (msm_pm_use_sync_timer)
-		return ktime_to_ns(ktime_get());
+		return sched_clock();
 
 	time = msm_timer_get_sclk_time(period);
 	if (!time)
@@ -634,7 +666,7 @@
 static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
 {
 	if (msm_pm_use_sync_timer)
-		return ktime_to_ns(ktime_get()) - time;
+		return sched_clock() - time;
 
 	if (time != 0) {
 		int64_t end_time = msm_timer_get_sclk_time(NULL);
@@ -996,10 +1028,15 @@
 	 * up as they enter the deepest sleep mode, namely RPM assited power
 	 * collapse
 	 */
-	if (!enable)
+	if (!enable) {
+		preempt_disable();
 		smp_call_function_many(cpu_online_mask,
 				msm_pm_ack_retention_disable,
 				NULL, true);
+		preempt_enable();
+
+
+	}
 }
 EXPORT_SYMBOL(msm_pm_enable_retention);
 
@@ -1373,7 +1410,6 @@
 {
 	char *key = NULL;
 	struct dentry *dent = NULL;
-	uint32_t val = 0;
 	struct resource *res = NULL;
 	int i ;
 	struct msm_pm_init_data_type pdata_local;
@@ -1415,14 +1451,14 @@
 
 	} else {
 		key = "qcom,pc-mode";
-		ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+		ret = msm_pm_get_pc_mode(pdev->dev.of_node,
+				key,
+				&pdata_local.pc_mode);
 		if (ret) {
-			pr_debug("%s: Cannot read %s,defaulting to 0",
+			pr_debug("%s: Error reading key %s",
 					__func__, key);
-			val = MSM_PM_PC_TZ_L2_INT;
-			ret = 0;
+			return -EINVAL;
 		}
-		pdata_local.pc_mode = val;
 
 		key = "qcom,use-sync-timer";
 		pdata_local.use_sync_timer =
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index c77b19c..3559510 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.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
@@ -32,6 +32,42 @@
 static void (*msm_pm_boot_before_pc)(unsigned int cpu, unsigned long entry);
 static void (*msm_pm_boot_after_pc)(unsigned int cpu);
 
+
+static int msm_pm_get_boot_config_mode(struct device_node *dev,
+		const char *key, uint32_t *boot_config_mode)
+{
+	struct pm_lookup_table {
+		uint32_t boot_config_mode;
+		const char *boot_config_name;
+	};
+	const char *boot_config_str;
+	struct pm_lookup_table boot_config_lookup[] = {
+		{MSM_PM_BOOT_CONFIG_TZ, "tz"},
+		{MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS, "reset_vector_phys"},
+		{MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT, "reset_vector_virt"},
+		{MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR, "remap_boot_addr"}
+	};
+	int ret;
+	int i;
+
+	ret = of_property_read_string(dev, key, &boot_config_str);
+	if (!ret) {
+		ret = -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(boot_config_lookup); i++) {
+			if (!strncmp(boot_config_str,
+				boot_config_lookup[i].boot_config_name,
+				strlen(boot_config_lookup[i].boot_config_name))
+			) {
+				*boot_config_mode =
+					boot_config_lookup[i].boot_config_mode;
+				ret = 0;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
 static void msm_pm_write_boot_vector(unsigned int cpu, unsigned long address)
 {
 	msm_pm_boot_vector[cpu] = address;
@@ -235,11 +271,9 @@
 	vaddr_val = 0;
 
 	key = "qcom,mode";
-	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
-	if (ret) {
-		pr_err("Unable to read boot mode Err(%d).\n", ret);
-		return -ENODEV;
-	}
+	ret = msm_pm_get_boot_config_mode(pdev->dev.of_node, key, &val);
+	if (ret)
+		goto fail;
 	pdata.mode = val;
 
 	key = "qcom,phy-addr";
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 8ca3bb5..2d5110d 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,10 +18,10 @@
 /* end */
 
 enum {
-	MSM_PM_BOOT_CONFIG_TZ		     = 0,
-	MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
-	MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
-	MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR   = 3,
+	MSM_PM_BOOT_CONFIG_TZ		    ,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR  ,
 };
 
 struct msm_pm_boot_platform_data {
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 0a83ad6..8a043d8 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -95,11 +95,11 @@
 };
 
 enum msm_pm_pc_mode_type {
-	MSM_PM_PC_TZ_L2_INT = 0,   /*Power collapse terminates in TZ;
+	MSM_PM_PC_TZ_L2_INT,   /*Power collapse terminates in TZ;
 					integrated L2 cache controller */
-	MSM_PM_PC_NOTZ_L2_EXT = 1, /* Power collapse doesn't terminate in
+	MSM_PM_PC_NOTZ_L2_EXT, /* Power collapse doesn't terminate in
 					TZ; external L2 cache controller */
-	MSM_PM_PC_TZ_L2_EXT = 2,   /* Power collapse terminates in TZ;
+	MSM_PM_PC_TZ_L2_EXT,   /* Power collapse terminates in TZ;
 					external L2 cache controller */
 };
 
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index febeb19..57378c7 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,62 +15,6 @@
 #include <mach/irqs.h>
 #include <mach/socinfo.h>
 
-/*
- * If a GIC is present, then all IRQ's < 32 are PPI's and can only be
- * requested and free'd using the percpu IRQ API.
- * If a VIC is present, then only the traditional request, free API works.
- *
- * All MPCore's have GIC's. The Cortex A5 however may or may not be MPcore, but
- * it still has a GIC. Except, the 7x27a, which is an A5 and yet has a VIC.
- * So if the chip is A5 but does not have a GIC, default to the traditional
- * IRQ {request, free}_irq API.
- */
-
-#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) \
-	|| defined(CONFIG_ARCH_MSM8625) || \
-	(defined(CONFIG_ARCH_MSM_CORTEX_A5) && !defined(CONFIG_MSM_VIC))
-
-static DEFINE_PER_CPU(u32, pmu_irq_cookie);
-
-static int
-multicore_request_irq(int irq, irq_handler_t *handle_irq)
-{
-	int err = 0;
-	int cpu;
-
-	err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
-			&pmu_irq_cookie);
-
-	if (!err) {
-		for_each_cpu(cpu, cpu_online_mask) {
-			smp_call_function_single(cpu,
-					enable_irq_callback, &irq, 1);
-		}
-	}
-
-	return err;
-}
-
-static void
-multicore_free_irq(int irq)
-{
-	int cpu;
-
-	if (irq >= 0) {
-		for_each_cpu(cpu, cpu_online_mask) {
-			smp_call_function_single(cpu,
-					disable_irq_callback, &irq, 1);
-		}
-		free_percpu_irq(irq, &pmu_irq_cookie);
-	}
-}
-
-static struct arm_pmu_platdata multicore_data = {
-	.request_pmu_irq = multicore_request_irq,
-	.free_pmu_irq = multicore_free_irq,
-};
-#endif
-
 static struct resource cpu_pmu_resource[] = {
 	{
 		.start = INT_ARMQC_PERFMON,
@@ -89,7 +33,7 @@
 };
 
 static struct platform_device l2_pmu_device = {
-	.name		= "l2-arm-pmu",
+	.name		= "l2-pmu",
 	.id		= ARM_PMU_DEVICE_L2CC,
 	.resource	= l2_pmu_resource,
 	.num_resources	= ARRAY_SIZE(l2_pmu_resource),
@@ -98,7 +42,7 @@
 #endif
 
 static struct platform_device cpu_pmu_device = {
-	.name		= "cpu-arm-pmu",
+	.name		= "cpu-pmu",
 	.id		= ARM_PMU_DEVICE_CPU,
 	.resource	= cpu_pmu_resource,
 	.num_resources	= ARRAY_SIZE(cpu_pmu_resource),
@@ -120,7 +64,7 @@
 };
 
 static struct platform_device msm8625_cpu_pmu_device = {
-	.name		= "cpu-arm-pmu",
+	.name		= "cpu-pmu",
 	.id		= ARM_PMU_DEVICE_CPU,
 	.resource	= msm8625_cpu_pmu_resource,
 	.num_resources	= ARRAY_SIZE(msm8625_cpu_pmu_resource),
@@ -135,7 +79,7 @@
 };
 
 static struct platform_device msm8625_l2_pmu_device = {
-	.name		= "l2-arm-pmu",
+	.name		= "l2-pmu",
 	.id		= ARM_PMU_DEVICE_L2CC,
 	.resource	= msm8625_l2_pmu_resource,
 	.num_resources	= ARRAY_SIZE(msm8625_l2_pmu_resource),
@@ -156,7 +100,6 @@
 	 * handlers to call the percpu API.
 	 * Defaults to unicore API {request,free}_irq().
 	 * See arch/arm/kernel/perf_event.c
-	 * See Comment above on the A5 and MSM_VIC.
 	 */
 #if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) \
 	|| (defined(CONFIG_ARCH_MSM_CORTEX_A5) && !defined(CONFIG_MSM_VIC))
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 4c106c5..6e60db1 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,7 @@
 #include <linux/sysfs.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <sound/apr_audio-v2.h>
 #include <asm/mach-types.h>
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smd.h>
@@ -114,6 +115,11 @@
 		.name = "VIDC",
 		.idx = 9,
 		.id = APR_SVC_VIDC,
+	},
+	{
+		.name = "LSM",
+		.idx = 9,
+		.id = APR_SVC_LSM,
 		.client_id = APR_CLIENT_AUDIO,
 	},
 };
@@ -280,7 +286,6 @@
 		return -ENETRESET;
 	}
 
-
 	spin_lock_irqsave(&svc->w_lock, flags);
 	dest_id = svc->dest_id;
 	client_id = svc->client_id;
@@ -391,7 +396,8 @@
 		    svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
 		    svc == APR_SVC_USM ||
 		    svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
-		    svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+		    svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP ||
+		    svc == APR_SVC_LSM)
 			clnt = APR_CLIENT_AUDIO;
 		else if (svc == APR_SVC_VIDC)
 			clnt = APR_CLIENT_AUDIO;
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/ramdump.h
index e43ca12..3a960a1 100644
--- a/arch/arm/mach-msm/ramdump.h
+++ b/arch/arm/mach-msm/ramdump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
 	unsigned long size;
 };
 
+#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
 void *create_ramdump_device(const char *dev_name, struct device *parent);
 void destroy_ramdump_device(void *dev);
 int do_ramdump(void *handle, struct ramdump_segment *segments,
@@ -27,4 +28,28 @@
 int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
 		int nsegments);
 
+#else
+static inline void *create_ramdump_device(const char *dev_name,
+		struct device *parent)
+{
+	return NULL;
+}
+
+static inline void destroy_ramdump_device(void *dev)
+{
+}
+
+static inline int do_ramdump(void *handle, struct ramdump_segment *segments,
+		int nsegments)
+{
+	return -ENODEV;
+}
+
+static inline int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
+		int nsegments)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
+
 #endif
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index a67af45..d95f979 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -253,7 +253,7 @@
 		__raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
 		__raw_writel(1, msm_tmr0_base + WDT0_EN);
 	} else {
-		/* Needed for 8974: Reset GCC_WDOG_DEBUG register */
+		/* Needed to bypass debug image on some chips */
 		msm_disable_wdog_debug();
 		__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
 	}
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index cffb211..40ef20e 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -49,6 +49,7 @@
 
 #include "smd_private.h"
 #include "modem_notifier.h"
+#include "ramdump.h"
 
 #if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
 	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
@@ -178,7 +179,10 @@
 };
 static uint32_t num_smem_areas;
 static struct smem_area *smem_areas;
+static struct ramdump_segment *smem_ramdump_segments;
+static void *smem_ramdump_dev;
 static void *smem_range_check(phys_addr_t base, unsigned offset);
+static void *smd_dev;
 
 struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
 
@@ -977,10 +981,6 @@
 
 	SMx_POWER_INFO("%s: starting reset\n", __func__);
 
-	/* release any held spinlocks */
-	remote_spin_release(&remote_spinlock, restart_pid);
-	remote_spin_release_all(restart_pid);
-
 	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
 	if (!shared) {
 		pr_err("%s: allocation table not initialized\n", __func__);
@@ -3720,6 +3720,7 @@
 	struct device_node *node;
 	int ret;
 	const char *compatible;
+	struct ramdump_segment *ramdump_segments_tmp;
 	int subnode_num = 0;
 	resource_size_t irq_out_size;
 
@@ -3757,13 +3758,33 @@
 		}
 	}
 
+	/* initialize SSR ramdump regions */
+	key = "smem";
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+	if (!r) {
+		pr_err("%s: missing '%s'\n", __func__, key);
+		return -ENODEV;
+	}
+	ramdump_segments_tmp = kmalloc_array(num_smem_areas + 1,
+			sizeof(struct ramdump_segment), GFP_KERNEL);
+
+	if (!ramdump_segments_tmp) {
+		pr_err("%s: ramdump segment kmalloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto free_smem_areas;
+	}
+	ramdump_segments_tmp[0].address = r->start;
+	ramdump_segments_tmp[0].size = resource_size(r);
+
 	if (num_smem_areas) {
+
 		smem_areas = kmalloc(sizeof(struct smem_area) * num_smem_areas,
 					GFP_KERNEL);
+
 		if (!smem_areas) {
 			pr_err("%s: smem areas kmalloc failed\n", __func__);
-			num_smem_areas = 0;
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto free_smem_areas;
 		}
 		count = 1;
 		while (1) {
@@ -3775,6 +3796,16 @@
 				break;
 			aux_mem_base = r->start;
 			aux_mem_size = resource_size(r);
+
+			/*
+			 * Add to ram-dumps segments.
+			 * ramdump_segments_tmp[0] is the main SMEM region,
+			 * so auxiliary segments are indexed by count
+			 * instead of count - 1.
+			 */
+			ramdump_segments_tmp[count].address = aux_mem_base;
+			ramdump_segments_tmp[count].size = aux_mem_size;
+
 			SMD_DBG("%s: %s = %pa %pa", __func__, temp_string,
 					&aux_mem_base, &aux_mem_size);
 			smem_areas[count - 1].phys_addr = aux_mem_base;
@@ -3822,6 +3853,7 @@
 		++subnode_num;
 	}
 
+	smem_ramdump_segments = ramdump_segments_tmp;
 	return 0;
 
 rollback_subnodes:
@@ -3838,6 +3870,7 @@
 	}
 free_smem_areas:
 	num_smem_areas = 0;
+	kfree(ramdump_segments_tmp);
 	kfree(smem_areas);
 	smem_areas = NULL;
 	return ret;
@@ -3869,6 +3902,7 @@
 								__func__);
 				return ret;
 			}
+			smd_dev = &pdev->dev;
 		} else if (pdev->dev.platform_data) {
 			ret = smd_core_platform_init(pdev);
 			if (ret) {
@@ -3928,6 +3962,26 @@
 				__func__, notifier->processor,
 				notifier->name);
 
+		remote_spin_release(&remote_spinlock, notifier->processor);
+		remote_spin_release_all(notifier->processor);
+
+		if (smem_ramdump_dev) {
+			int ret;
+
+			SMD_INFO("%s: saving ramdump\n", __func__);
+			/*
+			 * XPU protection does not currently allow the
+			 * auxiliary memory regions to be dumped.  If this
+			 * changes, then num_smem_areas + 1 should be passed
+			 * into do_elf_ramdump() to dump all regions.
+			 */
+			ret = do_elf_ramdump(smem_ramdump_dev,
+					smem_ramdump_segments, 1);
+			if (ret < 0)
+				pr_err("%s: unable to dump smem %d\n", __func__,
+						ret);
+		}
+
 		smd_channel_reset(notifier->processor);
 	}
 
@@ -3940,12 +3994,20 @@
 	void *handle;
 	struct restart_notifier_block *nb;
 
+	smem_ramdump_dev = create_ramdump_device("smem-smd", smd_dev);
+	if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
+		pr_err("%s: Unable to create smem ramdump device.\n",
+			__func__);
+		smem_ramdump_dev = NULL;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
 		nb = &restart_notifiers[i];
 		handle = subsys_notif_register_notifier(nb->name, &nb->nb);
 		SMD_DBG("%s: registering notif for '%s', handle=%p\n",
 				__func__, nb->name, handle);
 	}
+
 	return 0;
 }
 late_initcall(modem_restart_late_init);
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index eb7aa8a..7eb9ead 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -645,8 +645,9 @@
 	struct smd_pkt_dev *smd_pkt_devp = priv;
 
 	if (smd_pkt_devp->ch == 0) {
-		pr_err("%s on a closed smd_pkt_dev id:%d\n",
-			__func__, smd_pkt_devp->i);
+		if (event != SMD_EVENT_CLOSE)
+			pr_err("%s on a closed smd_pkt_dev id:%d\n",
+					__func__, smd_pkt_devp->i);
 		return;
 	}
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 3da1c63..efbd8c6 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -29,6 +29,7 @@
 #include <mach/socinfo.h>
 
 #include "smd_private.h"
+#include "boot_stats.h"
 
 #define BUILD_ID_LENGTH 32
 
@@ -1139,6 +1140,7 @@
 	if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id))
 		cur_cpu = cpu_of_id[socinfo->v1.id];
 
+	boot_stats_init();
 	socinfo_print();
 
 	return 0;
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 29481d3..5fe7a29 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -72,6 +72,11 @@
 	[SUBSYS_ONLINE] = "ONLINE",
 };
 
+static const char * const restart_levels[] = {
+	[RESET_SOC] = "SYSTEM",
+	[RESET_SUBSYS_COUPLED] = "RELATED",
+};
+
 /**
  * struct subsys_tracking - track state of a subsystem or restart order
  * @p_state: private state of subsystem/order
@@ -123,6 +128,7 @@
  * @owner: module that provides @desc
  * @count: reference count of subsystem_get()/subsystem_put()
  * @id: ida
+ * @restart_level: restart level (0 - panic, 1 - related, 2 - independent, etc.)
  * @restart_order: order of other devices this devices restarts with
  * @dentry: debugfs directory for this device
  * @do_ramdump_on_put: ramdump on subsystem_put() if true
@@ -140,6 +146,7 @@
 	struct module *owner;
 	int count;
 	int id;
+	int restart_level;
 	struct subsys_soc_restart_order *restart_order;
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *dentry;
@@ -167,6 +174,38 @@
 	return snprintf(buf, PAGE_SIZE, "%s\n", subsys_states[state]);
 }
 
+static ssize_t
+restart_level_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int level = to_subsys(dev)->restart_level;
+	return snprintf(buf, PAGE_SIZE, "%s\n", restart_levels[level]);
+}
+
+static ssize_t restart_level_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct subsys_device *subsys = to_subsys(dev);
+	int i;
+	const char *p;
+
+	p = memchr(buf, '\n', count);
+	if (p)
+		count = p - buf;
+
+	for (i = 0; i < ARRAY_SIZE(restart_levels); i++)
+		if (!strncasecmp(buf, restart_levels[i], count)) {
+			subsys->restart_level = i;
+			return count;
+		}
+	return -EPERM;
+}
+
+int subsys_get_restart_level(struct subsys_device *dev)
+{
+	return dev->restart_level;
+}
+EXPORT_SYMBOL(subsys_get_restart_level);
+
 static void subsys_set_state(struct subsys_device *subsys,
 			     enum subsys_state state)
 {
@@ -199,6 +238,7 @@
 static struct device_attribute subsys_attrs[] = {
 	__ATTR_RO(name),
 	__ATTR_RO(state),
+	__ATTR(restart_level, 0644, restart_level_show, restart_level_store),
 	__ATTR_NULL,
 };
 
@@ -259,48 +299,6 @@
 static struct subsys_soc_restart_order **restart_orders;
 static int n_restart_orders;
 
-static int restart_level = RESET_SOC;
-
-int get_restart_level()
-{
-	return restart_level;
-}
-EXPORT_SYMBOL(get_restart_level);
-
-static int restart_level_set(const char *val, struct kernel_param *kp)
-{
-	int ret;
-	int old_val = restart_level;
-
-	if (cpu_is_msm9615()) {
-		pr_err("Only Phase 1 subsystem restart is supported\n");
-		return -EINVAL;
-	}
-
-	ret = param_set_int(val, kp);
-	if (ret)
-		return ret;
-
-	switch (restart_level) {
-	case RESET_SUBSYS_INDEPENDENT:
-		if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
-			pr_info("Phase 3 is currently unsupported. Using phase 2 instead.\n");
-			restart_level = RESET_SUBSYS_COUPLED;
-		}
-	case RESET_SUBSYS_COUPLED:
-	case RESET_SOC:
-		pr_info("Phase %d behavior activated.\n", restart_level);
-		break;
-	default:
-		restart_level = old_val;
-		return -EINVAL;
-	}
-	return 0;
-}
-
-module_param_call(restart_level, restart_level_set, param_get_int,
-			&restart_level, 0644);
-
 static struct subsys_soc_restart_order *
 update_restart_order(struct subsys_device *dev)
 {
@@ -484,7 +482,7 @@
 {
 	struct subsys_soc_restart_order *order = subsys->restart_order;
 
-	if (restart_level != RESET_SUBSYS_INDEPENDENT && order)
+	if (order)
 		return &order->track;
 	else
 		return &subsys->track;
@@ -603,7 +601,7 @@
 	 * This is because the subsystem list inside the relevant
 	 * restart order is not being traversed.
 	 */
-	if (restart_level != RESET_SUBSYS_INDEPENDENT && order) {
+	if (order) {
 		list = order->subsys_ptrs;
 		count = order->count;
 		track = &order->track;
@@ -662,7 +660,8 @@
 	struct subsys_tracking *track;
 	unsigned long flags;
 
-	pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
+	pr_debug("Restarting %s [level=%s]!\n", desc->name,
+			restart_levels[dev->restart_level]);
 
 	track = subsys_get_track(dev);
 	/*
@@ -708,13 +707,12 @@
 		return -EBUSY;
 	}
 
-	pr_info("Restart sequence requested for %s, restart_level = %d.\n",
-		name, restart_level);
+	pr_info("Restart sequence requested for %s, restart_level = %s.\n",
+		name, restart_levels[dev->restart_level]);
 
-	switch (restart_level) {
+	switch (dev->restart_level) {
 
 	case RESET_SUBSYS_COUPLED:
-	case RESET_SUBSYS_INDEPENDENT:
 		__subsystem_restart_dev(dev);
 		break;
 	case RESET_SOC:
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index f410e7f..3144113 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -1082,9 +1082,11 @@
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
 		gpt->status_mask = BIT(10);
 		dgt->status_mask = BIT(2);
-		gpt->freq = 32765;
-		gpt_hz = 32765;
-		sclk_hz = 32765;
+		if (!soc_class_is_apq8064()) {
+			gpt->freq = 32765;
+			gpt_hz = 32765;
+			sclk_hz = 32765;
+		}
 		if (!soc_class_is_msm8930() && !cpu_is_msm8960ab()) {
 			gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
 			dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
diff --git a/arch/arm/mach-msm/wdog_debug.c b/arch/arm/mach-msm/wdog_debug.c
index 8b39d26..cccca26 100644
--- a/arch/arm/mach-msm/wdog_debug.c
+++ b/arch/arm/mach-msm/wdog_debug.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,144 +10,31 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
+#include <linux/module.h>
 #include <mach/scm.h>
-#include <linux/slab.h>
 
-#define MODULE_NAME "wdog_debug"
-#define WDOG_DEBUG_EN 17
-#define GCC_WDOG_DEBUG_OFFSET 0x780
-
-struct msm_wdog_debug_data {
-	unsigned int __iomem phys_base;
-	size_t size;
-	void __iomem *base;
-	struct device *dev;
-};
-
-static struct msm_wdog_debug_data *wdog_data;
-
-void msm_disable_wdog_debug(void)
-{
-	unsigned long int value;
-
-	if (wdog_data == NULL)
-		return;
-	value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
-	value &= ~BIT(WDOG_DEBUG_EN);
-	writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
-
-	/* Ensure the WDOG_DEBUG_EN status has changed */
-	while (readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET) &
-		BIT(WDOG_DEBUG_EN))
-			;
-}
-EXPORT_SYMBOL(msm_disable_wdog_debug);
+#define SCM_WDOG_DEBUG_BOOT_PART	0x9
+#define BOOT_PART_EN_VAL		0x5D1
 
 void msm_enable_wdog_debug(void)
 {
-	unsigned long int value;
+	int ret;
 
-	if (wdog_data == NULL)
-		return;
-	value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
-	value |= BIT(WDOG_DEBUG_EN);
-	writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+	ret = scm_call_atomic2(SCM_SVC_BOOT,
+			       SCM_WDOG_DEBUG_BOOT_PART, 0, BOOT_PART_EN_VAL);
+	if (ret)
+		pr_err("failed to enable wdog debug\n");
 }
 EXPORT_SYMBOL(msm_enable_wdog_debug);
 
-static int __devexit msm_wdog_debug_remove(struct platform_device *pdev)
-{
-	kfree(wdog_data);
-	wdog_data = NULL;
-	pr_info("MSM wdog_debug Exit - Deactivated\n");
-	return 0;
-}
-
-static int __devinit msm_wdog_debug_dt_to_pdata(struct platform_device *pdev,
-					struct msm_wdog_debug_data *pdata)
-{
-	struct resource *wdog_resource;
-
-	wdog_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!wdog_resource) {
-		dev_err(&pdev->dev, \
-		"%s cannot allocate resource for wdog_debug\n", \
-		 __func__);
-		return -ENXIO;
-	}
-	pdata->size = resource_size(wdog_resource);
-	pdata->phys_base = wdog_resource->start;
-	if (unlikely(!(devm_request_region(&pdev->dev, pdata->phys_base,
-					pdata->size, "msm-wdog-debug")))) {
-		dev_err(&pdev->dev, "%s cannot reserve wdog_debug region\n",
-								__func__);
-		return -ENXIO;
-	}
-	pdata->base  = devm_ioremap(&pdev->dev, pdata->phys_base,
-							pdata->size);
-	if (!pdata->base) {
-		dev_err(&pdev->dev, "%s cannot map wdog register space\n",
-				__func__);
-		return -ENXIO;
-	}
-
-	return 0;
-}
-
-static int __devinit msm_wdog_debug_probe(struct platform_device *pdev)
+void msm_disable_wdog_debug(void)
 {
 	int ret;
-	if (!pdev->dev.of_node)
-		return -ENODEV;
-	wdog_data = kzalloc(sizeof(struct msm_wdog_debug_data), GFP_KERNEL);
-	if (!wdog_data)
-		return -ENOMEM;
-	ret = msm_wdog_debug_dt_to_pdata(pdev, wdog_data);
+
+	ret = scm_call_atomic2(SCM_SVC_BOOT,
+			       SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
 	if (ret)
-		goto err;
-	wdog_data->dev = &pdev->dev;
-	platform_set_drvdata(pdev, wdog_data);
-	return 0;
-err:
-	kzfree(wdog_data);
-	wdog_data = NULL;
-	return ret;
+		pr_err("failed to disable wdog debug\n");
 }
-
-static struct of_device_id msm_wdog_debug_match_table[] = {
-	{ .compatible = "qcom,msm-wdog-debug" },
-	{}
-};
-
-static struct platform_driver msm_wdog_debug_driver = {
-	.probe = msm_wdog_debug_probe,
-	.remove = msm_wdog_debug_remove,
-	.driver = {
-		.name = MODULE_NAME,
-		.owner = THIS_MODULE,
-		.of_match_table = msm_wdog_debug_match_table,
-	},
-};
-
-static int __devinit wdog_debug_init(void)
-{
-	return platform_driver_register(&msm_wdog_debug_driver);
-}
-module_init(wdog_debug_init);
-
-static void __exit wdog_debug_exit(void)
-{
-	platform_driver_unregister(&msm_wdog_debug_driver);
-}
-module_exit(wdog_debug_exit);
-
-MODULE_DESCRIPTION("MSM Driver to disable debug Image");
-MODULE_LICENSE("GPL v2");
+EXPORT_SYMBOL(msm_disable_wdog_debug);
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 2ec87b8..892b007 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -425,9 +425,9 @@
 		writel_relaxed(1, l2x0_base + L2X0_CTRL);
 	}
 
-		outer_cache.inv_range = l2x0_inv_range;
-		outer_cache.clean_range = l2x0_clean_range;
-		outer_cache.flush_range = l2x0_flush_range;
+	outer_cache.inv_range = l2x0_inv_range;
+	outer_cache.clean_range = l2x0_clean_range;
+	outer_cache.flush_range = l2x0_flush_range;
 	outer_cache.sync = l2x0_cache_sync;
 	outer_cache.flush_all = l2x0_flush_all;
 	outer_cache.inv_all = l2x0_inv_all;
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 38da432..f16f700 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -381,6 +381,10 @@
 EXPORT_SYMBOL(memory_hole_start);
 unsigned long memory_hole_end;
 EXPORT_SYMBOL(memory_hole_end);
+unsigned long memory_hole_align;
+EXPORT_SYMBOL(memory_hole_align);
+unsigned long virtual_hole_start;
+unsigned long virtual_hole_end;
 
 #ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
 void find_memory_hole(void)
@@ -388,6 +392,7 @@
 	int i;
 	unsigned long hole_start;
 	unsigned long hole_size;
+	unsigned long hole_end_virt;
 
 	/*
 	 * Find the start and end of the hole, using meminfo
@@ -420,7 +425,32 @@
 			}
 		}
 	}
+
 	memory_hole_offset = memory_hole_start - PHYS_OFFSET;
+	if (!IS_ALIGNED(memory_hole_start, SECTION_SIZE)) {
+		pr_err("memory_hole_start %lx is not aligned to %lx\n",
+			memory_hole_start, SECTION_SIZE);
+		BUG();
+	}
+	if (!IS_ALIGNED(memory_hole_end, SECTION_SIZE)) {
+		pr_err("memory_hole_end %lx is not aligned to %lx\n",
+			memory_hole_end, SECTION_SIZE);
+		BUG();
+	}
+
+	hole_end_virt = __phys_to_virt(memory_hole_end);
+
+	if ((!IS_ALIGNED(hole_end_virt, PMD_SIZE) &&
+	     IS_ALIGNED(memory_hole_end, PMD_SIZE)) ||
+	     (IS_ALIGNED(hole_end_virt, PMD_SIZE) &&
+	      !IS_ALIGNED(memory_hole_end, PMD_SIZE))) {
+		memory_hole_align = max(hole_end_virt & ~PMD_MASK,
+					memory_hole_end & ~PMD_MASK);
+		virtual_hole_start = hole_end_virt;
+		virtual_hole_end = hole_end_virt + memory_hole_align;
+		pr_info("Physical memory hole is not aligned. There will be a virtual memory hole from %lx to %lx\n",
+			virtual_hole_start, virtual_hole_end);
+	}
 }
 
 #endif
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index 0c6db93..2136f58 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -206,7 +206,5 @@
 
 DECLARE_PER_CPU(u64, decrementers_next_tb);
 
-extern void decrementer_check_overflow(void);
-
 #endif /* __KERNEL__ */
 #endif /* __POWERPC_TIME_H */
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index f8df241..2c42cd7 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -769,15 +769,6 @@
 	       clock->name, clock->mult, clock->shift);
 }
 
-void decrementer_check_overflow(void)
-{
-	u64 now = get_tb_or_rtc();
-	struct decrementer_clock *decrementer = &__get_cpu_var(decrementers);
-
-	if (now >= decrementer->next_tb)
-		set_dec(1);
-}
-
 static int decrementer_set_next_event(unsigned long evt,
 				      struct clock_event_device *dev)
 {
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index f34b238..276359e 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -20,8 +20,6 @@
 
 #include "entry.h"
 
-#include "entry.h"
-
 #ifdef CONFIG_SPARC64
 
 #include <linux/jump_label.h>
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index f493e52..146bb62 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -749,7 +749,7 @@
  */
 
 const int amd_erratum_400[] =
-	AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0x0f, 0x4, 0x2, 0xff, 0xf),
+	AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
 			    AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
 EXPORT_SYMBOL_GPL(amd_erratum_400);
 
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 3a8bbc5..ed91480 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -213,8 +213,7 @@
 	__be32 *prop;
 	char *name;
 
-	if (strncmp(uname, "region@", 7) != 0 || depth != 2 ||
-	    !of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
+	if (!of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
 		return 0;
 
 	prop = of_get_flat_dt_prop(node, "reg", &len);
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 13e40b9..48be2ad 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -417,6 +417,27 @@
 }
 
 static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t wakeup_prevent_sleep_time_show(struct device *dev,
+					      struct device_attribute *attr,
+					      char *buf)
+{
+	s64 msec = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		msec = ktime_to_ms(dev->power.wakeup->prevent_sleep_time);
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444,
+		   wakeup_prevent_sleep_time_show, NULL);
+#endif /* CONFIG_PM_AUTOSLEEP */
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_ADVANCED_DEBUG
@@ -511,6 +532,9 @@
 	&dev_attr_wakeup_total_time_ms.attr,
 	&dev_attr_wakeup_max_time_ms.attr,
 	&dev_attr_wakeup_last_time_ms.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+	&dev_attr_wakeup_prevent_sleep_time_ms.attr,
+#endif
 #endif
 	NULL,
 };
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 1132799..cbb463b 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -133,6 +133,7 @@
 	spin_lock_init(&ws->lock);
 	setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
 	ws->active = false;
+	ws->last_time = ktime_get();
 
 	spin_lock_irq(&events_lock);
 	list_add_rcu(&ws->entry, &wakeup_sources);
@@ -380,6 +381,8 @@
 	ws->active = true;
 	ws->active_count++;
 	ws->last_time = ktime_get();
+	if (ws->autosleep_enabled)
+		ws->start_prevent_time = ws->last_time;
 
 	/* Increment the counter of events in progress. */
 	cec = atomic_inc_return(&combined_event_count);
@@ -449,6 +452,17 @@
 }
 EXPORT_SYMBOL_GPL(pm_stay_awake);
 
+#ifdef CONFIG_PM_AUTOSLEEP
+static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now)
+{
+	ktime_t delta = ktime_sub(now, ws->start_prevent_time);
+	ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta);
+}
+#else
+static inline void update_prevent_sleep_time(struct wakeup_source *ws,
+					     ktime_t now) {}
+#endif
+
 /**
  * wakup_source_deactivate - Mark given wakeup source as inactive.
  * @ws: Wakeup source to handle.
@@ -490,6 +504,9 @@
 	del_timer(&ws->timer);
 	ws->timer_expires = 0;
 
+	if (ws->autosleep_enabled)
+		update_prevent_sleep_time(ws, now);
+
 	/*
 	 * Increment the counter of registered wakeup events and decrement the
 	 * couter of wakeup events in progress simultaneously.
@@ -660,29 +677,33 @@
 /**
  * pm_get_wakeup_count - Read the number of registered wakeup events.
  * @count: Address to store the value at.
+ * @block: Whether or not to block.
  *
- * Store the number of registered wakeup events at the address in @count.  Block
- * if the current number of wakeup events being processed is nonzero.
+ * Store the number of registered wakeup events at the address in @count.  If
+ * @block is set, block until the current number of wakeup events being
+ * processed is zero.
  *
- * Return 'false' if the wait for the number of wakeup events being processed to
- * drop down to zero has been interrupted by a signal (and the current number
- * of wakeup events being processed is still nonzero).  Otherwise return 'true'.
+ * Return 'false' if the current number of wakeup events being processed is
+ * nonzero.  Otherwise return 'true'.
  */
-bool pm_get_wakeup_count(unsigned int *count)
+bool pm_get_wakeup_count(unsigned int *count, bool block)
 {
 	unsigned int cnt, inpr;
-	DEFINE_WAIT(wait);
 
-	for (;;) {
-		prepare_to_wait(&wakeup_count_wait_queue, &wait,
-				TASK_INTERRUPTIBLE);
-		split_counters(&cnt, &inpr);
-		if (inpr == 0 || signal_pending(current))
-			break;
+	if (block) {
+		DEFINE_WAIT(wait);
 
-		schedule();
+		for (;;) {
+			prepare_to_wait(&wakeup_count_wait_queue, &wait,
+					TASK_INTERRUPTIBLE);
+			split_counters(&cnt, &inpr);
+			if (inpr == 0 || signal_pending(current))
+				break;
+
+			schedule();
+		}
+		finish_wait(&wakeup_count_wait_queue, &wait);
 	}
-	finish_wait(&wakeup_count_wait_queue, &wait);
 
 	split_counters(&cnt, &inpr);
 	*count = cnt;
@@ -714,6 +735,34 @@
 	return events_check_enabled;
 }
 
+#ifdef CONFIG_PM_AUTOSLEEP
+/**
+ * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
+ * @enabled: Whether to set or to clear the autosleep_enabled flags.
+ */
+void pm_wakep_autosleep_enabled(bool set)
+{
+	struct wakeup_source *ws;
+	ktime_t now = ktime_get();
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+		spin_lock_irq(&ws->lock);
+		if (ws->autosleep_enabled != set) {
+			ws->autosleep_enabled = set;
+			if (ws->active) {
+				if (set)
+					ws->start_prevent_time = now;
+				else
+					update_prevent_sleep_time(ws, now);
+			}
+		}
+		spin_unlock_irq(&ws->lock);
+	}
+	rcu_read_unlock();
+}
+#endif /* CONFIG_PM_AUTOSLEEP */
+
 static struct dentry *wakeup_sources_stats_dentry;
 
 /**
@@ -729,28 +778,37 @@
 	ktime_t max_time;
 	unsigned long active_count;
 	ktime_t active_time;
+	ktime_t prevent_sleep_time;
 	int ret;
 
 	spin_lock_irqsave(&ws->lock, flags);
 
 	total_time = ws->total_time;
 	max_time = ws->max_time;
+	prevent_sleep_time = ws->prevent_sleep_time;
 	active_count = ws->active_count;
 	if (ws->active) {
-		active_time = ktime_sub(ktime_get(), ws->last_time);
+		ktime_t now = ktime_get();
+
+		active_time = ktime_sub(now, ws->last_time);
 		total_time = ktime_add(total_time, active_time);
 		if (active_time.tv64 > max_time.tv64)
 			max_time = active_time;
+
+		if (ws->autosleep_enabled)
+			prevent_sleep_time = ktime_add(prevent_sleep_time,
+				ktime_sub(now, ws->start_prevent_time));
 	} else {
 		active_time = ktime_set(0, 0);
 	}
 
 	ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
-			"%lld\t\t%lld\t\t%lld\t\t%lld\n",
+			"%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
 			ws->name, active_count, ws->event_count,
 			ws->wakeup_count, ws->expire_count,
 			ktime_to_ms(active_time), ktime_to_ms(total_time),
-			ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
+			ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
+			ktime_to_ms(prevent_sleep_time));
 
 	spin_unlock_irqrestore(&ws->lock, flags);
 
@@ -767,7 +825,7 @@
 
 	seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
 		"expire_count\tactive_since\ttotal_time\tmax_time\t"
-		"last_change\n");
+		"last_change\tprevent_suspend_time\n");
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(ws, &wakeup_sources, entry)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e4b6b6b..ea2f2d2 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -703,8 +703,7 @@
 		break;
 
 	case HCI_ACLDATA_PKT:
-		if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 &&
-						hdev->conn_hash.le_num < 1))
+		if (!data->bulk_tx_ep)
 			return -ENODEV;
 
 		urb = usb_alloc_urb(0, GFP_ATOMIC);
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 73fe5d6..0f4d613 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -89,7 +89,7 @@
 	int n = -1, err = 0;
 
 	VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
-			      (void __user *)start, len));
+					(void __user *)start, len));
 	if (err)
 		goto bail;
 	VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
@@ -611,27 +611,28 @@
 static int get_dev(struct fastrpc_apps *me, struct fastrpc_device **rdev)
 {
 	struct hlist_head *head;
-	struct fastrpc_device *dev = 0;
-	struct hlist_node *n;
+	struct fastrpc_device *dev = 0, *devfree = 0;
+	struct hlist_node *pos, *n;
 	uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
 	int err = 0;
 
 	spin_lock(&me->hlock);
 	head = &me->htbl[h];
-	hlist_for_each_entry(dev, n, head, hn) {
+	hlist_for_each_entry_safe(dev, pos, n, head, hn) {
 		if (dev->tgid == current->tgid) {
 			hlist_del(&dev->hn);
+			devfree = dev;
 			break;
 		}
 	}
 	spin_unlock(&me->hlock);
-	VERIFY(err, dev != 0);
+	VERIFY(err, devfree != 0);
 	if (err)
 		goto bail;
-	*rdev = dev;
+	*rdev = devfree;
  bail:
 	if (err) {
-		free_dev(dev);
+		free_dev(devfree);
 		err = alloc_dev(rdev);
 	}
 	return err;
@@ -756,22 +757,23 @@
 	struct fastrpc_apps *me = &gfa;
 	uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
 	struct hlist_head *head;
-	struct hlist_node *pos;
-	struct fastrpc_device *dev;
+	struct hlist_node *pos, *n;
+	struct fastrpc_device *dev, *devfree;
 
  rnext:
-	dev = 0;
+	devfree = dev = 0;
 	spin_lock(&me->hlock);
 	head = &me->htbl[h];
-	hlist_for_each_entry(dev, pos, head, hn) {
+	hlist_for_each_entry_safe(dev, pos, n, head, hn) {
 		if (dev->tgid == current->tgid) {
 			hlist_del(&dev->hn);
+			devfree = dev;
 			break;
 		}
 	}
 	spin_unlock(&me->hlock);
-	if (dev) {
-		free_dev(dev);
+	if (devfree) {
+		free_dev(devfree);
 		goto rnext;
 	}
 	return;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 6ae5d03..6d28042 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -37,6 +37,7 @@
 unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE];
 struct mutex dci_log_mask_mutex;
 struct mutex dci_event_mask_mutex;
+struct mutex dci_health_mutex;
 
 #define DCI_CHK_CAPACITY(entry, new_data_len)				\
 ((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0)	\
@@ -211,6 +212,7 @@
 				entry = &(driver->dci_client_tbl[i]);
 				event_mask_ptr = entry->dci_event_mask +
 								 byte_index;
+				mutex_lock(&dci_health_mutex);
 				if (*event_mask_ptr & byte_mask) {
 					/* copy to client buffer */
 					if (DCI_CHK_CAPACITY(entry,
@@ -218,7 +220,9 @@
 						pr_err("diag: DCI event drop\n");
 						driver->dci_client_tbl[i].
 							dropped_events++;
-						return;
+						mutex_unlock(
+							&dci_health_mutex);
+						break;
 					}
 					driver->dci_client_tbl[i].
 							received_events++;
@@ -230,6 +234,7 @@
 						, total_event_len);
 					entry->data_len += 4 + total_event_len;
 				}
+				mutex_unlock(&dci_health_mutex);
 			}
 		}
 		temp_len += 2 + timestamp_len + payload_len_field + payload_len;
@@ -264,6 +269,7 @@
 			if (!log_mask_ptr)
 				return;
 			log_mask_ptr = log_mask_ptr + byte_offset;
+			mutex_lock(&dci_health_mutex);
 			if (*log_mask_ptr & byte_mask) {
 				pr_debug("\t log code %x needed by client %d",
 					 log_code, entry->client->tgid);
@@ -273,6 +279,8 @@
 						pr_err("diag: DCI log drop\n");
 						driver->dci_client_tbl[i].
 								dropped_logs++;
+						mutex_unlock(
+							&dci_health_mutex);
 						return;
 				}
 				driver->dci_client_tbl[i].received_logs++;
@@ -282,6 +290,7 @@
 					    buf + 4, *(uint16_t *)(buf + 2));
 				entry->data_len += 4 + *(uint16_t *)(buf + 2);
 			}
+			mutex_unlock(&dci_health_mutex);
 		}
 	}
 }
@@ -1028,6 +1037,8 @@
 	mutex_init(&driver->dci_mutex);
 	mutex_init(&dci_log_mask_mutex);
 	mutex_init(&dci_event_mask_mutex);
+	mutex_init(&dci_health_mutex);
+
 	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
 		success = diag_smd_constructor(&driver->smd_dci[i],
 					i, SMD_DCI_TYPE);
@@ -1082,5 +1093,118 @@
 	kfree(driver->req_tracking_tbl);
 	kfree(driver->dci_client_tbl);
 	kfree(driver->apps_dci_buf);
+	mutex_destroy(&driver->dci_mutex);
+	mutex_destroy(&dci_log_mask_mutex);
+	mutex_destroy(&dci_event_mask_mutex);
+	mutex_destroy(&dci_health_mutex);
 	destroy_workqueue(driver->diag_dci_wq);
 }
+
+int diag_dci_clear_log_mask()
+{
+	int i, j, k, err = DIAG_DCI_NO_ERROR;
+	uint8_t *log_mask_ptr, *update_ptr;
+
+	i = diag_dci_find_client_index(current->tgid);
+	if (i == DCI_CLIENT_INDEX_INVALID)
+		return DIAG_DCI_TABLE_ERR;
+
+	mutex_lock(&dci_log_mask_mutex);
+	create_dci_log_mask_tbl(
+			driver->dci_client_tbl[i].dci_log_mask);
+	memset(dci_cumulative_log_mask,
+				0x0, DCI_LOG_MASK_SIZE);
+	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+		update_ptr = dci_cumulative_log_mask;
+		if (driver->dci_client_tbl[i].client) {
+			log_mask_ptr =
+				driver->dci_client_tbl[i].dci_log_mask;
+			for (j = 0; j < 16; j++) {
+				*update_ptr = j;
+				*(update_ptr + 1) = 1;
+				update_ptr += 2;
+				log_mask_ptr += 2;
+				for (k = 0; k < 513; k++) {
+					*update_ptr |= *log_mask_ptr;
+					update_ptr++;
+					log_mask_ptr++;
+				}
+			}
+		}
+	}
+	mutex_unlock(&dci_log_mask_mutex);
+	err = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
+	return err;
+}
+
+int diag_dci_clear_event_mask()
+{
+	int i, j, err = DIAG_DCI_NO_ERROR;
+	uint8_t *event_mask_ptr, *update_ptr;
+
+	i = diag_dci_find_client_index(current->tgid);
+	if (i == DCI_CLIENT_INDEX_INVALID)
+		return DIAG_DCI_TABLE_ERR;
+
+	mutex_lock(&dci_event_mask_mutex);
+	memset(driver->dci_client_tbl[i].dci_event_mask,
+			0x0, DCI_EVENT_MASK_SIZE);
+	memset(dci_cumulative_event_mask,
+			0x0, DCI_EVENT_MASK_SIZE);
+	update_ptr = dci_cumulative_event_mask;
+	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+		event_mask_ptr =
+			driver->dci_client_tbl[i].dci_event_mask;
+		for (j = 0; j < DCI_EVENT_MASK_SIZE; j++)
+			*(update_ptr + j) |= *(event_mask_ptr + j);
+	}
+	mutex_unlock(&dci_event_mask_mutex);
+	err = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
+	return err;
+}
+
+int diag_dci_query_log_mask(uint16_t log_code)
+{
+	uint16_t item_num;
+	uint8_t equip_id, *log_mask_ptr, byte_mask;
+	int i, byte_index, offset;
+
+	equip_id = LOG_GET_EQUIP_ID(log_code);
+	item_num = LOG_GET_ITEM_NUM(log_code);
+	byte_index = item_num/8 + 2;
+	byte_mask = 0x01 << (item_num % 8);
+	offset = equip_id * 514;
+
+	i = diag_dci_find_client_index(current->tgid);
+	if (i != DCI_CLIENT_INDEX_INVALID) {
+		log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
+		log_mask_ptr = log_mask_ptr + offset + byte_index;
+		return ((*log_mask_ptr & byte_mask) == byte_mask) ?
+								1 : 0;
+	}
+	return 0;
+}
+
+
+int diag_dci_query_event_mask(uint16_t event_id)
+{
+	uint8_t *event_mask_ptr, byte_mask;
+	int i, byte_index, bit_index;
+	byte_index = event_id/8;
+	bit_index = event_id % 8;
+	byte_mask = 0x1 << bit_index;
+
+	i = diag_dci_find_client_index(current->tgid);
+	if (i != DCI_CLIENT_INDEX_INVALID) {
+		event_mask_ptr =
+		driver->dci_client_tbl[i].dci_event_mask;
+		event_mask_ptr = event_mask_ptr + byte_index;
+		if ((*event_mask_ptr & byte_mask) == byte_mask)
+			return 1;
+		else
+			return 0;
+	}
+	return 0;
+}
+
+
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 9187516..260cdf3 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -37,6 +37,7 @@
 
 extern unsigned int dci_max_reg;
 extern unsigned int dci_max_clients;
+extern struct mutex dci_health_mutex;
 
 struct dci_pkt_req_tracking_tbl {
 	int pid;
@@ -68,6 +69,13 @@
 	int reset_status;
 };
 
+/* This is used for querying DCI Log
+   or Event Mask */
+struct diag_log_event_stats {
+	uint16_t code;
+	int is_set;
+};
+
 enum {
 	DIAG_DCI_NO_ERROR = 1001,	/* No error */
 	DIAG_DCI_NO_REG,		/* Could not register */
@@ -96,10 +104,14 @@
 void clear_client_dci_cumulative_log_mask(int client_index);
 int diag_send_dci_log_mask(smd_channel_t *ch);
 void extract_dci_log(unsigned char *buf);
+int diag_dci_clear_log_mask(void);
+int diag_dci_query_log_mask(uint16_t log_code);
 /* DCI event streaming functions */
 void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
 void clear_client_dci_cumulative_event_mask(int client_index);
 int diag_send_dci_event_mask(smd_channel_t *ch);
 void extract_dci_events(unsigned char *buf);
 void create_dci_event_mask_tbl(unsigned char *tbl_buf);
+int diag_dci_clear_event_mask(void);
+int diag_dci_query_event_mask(uint16_t event_id);
 #endif
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index df28dab..a4eea54 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -30,7 +30,6 @@
 #define IN_BUF_SIZE		16384
 #define MAX_IN_BUF_SIZE	32768
 #define MAX_SYNC_OBJ_NAME_SIZE	32
-#define UINT32_MAX	UINT_MAX
 /* Size of the buffer used for deframing a packet
   reveived from the PC tool*/
 #define HDLC_MAX 4096
@@ -86,8 +85,8 @@
 #define SMD_DCI_TYPE 2
 
 /* Maximum number of pkt reg supported at initialization*/
-extern unsigned int diag_max_reg;
-extern unsigned int diag_threshold_reg;
+extern int diag_max_reg;
+extern int diag_threshold_reg;
 
 #define APPEND_DEBUG(ch) \
 do {							\
@@ -292,6 +291,7 @@
 	struct diag_request *write_ptr_mdm;
 #endif
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+	spinlock_t hsic_ready_spinlock;
 	/* common for all bridges */
 	struct work_struct diag_disconnect_work;
 	/* SGLTE variables */
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 3e3d8fd..65fc89f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -66,8 +66,8 @@
 static unsigned int max_clients = 15;
 static unsigned int threshold_client_limit = 30;
 /* This is the maximum number of pkt registrations supported at initialization*/
-unsigned int diag_max_reg = 600;
-unsigned int diag_threshold_reg = 750;
+int diag_max_reg = 600;
+int diag_threshold_reg = 750;
 
 /* Timer variables */
 static struct timer_list drain_timer;
@@ -516,149 +516,379 @@
 	*pnum_data = num_data;
 	return exit_stat;
 }
+
+static void diag_update_data_ready(int index)
+{
+	int clear_bit = 1;
+	unsigned long hsic_lock_flags;
+	unsigned long ready_lock_flags;
+	int i;
+
+	/*
+	 * Determine whether the data_ready USER_SPACE_DATA_TYPE bit
+	 * should be updated/cleared or not. There is a race condition that
+	 * can occur when in MEMORY_DEVICE_MODE with the hsic data.
+	 * When new hsic data arrives we prepare the data so it can
+	 * later be copied to userspace.  We set the USER_SPACE_DATA_TYPE
+	 * bit in data ready at that time. We later copy the hsic data
+	 * to userspace and clear the USER_SPACE_DATA_TYPE bit in
+	 * data ready. The race condition occurs if new data arrives (bit set)
+	 * while we are processing the current data and sending
+	 * it to userspace (bit clear).  The clearing of the bit can
+	 * overwrite the setting of the bit.
+	 */
+
+	spin_lock_irqsave(&driver->hsic_ready_spinlock, ready_lock_flags);
+	for (i = 0; i < MAX_HSIC_CH; i++) {
+		if (diag_hsic[i].hsic_inited) {
+			spin_lock_irqsave(&diag_hsic[i].hsic_spinlock,
+							hsic_lock_flags);
+			if ((diag_hsic[i].num_hsic_buf_tbl_entries > 0) &&
+				diag_hsic[i].hsic_device_enabled &&
+				diag_hsic[i].hsic_ch) {
+				/* New data do not clear the bit */
+				clear_bit = 0;
+			}
+			spin_unlock_irqrestore(&diag_hsic[i].hsic_spinlock,
+							hsic_lock_flags);
+			if (!clear_bit)
+				break;
+		}
+	}
+
+	if (clear_bit)
+		driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
+
+	spin_unlock_irqrestore(&driver->hsic_ready_spinlock, ready_lock_flags);
+}
 #else
 inline uint16_t diag_get_remote_device_mask(void) { return 0; }
 inline int diag_copy_remote(char __user *buf, size_t count, int *pret,
 			    int *pnum_data) { return 0; }
+static void diag_update_data_ready(int index)
+{
+	driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
+}
 #endif
 
-long diagchar_ioctl(struct file *filp,
-			   unsigned int iocmd, unsigned long ioarg)
+int diag_command_reg(unsigned long ioarg)
 {
-	int i, j, temp, success = -1, status, index = -1;
-	unsigned int count_entries = 0, interim_count = 0;
+	int i = 0, success = -EINVAL, j;
 	void *temp_buf;
-	uint16_t support_list = 0;
-	struct diag_dci_client_tbl *dci_params;
-	struct diag_dci_health_stats stats;
-
-	if (iocmd == DIAG_IOCTL_COMMAND_REG) {
-		struct bindpkt_params_per_process pkt_params;
-		struct bindpkt_params *params;
-		struct bindpkt_params *head_params;
-		if (copy_from_user(&pkt_params, (void *)ioarg,
-			   sizeof(struct bindpkt_params_per_process))) {
-			return -EFAULT;
-		}
-		if ((UINT32_MAX/sizeof(struct bindpkt_params)) <
-							 pkt_params.count) {
-			pr_warning("diag: integer overflow while multiply\n");
-			return -EFAULT;
-		}
-		params = kzalloc(pkt_params.count*sizeof(
-			struct bindpkt_params), GFP_KERNEL);
-		if (!params) {
-			pr_err("diag: unable to alloc memory\n");
-			return -ENOMEM;
-		} else
-			head_params = params;
-
-		if (copy_from_user(params, pkt_params.params,
-			   pkt_params.count*sizeof(struct bindpkt_params))) {
-			kfree(head_params);
-			return -EFAULT;
-		}
-		mutex_lock(&driver->diagchar_mutex);
-		for (i = 0; i < diag_max_reg; i++) {
-			if (driver->table[i].process_id == 0) {
-				diag_add_reg(i, params, &success,
-							 &count_entries);
-				if (pkt_params.count > count_entries) {
-					params++;
-				} else {
-					mutex_unlock(&driver->diagchar_mutex);
-					kfree(head_params);
-					return success;
-				}
+	unsigned int count_entries = 0, interim_count = 0;
+	struct bindpkt_params_per_process pkt_params;
+	struct bindpkt_params *params;
+	struct bindpkt_params *head_params;
+	if (copy_from_user(&pkt_params, (void *)ioarg,
+		   sizeof(struct bindpkt_params_per_process))) {
+		return -EFAULT;
+	}
+	if ((UINT_MAX/sizeof(struct bindpkt_params)) <
+						 pkt_params.count) {
+		pr_warn("diag: integer overflow while multiply\n");
+		return -EFAULT;
+	}
+	head_params = kzalloc(pkt_params.count*sizeof(
+		struct bindpkt_params), GFP_KERNEL);
+	if (!head_params) {
+		pr_err("diag: unable to alloc memory\n");
+		return -ENOMEM;
+	} else
+		params = head_params;
+	if (copy_from_user(params, pkt_params.params,
+		   pkt_params.count*sizeof(struct bindpkt_params))) {
+		kfree(head_params);
+		return -EFAULT;
+	}
+	mutex_lock(&driver->diagchar_mutex);
+	for (i = 0; i < diag_max_reg; i++) {
+		if (driver->table[i].process_id == 0) {
+			diag_add_reg(i, params, &success,
+						 &count_entries);
+			if (pkt_params.count > count_entries) {
+				params++;
+			} else {
+				kfree(head_params);
+				mutex_unlock(&driver->diagchar_mutex);
+				return success;
 			}
 		}
-		if (i < diag_threshold_reg) {
-			/* Increase table size by amount required */
+	}
+	if (i < diag_threshold_reg) {
+		/* Increase table size by amount required */
+		if (pkt_params.count >= count_entries) {
+			interim_count = pkt_params.count -
+						 count_entries;
+		} else {
+			pr_warn("diag: error in params count\n");
+			kfree(head_params);
+			mutex_unlock(&driver->diagchar_mutex);
+			return -EFAULT;
+		}
+		if (UINT_MAX - diag_max_reg >=
+						interim_count) {
+			diag_max_reg += interim_count;
+		} else {
+			pr_warn("diag: Integer overflow\n");
+			kfree(head_params);
+			mutex_unlock(&driver->diagchar_mutex);
+			return -EFAULT;
+		}
+		/* Make sure size doesnt go beyond threshold */
+		if (diag_max_reg > diag_threshold_reg) {
+			diag_max_reg = diag_threshold_reg;
+			pr_err("diag: best case memory allocation\n");
+		}
+		if (UINT_MAX/sizeof(struct diag_master_table) <
+							 diag_max_reg) {
+			pr_warn("diag: integer overflow\n");
+			kfree(head_params);
+			mutex_unlock(&driver->diagchar_mutex);
+			return -EFAULT;
+		}
+		temp_buf = krealloc(driver->table,
+				 diag_max_reg*sizeof(struct
+				 diag_master_table), GFP_KERNEL);
+		if (!temp_buf) {
+			pr_err("diag: Insufficient memory for reg.\n");
+
 			if (pkt_params.count >= count_entries) {
 				interim_count = pkt_params.count -
 							 count_entries;
 			} else {
-				pr_warning("diag: error in params count\n");
+				pr_warn("diag: params count error\n");
 				kfree(head_params);
 				mutex_unlock(&driver->diagchar_mutex);
 				return -EFAULT;
 			}
-			if (UINT32_MAX - diag_max_reg >=
-							interim_count) {
-				diag_max_reg += interim_count;
+			if (diag_max_reg >= interim_count) {
+				diag_max_reg -= interim_count;
 			} else {
-				pr_warning("diag: Integer overflow\n");
+				pr_warn("diag: Integer underflow\n");
 				kfree(head_params);
 				mutex_unlock(&driver->diagchar_mutex);
 				return -EFAULT;
 			}
-			/* Make sure size doesnt go beyond threshold */
-			if (diag_max_reg > diag_threshold_reg) {
-				diag_max_reg = diag_threshold_reg;
-				pr_info("diag: best case memory allocation\n");
-			}
-			if (UINT32_MAX/sizeof(struct diag_master_table) <
-								 diag_max_reg) {
-				pr_warning("diag: integer overflow\n");
-				kfree(head_params);
-				mutex_unlock(&driver->diagchar_mutex);
-				return -EFAULT;
-			}
-			temp_buf = krealloc(driver->table,
-					 diag_max_reg*sizeof(struct
-					 diag_master_table), GFP_KERNEL);
-			if (!temp_buf) {
-				pr_alert("diag: Insufficient memory for reg.\n");
-				mutex_unlock(&driver->diagchar_mutex);
-
-				if (pkt_params.count >= count_entries) {
-					interim_count = pkt_params.count -
-								 count_entries;
-				} else {
-					pr_warning("diag: params count error\n");
-					mutex_unlock(&driver->diagchar_mutex);
-					kfree(head_params);
-					return -EFAULT;
-				}
-				if (diag_max_reg >= interim_count) {
-					diag_max_reg -= interim_count;
-				} else {
-					pr_warning("diag: Integer underflow\n");
-					mutex_unlock(&driver->diagchar_mutex);
-					kfree(head_params);
-					return -EFAULT;
-				}
-				kfree(head_params);
-				return 0;
-			} else {
-				driver->table = temp_buf;
-			}
-			for (j = i; j < diag_max_reg; j++) {
-				diag_add_reg(j, params, &success,
-							 &count_entries);
-				if (pkt_params.count > count_entries) {
-					params++;
-				} else {
-					mutex_unlock(&driver->diagchar_mutex);
-					kfree(head_params);
-					return success;
-				}
-			}
 			kfree(head_params);
 			mutex_unlock(&driver->diagchar_mutex);
+			return 0;
 		} else {
-			mutex_unlock(&driver->diagchar_mutex);
-			kfree(head_params);
-			pr_err("Max size reached, Pkt Registration failed for"
-						" Process %d", current->tgid);
+			driver->table = temp_buf;
 		}
-		success = 0;
-	} else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) {
-		struct diagpkt_delay_params delay_params;
-		uint16_t interim_rsp_id;
-		int interim_size;
+		for (j = i; j < diag_max_reg; j++) {
+			diag_add_reg(j, params, &success,
+						 &count_entries);
+			if (pkt_params.count > count_entries) {
+				params++;
+			} else {
+				kfree(head_params);
+				mutex_unlock(&driver->diagchar_mutex);
+				return success;
+			}
+		}
+		kfree(head_params);
+		mutex_unlock(&driver->diagchar_mutex);
+	} else {
+		kfree(head_params);
+		mutex_unlock(&driver->diagchar_mutex);
+		pr_err("Max size reached, Pkt Registration failed for Process %d",
+					current->tgid);
+	}
+	success = 0;
+	return success;
+}
+
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode)
+{
+	if (old_mode == MEMORY_DEVICE_MODE && new_mode
+					== NO_LOGGING_MODE) {
+		diagfwd_disconnect_bridge(0);
+		diag_clear_hsic_tbl();
+	} else if (old_mode == NO_LOGGING_MODE && new_mode
+					== MEMORY_DEVICE_MODE) {
+		diagfwd_connect_bridge(0);
+	} else if (old_mode == USB_MODE && new_mode
+					 == NO_LOGGING_MODE) {
+		diagfwd_disconnect_bridge(0);
+	} else if (old_mode == NO_LOGGING_MODE && new_mode
+					== USB_MODE) {
+		diagfwd_connect_bridge(0);
+	} else if (old_mode == USB_MODE && new_mode
+					== MEMORY_DEVICE_MODE) {
+		diagfwd_cancel_hsic();
+		diagfwd_connect_bridge(0);
+	} else if (old_mode == MEMORY_DEVICE_MODE && new_mode
+					== USB_MODE) {
+		diag_clear_hsic_tbl();
+		diagfwd_cancel_hsic();
+		diagfwd_connect_bridge(0);
+	}
+}
+#else
+void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode)
+{
+
+}
+#endif
+
+#ifdef CONFIG_DIAG_SDIO_PIPE
+void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode)
+{
+	if (old_mode == MEMORY_DEVICE_MODE && new_mode
+					== NO_LOGGING_MODE) {
+		mutex_lock(&driver->diagchar_mutex);
+		driver->in_busy_sdio = 1;
+		mutex_unlock(&driver->diagchar_mutex);
+	} else if (old_mode == NO_LOGGING_MODE && new_mode
+					== MEMORY_DEVICE_MODE) {
+		mutex_lock(&driver->diagchar_mutex);
+		driver->in_busy_sdio = 0;
+		mutex_unlock(&driver->diagchar_mutex);
+		/* Poll SDIO channel to check for data */
+		if (driver->sdio_ch)
+			queue_work(driver->diag_sdio_wq,
+				&(driver->diag_read_sdio_work));
+	} else if (old_mode == USB_MODE && new_mode
+					== MEMORY_DEVICE_MODE) {
+		mutex_lock(&driver->diagchar_mutex);
+		driver->in_busy_sdio = 0;
+		mutex_unlock(&driver->diagchar_mutex);
+		/* Poll SDIO channel to check for data */
+		if (driver->sdio_ch)
+			queue_work(driver->diag_sdio_wq,
+				&(driver->diag_read_sdio_work));
+	}
+}
+#else
+void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode)
+{
+
+}
+#endif
+
+int diag_switch_logging(unsigned long ioarg)
+{
+	int i, temp, success = -EINVAL, status;
+	mutex_lock(&driver->diagchar_mutex);
+	temp = driver->logging_mode;
+	driver->logging_mode = (int)ioarg;
+	if (temp == driver->logging_mode) {
+		mutex_unlock(&driver->diagchar_mutex);
+		pr_err("diag: forbidden logging change requested\n");
+		return 0;
+	}
+
+	if (driver->logging_mode == MEMORY_DEVICE_MODE) {
+		diag_clear_hsic_tbl();
+		driver->mask_check = 1;
+		if (driver->socket_process) {
+			/*
+			 * Notify the socket logging process that we
+			 * are switching to MEMORY_DEVICE_MODE
+			 */
+			status = send_sig(SIGCONT,
+				 driver->socket_process, 0);
+			if (status) {
+				pr_err("diag: %s, Error notifying ",
+					__func__);
+				pr_err("socket process, status: %d\n",
+					status);
+			}
+		}
+	} else if (driver->logging_mode == SOCKET_MODE) {
+		driver->socket_process = current;
+	} else if (driver->logging_mode == CALLBACK_MODE) {
+		driver->callback_process = current;
+	}
+
+	if (driver->logging_mode == UART_MODE ||
+				driver->logging_mode == SOCKET_MODE ||
+				driver->logging_mode == CALLBACK_MODE) {
+		diag_clear_hsic_tbl();
+		driver->mask_check = 0;
+		driver->logging_mode = MEMORY_DEVICE_MODE;
+	}
+
+	driver->logging_process_id = current->tgid;
+	mutex_unlock(&driver->diagchar_mutex);
+
+	if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
+						== NO_LOGGING_MODE) {
+		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+			driver->smd_data[i].in_busy_1 = 0;
+			driver->smd_data[i].in_busy_2 = 0;
+		}
+		diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
+		diag_cmp_logging_modes_diagfwd_bridge(temp,
+							driver->logging_mode);
+	} else if (temp == NO_LOGGING_MODE && driver->logging_mode
+						== MEMORY_DEVICE_MODE) {
+		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+			driver->smd_data[i].in_busy_1 = 0;
+			driver->smd_data[i].in_busy_2 = 0;
+			/* Poll SMD channels to check for data*/
+			if (driver->smd_data[i].ch)
+				queue_work(driver->diag_wq,
+					&(driver->smd_data[i].
+						diag_read_smd_work));
+		}
+		diag_cmp_logging_modes_sdio_pipe(temp,
+						driver->logging_mode);
+		diag_cmp_logging_modes_diagfwd_bridge(temp,
+						driver->logging_mode);
+	} else if (temp == USB_MODE && driver->logging_mode
+						 == NO_LOGGING_MODE) {
+		diagfwd_disconnect();
+		diag_cmp_logging_modes_diagfwd_bridge(temp,
+						driver->logging_mode);
+	} else if (temp == NO_LOGGING_MODE && driver->logging_mode
+							== USB_MODE) {
+		diagfwd_connect();
+		diag_cmp_logging_modes_diagfwd_bridge(temp,
+						driver->logging_mode);
+	} else if (temp == USB_MODE && driver->logging_mode
+						== MEMORY_DEVICE_MODE) {
+		diagfwd_disconnect();
+		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+			driver->smd_data[i].in_busy_1 = 0;
+			driver->smd_data[i].in_busy_2 = 0;
+			/* Poll SMD channels to check for data*/
+			if (driver->smd_data[i].ch)
+				queue_work(driver->diag_wq,
+					&(driver->smd_data[i].
+						diag_read_smd_work));
+		}
+		diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
+		diag_cmp_logging_modes_diagfwd_bridge(temp,
+						driver->logging_mode);
+	} else if (temp == MEMORY_DEVICE_MODE &&
+			 driver->logging_mode == USB_MODE) {
+		diagfwd_connect();
+		diag_cmp_logging_modes_diagfwd_bridge(temp,
+						driver->logging_mode);
+	}
+	success = 1;
+	return success;
+}
+
+long diagchar_ioctl(struct file *filp,
+			   unsigned int iocmd, unsigned long ioarg)
+{
+	int i, result = -EINVAL, interim_size = 0, client_id = 0;
+	uint16_t support_list = 0, interim_rsp_id, remote_dev;
+	struct diag_dci_client_tbl *dci_params;
+	struct diag_dci_health_stats stats;
+	struct diag_log_event_stats le_stats;
+	struct diagpkt_delay_params delay_params;
+
+	switch (iocmd) {
+	case DIAG_IOCTL_COMMAND_REG:
+		result = diag_command_reg(ioarg);
+		break;
+	case DIAG_IOCTL_GET_DELAYED_RSP_ID:
 		if (copy_from_user(&delay_params, (void *)ioarg,
-					   sizeof(struct diagpkt_delay_params)))
+					sizeof(struct diagpkt_delay_params)))
 			return -EFAULT;
 		if ((delay_params.rsp_ptr) &&
 		 (delay_params.size == sizeof(delayed_rsp_id)) &&
@@ -672,9 +902,10 @@
 			if (copy_to_user((void *)delay_params.num_bytes_ptr,
 						 &interim_size, sizeof(int)))
 				return -EFAULT;
-			success = 0;
+			result = 0;
 		}
-	} else if (iocmd == DIAG_IOCTL_DCI_REG) {
+		break;
+	case DIAG_IOCTL_DCI_REG:
 		if (driver->dci_state == DIAG_DCI_NO_REG)
 			return DIAG_DCI_NO_REG;
 		if (driver->num_dci_client >= MAX_DCI_CLIENTS)
@@ -723,49 +954,47 @@
 		}
 		kfree(dci_params);
 		mutex_unlock(&driver->dci_mutex);
-		return driver->dci_client_id;
-	} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
-		success = -1;
-		/*
-		* Clear log/event masks and send updated
-		* masks to peripherals
-		*/
+		result = driver->dci_client_id;
+		break;
+	case DIAG_IOCTL_DCI_DEINIT:
+		result = -EIO;
+		/* Delete this process from DCI table */
 		mutex_lock(&driver->dci_mutex);
-		index = diag_dci_find_client_index(current->tgid);
-		if (index != DCI_CLIENT_INDEX_INVALID) {
+		i = diag_dci_find_client_index(current->tgid);
+		if (i == DCI_CLIENT_INDEX_INVALID) {
+			result = DIAG_DCI_NOT_SUPPORTED;
+		} else {
 			/* clear respective cumulative log masks */
-			clear_client_dci_cumulative_log_mask(index);
+			clear_client_dci_cumulative_log_mask(i);
 			/* send updated log mask to peripherals */
-			success =
+			result =
 			diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
-			if (success != DIAG_DCI_NO_ERROR) {
+			if (result != DIAG_DCI_NO_ERROR) {
 				mutex_unlock(&driver->dci_mutex);
-				return success;
+				return result;
 			}
 			/* clear respective cumulative event masks */
-			clear_client_dci_cumulative_event_mask(index);
+			clear_client_dci_cumulative_event_mask(i);
 			/* send updated event mask to peripherals */
-			success =
+			result =
 			diag_send_dci_event_mask(
 				driver->smd_cntl[MODEM_DATA].ch);
-			if (success != DIAG_DCI_NO_ERROR) {
+			if (result != DIAG_DCI_NO_ERROR) {
 				mutex_unlock(&driver->dci_mutex);
-				return success;
+				return result;
 			}
-		}
-		/* Delete this process from DCI table */
-		for (i = 0; i < dci_max_reg; i++)
-			if (driver->req_tracking_tbl[i].pid == current->tgid)
-				driver->req_tracking_tbl[i].pid = 0;
-		if (index != DCI_CLIENT_INDEX_INVALID) {
-			driver->dci_client_tbl[index].client = NULL;
-			success = index;
-		}
-		if (success >= 0)
+			result = i;
+			/* Delete this process from DCI table */
+			for (i = 0; i < dci_max_reg; i++)
+				if (driver->req_tracking_tbl[i].pid ==
+					 current->tgid)
+					driver->req_tracking_tbl[i].pid = 0;
+			driver->dci_client_tbl[result].client = NULL;
 			driver->num_dci_client--;
+		}
 		mutex_unlock(&driver->dci_mutex);
-		return success;
-	} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
+		break;
+	case DIAG_IOCTL_DCI_SUPPORT:
 		for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
 			if (driver->smd_dci[i].ch)
 				support_list |=
@@ -774,35 +1003,69 @@
 		if (copy_to_user((void *)ioarg, &support_list,
 							 sizeof(uint16_t)))
 			return -EFAULT;
-		return DIAG_DCI_NO_ERROR;
-	} else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) {
+		result = DIAG_DCI_NO_ERROR;
+		break;
+	case DIAG_IOCTL_DCI_HEALTH_STATS:
 		if (copy_from_user(&stats, (void *)ioarg,
 				 sizeof(struct diag_dci_health_stats)))
 			return -EFAULT;
-		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+		mutex_lock(&dci_health_mutex);
+		i = diag_dci_find_client_index(current->tgid);
+		if (i != DCI_CLIENT_INDEX_INVALID) {
 			dci_params = &(driver->dci_client_tbl[i]);
-			if (dci_params->client &&
-				dci_params->client->tgid == current->tgid) {
-				stats.dropped_logs = dci_params->dropped_logs;
-				stats.dropped_events =
-						 dci_params->dropped_events;
-				stats.received_logs = dci_params->received_logs;
-				stats.received_events =
-						 dci_params->received_events;
-				if (stats.reset_status) {
-					dci_params->dropped_logs = 0;
-					dci_params->dropped_events = 0;
-					dci_params->received_logs = 0;
-					dci_params->received_events = 0;
-				}
-				break;
+			stats.dropped_logs = dci_params->dropped_logs;
+			stats.dropped_events =
+					dci_params->dropped_events;
+			stats.received_logs =
+					dci_params->received_logs;
+			stats.received_events =
+					dci_params->received_events;
+			if (stats.reset_status) {
+				dci_params->dropped_logs = 0;
+				dci_params->dropped_events = 0;
+				dci_params->received_logs = 0;
+				dci_params->received_events = 0;
 			}
 		}
+		mutex_unlock(&dci_health_mutex);
 		if (copy_to_user((void *)ioarg, &stats,
 				   sizeof(struct diag_dci_health_stats)))
 			return -EFAULT;
-		return DIAG_DCI_NO_ERROR;
-	} else if (iocmd == DIAG_IOCTL_LSM_DEINIT) {
+		result = DIAG_DCI_NO_ERROR;
+		break;
+	case DIAG_IOCTL_DCI_LOG_STATUS:
+		if (copy_from_user(&le_stats, (void *)ioarg,
+				sizeof(struct diag_log_event_stats)))
+			return -EFAULT;
+		le_stats.is_set = diag_dci_query_log_mask(le_stats.code);
+		if (copy_to_user((void *)ioarg, &le_stats,
+				sizeof(struct diag_log_event_stats)))
+			return -EFAULT;
+		result = DIAG_DCI_NO_ERROR;
+		break;
+	case DIAG_IOCTL_DCI_EVENT_STATUS:
+		if (copy_from_user(&le_stats, (void *)ioarg,
+					sizeof(struct diag_log_event_stats)))
+			return -EFAULT;
+		le_stats.is_set = diag_dci_query_event_mask(le_stats.code);
+		if (copy_to_user((void *)ioarg, &le_stats,
+				sizeof(struct diag_log_event_stats)))
+			return -EFAULT;
+		result = DIAG_DCI_NO_ERROR;
+		break;
+	case DIAG_IOCTL_DCI_CLEAR_LOGS:
+		if (copy_from_user((void *)&client_id, (void *)ioarg,
+				sizeof(int)))
+			return -EFAULT;
+		result = diag_dci_clear_log_mask();
+		break;
+	case DIAG_IOCTL_DCI_CLEAR_EVENTS:
+		if (copy_from_user(&client_id, (void *)ioarg,
+				sizeof(int)))
+			return -EFAULT;
+		result = diag_dci_clear_event_mask();
+		break;
+	case DIAG_IOCTL_LSM_DEINIT:
 		for (i = 0; i < driver->num_clients; i++)
 			if (driver->client_map[i].pid == current->tgid)
 				break;
@@ -810,138 +1073,20 @@
 			return -EINVAL;
 		driver->data_ready[i] |= DEINIT_TYPE;
 		wake_up_interruptible(&driver->wait_q);
-		success = 1;
-	} else if (iocmd == DIAG_IOCTL_SWITCH_LOGGING) {
-		mutex_lock(&driver->diagchar_mutex);
-		temp = driver->logging_mode;
-		driver->logging_mode = (int)ioarg;
-		if (temp == driver->logging_mode) {
-			mutex_unlock(&driver->diagchar_mutex);
-			pr_alert("diag: forbidden logging change requested\n");
-			return 0;
-		}
-		if (driver->logging_mode == MEMORY_DEVICE_MODE) {
-			diag_clear_hsic_tbl();
-			driver->mask_check = 1;
-			if (driver->socket_process) {
-				/*
-				 * Notify the socket logging process that we
-				 * are switching to MEMORY_DEVICE_MODE
-				 */
-				status = send_sig(SIGCONT,
-					 driver->socket_process, 0);
-				if (status) {
-					pr_err("diag: %s, Error notifying ",
-						__func__);
-					pr_err("socket process, status: %d\n",
-						status);
-				}
-			}
-		}
-		if (driver->logging_mode == SOCKET_MODE)
-			driver->socket_process = current;
-		if (driver->logging_mode == CALLBACK_MODE)
-			driver->callback_process = current;
-		if (driver->logging_mode == UART_MODE ||
-			driver->logging_mode == SOCKET_MODE ||
-			driver->logging_mode == CALLBACK_MODE) {
-			diag_clear_hsic_tbl();
-			driver->mask_check = 0;
-			driver->logging_mode = MEMORY_DEVICE_MODE;
-		}
-		driver->logging_process_id = current->tgid;
-		mutex_unlock(&driver->diagchar_mutex);
-		if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
-							== NO_LOGGING_MODE) {
-			for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
-				driver->smd_data[i].in_busy_1 = 0;
-				driver->smd_data[i].in_busy_2 = 0;
-			}
-#ifdef CONFIG_DIAG_SDIO_PIPE
-			driver->in_busy_sdio = 1;
-#endif
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-			diagfwd_disconnect_bridge(0);
-			diag_clear_hsic_tbl();
-#endif
-		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
-							== MEMORY_DEVICE_MODE) {
-			for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
-				driver->smd_data[i].in_busy_1 = 0;
-				driver->smd_data[i].in_busy_2 = 0;
-				/* Poll SMD channels to check for data*/
-				if (driver->smd_data[i].ch)
-					queue_work(driver->diag_wq,
-						&(driver->smd_data[i].
-							diag_read_smd_work));
-			}
-#ifdef CONFIG_DIAG_SDIO_PIPE
-			driver->in_busy_sdio = 0;
-			/* Poll SDIO channel to check for data */
-			if (driver->sdio_ch)
-				queue_work(driver->diag_sdio_wq,
-					&(driver->diag_read_sdio_work));
-#endif
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-			diagfwd_connect_bridge(0);
-#endif
-		}
-#ifdef CONFIG_DIAG_OVER_USB
-		else if (temp == USB_MODE && driver->logging_mode
-							 == NO_LOGGING_MODE) {
-			diagfwd_disconnect();
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-			diagfwd_disconnect_bridge(0);
-#endif
-		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
-								== USB_MODE) {
-			diagfwd_connect();
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-			diagfwd_connect_bridge(0);
-#endif
-		} else if (temp == USB_MODE && driver->logging_mode
-							== MEMORY_DEVICE_MODE) {
-			diagfwd_disconnect();
-			for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
-				driver->smd_data[i].in_busy_1 = 0;
-				driver->smd_data[i].in_busy_2 = 0;
-				/* Poll SMD channels to check for data*/
-				if (driver->smd_data[i].ch)
-					queue_work(driver->diag_wq,
-						&(driver->smd_data[i].
-							diag_read_smd_work));
-			}
-#ifdef CONFIG_DIAG_SDIO_PIPE
-			driver->in_busy_sdio = 0;
-			/* Poll SDIO channel to check for data */
-			if (driver->sdio_ch)
-				queue_work(driver->diag_sdio_wq,
-					&(driver->diag_read_sdio_work));
-#endif
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-			diagfwd_cancel_hsic();
-			diagfwd_connect_bridge(0);
-#endif
-		} else if (temp == MEMORY_DEVICE_MODE &&
-				 driver->logging_mode == USB_MODE) {
-			diagfwd_connect();
-#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-			diag_clear_hsic_tbl();
-			diagfwd_cancel_hsic();
-			diagfwd_connect_bridge(0);
-#endif
-		}
-#endif /* DIAG over USB */
-		success = 1;
-	} else if (iocmd == DIAG_IOCTL_REMOTE_DEV) {
-		uint16_t remote_dev = diag_get_remote_device_mask();
+		result = 1;
+		break;
+	case DIAG_IOCTL_SWITCH_LOGGING:
+		result = diag_switch_logging(ioarg);
+		break;
+	case DIAG_IOCTL_REMOTE_DEV:
+		remote_dev = diag_get_remote_device_mask();
 		if (copy_to_user((void *)ioarg, &remote_dev, sizeof(uint16_t)))
-			success = -EFAULT;
+			result = -EFAULT;
 		else
-			success = 1;
+			result = 1;
+		break;
 	}
-
-	return success;
+	return result;
 }
 
 static int diagchar_read(struct file *file, char __user *buf, size_t count,
@@ -1068,7 +1213,7 @@
 		/* copy number of data fields */
 		COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
 		ret -= 4;
-		driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
+		diag_update_data_ready(index);
 		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
 			if (driver->smd_data[i].ch)
 				queue_work(driver->diag_wq,
@@ -1654,6 +1799,7 @@
 		diag_masks_init();
 		diagfwd_init();
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+		spin_lock_init(&driver->hsic_ready_spinlock);
 		diagfwd_bridge_init(HSIC);
 		diagfwd_bridge_init(HSIC_2);
 		/* register HSIC device */
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 2aca8cf..6a14143 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -351,12 +351,32 @@
 	diag_smd_send_req(smd_info);
 }
 
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+static void diag_mem_dev_mode_ready_update(int index, int hsic_updated)
+{
+	if (hsic_updated) {
+		unsigned long flags;
+		spin_lock_irqsave(&driver->hsic_ready_spinlock, flags);
+		driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
+		spin_unlock_irqrestore(&driver->hsic_ready_spinlock, flags);
+	} else {
+		driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
+	}
+}
+#else
+static void diag_mem_dev_mode_ready_update(int index, int hsic_updated)
+{
+	(void) hsic_updated;
+	driver->data_ready[index] |= USER_SPACE_DATA_TYPE;
+}
+#endif
 int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
 {
 	int i, err = 0, index;
 	index = 0;
 
 	if (driver->logging_mode == MEMORY_DEVICE_MODE) {
+		int hsic_updated = 0;
 		if (data_type == APPS_DATA) {
 			for (i = 0; i < driver->poolsize_write_struct; i++)
 				if (driver->buf_tbl[i].length == 0) {
@@ -377,6 +397,7 @@
 		else if (data_type == HSIC_DATA || data_type == HSIC_2_DATA) {
 			unsigned long flags;
 			int foundIndex = -1;
+			hsic_updated = 1;
 			index = data_type - HSIC_DATA;
 			spin_lock_irqsave(&diag_hsic[index].hsic_spinlock,
 									flags);
@@ -409,7 +430,7 @@
 						 driver->logging_process_id)
 				break;
 		if (i < driver->num_clients) {
-			driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
+			diag_mem_dev_mode_ready_update(i, hsic_updated);
 			pr_debug("diag: wake up logging process\n");
 			wake_up_interruptible(&driver->wait_q);
 		} else
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 5a67b0c..afbe4be 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -39,6 +39,10 @@
 int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
 			 int type);
 void diag_smd_destructor(struct diag_smd_info *smd_info);
+int diag_switch_logging(unsigned long);
+int diag_command_reg(unsigned long);
+void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode);
+void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode);
 /* State for diag forwarding */
 #ifdef CONFIG_DIAG_OVER_USB
 int diagfwd_connect(void);
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 522136d..2cfafc3 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -59,7 +59,7 @@
 /*
  * Assigned numbers, used for dynamic minors
  */
-#define DYNAMIC_MINORS 64 /* like dynamic majors */
+#define DYNAMIC_MINORS 96 /* like dynamic majors */
 static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
 
 #ifdef CONFIG_PROC_FS
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index c113cf1..f5ca5b6 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -1,6 +1,7 @@
 #
 # Makefile for the kernel tpm device drivers.
 #
+
 obj-$(CONFIG_TCG_TPM) += tpm.o
 ifdef CONFIG_ACPI
 	obj-$(CONFIG_TCG_TPM) += tpm_bios.o
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
deleted file mode 100644
index 94bb440..0000000
--- a/drivers/char/tty_io.c
+++ /dev/null
@@ -1,3154 +0,0 @@
-/*
- *  linux/drivers/char/tty_io.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
- * or rs-channels. It also implements echoing, cooked mode etc.
- *
- * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
- *
- * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
- * tty_struct and tty_queue structures.  Previously there was an array
- * of 256 tty_struct's which was statically allocated, and the
- * tty_queue structures were allocated at boot time.  Both are now
- * dynamically allocated only when the tty is open.
- *
- * Also restructured routines so that there is more of a separation
- * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
- * the low-level tty routines (serial.c, pty.c, console.c).  This
- * makes for cleaner and more compact code.  -TYT, 9/17/92
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- *
- * NOTE: pay no attention to the line discipline code (yet); its
- * interface is still subject to change in this version...
- * -- TYT, 1/31/92
- *
- * Added functionality to the OPOST tty handling.  No delays, but all
- * other bits should be there.
- *	-- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
- *
- * Rewrote canonical mode and added more termios flags.
- * 	-- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
- *
- * Reorganized FASYNC support so mouse code can share it.
- *	-- ctm@ardi.com, 9Sep95
- *
- * New TIOCLINUX variants added.
- *	-- mj@k332.feld.cvut.cz, 19-Nov-95
- *
- * Restrict vt switching via ioctl()
- *      -- grif@cs.ucr.edu, 5-Dec-95
- *
- * Move console and virtual terminal code to more appropriate files,
- * implement CONFIG_VT and generalize console device interface.
- *	-- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
- *
- * Rewrote tty_init_dev and tty_release_dev to eliminate races.
- *	-- Bill Hawes <whawes@star.net>, June 97
- *
- * Added devfs support.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
- *
- * Added support for a Unix98-style ptmx device.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- * Reduced memory usage for older ARM systems
- *      -- Russell King <rmk@arm.linux.org.uk>
- *
- * Move do_SAK() into process context.  Less stack use in devfs functions.
- * alloc_tty_struct() always uses kmalloc()
- *			 -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/fdtable.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-#undef TTY_DEBUG_HANGUP
-
-#define TTY_PARANOIA_CHECK 1
-#define CHECK_TTY_COUNT 1
-
-struct ktermios tty_std_termios = {	/* for the benefit of tty drivers  */
-	.c_iflag = ICRNL | IXON,
-	.c_oflag = OPOST | ONLCR,
-	.c_cflag = B38400 | CS8 | CREAD | HUPCL,
-	.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
-		   ECHOCTL | ECHOKE | IEXTEN,
-	.c_cc = INIT_C_CC,
-	.c_ispeed = 38400,
-	.c_ospeed = 38400
-};
-
-EXPORT_SYMBOL(tty_std_termios);
-
-/* This list gets poked at by procfs and various bits of boot up code. This
-   could do with some rationalisation such as pulling the tty proc function
-   into this file */
-
-LIST_HEAD(tty_drivers);			/* linked list of tty drivers */
-
-/* Mutex to protect creating and releasing a tty. This is shared with
-   vt.c for deeply disgusting hack reasons */
-DEFINE_MUTEX(tty_mutex);
-EXPORT_SYMBOL(tty_mutex);
-
-static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
-ssize_t redirected_tty_write(struct file *, const char __user *,
-							size_t, loff_t *);
-static unsigned int tty_poll(struct file *, poll_table *);
-static int tty_open(struct inode *, struct file *);
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-				unsigned long arg);
-#else
-#define tty_compat_ioctl NULL
-#endif
-static int tty_fasync(int fd, struct file *filp, int on);
-static void release_tty(struct tty_struct *tty, int idx);
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-
-/**
- *	alloc_tty_struct	-	allocate a tty object
- *
- *	Return a new empty tty structure. The data fields have not
- *	been initialized in any way but has been zeroed
- *
- *	Locking: none
- */
-
-struct tty_struct *alloc_tty_struct(void)
-{
-	return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
-}
-
-/**
- *	free_tty_struct		-	free a disused tty
- *	@tty: tty struct to free
- *
- *	Free the write buffers, tty queue and tty memory itself.
- *
- *	Locking: none. Must be called after tty is definitely unused
- */
-
-void free_tty_struct(struct tty_struct *tty)
-{
-	kfree(tty->write_buf);
-	tty_buffer_free_all(tty);
-	kfree(tty);
-}
-
-#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
-
-/**
- *	tty_name	-	return tty naming
- *	@tty: tty structure
- *	@buf: buffer for output
- *
- *	Convert a tty structure into a name. The name reflects the kernel
- *	naming policy and if udev is in use may not reflect user space
- *
- *	Locking: none
- */
-
-char *tty_name(struct tty_struct *tty, char *buf)
-{
-	if (!tty) /* Hmm.  NULL pointer.  That's fun. */
-		strcpy(buf, "NULL tty");
-	else
-		strcpy(buf, tty->name);
-	return buf;
-}
-
-EXPORT_SYMBOL(tty_name);
-
-int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
-			      const char *routine)
-{
-#ifdef TTY_PARANOIA_CHECK
-	if (!tty) {
-		printk(KERN_WARNING
-			"null TTY for (%d:%d) in %s\n",
-			imajor(inode), iminor(inode), routine);
-		return 1;
-	}
-	if (tty->magic != TTY_MAGIC) {
-		printk(KERN_WARNING
-			"bad magic number for tty struct (%d:%d) in %s\n",
-			imajor(inode), iminor(inode), routine);
-		return 1;
-	}
-#endif
-	return 0;
-}
-
-static int check_tty_count(struct tty_struct *tty, const char *routine)
-{
-#ifdef CHECK_TTY_COUNT
-	struct list_head *p;
-	int count = 0;
-
-	file_list_lock();
-	list_for_each(p, &tty->tty_files) {
-		count++;
-	}
-	file_list_unlock();
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_SLAVE &&
-	    tty->link && tty->link->count)
-		count++;
-	if (tty->count != count) {
-		printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
-				    "!= #fd's(%d) in %s\n",
-		       tty->name, tty->count, count, routine);
-		return count;
-	}
-#endif
-	return 0;
-}
-
-/**
- *	get_tty_driver		-	find device of a tty
- *	@dev_t: device identifier
- *	@index: returns the index of the tty
- *
- *	This routine returns a tty driver structure, given a device number
- *	and also passes back the index number.
- *
- *	Locking: caller must hold tty_mutex
- */
-
-static struct tty_driver *get_tty_driver(dev_t device, int *index)
-{
-	struct tty_driver *p;
-
-	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		dev_t base = MKDEV(p->major, p->minor_start);
-		if (device < base || device >= base + p->num)
-			continue;
-		*index = device - base;
-		return tty_driver_kref_get(p);
-	}
-	return NULL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-/**
- *	tty_find_polling_driver	-	find device of a polled tty
- *	@name: name string to match
- *	@line: pointer to resulting tty line nr
- *
- *	This routine returns a tty driver structure, given a name
- *	and the condition that the tty driver is capable of polled
- *	operation.
- */
-struct tty_driver *tty_find_polling_driver(char *name, int *line)
-{
-	struct tty_driver *p, *res = NULL;
-	int tty_line = 0;
-	int len;
-	char *str, *stp;
-
-	for (str = name; *str; str++)
-		if ((*str >= '0' && *str <= '9') || *str == ',')
-			break;
-	if (!*str)
-		return NULL;
-
-	len = str - name;
-	tty_line = simple_strtoul(str, &str, 10);
-
-	mutex_lock(&tty_mutex);
-	/* Search through the tty devices to look for a match */
-	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		if (strncmp(name, p->name, len) != 0)
-			continue;
-		stp = str;
-		if (*stp == ',')
-			stp++;
-		if (*stp == '\0')
-			stp = NULL;
-
-		if (tty_line >= 0 && tty_line <= p->num && p->ops &&
-		    p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
-			res = tty_driver_kref_get(p);
-			*line = tty_line;
-			break;
-		}
-	}
-	mutex_unlock(&tty_mutex);
-
-	return res;
-}
-EXPORT_SYMBOL_GPL(tty_find_polling_driver);
-#endif
-
-/**
- *	tty_check_change	-	check for POSIX terminal changes
- *	@tty: tty to check
- *
- *	If we try to write to, or set the state of, a terminal and we're
- *	not in the foreground, send a SIGTTOU.  If the signal is blocked or
- *	ignored, go ahead and perform the operation.  (POSIX 7.2)
- *
- *	Locking: ctrl_lock
- */
-
-int tty_check_change(struct tty_struct *tty)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	if (current->signal->tty != tty)
-		return 0;
-
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-
-	if (!tty->pgrp) {
-		printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
-		goto out_unlock;
-	}
-	if (task_pgrp(current) == tty->pgrp)
-		goto out_unlock;
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-	if (is_ignored(SIGTTOU))
-		goto out;
-	if (is_current_pgrp_orphaned()) {
-		ret = -EIO;
-		goto out;
-	}
-	kill_pgrp(task_pgrp(current), SIGTTOU, 1);
-	set_thread_flag(TIF_SIGPENDING);
-	ret = -ERESTARTSYS;
-out:
-	return ret;
-out_unlock:
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-	return ret;
-}
-
-EXPORT_SYMBOL(tty_check_change);
-
-static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
-				size_t count, loff_t *ppos)
-{
-	return 0;
-}
-
-static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
-				 size_t count, loff_t *ppos)
-{
-	return -EIO;
-}
-
-/* No kernel lock held - none needed ;) */
-static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
-{
-	return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
-}
-
-static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
-		unsigned long arg)
-{
-	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static long hung_up_tty_compat_ioctl(struct file *file,
-				     unsigned int cmd, unsigned long arg)
-{
-	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static const struct file_operations tty_fops = {
-	.llseek		= no_llseek,
-	.read		= tty_read,
-	.write		= tty_write,
-	.poll		= tty_poll,
-	.unlocked_ioctl	= tty_ioctl,
-	.compat_ioctl	= tty_compat_ioctl,
-	.open		= tty_open,
-	.release	= tty_release,
-	.fasync		= tty_fasync,
-};
-
-static const struct file_operations console_fops = {
-	.llseek		= no_llseek,
-	.read		= tty_read,
-	.write		= redirected_tty_write,
-	.poll		= tty_poll,
-	.unlocked_ioctl	= tty_ioctl,
-	.compat_ioctl	= tty_compat_ioctl,
-	.open		= tty_open,
-	.release	= tty_release,
-	.fasync		= tty_fasync,
-};
-
-static const struct file_operations hung_up_tty_fops = {
-	.llseek		= no_llseek,
-	.read		= hung_up_tty_read,
-	.write		= hung_up_tty_write,
-	.poll		= hung_up_tty_poll,
-	.unlocked_ioctl	= hung_up_tty_ioctl,
-	.compat_ioctl	= hung_up_tty_compat_ioctl,
-	.release	= tty_release,
-};
-
-static DEFINE_SPINLOCK(redirect_lock);
-static struct file *redirect;
-
-/**
- *	tty_wakeup	-	request more data
- *	@tty: terminal
- *
- *	Internal and external helper for wakeups of tty. This function
- *	informs the line discipline if present that the driver is ready
- *	to receive more output data.
- */
-
-void tty_wakeup(struct tty_struct *tty)
-{
-	struct tty_ldisc *ld;
-
-	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
-		ld = tty_ldisc_ref(tty);
-		if (ld) {
-			if (ld->ops->write_wakeup)
-				ld->ops->write_wakeup(tty);
-			tty_ldisc_deref(ld);
-		}
-	}
-	wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-EXPORT_SYMBOL_GPL(tty_wakeup);
-
-/**
- *	do_tty_hangup		-	actual handler for hangup events
- *	@work: tty device
- *
- *	This can be called by the "eventd" kernel thread.  That is process
- *	synchronous but doesn't hold any locks, so we need to make sure we
- *	have the appropriate locks for what we're doing.
- *
- *	The hangup event clears any pending redirections onto the hung up
- *	device. It ensures future writes will error and it does the needed
- *	line discipline hangup and signal delivery. The tty object itself
- *	remains intact.
- *
- *	Locking:
- *		BKL
- *		  redirect lock for undoing redirection
- *		  file list lock for manipulating list of ttys
- *		  tty_ldisc_lock from called functions
- *		  termios_mutex resetting termios data
- *		  tasklist_lock to walk task list for hangup event
- *		    ->siglock to protect ->signal/->sighand
- */
-static void do_tty_hangup(struct work_struct *work)
-{
-	struct tty_struct *tty =
-		container_of(work, struct tty_struct, hangup_work);
-	struct file *cons_filp = NULL;
-	struct file *filp, *f = NULL;
-	struct task_struct *p;
-	int    closecount = 0, n;
-	unsigned long flags;
-	int refs = 0;
-
-	if (!tty)
-		return;
-
-
-	spin_lock(&redirect_lock);
-	if (redirect && redirect->private_data == tty) {
-		f = redirect;
-		redirect = NULL;
-	}
-	spin_unlock(&redirect_lock);
-
-	/* inuse_filps is protected by the single kernel lock */
-	lock_kernel();
-	check_tty_count(tty, "do_tty_hangup");
-
-	file_list_lock();
-	/* This breaks for file handles being sent over AF_UNIX sockets ? */
-	list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) {
-		if (filp->f_op->write == redirected_tty_write)
-			cons_filp = filp;
-		if (filp->f_op->write != tty_write)
-			continue;
-		closecount++;
-		tty_fasync(-1, filp, 0);	/* can't block */
-		filp->f_op = &hung_up_tty_fops;
-	}
-	file_list_unlock();
-
-	tty_ldisc_hangup(tty);
-
-	read_lock(&tasklist_lock);
-	if (tty->session) {
-		do_each_pid_task(tty->session, PIDTYPE_SID, p) {
-			spin_lock_irq(&p->sighand->siglock);
-			if (p->signal->tty == tty) {
-				p->signal->tty = NULL;
-				/* We defer the dereferences outside fo
-				   the tasklist lock */
-				refs++;
-			}
-			if (!p->signal->leader) {
-				spin_unlock_irq(&p->sighand->siglock);
-				continue;
-			}
-			__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
-			__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
-			put_pid(p->signal->tty_old_pgrp);  /* A noop */
-			spin_lock_irqsave(&tty->ctrl_lock, flags);
-			if (tty->pgrp)
-				p->signal->tty_old_pgrp = get_pid(tty->pgrp);
-			spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-			spin_unlock_irq(&p->sighand->siglock);
-		} while_each_pid_task(tty->session, PIDTYPE_SID, p);
-	}
-	read_unlock(&tasklist_lock);
-
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	clear_bit(TTY_THROTTLED, &tty->flags);
-	clear_bit(TTY_PUSH, &tty->flags);
-	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-	put_pid(tty->session);
-	put_pid(tty->pgrp);
-	tty->session = NULL;
-	tty->pgrp = NULL;
-	tty->ctrl_status = 0;
-	set_bit(TTY_HUPPED, &tty->flags);
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-	/* Account for the p->signal references we killed */
-	while (refs--)
-		tty_kref_put(tty);
-
-	/*
-	 * If one of the devices matches a console pointer, we
-	 * cannot just call hangup() because that will cause
-	 * tty->count and state->count to go out of sync.
-	 * So we just call close() the right number of times.
-	 */
-	if (cons_filp) {
-		if (tty->ops->close)
-			for (n = 0; n < closecount; n++)
-				tty->ops->close(tty, cons_filp);
-	} else if (tty->ops->hangup)
-		(tty->ops->hangup)(tty);
-	/*
-	 * We don't want to have driver/ldisc interactions beyond
-	 * the ones we did here. The driver layer expects no
-	 * calls after ->hangup() from the ldisc side. However we
-	 * can't yet guarantee all that.
-	 */
-	set_bit(TTY_HUPPED, &tty->flags);
-	tty_ldisc_enable(tty);
-	unlock_kernel();
-	if (f)
-		fput(f);
-}
-
-/**
- *	tty_hangup		-	trigger a hangup event
- *	@tty: tty to hangup
- *
- *	A carrier loss (virtual or otherwise) has occurred on this like
- *	schedule a hangup sequence to run after this event.
- */
-
-void tty_hangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-	char	buf[64];
-	printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
-#endif
-	schedule_work(&tty->hangup_work);
-}
-
-EXPORT_SYMBOL(tty_hangup);
-
-/**
- *	tty_vhangup		-	process vhangup
- *	@tty: tty to hangup
- *
- *	The user has asked via system call for the terminal to be hung up.
- *	We do this synchronously so that when the syscall returns the process
- *	is complete. That guarantee is necessary for security reasons.
- */
-
-void tty_vhangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-	char	buf[64];
-
-	printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
-#endif
-	do_tty_hangup(&tty->hangup_work);
-}
-
-EXPORT_SYMBOL(tty_vhangup);
-
-/**
- *	tty_vhangup_self	-	process vhangup for own ctty
- *
- *	Perform a vhangup on the current controlling tty
- */
-
-void tty_vhangup_self(void)
-{
-	struct tty_struct *tty;
-
-	tty = get_current_tty();
-	if (tty) {
-		tty_vhangup(tty);
-		tty_kref_put(tty);
-	}
-}
-
-/**
- *	tty_hung_up_p		-	was tty hung up
- *	@filp: file pointer of tty
- *
- *	Return true if the tty has been subject to a vhangup or a carrier
- *	loss
- */
-
-int tty_hung_up_p(struct file *filp)
-{
-	return (filp->f_op == &hung_up_tty_fops);
-}
-
-EXPORT_SYMBOL(tty_hung_up_p);
-
-static void session_clear_tty(struct pid *session)
-{
-	struct task_struct *p;
-	do_each_pid_task(session, PIDTYPE_SID, p) {
-		proc_clear_tty(p);
-	} while_each_pid_task(session, PIDTYPE_SID, p);
-}
-
-/**
- *	disassociate_ctty	-	disconnect controlling tty
- *	@on_exit: true if exiting so need to "hang up" the session
- *
- *	This function is typically called only by the session leader, when
- *	it wants to disassociate itself from its controlling tty.
- *
- *	It performs the following functions:
- * 	(1)  Sends a SIGHUP and SIGCONT to the foreground process group
- * 	(2)  Clears the tty from being controlling the session
- * 	(3)  Clears the controlling tty for all processes in the
- * 		session group.
- *
- *	The argument on_exit is set to 1 if called when a process is
- *	exiting; it is 0 if called by the ioctl TIOCNOTTY.
- *
- *	Locking:
- *		BKL is taken for hysterical raisins
- *		  tty_mutex is taken to protect tty
- *		  ->siglock is taken to protect ->signal/->sighand
- *		  tasklist_lock is taken to walk process list for sessions
- *		    ->siglock is taken to protect ->signal/->sighand
- */
-
-void disassociate_ctty(int on_exit)
-{
-	struct tty_struct *tty;
-	struct pid *tty_pgrp = NULL;
-
-	if (!current->signal->leader)
-		return;
-
-	tty = get_current_tty();
-	if (tty) {
-		tty_pgrp = get_pid(tty->pgrp);
-		lock_kernel();
-		if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
-			tty_vhangup(tty);
-		unlock_kernel();
-		tty_kref_put(tty);
-	} else if (on_exit) {
-		struct pid *old_pgrp;
-		spin_lock_irq(&current->sighand->siglock);
-		old_pgrp = current->signal->tty_old_pgrp;
-		current->signal->tty_old_pgrp = NULL;
-		spin_unlock_irq(&current->sighand->siglock);
-		if (old_pgrp) {
-			kill_pgrp(old_pgrp, SIGHUP, on_exit);
-			kill_pgrp(old_pgrp, SIGCONT, on_exit);
-			put_pid(old_pgrp);
-		}
-		return;
-	}
-	if (tty_pgrp) {
-		kill_pgrp(tty_pgrp, SIGHUP, on_exit);
-		if (!on_exit)
-			kill_pgrp(tty_pgrp, SIGCONT, on_exit);
-		put_pid(tty_pgrp);
-	}
-
-	spin_lock_irq(&current->sighand->siglock);
-	put_pid(current->signal->tty_old_pgrp);
-	current->signal->tty_old_pgrp = NULL;
-	spin_unlock_irq(&current->sighand->siglock);
-
-	tty = get_current_tty();
-	if (tty) {
-		unsigned long flags;
-		spin_lock_irqsave(&tty->ctrl_lock, flags);
-		put_pid(tty->session);
-		put_pid(tty->pgrp);
-		tty->session = NULL;
-		tty->pgrp = NULL;
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		tty_kref_put(tty);
-	} else {
-#ifdef TTY_DEBUG_HANGUP
-		printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
-		       " = NULL", tty);
-#endif
-	}
-
-	/* Now clear signal->tty under the lock */
-	read_lock(&tasklist_lock);
-	session_clear_tty(task_session(current));
-	read_unlock(&tasklist_lock);
-}
-
-/**
- *
- *	no_tty	- Ensure the current process does not have a controlling tty
- */
-void no_tty(void)
-{
-	struct task_struct *tsk = current;
-	lock_kernel();
-	disassociate_ctty(0);
-	unlock_kernel();
-	proc_clear_tty(tsk);
-}
-
-
-/**
- *	stop_tty	-	propagate flow control
- *	@tty: tty to stop
- *
- *	Perform flow control to the driver. For PTY/TTY pairs we
- *	must also propagate the TIOCKPKT status. May be called
- *	on an already stopped device and will not re-call the driver
- *	method.
- *
- *	This functionality is used by both the line disciplines for
- *	halting incoming flow and by the driver. It may therefore be
- *	called from any context, may be under the tty atomic_write_lock
- *	but not always.
- *
- *	Locking:
- *		Uses the tty control lock internally
- */
-
-void stop_tty(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	if (tty->stopped) {
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		return;
-	}
-	tty->stopped = 1;
-	if (tty->link && tty->link->packet) {
-		tty->ctrl_status &= ~TIOCPKT_START;
-		tty->ctrl_status |= TIOCPKT_STOP;
-		wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-	}
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-	if (tty->ops->stop)
-		(tty->ops->stop)(tty);
-}
-
-EXPORT_SYMBOL(stop_tty);
-
-/**
- *	start_tty	-	propagate flow control
- *	@tty: tty to start
- *
- *	Start a tty that has been stopped if at all possible. Perform
- *	any necessary wakeups and propagate the TIOCPKT status. If this
- *	is the tty was previous stopped and is being started then the
- *	driver start method is invoked and the line discipline woken.
- *
- *	Locking:
- *		ctrl_lock
- */
-
-void start_tty(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	if (!tty->stopped || tty->flow_stopped) {
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		return;
-	}
-	tty->stopped = 0;
-	if (tty->link && tty->link->packet) {
-		tty->ctrl_status &= ~TIOCPKT_STOP;
-		tty->ctrl_status |= TIOCPKT_START;
-		wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-	}
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-	if (tty->ops->start)
-		(tty->ops->start)(tty);
-	/* If we have a running line discipline it may need kicking */
-	tty_wakeup(tty);
-}
-
-EXPORT_SYMBOL(start_tty);
-
-/**
- *	tty_read	-	read method for tty device files
- *	@file: pointer to tty file
- *	@buf: user buffer
- *	@count: size of user buffer
- *	@ppos: unused
- *
- *	Perform the read system call function on this terminal device. Checks
- *	for hung up devices before calling the line discipline method.
- *
- *	Locking:
- *		Locks the line discipline internally while needed. Multiple
- *	read calls may be outstanding in parallel.
- */
-
-static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
-			loff_t *ppos)
-{
-	int i;
-	struct tty_struct *tty;
-	struct inode *inode;
-	struct tty_ldisc *ld;
-
-	tty = (struct tty_struct *)file->private_data;
-	inode = file->f_path.dentry->d_inode;
-	if (tty_paranoia_check(tty, inode, "tty_read"))
-		return -EIO;
-	if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
-		return -EIO;
-
-	/* We want to wait for the line discipline to sort out in this
-	   situation */
-	ld = tty_ldisc_ref_wait(tty);
-	if (ld->ops->read)
-		i = (ld->ops->read)(tty, file, buf, count);
-	else
-		i = -EIO;
-	tty_ldisc_deref(ld);
-	if (i > 0)
-		inode->i_atime = current_fs_time(inode->i_sb);
-	return i;
-}
-
-void tty_write_unlock(struct tty_struct *tty)
-{
-	mutex_unlock(&tty->atomic_write_lock);
-	wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-int tty_write_lock(struct tty_struct *tty, int ndelay)
-{
-	if (!mutex_trylock(&tty->atomic_write_lock)) {
-		if (ndelay)
-			return -EAGAIN;
-		if (mutex_lock_interruptible(&tty->atomic_write_lock))
-			return -ERESTARTSYS;
-	}
-	return 0;
-}
-
-/*
- * Split writes up in sane blocksizes to avoid
- * denial-of-service type attacks
- */
-static inline ssize_t do_tty_write(
-	ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
-	struct tty_struct *tty,
-	struct file *file,
-	const char __user *buf,
-	size_t count)
-{
-	ssize_t ret, written = 0;
-	unsigned int chunk;
-
-	ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
-	if (ret < 0)
-		return ret;
-
-	/*
-	 * We chunk up writes into a temporary buffer. This
-	 * simplifies low-level drivers immensely, since they
-	 * don't have locking issues and user mode accesses.
-	 *
-	 * But if TTY_NO_WRITE_SPLIT is set, we should use a
-	 * big chunk-size..
-	 *
-	 * The default chunk-size is 2kB, because the NTTY
-	 * layer has problems with bigger chunks. It will
-	 * claim to be able to handle more characters than
-	 * it actually does.
-	 *
-	 * FIXME: This can probably go away now except that 64K chunks
-	 * are too likely to fail unless switched to vmalloc...
-	 */
-	chunk = 2048;
-	if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
-		chunk = 65536;
-	if (count < chunk)
-		chunk = count;
-
-	/* write_buf/write_cnt is protected by the atomic_write_lock mutex */
-	if (tty->write_cnt < chunk) {
-		unsigned char *buf_chunk;
-
-		if (chunk < 1024)
-			chunk = 1024;
-
-		buf_chunk = kmalloc(chunk, GFP_KERNEL);
-		if (!buf_chunk) {
-			ret = -ENOMEM;
-			goto out;
-		}
-		kfree(tty->write_buf);
-		tty->write_cnt = chunk;
-		tty->write_buf = buf_chunk;
-	}
-
-	/* Do the write .. */
-	for (;;) {
-		size_t size = count;
-		if (size > chunk)
-			size = chunk;
-		ret = -EFAULT;
-		if (copy_from_user(tty->write_buf, buf, size))
-			break;
-		ret = write(tty, file, tty->write_buf, size);
-		if (ret <= 0)
-			break;
-		written += ret;
-		buf += ret;
-		count -= ret;
-		if (!count)
-			break;
-		ret = -ERESTARTSYS;
-		if (signal_pending(current))
-			break;
-		cond_resched();
-	}
-	if (written) {
-		struct inode *inode = file->f_path.dentry->d_inode;
-		inode->i_mtime = current_fs_time(inode->i_sb);
-		ret = written;
-	}
-out:
-	tty_write_unlock(tty);
-	return ret;
-}
-
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- *
- * We must still hold the BKL and test the CLOSING flag for the moment.
- */
-
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
-	if (tty) {
-		mutex_lock(&tty->atomic_write_lock);
-		lock_kernel();
-		if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
-			unlock_kernel();
-			tty->ops->write(tty, msg, strlen(msg));
-		} else
-			unlock_kernel();
-		tty_write_unlock(tty);
-	}
-	return;
-}
-
-
-/**
- *	tty_write		-	write method for tty device file
- *	@file: tty file pointer
- *	@buf: user data to write
- *	@count: bytes to write
- *	@ppos: unused
- *
- *	Write data to a tty device via the line discipline.
- *
- *	Locking:
- *		Locks the line discipline as required
- *		Writes to the tty driver are serialized by the atomic_write_lock
- *	and are then processed in chunks to the device. The line discipline
- *	write method will not be invoked in parallel for each device.
- */
-
-static ssize_t tty_write(struct file *file, const char __user *buf,
-						size_t count, loff_t *ppos)
-{
-	struct tty_struct *tty;
-	struct inode *inode = file->f_path.dentry->d_inode;
-	ssize_t ret;
-	struct tty_ldisc *ld;
-
-	tty = (struct tty_struct *)file->private_data;
-	if (tty_paranoia_check(tty, inode, "tty_write"))
-		return -EIO;
-	if (!tty || !tty->ops->write ||
-		(test_bit(TTY_IO_ERROR, &tty->flags)))
-			return -EIO;
-	/* Short term debug to catch buggy drivers */
-	if (tty->ops->write_room == NULL)
-		printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
-			tty->driver->name);
-	ld = tty_ldisc_ref_wait(tty);
-	if (!ld->ops->write)
-		ret = -EIO;
-	else
-		ret = do_tty_write(ld->ops->write, tty, file, buf, count);
-	tty_ldisc_deref(ld);
-	return ret;
-}
-
-ssize_t redirected_tty_write(struct file *file, const char __user *buf,
-						size_t count, loff_t *ppos)
-{
-	struct file *p = NULL;
-
-	spin_lock(&redirect_lock);
-	if (redirect) {
-		get_file(redirect);
-		p = redirect;
-	}
-	spin_unlock(&redirect_lock);
-
-	if (p) {
-		ssize_t res;
-		res = vfs_write(p, buf, count, &p->f_pos);
-		fput(p);
-		return res;
-	}
-	return tty_write(file, buf, count, ppos);
-}
-
-static char ptychar[] = "pqrstuvwxyzabcde";
-
-/**
- *	pty_line_name	-	generate name for a pty
- *	@driver: the tty driver in use
- *	@index: the minor number
- *	@p: output buffer of at least 6 bytes
- *
- *	Generate a name from a driver reference and write it to the output
- *	buffer.
- *
- *	Locking: None
- */
-static void pty_line_name(struct tty_driver *driver, int index, char *p)
-{
-	int i = index + driver->name_base;
-	/* ->name is initialized to "ttyp", but "tty" is expected */
-	sprintf(p, "%s%c%x",
-		driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
-		ptychar[i >> 4 & 0xf], i & 0xf);
-}
-
-/**
- *	tty_line_name	-	generate name for a tty
- *	@driver: the tty driver in use
- *	@index: the minor number
- *	@p: output buffer of at least 7 bytes
- *
- *	Generate a name from a driver reference and write it to the output
- *	buffer.
- *
- *	Locking: None
- */
-static void tty_line_name(struct tty_driver *driver, int index, char *p)
-{
-	sprintf(p, "%s%d", driver->name, index + driver->name_base);
-}
-
-/**
- *	tty_driver_lookup_tty() - find an existing tty, if any
- *	@driver: the driver for the tty
- *	@idx:	 the minor number
- *
- *	Return the tty, if found or ERR_PTR() otherwise.
- *
- *	Locking: tty_mutex must be held. If tty is found, the mutex must
- *	be held until the 'fast-open' is also done. Will change once we
- *	have refcounting in the driver and per driver locking
- */
-static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
-		struct inode *inode, int idx)
-{
-	struct tty_struct *tty;
-
-	if (driver->ops->lookup)
-		return driver->ops->lookup(driver, inode, idx);
-
-	tty = driver->ttys[idx];
-	return tty;
-}
-
-/**
- *	tty_init_termios	-  helper for termios setup
- *	@tty: the tty to set up
- *
- *	Initialise the termios structures for this tty. Thus runs under
- *	the tty_mutex currently so we can be relaxed about ordering.
- */
-
-int tty_init_termios(struct tty_struct *tty)
-{
-	struct ktermios *tp;
-	int idx = tty->index;
-
-	tp = tty->driver->termios[idx];
-	if (tp == NULL) {
-		tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-		if (tp == NULL)
-			return -ENOMEM;
-		memcpy(tp, &tty->driver->init_termios,
-						sizeof(struct ktermios));
-		tty->driver->termios[idx] = tp;
-	}
-	tty->termios = tp;
-	tty->termios_locked = tp + 1;
-
-	/* Compatibility until drivers always set this */
-	tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-	tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(tty_init_termios);
-
-/**
- *	tty_driver_install_tty() - install a tty entry in the driver
- *	@driver: the driver for the tty
- *	@tty: the tty
- *
- *	Install a tty object into the driver tables. The tty->index field
- *	will be set by the time this is called. This method is responsible
- *	for ensuring any need additional structures are allocated and
- *	configured.
- *
- *	Locking: tty_mutex for now
- */
-static int tty_driver_install_tty(struct tty_driver *driver,
-						struct tty_struct *tty)
-{
-	int idx = tty->index;
-	int ret;
-
-	if (driver->ops->install) {
-		lock_kernel();
-		ret = driver->ops->install(driver, tty);
-		unlock_kernel();
-		return ret;
-	}
-
-	if (tty_init_termios(tty) == 0) {
-		lock_kernel();
-		tty_driver_kref_get(driver);
-		tty->count++;
-		driver->ttys[idx] = tty;
-		unlock_kernel();
-		return 0;
-	}
-	return -ENOMEM;
-}
-
-/**
- *	tty_driver_remove_tty() - remove a tty from the driver tables
- *	@driver: the driver for the tty
- *	@idx:	 the minor number
- *
- *	Remvoe a tty object from the driver tables. The tty->index field
- *	will be set by the time this is called.
- *
- *	Locking: tty_mutex for now
- */
-static void tty_driver_remove_tty(struct tty_driver *driver,
-						struct tty_struct *tty)
-{
-	if (driver->ops->remove)
-		driver->ops->remove(driver, tty);
-	else
-		driver->ttys[tty->index] = NULL;
-}
-
-/*
- * 	tty_reopen()	- fast re-open of an open tty
- * 	@tty	- the tty to open
- *
- *	Return 0 on success, -errno on error.
- *
- *	Locking: tty_mutex must be held from the time the tty was found
- *		 till this open completes.
- */
-static int tty_reopen(struct tty_struct *tty)
-{
-	struct tty_driver *driver = tty->driver;
-
-	if (test_bit(TTY_CLOSING, &tty->flags))
-		return -EIO;
-
-	if (driver->type == TTY_DRIVER_TYPE_PTY &&
-	    driver->subtype == PTY_TYPE_MASTER) {
-		/*
-		 * special case for PTY masters: only one open permitted,
-		 * and the slave side open count is incremented as well.
-		 */
-		if (tty->count)
-			return -EIO;
-
-		tty->link->count++;
-	}
-	tty->count++;
-	tty->driver = driver; /* N.B. why do this every time?? */
-
-	mutex_lock(&tty->ldisc_mutex);
-	WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
-	mutex_unlock(&tty->ldisc_mutex);
-
-	return 0;
-}
-
-/**
- *	tty_init_dev		-	initialise a tty device
- *	@driver: tty driver we are opening a device on
- *	@idx: device index
- *	@ret_tty: returned tty structure
- *	@first_ok: ok to open a new device (used by ptmx)
- *
- *	Prepare a tty device. This may not be a "new" clean device but
- *	could also be an active device. The pty drivers require special
- *	handling because of this.
- *
- *	Locking:
- *		The function is called under the tty_mutex, which
- *	protects us from the tty struct or driver itself going away.
- *
- *	On exit the tty device has the line discipline attached and
- *	a reference count of 1. If a pair was created for pty/tty use
- *	and the other was a pty master then it too has a reference count of 1.
- *
- * WSH 06/09/97: Rewritten to remove races and properly clean up after a
- * failed open.  The new code protects the open with a mutex, so it's
- * really quite straightforward.  The mutex locking can probably be
- * relaxed for the (most common) case of reopening a tty.
- */
-
-struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
-								int first_ok)
-{
-	struct tty_struct *tty;
-	int retval;
-
-	lock_kernel();
-	/* Check if pty master is being opened multiple times */
-	if (driver->subtype == PTY_TYPE_MASTER &&
-		(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
-		unlock_kernel();
-		return ERR_PTR(-EIO);
-	}
-	unlock_kernel();
-
-	/*
-	 * First time open is complex, especially for PTY devices.
-	 * This code guarantees that either everything succeeds and the
-	 * TTY is ready for operation, or else the table slots are vacated
-	 * and the allocated memory released.  (Except that the termios
-	 * and locked termios may be retained.)
-	 */
-
-	if (!try_module_get(driver->owner))
-		return ERR_PTR(-ENODEV);
-
-	tty = alloc_tty_struct();
-	if (!tty)
-		goto fail_no_mem;
-	initialize_tty_struct(tty, driver, idx);
-
-	retval = tty_driver_install_tty(driver, tty);
-	if (retval < 0) {
-		free_tty_struct(tty);
-		module_put(driver->owner);
-		return ERR_PTR(retval);
-	}
-
-	/*
-	 * Structures all installed ... call the ldisc open routines.
-	 * If we fail here just call release_tty to clean up.  No need
-	 * to decrement the use counts, as release_tty doesn't care.
-	 */
-	retval = tty_ldisc_setup(tty, tty->link);
-	if (retval)
-		goto release_mem_out;
-	return tty;
-
-fail_no_mem:
-	module_put(driver->owner);
-	return ERR_PTR(-ENOMEM);
-
-	/* call the tty release_tty routine to clean out this slot */
-release_mem_out:
-	if (printk_ratelimit())
-		printk(KERN_INFO "tty_init_dev: ldisc open failed, "
-				 "clearing slot %d\n", idx);
-	lock_kernel();
-	release_tty(tty, idx);
-	unlock_kernel();
-	return ERR_PTR(retval);
-}
-
-void tty_free_termios(struct tty_struct *tty)
-{
-	struct ktermios *tp;
-	int idx = tty->index;
-	/* Kill this flag and push into drivers for locking etc */
-	if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-		/* FIXME: Locking on ->termios array */
-		tp = tty->termios;
-		tty->driver->termios[idx] = NULL;
-		kfree(tp);
-	}
-}
-EXPORT_SYMBOL(tty_free_termios);
-
-void tty_shutdown(struct tty_struct *tty)
-{
-	tty_driver_remove_tty(tty->driver, tty);
-	tty_free_termios(tty);
-}
-EXPORT_SYMBOL(tty_shutdown);
-
-/**
- *	release_one_tty		-	release tty structure memory
- *	@kref: kref of tty we are obliterating
- *
- *	Releases memory associated with a tty structure, and clears out the
- *	driver table slots. This function is called when a device is no longer
- *	in use. It also gets called when setup of a device fails.
- *
- *	Locking:
- *		tty_mutex - sometimes only
- *		takes the file list lock internally when working on the list
- *	of ttys that the driver keeps.
- *
- *	This method gets called from a work queue so that the driver private
- *	cleanup ops can sleep (needed for USB at least)
- */
-static void release_one_tty(struct work_struct *work)
-{
-	struct tty_struct *tty =
-		container_of(work, struct tty_struct, hangup_work);
-	struct tty_driver *driver = tty->driver;
-
-	if (tty->ops->cleanup)
-		tty->ops->cleanup(tty);
-
-	tty->magic = 0;
-	tty_driver_kref_put(driver);
-	module_put(driver->owner);
-
-	file_list_lock();
-	list_del_init(&tty->tty_files);
-	file_list_unlock();
-
-	put_pid(tty->pgrp);
-	put_pid(tty->session);
-	free_tty_struct(tty);
-}
-
-static void queue_release_one_tty(struct kref *kref)
-{
-	struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
-
-	if (tty->ops->shutdown)
-		tty->ops->shutdown(tty);
-	else
-		tty_shutdown(tty);
-
-	/* The hangup queue is now free so we can reuse it rather than
-	   waste a chunk of memory for each port */
-	INIT_WORK(&tty->hangup_work, release_one_tty);
-	schedule_work(&tty->hangup_work);
-}
-
-/**
- *	tty_kref_put		-	release a tty kref
- *	@tty: tty device
- *
- *	Release a reference to a tty device and if need be let the kref
- *	layer destruct the object for us
- */
-
-void tty_kref_put(struct tty_struct *tty)
-{
-	if (tty)
-		kref_put(&tty->kref, queue_release_one_tty);
-}
-EXPORT_SYMBOL(tty_kref_put);
-
-/**
- *	release_tty		-	release tty structure memory
- *
- *	Release both @tty and a possible linked partner (think pty pair),
- *	and decrement the refcount of the backing module.
- *
- *	Locking:
- *		tty_mutex - sometimes only
- *		takes the file list lock internally when working on the list
- *	of ttys that the driver keeps.
- *		FIXME: should we require tty_mutex is held here ??
- *
- */
-static void release_tty(struct tty_struct *tty, int idx)
-{
-	/* This should always be true but check for the moment */
-	WARN_ON(tty->index != idx);
-
-	if (tty->link)
-		tty_kref_put(tty->link);
-	tty_kref_put(tty);
-}
-
-/**
- *	tty_release		-	vfs callback for close
- *	@inode: inode of tty
- *	@filp: file pointer for handle to tty
- *
- *	Called the last time each file handle is closed that references
- *	this tty. There may however be several such references.
- *
- *	Locking:
- *		Takes bkl. See tty_release_dev
- *
- * Even releasing the tty structures is a tricky business.. We have
- * to be very careful that the structures are all released at the
- * same time, as interrupts might otherwise get the wrong pointers.
- *
- * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
- * lead to double frees or releasing memory still in use.
- */
-
-int tty_release(struct inode *inode, struct file *filp)
-{
-	struct tty_struct *tty, *o_tty;
-	int	pty_master, tty_closing, o_tty_closing, do_sleep;
-	int	devpts;
-	int	idx;
-	char	buf[64];
-
-	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, inode, "tty_release_dev"))
-		return 0;
-
-	lock_kernel();
-	check_tty_count(tty, "tty_release_dev");
-
-	tty_fasync(-1, filp, 0);
-
-	idx = tty->index;
-	pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-		      tty->driver->subtype == PTY_TYPE_MASTER);
-	devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
-	o_tty = tty->link;
-
-#ifdef TTY_PARANOIA_CHECK
-	if (idx < 0 || idx >= tty->driver->num) {
-		printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
-				  "free (%s)\n", tty->name);
-		unlock_kernel();
-		return 0;
-	}
-	if (!devpts) {
-		if (tty != tty->driver->ttys[idx]) {
-			unlock_kernel();
-			printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
-			       "for (%s)\n", idx, tty->name);
-			return 0;
-		}
-		if (tty->termios != tty->driver->termios[idx]) {
-			unlock_kernel();
-			printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
-			       "for (%s)\n",
-			       idx, tty->name);
-			return 0;
-		}
-	}
-#endif
-
-#ifdef TTY_DEBUG_HANGUP
-	printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
-	       tty_name(tty, buf), tty->count);
-#endif
-
-#ifdef TTY_PARANOIA_CHECK
-	if (tty->driver->other &&
-	     !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
-		if (o_tty != tty->driver->other->ttys[idx]) {
-			unlock_kernel();
-			printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
-					  "not o_tty for (%s)\n",
-			       idx, tty->name);
-			return 0 ;
-		}
-		if (o_tty->termios != tty->driver->other->termios[idx]) {
-			unlock_kernel();
-			printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
-					  "not o_termios for (%s)\n",
-			       idx, tty->name);
-			return 0;
-		}
-		if (o_tty->link != tty) {
-			unlock_kernel();
-			printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
-			return 0;
-		}
-	}
-#endif
-	if (tty->ops->close)
-		tty->ops->close(tty, filp);
-
-	unlock_kernel();
-	/*
-	 * Sanity check: if tty->count is going to zero, there shouldn't be
-	 * any waiters on tty->read_wait or tty->write_wait.  We test the
-	 * wait queues and kick everyone out _before_ actually starting to
-	 * close.  This ensures that we won't block while releasing the tty
-	 * structure.
-	 *
-	 * The test for the o_tty closing is necessary, since the master and
-	 * slave sides may close in any order.  If the slave side closes out
-	 * first, its count will be one, since the master side holds an open.
-	 * Thus this test wouldn't be triggered at the time the slave closes,
-	 * so we do it now.
-	 *
-	 * Note that it's possible for the tty to be opened again while we're
-	 * flushing out waiters.  By recalculating the closing flags before
-	 * each iteration we avoid any problems.
-	 */
-	while (1) {
-		/* Guard against races with tty->count changes elsewhere and
-		   opens on /dev/tty */
-
-		mutex_lock(&tty_mutex);
-		lock_kernel();
-		tty_closing = tty->count <= 1;
-		o_tty_closing = o_tty &&
-			(o_tty->count <= (pty_master ? 1 : 0));
-		do_sleep = 0;
-
-		if (tty_closing) {
-			if (waitqueue_active(&tty->read_wait)) {
-				wake_up_poll(&tty->read_wait, POLLIN);
-				do_sleep++;
-			}
-			if (waitqueue_active(&tty->write_wait)) {
-				wake_up_poll(&tty->write_wait, POLLOUT);
-				do_sleep++;
-			}
-		}
-		if (o_tty_closing) {
-			if (waitqueue_active(&o_tty->read_wait)) {
-				wake_up_poll(&o_tty->read_wait, POLLIN);
-				do_sleep++;
-			}
-			if (waitqueue_active(&o_tty->write_wait)) {
-				wake_up_poll(&o_tty->write_wait, POLLOUT);
-				do_sleep++;
-			}
-		}
-		if (!do_sleep)
-			break;
-
-		printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
-				    "active!\n", tty_name(tty, buf));
-		unlock_kernel();
-		mutex_unlock(&tty_mutex);
-		schedule();
-	}
-
-	/*
-	 * The closing flags are now consistent with the open counts on
-	 * both sides, and we've completed the last operation that could
-	 * block, so it's safe to proceed with closing.
-	 */
-	if (pty_master) {
-		if (--o_tty->count < 0) {
-			printk(KERN_WARNING "tty_release_dev: bad pty slave count "
-					    "(%d) for %s\n",
-			       o_tty->count, tty_name(o_tty, buf));
-			o_tty->count = 0;
-		}
-	}
-	if (--tty->count < 0) {
-		printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
-		       tty->count, tty_name(tty, buf));
-		tty->count = 0;
-	}
-
-	/*
-	 * We've decremented tty->count, so we need to remove this file
-	 * descriptor off the tty->tty_files list; this serves two
-	 * purposes:
-	 *  - check_tty_count sees the correct number of file descriptors
-	 *    associated with this tty.
-	 *  - do_tty_hangup no longer sees this file descriptor as
-	 *    something that needs to be handled for hangups.
-	 */
-	file_kill(filp);
-	filp->private_data = NULL;
-
-	/*
-	 * Perform some housekeeping before deciding whether to return.
-	 *
-	 * Set the TTY_CLOSING flag if this was the last open.  In the
-	 * case of a pty we may have to wait around for the other side
-	 * to close, and TTY_CLOSING makes sure we can't be reopened.
-	 */
-	if (tty_closing)
-		set_bit(TTY_CLOSING, &tty->flags);
-	if (o_tty_closing)
-		set_bit(TTY_CLOSING, &o_tty->flags);
-
-	/*
-	 * If _either_ side is closing, make sure there aren't any
-	 * processes that still think tty or o_tty is their controlling
-	 * tty.
-	 */
-	if (tty_closing || o_tty_closing) {
-		read_lock(&tasklist_lock);
-		session_clear_tty(tty->session);
-		if (o_tty)
-			session_clear_tty(o_tty->session);
-		read_unlock(&tasklist_lock);
-	}
-
-	mutex_unlock(&tty_mutex);
-
-	/* check whether both sides are closing ... */
-	if (!tty_closing || (o_tty && !o_tty_closing)) {
-		unlock_kernel();
-		return 0;
-	}
-
-#ifdef TTY_DEBUG_HANGUP
-	printk(KERN_DEBUG "freeing tty structure...");
-#endif
-	/*
-	 * Ask the line discipline code to release its structures
-	 */
-	tty_ldisc_release(tty, o_tty);
-	/*
-	 * The release_tty function takes care of the details of clearing
-	 * the slots and preserving the termios structure.
-	 */
-	release_tty(tty, idx);
-
-	/* Make this pty number available for reallocation */
-	if (devpts)
-		devpts_kill_index(inode, idx);
-	unlock_kernel();
-	return 0;
-}
-
-/**
- *	tty_open		-	open a tty device
- *	@inode: inode of device file
- *	@filp: file pointer to tty
- *
- *	tty_open and tty_release keep up the tty count that contains the
- *	number of opens done on a tty. We cannot use the inode-count, as
- *	different inodes might point to the same tty.
- *
- *	Open-counting is needed for pty masters, as well as for keeping
- *	track of serial lines: DTR is dropped when the last close happens.
- *	(This is not done solely through tty->count, now.  - Ted 1/27/92)
- *
- *	The termios state of a pty is reset on first open so that
- *	settings don't persist across reuse.
- *
- *	Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
- *		 tty->count should protect the rest.
- *		 ->siglock protects ->signal/->sighand
- */
-
-static int tty_open(struct inode *inode, struct file *filp)
-{
-	struct tty_struct *tty = NULL;
-	int noctty, retval;
-	struct tty_driver *driver;
-	int index;
-	dev_t device = inode->i_rdev;
-	unsigned saved_flags = filp->f_flags;
-
-	nonseekable_open(inode, filp);
-
-retry_open:
-	noctty = filp->f_flags & O_NOCTTY;
-	index  = -1;
-	retval = 0;
-
-	mutex_lock(&tty_mutex);
-	lock_kernel();
-
-	if (device == MKDEV(TTYAUX_MAJOR, 0)) {
-		tty = get_current_tty();
-		if (!tty) {
-			unlock_kernel();
-			mutex_unlock(&tty_mutex);
-			return -ENXIO;
-		}
-		driver = tty_driver_kref_get(tty->driver);
-		index = tty->index;
-		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
-		/* noctty = 1; */
-		/* FIXME: Should we take a driver reference ? */
-		tty_kref_put(tty);
-		goto got_driver;
-	}
-#ifdef CONFIG_VT
-	if (device == MKDEV(TTY_MAJOR, 0)) {
-		extern struct tty_driver *console_driver;
-		driver = tty_driver_kref_get(console_driver);
-		index = fg_console;
-		noctty = 1;
-		goto got_driver;
-	}
-#endif
-	if (device == MKDEV(TTYAUX_MAJOR, 1)) {
-		struct tty_driver *console_driver = console_device(&index);
-		if (console_driver) {
-			driver = tty_driver_kref_get(console_driver);
-			if (driver) {
-				/* Don't let /dev/console block */
-				filp->f_flags |= O_NONBLOCK;
-				noctty = 1;
-				goto got_driver;
-			}
-		}
-		unlock_kernel();
-		mutex_unlock(&tty_mutex);
-		return -ENODEV;
-	}
-
-	driver = get_tty_driver(device, &index);
-	if (!driver) {
-		unlock_kernel();
-		mutex_unlock(&tty_mutex);
-		return -ENODEV;
-	}
-got_driver:
-	if (!tty) {
-		/* check whether we're reopening an existing tty */
-		tty = tty_driver_lookup_tty(driver, inode, index);
-
-		if (IS_ERR(tty)) {
-			unlock_kernel();
-			mutex_unlock(&tty_mutex);
-			return PTR_ERR(tty);
-		}
-	}
-
-	if (tty) {
-		retval = tty_reopen(tty);
-		if (retval)
-			tty = ERR_PTR(retval);
-	} else
-		tty = tty_init_dev(driver, index, 0);
-
-	mutex_unlock(&tty_mutex);
-	tty_driver_kref_put(driver);
-	if (IS_ERR(tty)) {
-		unlock_kernel();
-		return PTR_ERR(tty);
-	}
-
-	filp->private_data = tty;
-	file_move(filp, &tty->tty_files);
-	check_tty_count(tty, "tty_open");
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_MASTER)
-		noctty = 1;
-#ifdef TTY_DEBUG_HANGUP
-	printk(KERN_DEBUG "opening %s...", tty->name);
-#endif
-	if (!retval) {
-		if (tty->ops->open)
-			retval = tty->ops->open(tty, filp);
-		else
-			retval = -ENODEV;
-	}
-	filp->f_flags = saved_flags;
-
-	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
-						!capable(CAP_SYS_ADMIN))
-		retval = -EBUSY;
-
-	if (retval) {
-#ifdef TTY_DEBUG_HANGUP
-		printk(KERN_DEBUG "error %d in opening %s...", retval,
-		       tty->name);
-#endif
-		tty_release(inode, filp);
-		if (retval != -ERESTARTSYS) {
-			unlock_kernel();
-			return retval;
-		}
-		if (signal_pending(current)) {
-			unlock_kernel();
-			return retval;
-		}
-		schedule();
-		/*
-		 * Need to reset f_op in case a hangup happened.
-		 */
-		if (filp->f_op == &hung_up_tty_fops)
-			filp->f_op = &tty_fops;
-		unlock_kernel();
-		goto retry_open;
-	}
-	unlock_kernel();
-
-
-	mutex_lock(&tty_mutex);
-	lock_kernel();
-	spin_lock_irq(&current->sighand->siglock);
-	if (!noctty &&
-	    current->signal->leader &&
-	    !current->signal->tty &&
-	    tty->session == NULL)
-		__proc_set_tty(current, tty);
-	spin_unlock_irq(&current->sighand->siglock);
-	unlock_kernel();
-	mutex_unlock(&tty_mutex);
-	return 0;
-}
-
-
-
-/**
- *	tty_poll	-	check tty status
- *	@filp: file being polled
- *	@wait: poll wait structures to update
- *
- *	Call the line discipline polling method to obtain the poll
- *	status of the device.
- *
- *	Locking: locks called line discipline but ldisc poll method
- *	may be re-entered freely by other callers.
- */
-
-static unsigned int tty_poll(struct file *filp, poll_table *wait)
-{
-	struct tty_struct *tty;
-	struct tty_ldisc *ld;
-	int ret = 0;
-
-	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
-		return 0;
-
-	ld = tty_ldisc_ref_wait(tty);
-	if (ld->ops->poll)
-		ret = (ld->ops->poll)(tty, filp, wait);
-	tty_ldisc_deref(ld);
-	return ret;
-}
-
-static int tty_fasync(int fd, struct file *filp, int on)
-{
-	struct tty_struct *tty;
-	unsigned long flags;
-	int retval = 0;
-
-	lock_kernel();
-	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
-		goto out;
-
-	retval = fasync_helper(fd, filp, on, &tty->fasync);
-	if (retval <= 0)
-		goto out;
-
-	if (on) {
-		enum pid_type type;
-		struct pid *pid;
-		if (!waitqueue_active(&tty->read_wait))
-			tty->minimum_to_wake = 1;
-		spin_lock_irqsave(&tty->ctrl_lock, flags);
-		if (tty->pgrp) {
-			pid = tty->pgrp;
-			type = PIDTYPE_PGID;
-		} else {
-			pid = task_pid(current);
-			type = PIDTYPE_PID;
-		}
-		get_pid(pid);
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		retval = __f_setown(filp, pid, type, 0);
-		put_pid(pid);
-		if (retval)
-			goto out;
-	} else {
-		if (!tty->fasync && !waitqueue_active(&tty->read_wait))
-			tty->minimum_to_wake = N_TTY_BUF_SIZE;
-	}
-	retval = 0;
-out:
-	unlock_kernel();
-	return retval;
-}
-
-/**
- *	tiocsti			-	fake input character
- *	@tty: tty to fake input into
- *	@p: pointer to character
- *
- *	Fake input to a tty device. Does the necessary locking and
- *	input management.
- *
- *	FIXME: does not honour flow control ??
- *
- *	Locking:
- *		Called functions take tty_ldisc_lock
- *		current->signal->tty check is safe without locks
- *
- *	FIXME: may race normal receive processing
- */
-
-static int tiocsti(struct tty_struct *tty, char __user *p)
-{
-	char ch, mbz = 0;
-	struct tty_ldisc *ld;
-
-	if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	if (get_user(ch, p))
-		return -EFAULT;
-	tty_audit_tiocsti(tty, ch);
-	ld = tty_ldisc_ref_wait(tty);
-	ld->ops->receive_buf(tty, &ch, &mbz, 1);
-	tty_ldisc_deref(ld);
-	return 0;
-}
-
-/**
- *	tiocgwinsz		-	implement window query ioctl
- *	@tty; tty
- *	@arg: user buffer for result
- *
- *	Copies the kernel idea of the window size into the user buffer.
- *
- *	Locking: tty->termios_mutex is taken to ensure the winsize data
- *		is consistent.
- */
-
-static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-	int err;
-
-	mutex_lock(&tty->termios_mutex);
-	err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
-	mutex_unlock(&tty->termios_mutex);
-
-	return err ? -EFAULT: 0;
-}
-
-/**
- *	tty_do_resize		-	resize event
- *	@tty: tty being resized
- *	@rows: rows (character)
- *	@cols: cols (character)
- *
- *	Update the termios variables and send the necessary signals to
- *	peform a terminal resize correctly
- */
-
-int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
-{
-	struct pid *pgrp;
-	unsigned long flags;
-
-	/* Lock the tty */
-	mutex_lock(&tty->termios_mutex);
-	if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
-		goto done;
-	/* Get the PID values and reference them so we can
-	   avoid holding the tty ctrl lock while sending signals */
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	pgrp = get_pid(tty->pgrp);
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-	if (pgrp)
-		kill_pgrp(pgrp, SIGWINCH, 1);
-	put_pid(pgrp);
-
-	tty->winsize = *ws;
-done:
-	mutex_unlock(&tty->termios_mutex);
-	return 0;
-}
-
-/**
- *	tiocswinsz		-	implement window size set ioctl
- *	@tty; tty side of tty
- *	@arg: user buffer for result
- *
- *	Copies the user idea of the window size to the kernel. Traditionally
- *	this is just advisory information but for the Linux console it
- *	actually has driver level meaning and triggers a VC resize.
- *
- *	Locking:
- *		Driver dependant. The default do_resize method takes the
- *	tty termios mutex and ctrl_lock. The console takes its own lock
- *	then calls into the default method.
- */
-
-static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-	struct winsize tmp_ws;
-	if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
-		return -EFAULT;
-
-	if (tty->ops->resize)
-		return tty->ops->resize(tty, &tmp_ws);
-	else
-		return tty_do_resize(tty, &tmp_ws);
-}
-
-/**
- *	tioccons	-	allow admin to move logical console
- *	@file: the file to become console
- *
- *	Allow the adminstrator to move the redirected console device
- *
- *	Locking: uses redirect_lock to guard the redirect information
- */
-
-static int tioccons(struct file *file)
-{
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	if (file->f_op->write == redirected_tty_write) {
-		struct file *f;
-		spin_lock(&redirect_lock);
-		f = redirect;
-		redirect = NULL;
-		spin_unlock(&redirect_lock);
-		if (f)
-			fput(f);
-		return 0;
-	}
-	spin_lock(&redirect_lock);
-	if (redirect) {
-		spin_unlock(&redirect_lock);
-		return -EBUSY;
-	}
-	get_file(file);
-	redirect = file;
-	spin_unlock(&redirect_lock);
-	return 0;
-}
-
-/**
- *	fionbio		-	non blocking ioctl
- *	@file: file to set blocking value
- *	@p: user parameter
- *
- *	Historical tty interfaces had a blocking control ioctl before
- *	the generic functionality existed. This piece of history is preserved
- *	in the expected tty API of posix OS's.
- *
- *	Locking: none, the open file handle ensures it won't go away.
- */
-
-static int fionbio(struct file *file, int __user *p)
-{
-	int nonblock;
-
-	if (get_user(nonblock, p))
-		return -EFAULT;
-
-	spin_lock(&file->f_lock);
-	if (nonblock)
-		file->f_flags |= O_NONBLOCK;
-	else
-		file->f_flags &= ~O_NONBLOCK;
-	spin_unlock(&file->f_lock);
-	return 0;
-}
-
-/**
- *	tiocsctty	-	set controlling tty
- *	@tty: tty structure
- *	@arg: user argument
- *
- *	This ioctl is used to manage job control. It permits a session
- *	leader to set this tty as the controlling tty for the session.
- *
- *	Locking:
- *		Takes tty_mutex() to protect tty instance
- *		Takes tasklist_lock internally to walk sessions
- *		Takes ->siglock() when updating signal->tty
- */
-
-static int tiocsctty(struct tty_struct *tty, int arg)
-{
-	int ret = 0;
-	if (current->signal->leader && (task_session(current) == tty->session))
-		return ret;
-
-	mutex_lock(&tty_mutex);
-	/*
-	 * The process must be a session leader and
-	 * not have a controlling tty already.
-	 */
-	if (!current->signal->leader || current->signal->tty) {
-		ret = -EPERM;
-		goto unlock;
-	}
-
-	if (tty->session) {
-		/*
-		 * This tty is already the controlling
-		 * tty for another session group!
-		 */
-		if (arg == 1 && capable(CAP_SYS_ADMIN)) {
-			/*
-			 * Steal it away
-			 */
-			read_lock(&tasklist_lock);
-			session_clear_tty(tty->session);
-			read_unlock(&tasklist_lock);
-		} else {
-			ret = -EPERM;
-			goto unlock;
-		}
-	}
-	proc_set_tty(current, tty);
-unlock:
-	mutex_unlock(&tty_mutex);
-	return ret;
-}
-
-/**
- *	tty_get_pgrp	-	return a ref counted pgrp pid
- *	@tty: tty to read
- *
- *	Returns a refcounted instance of the pid struct for the process
- *	group controlling the tty.
- */
-
-struct pid *tty_get_pgrp(struct tty_struct *tty)
-{
-	unsigned long flags;
-	struct pid *pgrp;
-
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	pgrp = get_pid(tty->pgrp);
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-	return pgrp;
-}
-EXPORT_SYMBOL_GPL(tty_get_pgrp);
-
-/**
- *	tiocgpgrp		-	get process group
- *	@tty: tty passed by user
- *	@real_tty: tty side of the tty pased by the user if a pty else the tty
- *	@p: returned pid
- *
- *	Obtain the process group of the tty. If there is no process group
- *	return an error.
- *
- *	Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-	struct pid *pid;
-	int ret;
-	/*
-	 * (tty == real_tty) is a cheap way of
-	 * testing if the tty is NOT a master pty.
-	 */
-	if (tty == real_tty && current->signal->tty != real_tty)
-		return -ENOTTY;
-	pid = tty_get_pgrp(real_tty);
-	ret =  put_user(pid_vnr(pid), p);
-	put_pid(pid);
-	return ret;
-}
-
-/**
- *	tiocspgrp		-	attempt to set process group
- *	@tty: tty passed by user
- *	@real_tty: tty side device matching tty passed by user
- *	@p: pid pointer
- *
- *	Set the process group of the tty to the session passed. Only
- *	permitted where the tty session is our session.
- *
- *	Locking: RCU, ctrl lock
- */
-
-static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-	struct pid *pgrp;
-	pid_t pgrp_nr;
-	int retval = tty_check_change(real_tty);
-	unsigned long flags;
-
-	if (retval == -EIO)
-		return -ENOTTY;
-	if (retval)
-		return retval;
-	if (!current->signal->tty ||
-	    (current->signal->tty != real_tty) ||
-	    (real_tty->session != task_session(current)))
-		return -ENOTTY;
-	if (get_user(pgrp_nr, p))
-		return -EFAULT;
-	if (pgrp_nr < 0)
-		return -EINVAL;
-	rcu_read_lock();
-	pgrp = find_vpid(pgrp_nr);
-	retval = -ESRCH;
-	if (!pgrp)
-		goto out_unlock;
-	retval = -EPERM;
-	if (session_of_pgrp(pgrp) != task_session(current))
-		goto out_unlock;
-	retval = 0;
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	put_pid(real_tty->pgrp);
-	real_tty->pgrp = get_pid(pgrp);
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-out_unlock:
-	rcu_read_unlock();
-	return retval;
-}
-
-/**
- *	tiocgsid		-	get session id
- *	@tty: tty passed by user
- *	@real_tty: tty side of the tty pased by the user if a pty else the tty
- *	@p: pointer to returned session id
- *
- *	Obtain the session id of the tty. If there is no session
- *	return an error.
- *
- *	Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-	/*
-	 * (tty == real_tty) is a cheap way of
-	 * testing if the tty is NOT a master pty.
-	*/
-	if (tty == real_tty && current->signal->tty != real_tty)
-		return -ENOTTY;
-	if (!real_tty->session)
-		return -ENOTTY;
-	return put_user(pid_vnr(real_tty->session), p);
-}
-
-/**
- *	tiocsetd	-	set line discipline
- *	@tty: tty device
- *	@p: pointer to user data
- *
- *	Set the line discipline according to user request.
- *
- *	Locking: see tty_set_ldisc, this function is just a helper
- */
-
-static int tiocsetd(struct tty_struct *tty, int __user *p)
-{
-	int ldisc;
-	int ret;
-
-	if (get_user(ldisc, p))
-		return -EFAULT;
-
-	ret = tty_set_ldisc(tty, ldisc);
-
-	return ret;
-}
-
-/**
- *	send_break	-	performed time break
- *	@tty: device to break on
- *	@duration: timeout in mS
- *
- *	Perform a timed break on hardware that lacks its own driver level
- *	timed break functionality.
- *
- *	Locking:
- *		atomic_write_lock serializes
- *
- */
-
-static int send_break(struct tty_struct *tty, unsigned int duration)
-{
-	int retval;
-
-	if (tty->ops->break_ctl == NULL)
-		return 0;
-
-	if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
-		retval = tty->ops->break_ctl(tty, duration);
-	else {
-		/* Do the work ourselves */
-		if (tty_write_lock(tty, 0) < 0)
-			return -EINTR;
-		retval = tty->ops->break_ctl(tty, -1);
-		if (retval)
-			goto out;
-		if (!signal_pending(current))
-			msleep_interruptible(duration);
-		retval = tty->ops->break_ctl(tty, 0);
-out:
-		tty_write_unlock(tty);
-		if (signal_pending(current))
-			retval = -EINTR;
-	}
-	return retval;
-}
-
-/**
- *	tty_tiocmget		-	get modem status
- *	@tty: tty device
- *	@file: user file pointer
- *	@p: pointer to result
- *
- *	Obtain the modem status bits from the tty driver if the feature
- *	is supported. Return -EINVAL if it is not available.
- *
- *	Locking: none (up to the driver)
- */
-
-static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
-{
-	int retval = -EINVAL;
-
-	if (tty->ops->tiocmget) {
-		retval = tty->ops->tiocmget(tty, file);
-
-		if (retval >= 0)
-			retval = put_user(retval, p);
-	}
-	return retval;
-}
-
-/**
- *	tty_tiocmset		-	set modem status
- *	@tty: tty device
- *	@file: user file pointer
- *	@cmd: command - clear bits, set bits or set all
- *	@p: pointer to desired bits
- *
- *	Set the modem status bits from the tty driver if the feature
- *	is supported. Return -EINVAL if it is not available.
- *
- *	Locking: none (up to the driver)
- */
-
-static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
-	     unsigned __user *p)
-{
-	int retval;
-	unsigned int set, clear, val;
-
-	if (tty->ops->tiocmset == NULL)
-		return -EINVAL;
-
-	retval = get_user(val, p);
-	if (retval)
-		return retval;
-	set = clear = 0;
-	switch (cmd) {
-	case TIOCMBIS:
-		set = val;
-		break;
-	case TIOCMBIC:
-		clear = val;
-		break;
-	case TIOCMSET:
-		set = val;
-		clear = ~val;
-		break;
-	}
-	set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP|TIOCM_CD|
-		TIOCM_RI|TIOCM_DSR|TIOCM_CTS;
-	clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP|TIOCM_CD|
-		TIOCM_RI|TIOCM_DSR|TIOCM_CTS;
-	return tty->ops->tiocmset(tty, file, set, clear);
-}
-
-struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
-{
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_MASTER)
-		tty = tty->link;
-	return tty;
-}
-EXPORT_SYMBOL(tty_pair_get_tty);
-
-struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
-{
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_MASTER)
-	    return tty;
-	return tty->link;
-}
-EXPORT_SYMBOL(tty_pair_get_pty);
-
-/*
- * Split this up, as gcc can choke on it otherwise..
- */
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct tty_struct *tty, *real_tty;
-	void __user *p = (void __user *)arg;
-	int retval;
-	struct tty_ldisc *ld;
-	struct inode *inode = file->f_dentry->d_inode;
-
-	tty = (struct tty_struct *)file->private_data;
-	if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-		return -EINVAL;
-
-	real_tty = tty_pair_get_tty(tty);
-
-	/*
-	 * Factor out some common prep work
-	 */
-	switch (cmd) {
-	case TIOCSETD:
-	case TIOCSBRK:
-	case TIOCCBRK:
-	case TCSBRK:
-	case TCSBRKP:
-		retval = tty_check_change(tty);
-		if (retval)
-			return retval;
-		if (cmd != TIOCCBRK) {
-			tty_wait_until_sent(tty, 0);
-			if (signal_pending(current))
-				return -EINTR;
-		}
-		break;
-	}
-
-	/*
-	 *	Now do the stuff.
-	 */
-	switch (cmd) {
-	case TIOCSTI:
-		return tiocsti(tty, p);
-	case TIOCGWINSZ:
-		return tiocgwinsz(real_tty, p);
-	case TIOCSWINSZ:
-		return tiocswinsz(real_tty, p);
-	case TIOCCONS:
-		return real_tty != tty ? -EINVAL : tioccons(file);
-	case FIONBIO:
-		return fionbio(file, p);
-	case TIOCEXCL:
-		set_bit(TTY_EXCLUSIVE, &tty->flags);
-		return 0;
-	case TIOCNXCL:
-		clear_bit(TTY_EXCLUSIVE, &tty->flags);
-		return 0;
-	case TIOCNOTTY:
-		if (current->signal->tty != tty)
-			return -ENOTTY;
-		no_tty();
-		return 0;
-	case TIOCSCTTY:
-		return tiocsctty(tty, arg);
-	case TIOCGPGRP:
-		return tiocgpgrp(tty, real_tty, p);
-	case TIOCSPGRP:
-		return tiocspgrp(tty, real_tty, p);
-	case TIOCGSID:
-		return tiocgsid(tty, real_tty, p);
-	case TIOCGETD:
-		return put_user(tty->ldisc->ops->num, (int __user *)p);
-	case TIOCSETD:
-		return tiocsetd(tty, p);
-	/*
-	 * Break handling
-	 */
-	case TIOCSBRK:	/* Turn break on, unconditionally */
-		if (tty->ops->break_ctl)
-			return tty->ops->break_ctl(tty, -1);
-		return 0;
-	case TIOCCBRK:	/* Turn break off, unconditionally */
-		if (tty->ops->break_ctl)
-			return tty->ops->break_ctl(tty, 0);
-		return 0;
-	case TCSBRK:   /* SVID version: non-zero arg --> no break */
-		/* non-zero arg means wait for all output data
-		 * to be sent (performed above) but don't send break.
-		 * This is used by the tcdrain() termios function.
-		 */
-		if (!arg)
-			return send_break(tty, 250);
-		return 0;
-	case TCSBRKP:	/* support for POSIX tcsendbreak() */
-		return send_break(tty, arg ? arg*100 : 250);
-
-	case TIOCMGET:
-		return tty_tiocmget(tty, file, p);
-	case TIOCMSET:
-	case TIOCMBIC:
-	case TIOCMBIS:
-		return tty_tiocmset(tty, file, cmd, p);
-	case TCFLSH:
-		switch (arg) {
-		case TCIFLUSH:
-		case TCIOFLUSH:
-		/* flush tty buffer and allow ldisc to process ioctl */
-			tty_buffer_flush(tty);
-			break;
-		}
-		break;
-	}
-	if (tty->ops->ioctl) {
-		retval = (tty->ops->ioctl)(tty, file, cmd, arg);
-		if (retval != -ENOIOCTLCMD)
-			return retval;
-	}
-	ld = tty_ldisc_ref_wait(tty);
-	retval = -EINVAL;
-	if (ld->ops->ioctl) {
-		retval = ld->ops->ioctl(tty, file, cmd, arg);
-		if (retval == -ENOIOCTLCMD)
-			retval = -EINVAL;
-	}
-	tty_ldisc_deref(ld);
-	return retval;
-}
-
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-				unsigned long arg)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	struct tty_struct *tty = file->private_data;
-	struct tty_ldisc *ld;
-	int retval = -ENOIOCTLCMD;
-
-	if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-		return -EINVAL;
-
-	if (tty->ops->compat_ioctl) {
-		retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
-		if (retval != -ENOIOCTLCMD)
-			return retval;
-	}
-
-	ld = tty_ldisc_ref_wait(tty);
-	if (ld->ops->compat_ioctl)
-		retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
-	tty_ldisc_deref(ld);
-
-	return retval;
-}
-#endif
-
-/*
- * This implements the "Secure Attention Key" ---  the idea is to
- * prevent trojan horses by killing all processes associated with this
- * tty when the user hits the "Secure Attention Key".  Required for
- * super-paranoid applications --- see the Orange Book for more details.
- *
- * This code could be nicer; ideally it should send a HUP, wait a few
- * seconds, then send a INT, and then a KILL signal.  But you then
- * have to coordinate with the init process, since all processes associated
- * with the current tty must be dead before the new getty is allowed
- * to spawn.
- *
- * Now, if it would be correct ;-/ The current code has a nasty hole -
- * it doesn't catch files in flight. We may send the descriptor to ourselves
- * via AF_UNIX socket, close it and later fetch from socket. FIXME.
- *
- * Nasty bug: do_SAK is being called in interrupt context.  This can
- * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
- */
-void __do_SAK(struct tty_struct *tty)
-{
-#ifdef TTY_SOFT_SAK
-	tty_hangup(tty);
-#else
-	struct task_struct *g, *p;
-	struct pid *session;
-	int		i;
-	struct file	*filp;
-	struct fdtable *fdt;
-
-	if (!tty)
-		return;
-	session = tty->session;
-
-	tty_ldisc_flush(tty);
-
-	tty_driver_flush_buffer(tty);
-
-	read_lock(&tasklist_lock);
-	/* Kill the entire session */
-	do_each_pid_task(session, PIDTYPE_SID, p) {
-		printk(KERN_NOTICE "SAK: killed process %d"
-			" (%s): task_session(p)==tty->session\n",
-			task_pid_nr(p), p->comm);
-		send_sig(SIGKILL, p, 1);
-	} while_each_pid_task(session, PIDTYPE_SID, p);
-	/* Now kill any processes that happen to have the
-	 * tty open.
-	 */
-	do_each_thread(g, p) {
-		if (p->signal->tty == tty) {
-			printk(KERN_NOTICE "SAK: killed process %d"
-			    " (%s): task_session(p)==tty->session\n",
-			    task_pid_nr(p), p->comm);
-			send_sig(SIGKILL, p, 1);
-			continue;
-		}
-		task_lock(p);
-		if (p->files) {
-			/*
-			 * We don't take a ref to the file, so we must
-			 * hold ->file_lock instead.
-			 */
-			spin_lock(&p->files->file_lock);
-			fdt = files_fdtable(p->files);
-			for (i = 0; i < fdt->max_fds; i++) {
-				filp = fcheck_files(p->files, i);
-				if (!filp)
-					continue;
-				if (filp->f_op->read == tty_read &&
-				    filp->private_data == tty) {
-					printk(KERN_NOTICE "SAK: killed process %d"
-					    " (%s): fd#%d opened to the tty\n",
-					    task_pid_nr(p), p->comm, i);
-					force_sig(SIGKILL, p);
-					break;
-				}
-			}
-			spin_unlock(&p->files->file_lock);
-		}
-		task_unlock(p);
-	} while_each_thread(g, p);
-	read_unlock(&tasklist_lock);
-#endif
-}
-
-static void do_SAK_work(struct work_struct *work)
-{
-	struct tty_struct *tty =
-		container_of(work, struct tty_struct, SAK_work);
-	__do_SAK(tty);
-}
-
-/*
- * The tq handling here is a little racy - tty->SAK_work may already be queued.
- * Fortunately we don't need to worry, because if ->SAK_work is already queued,
- * the values which we write to it will be identical to the values which it
- * already has. --akpm
- */
-void do_SAK(struct tty_struct *tty)
-{
-	if (!tty)
-		return;
-	schedule_work(&tty->SAK_work);
-}
-
-EXPORT_SYMBOL(do_SAK);
-
-/**
- *	initialize_tty_struct
- *	@tty: tty to initialize
- *
- *	This subroutine initializes a tty structure that has been newly
- *	allocated.
- *
- *	Locking: none - tty in question must not be exposed at this point
- */
-
-void initialize_tty_struct(struct tty_struct *tty,
-		struct tty_driver *driver, int idx)
-{
-	memset(tty, 0, sizeof(struct tty_struct));
-	kref_init(&tty->kref);
-	tty->magic = TTY_MAGIC;
-	tty_ldisc_init(tty);
-	tty->session = NULL;
-	tty->pgrp = NULL;
-	tty->overrun_time = jiffies;
-	tty->buf.head = tty->buf.tail = NULL;
-	tty_buffer_init(tty);
-	mutex_init(&tty->termios_mutex);
-	mutex_init(&tty->ldisc_mutex);
-	init_waitqueue_head(&tty->write_wait);
-	init_waitqueue_head(&tty->read_wait);
-	INIT_WORK(&tty->hangup_work, do_tty_hangup);
-	mutex_init(&tty->atomic_read_lock);
-	mutex_init(&tty->atomic_write_lock);
-	mutex_init(&tty->output_lock);
-	mutex_init(&tty->echo_lock);
-	spin_lock_init(&tty->read_lock);
-	spin_lock_init(&tty->ctrl_lock);
-	INIT_LIST_HEAD(&tty->tty_files);
-	INIT_WORK(&tty->SAK_work, do_SAK_work);
-
-	tty->driver = driver;
-	tty->ops = driver->ops;
-	tty->index = idx;
-	tty_line_name(driver, idx, tty->name);
-}
-
-/**
- *	tty_put_char	-	write one character to a tty
- *	@tty: tty
- *	@ch: character
- *
- *	Write one byte to the tty using the provided put_char method
- *	if present. Returns the number of characters successfully output.
- *
- *	Note: the specific put_char operation in the driver layer may go
- *	away soon. Don't call it directly, use this method
- */
-
-int tty_put_char(struct tty_struct *tty, unsigned char ch)
-{
-	if (tty->ops->put_char)
-		return tty->ops->put_char(tty, ch);
-	return tty->ops->write(tty, &ch, 1);
-}
-EXPORT_SYMBOL_GPL(tty_put_char);
-
-struct class *tty_class;
-
-/**
- *	tty_register_device - register a tty device
- *	@driver: the tty driver that describes the tty device
- *	@index: the index in the tty driver for this tty device
- *	@device: a struct device that is associated with this tty device.
- *		This field is optional, if there is no known struct device
- *		for this tty device it can be set to NULL safely.
- *
- *	Returns a pointer to the struct device for this tty device
- *	(or ERR_PTR(-EFOO) on error).
- *
- *	This call is required to be made to register an individual tty device
- *	if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If
- *	that bit is not set, this function should not be called by a tty
- *	driver.
- *
- *	Locking: ??
- */
-
-struct device *tty_register_device(struct tty_driver *driver, unsigned index,
-				   struct device *device)
-{
-	char name[64];
-	dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
-
-	if (index >= driver->num) {
-		printk(KERN_ERR "Attempt to register invalid tty line number "
-		       " (%d).\n", index);
-		return ERR_PTR(-EINVAL);
-	}
-
-	if (driver->type == TTY_DRIVER_TYPE_PTY)
-		pty_line_name(driver, index, name);
-	else
-		tty_line_name(driver, index, name);
-
-	return device_create(tty_class, device, dev, NULL, name);
-}
-EXPORT_SYMBOL(tty_register_device);
-
-/**
- * 	tty_unregister_device - unregister a tty device
- * 	@driver: the tty driver that describes the tty device
- * 	@index: the index in the tty driver for this tty device
- *
- * 	If a tty device is registered with a call to tty_register_device() then
- *	this function must be called when the tty device is gone.
- *
- *	Locking: ??
- */
-
-void tty_unregister_device(struct tty_driver *driver, unsigned index)
-{
-	device_destroy(tty_class,
-		MKDEV(driver->major, driver->minor_start) + index);
-}
-EXPORT_SYMBOL(tty_unregister_device);
-
-struct tty_driver *alloc_tty_driver(int lines)
-{
-	struct tty_driver *driver;
-
-	driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
-	if (driver) {
-		kref_init(&driver->kref);
-		driver->magic = TTY_DRIVER_MAGIC;
-		driver->num = lines;
-		/* later we'll move allocation of tables here */
-	}
-	return driver;
-}
-EXPORT_SYMBOL(alloc_tty_driver);
-
-static void destruct_tty_driver(struct kref *kref)
-{
-	struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
-	int i;
-	struct ktermios *tp;
-	void *p;
-
-	if (driver->flags & TTY_DRIVER_INSTALLED) {
-		/*
-		 * Free the termios and termios_locked structures because
-		 * we don't want to get memory leaks when modular tty
-		 * drivers are removed from the kernel.
-		 */
-		for (i = 0; i < driver->num; i++) {
-			tp = driver->termios[i];
-			if (tp) {
-				driver->termios[i] = NULL;
-				kfree(tp);
-			}
-			if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
-				tty_unregister_device(driver, i);
-		}
-		p = driver->ttys;
-		proc_tty_unregister_driver(driver);
-		driver->ttys = NULL;
-		driver->termios = NULL;
-		kfree(p);
-		cdev_del(&driver->cdev);
-	}
-	kfree(driver);
-}
-
-void tty_driver_kref_put(struct tty_driver *driver)
-{
-	kref_put(&driver->kref, destruct_tty_driver);
-}
-EXPORT_SYMBOL(tty_driver_kref_put);
-
-void tty_set_operations(struct tty_driver *driver,
-			const struct tty_operations *op)
-{
-	driver->ops = op;
-};
-EXPORT_SYMBOL(tty_set_operations);
-
-void put_tty_driver(struct tty_driver *d)
-{
-	tty_driver_kref_put(d);
-}
-EXPORT_SYMBOL(put_tty_driver);
-
-/*
- * Called by a tty driver to register itself.
- */
-int tty_register_driver(struct tty_driver *driver)
-{
-	int error;
-	int i;
-	dev_t dev;
-	void **p = NULL;
-
-	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-		p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
-		if (!p)
-			return -ENOMEM;
-	}
-
-	if (!driver->major) {
-		error = alloc_chrdev_region(&dev, driver->minor_start,
-						driver->num, driver->name);
-		if (!error) {
-			driver->major = MAJOR(dev);
-			driver->minor_start = MINOR(dev);
-		}
-	} else {
-		dev = MKDEV(driver->major, driver->minor_start);
-		error = register_chrdev_region(dev, driver->num, driver->name);
-	}
-	if (error < 0) {
-		kfree(p);
-		return error;
-	}
-
-	if (p) {
-		driver->ttys = (struct tty_struct **)p;
-		driver->termios = (struct ktermios **)(p + driver->num);
-	} else {
-		driver->ttys = NULL;
-		driver->termios = NULL;
-	}
-
-	cdev_init(&driver->cdev, &tty_fops);
-	driver->cdev.owner = driver->owner;
-	error = cdev_add(&driver->cdev, dev, driver->num);
-	if (error) {
-		unregister_chrdev_region(dev, driver->num);
-		driver->ttys = NULL;
-		driver->termios = NULL;
-		kfree(p);
-		return error;
-	}
-
-	mutex_lock(&tty_mutex);
-	list_add(&driver->tty_drivers, &tty_drivers);
-	mutex_unlock(&tty_mutex);
-
-	if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
-		for (i = 0; i < driver->num; i++)
-		    tty_register_device(driver, i, NULL);
-	}
-	proc_tty_register_driver(driver);
-	driver->flags |= TTY_DRIVER_INSTALLED;
-	return 0;
-}
-
-EXPORT_SYMBOL(tty_register_driver);
-
-/*
- * Called by a tty driver to unregister itself.
- */
-int tty_unregister_driver(struct tty_driver *driver)
-{
-#if 0
-	/* FIXME */
-	if (driver->refcount)
-		return -EBUSY;
-#endif
-	unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
-				driver->num);
-	mutex_lock(&tty_mutex);
-	list_del(&driver->tty_drivers);
-	mutex_unlock(&tty_mutex);
-	return 0;
-}
-
-EXPORT_SYMBOL(tty_unregister_driver);
-
-dev_t tty_devnum(struct tty_struct *tty)
-{
-	return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
-}
-EXPORT_SYMBOL(tty_devnum);
-
-void proc_clear_tty(struct task_struct *p)
-{
-	unsigned long flags;
-	struct tty_struct *tty;
-	spin_lock_irqsave(&p->sighand->siglock, flags);
-	tty = p->signal->tty;
-	p->signal->tty = NULL;
-	spin_unlock_irqrestore(&p->sighand->siglock, flags);
-	tty_kref_put(tty);
-}
-
-/* Called under the sighand lock */
-
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-	if (tty) {
-		unsigned long flags;
-		/* We should not have a session or pgrp to put here but.... */
-		spin_lock_irqsave(&tty->ctrl_lock, flags);
-		put_pid(tty->session);
-		put_pid(tty->pgrp);
-		tty->pgrp = get_pid(task_pgrp(tsk));
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		tty->session = get_pid(task_session(tsk));
-		if (tsk->signal->tty) {
-			printk(KERN_DEBUG "tty not NULL!!\n");
-			tty_kref_put(tsk->signal->tty);
-		}
-	}
-	put_pid(tsk->signal->tty_old_pgrp);
-	tsk->signal->tty = tty_kref_get(tty);
-	tsk->signal->tty_old_pgrp = NULL;
-}
-
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-	spin_lock_irq(&tsk->sighand->siglock);
-	__proc_set_tty(tsk, tty);
-	spin_unlock_irq(&tsk->sighand->siglock);
-}
-
-struct tty_struct *get_current_tty(void)
-{
-	struct tty_struct *tty;
-	unsigned long flags;
-
-	spin_lock_irqsave(&current->sighand->siglock, flags);
-	tty = tty_kref_get(current->signal->tty);
-	spin_unlock_irqrestore(&current->sighand->siglock, flags);
-	return tty;
-}
-EXPORT_SYMBOL_GPL(get_current_tty);
-
-void tty_default_fops(struct file_operations *fops)
-{
-	*fops = tty_fops;
-}
-
-/*
- * Initialize the console device. This is called *early*, so
- * we can't necessarily depend on lots of kernel help here.
- * Just do some early initializations, and do the complex setup
- * later.
- */
-void __init console_init(void)
-{
-	initcall_t *call;
-
-	/* Setup the default TTY line discipline. */
-	tty_ldisc_begin();
-
-	/*
-	 * set up the console device so that later boot sequences can
-	 * inform about problems etc..
-	 */
-	call = __con_initcall_start;
-	while (call < __con_initcall_end) {
-		(*call)();
-		call++;
-	}
-}
-
-static char *tty_devnode(struct device *dev, mode_t *mode)
-{
-	if (!mode)
-		return NULL;
-	if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
-	    dev->devt == MKDEV(TTYAUX_MAJOR, 2))
-		*mode = 0666;
-	return NULL;
-}
-
-static int __init tty_class_init(void)
-{
-	tty_class = class_create(THIS_MODULE, "tty");
-	if (IS_ERR(tty_class))
-		return PTR_ERR(tty_class);
-	tty_class->devnode = tty_devnode;
-	return 0;
-}
-
-postcore_initcall(tty_class_init);
-
-/* 3/2004 jmc: why do these devices exist? */
-
-static struct cdev tty_cdev, console_cdev;
-
-/*
- * Ok, now we can initialize the rest of the tty devices and can count
- * on memory allocations, interrupts etc..
- */
-int __init tty_init(void)
-{
-	cdev_init(&tty_cdev, &tty_fops);
-	if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
-	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
-		panic("Couldn't register /dev/tty driver\n");
-	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
-			      "tty");
-
-	cdev_init(&console_cdev, &console_fops);
-	if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
-	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
-		panic("Couldn't register /dev/console driver\n");
-	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
-			      "console");
-
-#ifdef CONFIG_VT
-	vty_init(&console_fops);
-#endif
-	return 0;
-}
-
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 2ae54ea..1033233 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -265,6 +265,16 @@
 
 static struct etm_drvdata *etmdrvdata[NR_CPUS];
 
+static bool etm_os_lock_present(struct etm_drvdata *drvdata)
+{
+	uint32_t etmoslsr;
+
+	etmoslsr = etm_readl(drvdata, ETMOSLSR);
+	if (!BVAL(etmoslsr, 0) && !BVAL(etmoslsr, 3))
+		return false;
+	return true;
+}
+
 /*
  * Memory mapped writes to clear os lock are not supported on Krait v1, v2
  * and OS lock must be unlocked before any memory mapped access, otherwise
@@ -272,10 +282,17 @@
  */
 static void etm_os_unlock(void *info)
 {
+	struct etm_drvdata *drvdata = (struct etm_drvdata *) info;
+
+	ETM_UNLOCK(drvdata);
 	if (cpu_is_krait()) {
 		etm_writel_cp14(0x0, ETMOSLAR);
 		isb();
+	} else if (etm_os_lock_present(drvdata)) {
+		etm_writel(drvdata, 0x0, ETMOSLAR);
+		mb();
 	}
+	ETM_LOCK(drvdata);
 }
 
 /*
@@ -2104,7 +2121,7 @@
 	get_online_cpus();
 	etmdrvdata[drvdata->cpu] = drvdata;
 
-	if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, NULL, 1))
+	if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, drvdata, 1))
 		drvdata->os_unlock = true;
 	/*
 	 * Use CPU0 to populate read-only configuration data for ETM0. For
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 0afb5a2..86276b7 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -217,7 +217,7 @@
 {
 	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
 
-	get_bam2bam_connection_info(0, PEER_PERIPHERAL_TO_USB,
+	get_bam2bam_connection_info(usb_bam_get_qdss_idx(0),
 				    &bamdata->dest,
 				    &bamdata->dest_pipe_idx,
 				    &bamdata->src_pipe_idx,
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index be71347..3d5614b 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -787,6 +787,8 @@
 
 			spin_lock_irqsave(&cpufreq_driver_lock, flags);
 			cpumask_copy(managed_policy->cpus, policy->cpus);
+			cpumask_and(managed_policy->cpus,
+					managed_policy->cpus, cpu_online_mask);
 			per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
 			spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 3157a86..ec38843 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -163,15 +163,6 @@
 {
 	int mult = 1;
 
-	/* for higher loadavg, we are more reluctant */
-
-	/*
-	 * this doesn't work as intended - it is almost always 0, but can
-	 * sometimes, depending on workload, spike very high into the hundreds
-	 * even when the average cpu load is under 10%.
-	 */
-	/* mult += 2 * get_loadavg(); */
-
 	/* for IO wait tasks (per cpu!) we add 5x each */
 	mult += 10 * nr_iowait_cpu(smp_processor_id());
 
diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c
index 7f8460b..5c1cc5a 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -505,19 +505,6 @@
 	return nents;
 }
 
-static int dma_map_pmem_sg(struct buf_info *pmem, unsigned entries,
-						struct scatterlist *sg)
-{
-	int i = 0;
-	for (i = 0; i < entries; i++) {
-
-		sg->dma_address = (dma_addr_t)pmem->offset;
-		sg++;
-		pmem++;
-	}
-	return 0;
-}
-
 static int _probe_ce_engine(struct qce_device *pce_dev)
 {
 	unsigned int val;
@@ -1084,52 +1071,6 @@
 	return 0;
 };
 
-static int _ablk_cipher_use_pmem_complete(struct qce_device *pce_dev)
-{
-	struct ablkcipher_request *areq;
-	uint32_t iv_out[4];
-	unsigned char iv[4 * sizeof(uint32_t)];
-	uint32_t status;
-
-	areq = (struct ablkcipher_request *) pce_dev->areq;
-
-	/* check ce error status */
-	status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
-	if (status & (1 << CRYPTO_SW_ERR)) {
-		pce_dev->err++;
-		dev_err(pce_dev->pdev,
-			"Qualcomm Crypto Error at 0x%x, status%x\n",
-			pce_dev->phy_iobase, status);
-		_init_ce_engine(pce_dev);
-		clk_disable(pce_dev->ce_clk);
-		pce_dev->qce_cb(areq, NULL, NULL, -ENXIO);
-		return 0;
-	};
-
-	/* get iv out */
-	if (pce_dev->mode == QCE_MODE_ECB) {
-		clk_disable(pce_dev->ce_clk);
-		pce_dev->qce_cb(areq, NULL, NULL, pce_dev->chan_ce_in_status |
-					pce_dev->chan_ce_out_status);
-	} else {
-		iv_out[0] = readl_relaxed(pce_dev->iobase +
-							CRYPTO_CNTR0_IV0_REG);
-		iv_out[1] = readl_relaxed(pce_dev->iobase +
-							CRYPTO_CNTR1_IV1_REG);
-		iv_out[2] = readl_relaxed(pce_dev->iobase +
-							CRYPTO_CNTR2_IV2_REG);
-		iv_out[3] = readl_relaxed(pce_dev->iobase +
-							CRYPTO_CNTR3_IV3_REG);
-
-		_net_words_to_byte_stream(iv_out, iv, sizeof(iv));
-		clk_disable(pce_dev->ce_clk);
-		pce_dev->qce_cb(areq, NULL, iv, pce_dev->chan_ce_in_status |
-					pce_dev->chan_ce_out_status);
-	}
-
-	return 0;
-};
-
 static int qce_split_and_insert_dm_desc(struct dmov_desc *pdesc,
 			unsigned int plen, unsigned int paddr, int *index)
 {
@@ -1555,53 +1496,6 @@
 };
 
 
-static void _ablk_cipher_ce_in_call_back_pmem(struct msm_dmov_cmd *cmd_ptr,
-		unsigned int result, struct msm_dmov_errdata *err)
-{
-	struct qce_device *pce_dev;
-
-	pce_dev = (struct qce_device *) cmd_ptr->user;
-	if (result != ADM_STATUS_OK) {
-		dev_err(pce_dev->pdev, "Qualcomm ADM status error %x\n",
-						result);
-		pce_dev->chan_ce_in_status = -1;
-	} else
-		pce_dev->chan_ce_in_status = 0;
-
-	pce_dev->chan_ce_in_state = QCE_CHAN_STATE_COMP;
-	if (pce_dev->chan_ce_out_state == QCE_CHAN_STATE_COMP) {
-		pce_dev->chan_ce_in_state = QCE_CHAN_STATE_IDLE;
-		pce_dev->chan_ce_out_state = QCE_CHAN_STATE_IDLE;
-
-		/* done */
-		_ablk_cipher_use_pmem_complete(pce_dev);
-	}
-};
-
-static void _ablk_cipher_ce_out_call_back_pmem(struct msm_dmov_cmd *cmd_ptr,
-		unsigned int result, struct msm_dmov_errdata *err)
-{
-	struct qce_device *pce_dev;
-
-	pce_dev = (struct qce_device *) cmd_ptr->user;
-	if (result != ADM_STATUS_OK) {
-		dev_err(pce_dev->pdev, "Qualcomm ADM status error %x\n",
-						result);
-		pce_dev->chan_ce_out_status = -1;
-	} else {
-		pce_dev->chan_ce_out_status = 0;
-	};
-
-	pce_dev->chan_ce_out_state = QCE_CHAN_STATE_COMP;
-	if (pce_dev->chan_ce_in_state == QCE_CHAN_STATE_COMP) {
-		pce_dev->chan_ce_in_state = QCE_CHAN_STATE_IDLE;
-		pce_dev->chan_ce_out_state = QCE_CHAN_STATE_IDLE;
-
-		/* done */
-		_ablk_cipher_use_pmem_complete(pce_dev);
-	}
-};
-
 static int _setup_cmd_template(struct qce_device *pce_dev)
 {
 	dmov_sg *pcmd;
@@ -2183,14 +2077,9 @@
 	/* cipher input       */
 	pce_dev->src_nents = count_sg(areq->src, areq->nbytes);
 
-	if (c_req->use_pmem != 1)
-		qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+	qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
 			(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
 								DMA_TO_DEVICE);
-	else
-		dma_map_pmem_sg(&c_req->pmem->src[0], pce_dev->src_nents,
-								areq->src);
-
 	if (_chain_sg_buffer_in(pce_dev, areq->src, areq->nbytes) < 0) {
 		rc = -ENOMEM;
 		goto bad;
@@ -2199,12 +2088,8 @@
 	/* cipher output      */
 	if (areq->src != areq->dst) {
 		pce_dev->dst_nents = count_sg(areq->dst, areq->nbytes);
-		if (c_req->use_pmem != 1)
-			qce_dma_map_sg(pce_dev->pdev, areq->dst,
+		qce_dma_map_sg(pce_dev->pdev, areq->dst,
 					pce_dev->dst_nents, DMA_FROM_DEVICE);
-		else
-			dma_map_pmem_sg(&c_req->pmem->dst[0],
-					pce_dev->dst_nents, areq->dst);
 	};
 	if (_chain_sg_buffer_out(pce_dev, areq->dst, areq->nbytes) < 0) {
 		rc = -ENOMEM;
@@ -2241,34 +2126,25 @@
 	/* setup for callback, and issue command to adm */
 	pce_dev->areq = areq;
 	pce_dev->qce_cb = c_req->qce_cb;
-	if (c_req->use_pmem == 1) {
-		pce_dev->chan_ce_in_cmd->complete_func =
-					_ablk_cipher_ce_in_call_back_pmem;
-		pce_dev->chan_ce_out_cmd->complete_func =
-					_ablk_cipher_ce_out_call_back_pmem;
-	} else {
-		pce_dev->chan_ce_in_cmd->complete_func =
+	pce_dev->chan_ce_in_cmd->complete_func =
 					_ablk_cipher_ce_in_call_back;
-		pce_dev->chan_ce_out_cmd->complete_func =
+	pce_dev->chan_ce_out_cmd->complete_func =
 					_ablk_cipher_ce_out_call_back;
-	}
 	rc = _qce_start_dma(pce_dev, true, true);
 
 	if (rc == 0)
 		return 0;
 bad:
-	if (c_req->use_pmem != 1) {
-		if (pce_dev->dst_nents) {
-			qce_dma_unmap_sg(pce_dev->pdev, areq->dst,
-				pce_dev->dst_nents, DMA_FROM_DEVICE);
-		}
-		if (pce_dev->src_nents) {
-			qce_dma_unmap_sg(pce_dev->pdev, areq->src,
-					pce_dev->src_nents,
-					(areq->src == areq->dst) ?
-						DMA_BIDIRECTIONAL :
-						DMA_TO_DEVICE);
-		}
+	if (pce_dev->dst_nents) {
+		qce_dma_unmap_sg(pce_dev->pdev, areq->dst,
+			pce_dev->dst_nents, DMA_FROM_DEVICE);
+	}
+	if (pce_dev->src_nents) {
+		qce_dma_unmap_sg(pce_dev->pdev, areq->src,
+				pce_dev->src_nents,
+				(areq->src == areq->dst) ?
+					DMA_BIDIRECTIONAL :
+					DMA_TO_DEVICE);
 	}
 	return rc;
 }
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 1facf24..9d8e825 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -353,6 +353,9 @@
 	pce = cmdlistinfo->auth_seg_size;
 	pce->data = sreq->size;
 
+	pce = cmdlistinfo->encr_seg_cfg;
+	pce->data = 0;
+
 	/* write auth seg size start*/
 	pce = cmdlistinfo->auth_seg_start;
 	pce->data = 0;
@@ -521,8 +524,12 @@
 			pce->data = totallen_in - creq->authsize;
 		pce = cmdlistinfo->auth_seg_start;
 		pce->data = 0;
+	} else {
+		if (creq->op != QCE_REQ_AEAD) {
+			pce = cmdlistinfo->auth_seg_cfg;
+			pce->data = 0;
+		}
 	}
-
 	switch (creq->mode) {
 	case QCE_MODE_ECB:
 		encr_cfg |= (CRYPTO_ENCR_MODE_ECB << CRYPTO_ENCR_MODE);
@@ -1289,7 +1296,7 @@
 					CRYPTO_RESULT_DUMP_SIZE,
 					  &pce_dev->ce_sps.out_transfer);
 		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
-				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_INT);
+				SPS_IOVEC_FLAG_INT);
 		rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
 					  &pce_dev->ce_sps.out_transfer);
 		if (rc) {
@@ -1364,7 +1371,7 @@
 					CRYPTO_RESULT_DUMP_SIZE,
 					  &pce_dev->ce_sps.out_transfer);
 		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
-				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_INT);
+				SPS_IOVEC_FLAG_INT);
 		rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
 					  &pce_dev->ce_sps.out_transfer);
 		if (rc) {
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 41ab8dc..2440404 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -12,7 +12,7 @@
  * GNU General Public License for more details.
  */
 #include <linux/mman.h>
-#include <linux/android_pmem.h>
+
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
@@ -454,14 +454,12 @@
 
 	/* start the command on the podev->active_command */
 	qcedev_areq = podev->active_command;
-
 	qcedev_areq->cipher_req.cookie = qcedev_areq->handle;
-	creq.use_pmem = qcedev_areq->cipher_op_req.use_pmem;
-	if (qcedev_areq->cipher_op_req.use_pmem == QCEDEV_USE_PMEM)
-		creq.pmem = &qcedev_areq->cipher_op_req.pmem;
-	else
-		creq.pmem = NULL;
-
+	if (qcedev_areq->cipher_op_req.use_pmem == QCEDEV_USE_PMEM) {
+		pr_err("%s: Use of PMEM is not supported\n", __func__);
+		goto unsupported;
+	}
+	creq.pmem = NULL;
 	switch (qcedev_areq->cipher_op_req.alg) {
 	case QCEDEV_ALG_DES:
 		creq.alg = CIPHER_ALG_DES;
@@ -1274,224 +1272,6 @@
 		return qcedev_hmac_final(areq, handle);
 }
 
-#ifdef CONFIG_ANDROID_PMEM
-static int qcedev_pmem_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
-						struct qcedev_handle *handle)
-{
-	int i = 0;
-	int err = 0;
-	struct scatterlist *sg_src = NULL;
-	struct scatterlist *sg_dst = NULL;
-	struct scatterlist *sg_ndex = NULL;
-	struct file *file_src = NULL;
-	struct file *file_dst = NULL;
-	unsigned long paddr;
-	unsigned long kvaddr;
-	unsigned long len;
-
-	sg_src = kmalloc((sizeof(struct scatterlist) *
-				areq->cipher_op_req.entries),	GFP_KERNEL);
-	if (sg_src == NULL) {
-		pr_err("%s: Can't Allocate memory:sg_src 0x%x\n",
-			__func__, (uint32_t)sg_src);
-		return -ENOMEM;
-
-	}
-	memset(sg_src, 0, (sizeof(struct scatterlist) *
-				areq->cipher_op_req.entries));
-	sg_ndex = sg_src;
-	areq->cipher_req.creq.src = sg_src;
-
-	/* address src */
-	get_pmem_file(areq->cipher_op_req.pmem.fd_src, &paddr,
-					&kvaddr, &len, &file_src);
-
-	for (i = 0; i < areq->cipher_op_req.entries; i++) {
-		sg_set_buf(sg_ndex,
-		((uint8_t *)(areq->cipher_op_req.pmem.src[i].offset) + kvaddr),
-		areq->cipher_op_req.pmem.src[i].len);
-		sg_ndex++;
-	}
-	sg_mark_end(--sg_ndex);
-
-	for (i = 0; i < areq->cipher_op_req.entries; i++)
-		areq->cipher_op_req.pmem.src[i].offset += (uint32_t)paddr;
-
-	/* address dst */
-	/* If not place encryption/decryption */
-	if (areq->cipher_op_req.in_place_op != 1) {
-		sg_dst = kmalloc((sizeof(struct scatterlist) *
-				areq->cipher_op_req.entries), GFP_KERNEL);
-		if (sg_dst == NULL) {
-			pr_err("%s: Can't Allocate memory: sg_dst 0x%x\n",
-			__func__, (uint32_t)sg_dst);
-			return -ENOMEM;
-		}
-		memset(sg_dst, 0, (sizeof(struct scatterlist) *
-					areq->cipher_op_req.entries));
-		areq->cipher_req.creq.dst = sg_dst;
-		sg_ndex = sg_dst;
-
-		get_pmem_file(areq->cipher_op_req.pmem.fd_dst, &paddr,
-					&kvaddr, &len, &file_dst);
-		for (i = 0; i < areq->cipher_op_req.entries; i++)
-			sg_set_buf(sg_ndex++,
-			((uint8_t *)(areq->cipher_op_req.pmem.dst[i].offset)
-			+ kvaddr), areq->cipher_op_req.pmem.dst[i].len);
-		sg_mark_end(--sg_ndex);
-
-		for (i = 0; i < areq->cipher_op_req.entries; i++)
-			areq->cipher_op_req.pmem.dst[i].offset +=
-							(uint32_t)paddr;
-	} else {
-		areq->cipher_req.creq.dst = sg_src;
-		for (i = 0; i < areq->cipher_op_req.entries; i++) {
-			areq->cipher_op_req.pmem.dst[i].offset =
-				areq->cipher_op_req.pmem.src[i].offset;
-			areq->cipher_op_req.pmem.dst[i].len =
-				areq->cipher_op_req.pmem.src[i].len;
-		}
-	}
-
-	areq->cipher_req.creq.nbytes = areq->cipher_op_req.data_len;
-	areq->cipher_req.creq.info = areq->cipher_op_req.iv;
-
-	err = submit_req(areq, handle);
-
-	kfree(sg_src);
-	kfree(sg_dst);
-
-	if (file_dst)
-		put_pmem_file(file_dst);
-	if (file_src)
-		put_pmem_file(file_src);
-
-	return err;
-};
-
-
-static int qcedev_pmem_ablk_cipher(struct qcedev_async_req *qcedev_areq,
-						struct qcedev_handle *handle)
-{
-	int err = 0;
-	int i = 0;
-	int j = 0;
-	int k = 0;
-	int num_entries = 0;
-	uint32_t total = 0;
-	struct qcedev_cipher_op_req *saved_req;
-	struct qcedev_cipher_op_req *creq = &qcedev_areq->cipher_op_req;
-
-	saved_req = kmalloc(sizeof(struct qcedev_cipher_op_req), GFP_KERNEL);
-	if (saved_req == NULL) {
-		pr_err(KERN_ERR "%s:Can't Allocate mem:saved_req 0x%x\n",
-		__func__, (uint32_t)saved_req);
-		return -ENOMEM;
-	}
-	memcpy(saved_req, creq, sizeof(struct qcedev_cipher_op_req));
-
-	if (qcedev_areq->cipher_op_req.data_len > QCE_MAX_OPER_DATA) {
-
-		struct qcedev_cipher_op_req req;
-
-		/* save the original req structure */
-		memcpy(&req, creq, sizeof(struct qcedev_cipher_op_req));
-
-		i = 0;
-		/* Address 32 KB  at a time */
-		while ((i < req.entries) && (err == 0)) {
-			if (creq->pmem.src[i].len > QCE_MAX_OPER_DATA) {
-				creq->pmem.src[0].len =	QCE_MAX_OPER_DATA;
-				if (i > 0) {
-					creq->pmem.src[0].offset =
-						creq->pmem.src[i].offset;
-				}
-
-				creq->data_len = QCE_MAX_OPER_DATA;
-				creq->entries = 1;
-
-				err =
-				qcedev_pmem_ablk_cipher_max_xfer(qcedev_areq,
-								handle);
-
-				creq->pmem.src[i].len =	req.pmem.src[i].len -
-							QCE_MAX_OPER_DATA;
-				creq->pmem.src[i].offset =
-						req.pmem.src[i].offset +
-						QCE_MAX_OPER_DATA;
-				req.pmem.src[i].offset =
-						creq->pmem.src[i].offset;
-				req.pmem.src[i].len = creq->pmem.src[i].len;
-			} else {
-				total = 0;
-				for (j = i; j < req.entries; j++) {
-					num_entries++;
-					if ((total + creq->pmem.src[j].len)
-							>= QCE_MAX_OPER_DATA) {
-						creq->pmem.src[j].len =
-						QCE_MAX_OPER_DATA - total;
-						total = QCE_MAX_OPER_DATA;
-						break;
-					}
-					total += creq->pmem.src[j].len;
-				}
-
-				creq->data_len = total;
-				if (i > 0)
-					for (k = 0; k < num_entries; k++) {
-						creq->pmem.src[k].len =
-						creq->pmem.src[i+k].len;
-						creq->pmem.src[k].offset =
-						creq->pmem.src[i+k].offset;
-					}
-				creq->entries =  num_entries;
-
-				i = j;
-				err =
-				qcedev_pmem_ablk_cipher_max_xfer(qcedev_areq,
-								handle);
-				num_entries = 0;
-
-					creq->pmem.src[i].offset =
-						req.pmem.src[i].offset +
-						creq->pmem.src[i].len;
-					creq->pmem.src[i].len =
-						req.pmem.src[i].len -
-						creq->pmem.src[i].len;
-					req.pmem.src[i].offset =
-						creq->pmem.src[i].offset;
-					req.pmem.src[i].len =
-						creq->pmem.src[i].len;
-
-				if (creq->pmem.src[i].len == 0)
-					i++;
-			}
-
-		} /* end of while ((i < req.entries) && (err == 0)) */
-
-	} else
-		err = qcedev_pmem_ablk_cipher_max_xfer(qcedev_areq, handle);
-
-	/* Restore the original req structure */
-	for (i = 0; i < saved_req->entries; i++) {
-		creq->pmem.src[i].len = saved_req->pmem.src[i].len;
-		creq->pmem.src[i].offset = saved_req->pmem.src[i].offset;
-	}
-	creq->entries = saved_req->entries;
-	creq->data_len = saved_req->data_len;
-	kfree(saved_req);
-
-	return err;
-
-}
-#else
-static int qcedev_pmem_ablk_cipher(struct qcedev_async_req *qcedev_areq,
-						struct qcedev_handle *handle)
-{
-	return -EPERM;
-}
-#endif/*CONFIG_ANDROID_PMEM*/
-
 static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
 				int *di, struct qcedev_handle *handle,
 				uint8_t *k_align_src)
@@ -1753,6 +1533,10 @@
 static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req,
 						struct qcedev_control *podev)
 {
+	if (req->use_pmem) {
+		pr_err("%s: Use of PMEM is not supported\n", __func__);
+		goto error;
+	}
 	if ((req->entries == 0) || (req->data_len == 0))
 		goto error;
 	if ((req->alg >= QCEDEV_ALG_LAST) ||
@@ -1792,15 +1576,6 @@
 	if (req->byteoffset) {
 		if (req->mode != QCEDEV_AES_MODE_CTR)
 			goto error;
-		else { /* if using CTR mode make sure not using Pmem */
-			if (req->use_pmem)
-				goto error;
-		}
-	}
-	/* if using PMEM with non-zero byteoffset, ensure it is in_place_op */
-	if (req->use_pmem) {
-		if (!req->in_place_op)
-			goto error;
 	}
 	/* Ensure zer ivlen for ECB  mode  */
 	if (req->ivlen != 0) {
@@ -1890,10 +1665,7 @@
 				podev))
 			return -EINVAL;
 
-		if (qcedev_areq.cipher_op_req.use_pmem)
-			err = qcedev_pmem_ablk_cipher(&qcedev_areq, handle);
-		else
-			err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle);
+		err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle);
 		if (err)
 			return err;
 		if (__copy_to_user((void __user *)arg,
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index 574a06b..af75ddd 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/devfreq.h>
+#include "governor.h"
 
 static int devfreq_performance_func(struct devfreq *df,
 				    unsigned long *freq)
@@ -25,8 +26,14 @@
 	return 0;
 }
 
+static int performance_init(struct devfreq *devfreq)
+{
+	return update_devfreq(devfreq);
+}
+
 const struct devfreq_governor devfreq_performance = {
 	.name = "performance",
+	.init = performance_init,
 	.get_target_freq = devfreq_performance_func,
 	.no_central_polling = true,
 };
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index d742d4a..fec0cdb 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/devfreq.h>
+#include "governor.h"
 
 static int devfreq_powersave_func(struct devfreq *df,
 				  unsigned long *freq)
@@ -22,8 +23,14 @@
 	return 0;
 }
 
+static int powersave_init(struct devfreq *devfreq)
+{
+	return update_devfreq(devfreq);
+}
+
 const struct devfreq_governor devfreq_powersave = {
 	.name = "powersave",
+	.init = powersave_init,
 	.get_target_freq = devfreq_powersave_func,
 	.no_central_polling = true,
 };
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index b114875..9d24d65 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3737,10 +3737,6 @@
 # define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE		(1 << 12)
 # define GEN6_RCCUNIT_CLOCK_GATE_DISABLE		(1 << 11)
 
-#define GEN6_UCGCTL2				0x9404
-# define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE		(1 << 12)
-# define GEN6_RCCUNIT_CLOCK_GATE_DISABLE		(1 << 11)
-
 #define GEN6_RPNSWREQ				0xA008
 #define   GEN6_TURBO_DISABLE			(1<<31)
 #define   GEN6_FREQUENCY(x)			((x)<<25)
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 48dae40..f7eb5d8 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -439,9 +439,6 @@
 	struct radeon_i2c_chan *ddc_bus;
 	/* some systems have an hdmi and vga port with a shared ddc line */
 	bool shared_ddc;
-	/* for some Radeon chip families we apply an additional EDID header
-	   check as part of the DDC probe */
-	bool requires_extended_probe;
 	bool use_digital;
 	/* we need to mind the EDID between detect
 	   and get modes due to analog/digital/tvencoder */
@@ -529,8 +526,7 @@
 				u8 val);
 extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
 extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
-extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector,
-			bool requires_extended_probe);
+extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
 extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
 
 extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 0904f9fe..9ab2343 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -914,7 +914,7 @@
 		if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
 			type == ION_HEAP_TYPE_CARVEOUT ||
 			type == (enum ion_heap_type) ION_HEAP_TYPE_CP)
-			seq_printf(s, " : %12lx", handle->buffer->priv_phys);
+			seq_printf(s, " : %12pa", &handle->buffer->priv_phys);
 		else
 			seq_printf(s, " : %12s", "N/A");
 
@@ -1988,8 +1988,8 @@
 		ret = memblock_reserve(data->heaps[i].base,
 				       data->heaps[i].size);
 		if (ret)
-			pr_err("memblock reserve of %x@%lx failed\n",
+			pr_err("memblock reserve of %x@%pa failed\n",
 			       data->heaps[i].size,
-			       data->heaps[i].base);
+			       &data->heaps[i].base);
 	}
 }
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 3e55a57..b51fa6a 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -297,8 +297,11 @@
 			const char *client_name = "(null)";
 
 			if (last_end < data->addr) {
-				seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
-					   "FREE", last_end, data->addr-1,
+				phys_addr_t da;
+
+				da = data->addr-1;
+				seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+					   "FREE", &last_end, &da,
 					   data->addr-last_end,
 					   data->addr-last_end);
 			}
@@ -306,9 +309,9 @@
 			if (data->client_name)
 				client_name = data->client_name;
 
-			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
-				   client_name, data->addr,
-				   data->addr_end,
+			seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+				   client_name, &data->addr,
+				   &data->addr_end,
 				   data->size, data->size);
 			last_end = data->addr_end+1;
 		}
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
index 4f5ac75..8063138 100644
--- a/drivers/gpu/ion/ion_cma_heap.c
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -325,9 +325,9 @@
 			if (data->client_name)
 				client_name = data->client_name;
 
-			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
-				   client_name, data->addr,
-				   data->addr_end,
+			seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+				   client_name, &data->addr,
+				   &data->addr_end,
 				   data->size, data->size);
 		}
 	}
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 2c0e5ae..496e5b4 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -359,9 +359,9 @@
 			if (data->client_name)
 				client_name = data->client_name;
 
-			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
-				   client_name, data->addr,
-				   data->addr_end,
+			seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+				   client_name, &data->addr,
+				   &data->addr_end,
 				   data->size, data->size);
 		}
 	}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 56ccc8f..a7473e2 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -256,8 +256,8 @@
 			atomic_dec(&cp_heap->protect_cnt);
 		} else {
 			cp_heap->heap_protected = HEAP_PROTECTED;
-			pr_debug("Protected heap %s @ 0x%lx\n",
-				heap->name, cp_heap->base);
+			pr_debug("Protected heap %s @ 0x%pa\n",
+				heap->name, &cp_heap->base);
 		}
 	}
 out:
@@ -804,8 +804,11 @@
 			const char *client_name = "(null)";
 
 			if (last_end < data->addr) {
-				seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
-					   "FREE", last_end, data->addr-1,
+				phys_addr_t da;
+
+				da = data->addr-1;
+				seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+					   "FREE", &last_end, &da,
 					   data->addr-last_end,
 					   data->addr-last_end);
 			}
@@ -813,9 +816,9 @@
 			if (data->client_name)
 				client_name = data->client_name;
 
-			seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
-				   client_name, data->addr,
-				   data->addr_end,
+			seq_printf(s, "%16.s %14pa %14pa %14lu (%lx)\n",
+				   client_name, &data->addr,
+				   &data->addr_end,
 				   data->size, data->size);
 			last_end = data->addr_end+1;
 		}
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index ff2b8dd..46fefb5 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -56,9 +56,9 @@
 	}
 
 	if (IS_ERR_OR_NULL(heap)) {
-		pr_err("%s: error creating heap %s type %d base %lu size %u\n",
+		pr_err("%s: error creating heap %s type %d base %pa size %u\n",
 		       __func__, heap_data->name, heap_data->type,
-		       heap_data->base, heap_data->size);
+		       &heap_data->base, heap_data->size);
 		return ERR_PTR(-EINVAL);
 	}
 
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 9d1e90e..2ab2ed6 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -189,8 +189,8 @@
  */
 struct mem_map_data {
 	struct rb_node node;
-	unsigned long addr;
-	unsigned long addr_end;
+	ion_phys_addr_t addr;
+	ion_phys_addr_t addr_end;
 	unsigned long size;
 	const char *client_name;
 };
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 7840d87..bd27385 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -172,7 +172,7 @@
 }
 EXPORT_SYMBOL(msm_ion_do_cache_op);
 
-static unsigned long msm_ion_get_base(unsigned long size, int memory_type,
+static ion_phys_addr_t msm_ion_get_base(unsigned long size, int memory_type,
 				    unsigned int align)
 {
 	switch (memory_type) {
@@ -340,10 +340,10 @@
 static int is_heap_overlapping(const struct ion_platform_heap *heap1,
 				const struct ion_platform_heap *heap2)
 {
-	unsigned long heap1_base = heap1->base;
-	unsigned long heap2_base = heap2->base;
-	unsigned long heap1_end = heap1->base + heap1->size - 1;
-	unsigned long heap2_end = heap2->base + heap2->size - 1;
+	ion_phys_addr_t heap1_base = heap1->base;
+	ion_phys_addr_t heap2_base = heap2->base;
+	ion_phys_addr_t heap1_end = heap1->base + heap1->size - 1;
+	ion_phys_addr_t heap2_end = heap2->base + heap2->size - 1;
 
 	if (heap1_base == heap2_base)
 		return 1;
@@ -792,9 +792,9 @@
 			continue;
 		} else {
 			if (heap_data->size)
-				pr_info("ION heap %s created at %lx "
+				pr_info("ION heap %s created at %pa "
 					"with size %x\n", heap_data->name,
-							  heap_data->base,
+							  &heap_data->base,
 							  heap_data->size);
 			else
 				pr_info("ION heap %s created\n",
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b1a45bf..bf45a63 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -251,23 +251,19 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 
-	result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc,
-				     GSL_PT_PAGE_RV);
+	result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc);
 	if (result)
 		goto error;
 
-	result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc,
-				     GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+	result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
 	if (result)
 		goto unmap_buffer_desc;
 
-	result = kgsl_mmu_map_global(pagetable, &device->memstore,
-				     GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+	result = kgsl_mmu_map_global(pagetable, &device->memstore);
 	if (result)
 		goto unmap_memptrs_desc;
 
-	result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory,
-				     GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+	result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory);
 	if (result)
 		goto unmap_memstore_desc;
 
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 5cdf911..69b34fa 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -485,6 +485,7 @@
 	 */
 	rb->sizedwords = KGSL_RB_SIZE >> 2;
 
+	rb->buffer_desc.flags = KGSL_MEMFLAGS_GPUREADONLY;
 	/* allocate memory for ringbuffer */
 	status = kgsl_allocate_contiguous(&rb->buffer_desc,
 		(rb->sizedwords << 2));
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 130474a..e2869d4 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1871,10 +1871,7 @@
 	else if (entry->memdesc.size >= SZ_64K)
 		kgsl_memdesc_set_align(&entry->memdesc, ilog2(SZ_64));
 
-	result = kgsl_mmu_map(private->pagetable,
-			      &entry->memdesc,
-			      GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
-
+	result = kgsl_mmu_map(private->pagetable, &entry->memdesc);
 	if (result)
 		goto error_put_file_ptr;
 
@@ -2065,8 +2062,7 @@
 	if (result)
 		return result;
 
-	result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
-				kgsl_memdesc_protflags(&entry->memdesc));
+	result = kgsl_mmu_map(private->pagetable, &entry->memdesc);
 	if (result)
 		goto err;
 
@@ -2104,8 +2100,7 @@
 		goto err;
 
 	if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
-		result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
-				kgsl_memdesc_protflags(&entry->memdesc));
+		result = kgsl_mmu_map(private->pagetable, &entry->memdesc);
 		if (result)
 			goto err;
 	}
@@ -2482,7 +2477,11 @@
 		mutex_unlock(&dev_priv->device->mutex);
 	}
 
-	if (ret == 0 && (cmd & IOC_OUT)) {
+	/*
+	 * Still copy back on failure, but assume function took
+	 * all necessary precautions sanitizing the return values.
+	 */
+	if (cmd & IOC_OUT) {
 		if (copy_to_user((void __user *) arg, uptr, _IOC_SIZE(cmd)))
 			ret = -EFAULT;
 	}
@@ -2719,8 +2718,7 @@
 	if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
 		entry->memdesc.gpuaddr = vma->vm_start;
 
-		ret = kgsl_mmu_map(private->pagetable, &entry->memdesc,
-				   kgsl_memdesc_protflags(&entry->memdesc));
+		ret = kgsl_mmu_map(private->pagetable, &entry->memdesc);
 		if (ret) {
 			kgsl_mem_entry_put(entry);
 			return ret;
@@ -2753,6 +2751,29 @@
 	}
 
 	vma->vm_ops = &kgsl_gpumem_vm_ops;
+
+	if (cache == KGSL_CACHEMODE_WRITEBACK
+		|| cache == KGSL_CACHEMODE_WRITETHROUGH) {
+		struct scatterlist *s;
+		int i;
+		int sglen = entry->memdesc.sglen;
+		unsigned long addr = vma->vm_start;
+
+		/* don't map in the guard page, it should always fault */
+		if (kgsl_memdesc_has_guard_page(&entry->memdesc))
+			sglen--;
+
+		for_each_sg(entry->memdesc.sg, s, sglen, i) {
+			int j;
+			for (j = 0; j < (sg_dma_len(s) >> PAGE_SHIFT); j++) {
+				struct page *page = sg_page(s);
+				page = nth_page(page, j);
+				vm_insert_page(vma, addr, page);
+				addr += PAGE_SIZE;
+			}
+		}
+	}
+
 	vma->vm_file = file;
 
 	entry->memdesc.useraddr = vma->vm_start;
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 3eb8831..c568db5 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -149,6 +149,8 @@
 #define KGSL_MEMDESC_GUARD_PAGE BIT(0)
 /* Set if the memdesc is mapped into all pagetables */
 #define KGSL_MEMDESC_GLOBAL BIT(1)
+/* The memdesc is frozen during a snapshot */
+#define KGSL_MEMDESC_FROZEN BIT(2)
 
 /* shared memory allocation */
 struct kgsl_memdesc {
@@ -156,7 +158,7 @@
 	void *hostptr; /* kernel virtual address */
 	unsigned long useraddr; /* userspace address */
 	unsigned int gpuaddr;
-	unsigned int physaddr;
+	phys_addr_t physaddr;
 	unsigned int size;
 	unsigned int priv; /* Internal flags and settings */
 	struct scatterlist *sg;
@@ -175,15 +177,10 @@
 #define KGSL_MEM_ENTRY_ION    4
 #define KGSL_MEM_ENTRY_MAX    5
 
-/* List of flags */
-
-#define KGSL_MEM_ENTRY_FROZEN (1 << 0)
-
 struct kgsl_mem_entry {
 	struct kref refcount;
 	struct kgsl_memdesc memdesc;
 	int memtype;
-	int flags;
 	void *priv_data;
 	struct rb_node node;
 	unsigned int id;
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index c24e03b..11d6ffa 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -210,8 +210,7 @@
 				return result;
 			}
 
-			result = kgsl_mmu_map(priv->pagetable, &priv->memdesc,
-					GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+			result = kgsl_mmu_map(priv->pagetable, &priv->memdesc);
 			if (result) {
 				DRM_ERROR(
 				"kgsl_mmu_map failed.  result = %d\n", result);
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 8f28505..9a1a431 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.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
@@ -161,7 +161,7 @@
 }
 
 static void *
-_kgsl_ptpool_get_entry(struct kgsl_ptpool *pool, unsigned int *physaddr)
+_kgsl_ptpool_get_entry(struct kgsl_ptpool *pool, phys_addr_t *physaddr)
 {
 	struct kgsl_ptpool_chunk *chunk;
 
@@ -227,7 +227,7 @@
  */
 
 static void *kgsl_ptpool_alloc(struct kgsl_ptpool *pool,
-				unsigned int *physaddr)
+				phys_addr_t *physaddr)
 {
 	void *addr = NULL;
 	int ret;
diff --git a/drivers/gpu/msm/kgsl_gpummu.h b/drivers/gpu/msm/kgsl_gpummu.h
index 99e7d5f..1753aff 100644
--- a/drivers/gpu/msm/kgsl_gpummu.h
+++ b/drivers/gpu/msm/kgsl_gpummu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -57,7 +57,7 @@
 	int dynamic;
 
 	void *data;
-	unsigned int phys;
+	phys_addr_t phys;
 
 	unsigned long *bitmap;
 	struct list_head list;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index df8e1d0..93b7e5d 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -43,6 +43,8 @@
 	{ 0x820, 0, 0 },			/* RESUME */
 	{ 0x03C, 0, 0 },			/* TLBLKCR */
 	{ 0x818, 0, 0 },			/* V2PUR */
+	{ 0x2C, 0, 0 },                         /* FSYNR0 */
+	{ 0x2C, 0, 0 },                         /* FSYNR0 */
 };
 
 static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
@@ -51,7 +53,11 @@
 	{ 0x28, 0x00FFFFFF, 14 },		/* TTBR1 */
 	{ 0x58, 0, 0 },				/* FSR */
 	{ 0x618, 0, 0 },			/* TLBIALL */
-	{ 0x008, 0, 0 }				/* RESUME */
+	{ 0x008, 0, 0 },			/* RESUME */
+	{ 0, 0, 0 },				/* TLBLKCR */
+	{ 0, 0, 0 },				/* V2PUR */
+	{ 0x68, 0, 0 },				/* FSYNR0 */
+	{ 0x6C, 0, 0 }				/* FSYNR1 */
 };
 
 struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars;
@@ -118,6 +124,7 @@
 	unsigned int gpuaddr;
 	unsigned int size;
 	unsigned int flags;
+	unsigned int priv;
 	pid_t pid;
 };
 
@@ -146,7 +153,8 @@
 		if (entry->memdesc.gpuaddr > ret->gpuaddr) {
 			ret->gpuaddr = entry->memdesc.gpuaddr;
 			ret->size = entry->memdesc.size;
-			ret->flags = entry->flags;
+			ret->flags = entry->memdesc.flags;
+			ret->priv = entry->memdesc.priv;
 			ret->pid = priv->pid;
 		}
 
@@ -179,7 +187,8 @@
 		if (entry->memdesc.gpuaddr < ret->gpuaddr) {
 			ret->gpuaddr = entry->memdesc.gpuaddr;
 			ret->size = entry->memdesc.size;
-			ret->flags = entry->flags;
+			ret->flags = entry->memdesc.flags;
+			ret->priv = entry->memdesc.priv;
 			ret->pid = priv->pid;
 		}
 
@@ -224,9 +233,10 @@
 	kgsl_get_memory_usage(name, sizeof(name) - 1, entry->flags);
 
 	KGSL_LOG_DUMP(device,
-		"[%8.8X - %8.8X] (pid = %d) (%s)\n",
+		"[%8.8X - %8.8X] %s (pid = %d) (%s)\n",
 		entry->gpuaddr,
 		entry->gpuaddr + entry->size,
+		entry->priv & KGSL_MEMDESC_GUARD_PAGE ? "(+guard)" : "",
 		entry->pid, name);
 }
 
@@ -275,6 +285,8 @@
 	unsigned int pid;
 
 	struct _mem_entry prev, next;
+	unsigned int fsynr0, fsynr1;
+	int write;
 
 	ret = get_iommu_unit(dev, &mmu, &iommu_unit);
 	if (ret)
@@ -292,12 +304,25 @@
 
 	fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
 		iommu_dev->ctx_id, FSR);
+	fsynr0 = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
+		iommu_dev->ctx_id, FSYNR0);
+	fsynr1 = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
+		iommu_dev->ctx_id, FSYNR1);
+
+	if (msm_soc_version_supports_iommu_v0())
+		write = ((fsynr1 & (KGSL_IOMMU_FSYNR1_AWRITE_MASK <<
+			KGSL_IOMMU_FSYNR1_AWRITE_SHIFT)) ? 1 : 0);
+	else
+		write = ((fsynr0 & (KGSL_IOMMU_V1_FSYNR0_WNR_MASK <<
+			KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT)) ? 1 : 0);
 
 	pid = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase);
 	KGSL_MEM_CRIT(iommu_dev->kgsldev,
 		"GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
-	KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
-		iommu_dev->ctx_id, fsr);
+	KGSL_MEM_CRIT(iommu_dev->kgsldev,
+		"context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
+		iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
+		write ? "write" : "read");
 
 	_check_if_freed(iommu_dev, addr, pid);
 
@@ -321,7 +346,8 @@
 	iommu_dev->fault = 1;
 
 	trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
-			kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
+			kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
+			write ? "write" : "read");
 
 	/*
 	 * We do not want the h/w to resume fetching data from an iommu unit
@@ -1118,16 +1144,14 @@
 
 	for (i = 0; i < iommu->unit_count; i++) {
 		status = kgsl_mmu_map_global(pt,
-				&(iommu->iommu_units[i].reg_map),
-				GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+				&(iommu->iommu_units[i].reg_map));
 		if (status)
 			goto err;
 	}
 
 	/* Map Lock variables to GPU pagetable */
 	if (iommu->sync_lock_initialized) {
-		status = kgsl_mmu_map_global(pt, &iommu->sync_lock_desc,
-				GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+		status = kgsl_mmu_map_global(pt, &iommu->sync_lock_desc);
 		if (status)
 			goto err;
 	}
@@ -1499,25 +1523,39 @@
 	unsigned int iommu_virt_addr;
 	struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
 	int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
-	unsigned int iommu_flags = IOMMU_READ;
 
 	BUG_ON(NULL == iommu_pt);
 
-	if (protflags & GSL_PT_PAGE_WV)
-		iommu_flags |= IOMMU_WRITE;
+	/* if there's a guard page, we'll map it read only below */
+	if ((protflags & IOMMU_WRITE) && kgsl_memdesc_has_guard_page(memdesc))
+			size -= PAGE_SIZE;
 
 	iommu_virt_addr = memdesc->gpuaddr;
 
 	ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
-				size, iommu_flags);
+				size, protflags);
 	if (ret) {
-		KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
-				"failed with err: %d\n", iommu_pt->domain,
-				iommu_virt_addr, memdesc->sg, size,
-				iommu_flags, ret);
+		KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %x) err: %d\n",
+			iommu_pt->domain, iommu_virt_addr, memdesc->sg, size,
+			protflags, ret);
 		return ret;
 	}
+	if ((protflags & IOMMU_WRITE) && kgsl_memdesc_has_guard_page(memdesc)) {
+		struct scatterlist *sg = &memdesc->sg[memdesc->sglen - 1];
 
+		ret = iommu_map(iommu_pt->domain, iommu_virt_addr + size,
+				kgsl_get_sg_pa(sg), PAGE_SIZE,
+				protflags & ~IOMMU_WRITE);
+		if (ret) {
+			KGSL_CORE_ERR("iommu_map(%p, %x, %x, %x) err: %d\n",
+				iommu_pt->domain, iommu_virt_addr + size,
+				kgsl_get_sg_pa(sg), protflags & ~IOMMU_WRITE,
+				ret);
+			/* cleanup the partial mapping */
+			iommu_unmap_range(iommu_pt->domain, iommu_virt_addr,
+					  size);
+		}
+	}
 	return ret;
 }
 
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index bf40113..c09bc4b 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -19,7 +19,7 @@
 #define KGSL_IOMMU_CTX_OFFSET_V1	0x8000
 #define KGSL_IOMMU_CTX_SHIFT		12
 
-/* TLBLKCR feilds */
+/* TLBLKCR fields */
 #define KGSL_IOMMU_TLBLKCR_LKE_MASK		0x00000001
 #define KGSL_IOMMU_TLBLKCR_LKE_SHIFT		0
 #define KGSL_IOMMU_TLBLKCR_TLBIALLCFG_MASK	0x00000001
@@ -33,12 +33,19 @@
 #define KGSL_IOMMU_TLBLKCR_VICTIM_MASK		0x000000FF
 #define KGSL_IOMMU_TLBLKCR_VICTIM_SHIFT		16
 
-/* V2PXX feilds */
+/* V2PXX fields */
 #define KGSL_IOMMU_V2PXX_INDEX_MASK		0x000000FF
 #define KGSL_IOMMU_V2PXX_INDEX_SHIFT		0
 #define KGSL_IOMMU_V2PXX_VA_MASK		0x000FFFFF
 #define KGSL_IOMMU_V2PXX_VA_SHIFT		12
 
+/* FSYNR1 V0 fields */
+#define KGSL_IOMMU_FSYNR1_AWRITE_MASK		0x00000001
+#define KGSL_IOMMU_FSYNR1_AWRITE_SHIFT		8
+/* FSYNR0 V1 fields */
+#define KGSL_IOMMU_V1_FSYNR0_WNR_MASK		0x00000001
+#define KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT		4
+
 enum kgsl_iommu_reg_map {
 	KGSL_IOMMU_GLOBAL_BASE = 0,
 	KGSL_IOMMU_CTX_TTBR0,
@@ -48,6 +55,8 @@
 	KGSL_IOMMU_CTX_RESUME,
 	KGSL_IOMMU_CTX_TLBLKCR,
 	KGSL_IOMMU_CTX_V2PUR,
+	KGSL_IOMMU_CTX_FSYNR0,
+	KGSL_IOMMU_CTX_FSYNR1,
 	KGSL_IOMMU_REG_MAX
 };
 
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index f71cf8c..01b255c 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -580,13 +580,13 @@
 
 int
 kgsl_mmu_map(struct kgsl_pagetable *pagetable,
-				struct kgsl_memdesc *memdesc,
-				unsigned int protflags)
+				struct kgsl_memdesc *memdesc)
 {
 	int ret;
 	struct gen_pool *pool = NULL;
 	int size;
 	int page_align = ilog2(PAGE_SIZE);
+	unsigned int protflags = kgsl_memdesc_protflags(memdesc);
 
 	if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
 		if (memdesc->sglen == 1) {
@@ -738,7 +738,7 @@
 EXPORT_SYMBOL(kgsl_mmu_unmap);
 
 int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable,
-			struct kgsl_memdesc *memdesc, unsigned int protflags)
+			struct kgsl_memdesc *memdesc)
 {
 	int result = -EINVAL;
 	unsigned int gpuaddr = 0;
@@ -750,19 +750,17 @@
 	/* Not all global mappings are needed for all MMU types */
 	if (!memdesc->size)
 		return 0;
-
 	gpuaddr = memdesc->gpuaddr;
 	memdesc->priv |= KGSL_MEMDESC_GLOBAL;
 
-	result = kgsl_mmu_map(pagetable, memdesc, protflags);
+	result = kgsl_mmu_map(pagetable, memdesc);
 	if (result)
 		goto error;
 
 	/*global mappings must have the same gpu address in all pagetables*/
 	if (gpuaddr && gpuaddr != memdesc->gpuaddr) {
-		KGSL_CORE_ERR("pt %p addr mismatch phys 0x%08x"
-			"gpu 0x%0x 0x%08x", pagetable, memdesc->physaddr,
-			gpuaddr, memdesc->gpuaddr);
+		KGSL_CORE_ERR("pt %p addr mismatch phys %pa gpu 0x%0x 0x%08x",
+		     pagetable, &memdesc->physaddr, gpuaddr, memdesc->gpuaddr);
 		goto error_unmap;
 	}
 	return result;
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 2b33baf..0458a13 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -201,10 +201,9 @@
 int kgsl_mmu_start(struct kgsl_device *device);
 int kgsl_mmu_close(struct kgsl_device *device);
 int kgsl_mmu_map(struct kgsl_pagetable *pagetable,
-		 struct kgsl_memdesc *memdesc,
-		 unsigned int protflags);
+		 struct kgsl_memdesc *memdesc);
 int kgsl_mmu_map_global(struct kgsl_pagetable *pagetable,
-			struct kgsl_memdesc *memdesc, unsigned int protflags);
+			struct kgsl_memdesc *memdesc);
 int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
 		    struct kgsl_memdesc *memdesc);
 unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 0dcbfdf..d9dbad8 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -130,6 +130,16 @@
 	 */
 
 	pwr->active_pwrlevel = new_level;
+	pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
+
+	if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
+
+		if (pwr->pcl)
+			msm_bus_scale_client_update_request(pwr->pcl,
+				pwrlevel->bus_freq);
+		else if (pwr->ebi1_clk)
+			clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
+	}
 
 	if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
 		(device->state == KGSL_STATE_NAP)) {
@@ -156,16 +166,6 @@
 		}
 	}
 
-	pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
-
-	if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
-
-		if (pwr->pcl)
-			msm_bus_scale_client_update_request(pwr->pcl,
-				pwrlevel->bus_freq);
-		else if (pwr->ebi1_clk)
-			clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
-	}
 
 	trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq);
 }
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 27b9151..279490f 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -19,6 +19,7 @@
 #include "kgsl_mmu.h"
 #include <linux/slab.h>
 #include <linux/kmemleak.h>
+#include <linux/iommu.h>
 
 #include "kgsl_log.h"
 
@@ -195,15 +196,24 @@
 /*
  * kgsl_memdesc_protflags - get mmu protection flags
  * @memdesc - the memdesc
- * Returns a mask of GSL_PT_PAGE* values based on the
- * memdesc flags.
+ * Returns a mask of GSL_PT_PAGE* or IOMMU* values based
+ * on the memdesc flags.
  */
 static inline unsigned int
 kgsl_memdesc_protflags(const struct kgsl_memdesc *memdesc)
 {
-	unsigned int protflags = GSL_PT_PAGE_RV;
-	if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
-		protflags |= GSL_PT_PAGE_WV;
+	unsigned int protflags = 0;
+	enum kgsl_mmutype mmutype = kgsl_mmu_get_mmutype();
+
+	if (mmutype == KGSL_MMU_TYPE_GPU) {
+		protflags = GSL_PT_PAGE_RV;
+		if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
+			protflags |= GSL_PT_PAGE_WV;
+	} else if (mmutype == KGSL_MMU_TYPE_IOMMU) {
+		protflags = IOMMU_READ;
+		if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
+			protflags |= IOMMU_WRITE;
+	}
 	return protflags;
 }
 
@@ -248,8 +258,7 @@
 	ret = kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
 	if (ret)
 		return ret;
-	ret = kgsl_mmu_map(pagetable, memdesc,
-			   kgsl_memdesc_protflags(memdesc));
+	ret = kgsl_mmu_map(pagetable, memdesc);
 	if (ret)
 		kgsl_sharedmem_free(memdesc);
 	return ret;
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 0935f64..c4647a1 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -283,7 +283,7 @@
 {
 	list_del(&obj->node);
 
-	obj->entry->flags &= ~KGSL_MEM_ENTRY_FROZEN;
+	obj->entry->memdesc.priv &= ~KGSL_MEMDESC_FROZEN;
 	kgsl_mem_entry_put(obj->entry);
 
 	kfree(obj);
@@ -416,10 +416,10 @@
 	 * 0 so it doesn't get counted twice
 	 */
 
-	if (entry->flags & KGSL_MEM_ENTRY_FROZEN)
+	if (entry->memdesc.priv & KGSL_MEMDESC_FROZEN)
 		return 0;
 
-	entry->flags |= KGSL_MEM_ENTRY_FROZEN;
+	entry->memdesc.priv |= KGSL_MEMDESC_FROZEN;
 
 	return entry->memdesc.size;
 }
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index e578b0e..f0410d6 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -244,20 +244,17 @@
 	int result = 0;
 	struct z180_device *z180_dev = Z180_DEVICE(device);
 
-	result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory,
-				     GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+	result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory);
 
 	if (result)
 		goto error;
 
-	result = kgsl_mmu_map_global(pagetable, &device->memstore,
-				     GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+	result = kgsl_mmu_map_global(pagetable, &device->memstore);
 	if (result)
 		goto error_unmap_dummy;
 
 	result = kgsl_mmu_map_global(pagetable,
-				     &z180_dev->ringbuffer.cmdbufdesc,
-				     GSL_PT_PAGE_RV);
+				     &z180_dev->ringbuffer.cmdbufdesc);
 	if (result)
 		goto error_unmap_memstore;
 	/*
@@ -498,6 +495,7 @@
 	struct z180_device *z180_dev = Z180_DEVICE(device);
 	memset(&z180_dev->ringbuffer, 0, sizeof(struct z180_ringbuffer));
 	z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT;
+	z180_dev->ringbuffer.cmdbufdesc.flags = KGSL_MEMFLAGS_GPUREADONLY;
 	return kgsl_allocate_contiguous(&z180_dev->ringbuffer.cmdbufdesc,
 		Z180_RB_SIZE);
 }
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index c2b5f38..51ffd21 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -586,12 +586,16 @@
 	return 0;
 }
 
-static int epm_psoc_scale_result(uint32_t result, uint32_t index)
+static int epm_psoc_scale_result(int16_t result, uint32_t index)
 {
 	struct epm_adc_drv *epm_adc = epm_adc_drv;
-	int32_t result_cur;
+	int32_t result_cur, neg = 0;
 
 	if ((1 << index) & epm_adc->channel_mask) {
+		if (result & 0x800) {
+			neg = 1;
+			result = result & 0x7ff;
+		}
 		/* result = (2.048V * code)/(4096 * gain * rsense) */
 		result_cur = ((EPM_PSOC_VREF_VOLTAGE * result)/
 				EPM_PSOC_MAX_ADC_CODE_12_BIT);
@@ -599,14 +603,22 @@
 		result_cur = (result_cur/
 			(epm_adc->epm_psoc_ch_prop[index].gain *
 			epm_adc->epm_psoc_ch_prop[index].resistorvalue));
+		if (neg)
+			result_cur -= result_cur;
 	} else {
+		if (result & 0x8000) {
+			neg = 1;
+			result = result & 0x7fff;
+		}
 		/* result = (2.048V * code)/(32767 * gain * rsense) */
-		result_cur = (((EPM_PSOC_VREF_VOLTAGE * result)/
+		result_cur = (((EPM_PSOC_VREF_VOLTAGE * (int) result)/
 				EPM_PSOC_MAX_ADC_CODE_15_BIT) * 1000);
 
 		result_cur = (result_cur/
 		(epm_adc->epm_psoc_ch_prop[index].gain *
 			epm_adc->epm_psoc_ch_prop[index].resistorvalue));
+		if (neg)
+			result_cur -= result_cur;
 	}
 
 	return result_cur;
@@ -869,10 +881,8 @@
 	psoc_get_meas->timestamp_resp_value = (rx_buf[3] << 24) |
 			(rx_buf[4] << 16) | (rx_buf[5] << 8) |
 			rx_buf[6];
-	psoc_get_meas->reading_value = (rx_buf[7] << 8) | rx_buf[8];
+	psoc_get_meas->reading_raw = (rx_buf[7] << 8) | rx_buf[8];
 
-	pr_debug("dev_num:%d, chan_num:%d\n", rx_buf[1], rx_buf[2]);
-	pr_debug("data %d\n", psoc_get_meas->reading_value);
 	return rc;
 }
 
@@ -1336,7 +1346,7 @@
 			}
 
 			psoc_get_data.reading_value = epm_psoc_scale_result(
-				psoc_get_data.reading_value,
+				psoc_get_data.reading_raw,
 				psoc_get_data.chan_num);
 
 			if (copy_to_user((void __user *)arg, &psoc_get_data,
@@ -1753,8 +1763,6 @@
 	conv.device_idx = attr->index / pdata->chan_per_adc;
 	conv.channel_idx = attr->index % pdata->chan_per_adc;
 	conv.physical = 0;
-	pr_info("%s: device_idx=%d channel_idx=%d", __func__, conv.device_idx,
-			conv.channel_idx);
 
 	if (!epm_adc_expander_register) {
 		rc = epm_adc_i2c_expander_register();
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index fda9e0a..3a78489 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1363,7 +1363,7 @@
 	int is_eth;
 	int is_vlan = 0;
 	int is_grh;
-	u16 vlan = 0;
+	u16 vlan;
 
 	send_size = 0;
 	for (i = 0; i < wr->num_sge; ++i)
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 4c72b65..bfa48de 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -411,13 +411,6 @@
 	  To compile this driver as a module, choose M here; the
 	  module will be called opencores-kbd.
 
-config KEYBOARD_PM8058
-	bool "Qualcomm PM8058 Matrix Keypad support"
-	depends on PM8058
-	help
-	  Say Y here to enable the driver for the keypad matrix interface
-	  on the Qualcomm PM8058 power management I/C device.
-
 config KEYBOARD_PXA27x
 	tristate "PXA27x/PXA3xx keypad support"
 	depends on PXA27x || PXA3xx || ARCH_MMP
@@ -623,5 +616,3 @@
 	  module will be called w90p910_keypad.
 
 endif
-
-
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 833904a..85f1d86 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -54,4 +54,3 @@
 obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
 obj-$(CONFIG_KEYBOARD_QCIKBD)       += qci_kbd.o
 obj-$(CONFIG_KEYBOARD_W90P910)		+= w90p910_keypad.o
-obj-$(CONFIG_KEYBOARD_PMIC8058)		+= pmic8058-keypad.o
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index ad43bbf..1f309d8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -17,7 +17,6 @@
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)	+= auo-pixcir-ts.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
-obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CYPRESS_TMG)	+= cy8c_tmg_ts.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)	+= bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
@@ -29,7 +28,6 @@
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
 obj-$(CONFIG_TOUCHSCREEN_EETI)		+= eeti_ts.o
-obj-$(CONFIG_TOUCHSCREEN_ELAN_I2C_8232) += elan8232_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index db4ec9d..330c850 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -16,7 +16,7 @@
 # MSM IOMMU support
 config MSM_IOMMU
 	bool "MSM IOMMU Support"
-	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8610 || ARCH_MSM8226
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8610 || ARCH_MSM8226 || ARCH_MSMZINC
 	select IOMMU_API
 	help
 	  Support for the IOMMUs found on certain Qualcomm SOCs.
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 26e8496..f13e55a 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -195,23 +195,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called leds-msm-tricolor.
 
-config LEDS_GPIO_PLATFORM
-	bool "Platform device bindings for GPIO LEDs"
-	depends on LEDS_GPIO
-	default y
-	help
-	  Let the leds-gpio driver drive LEDs which have been defined as
-	  platform devices.  If you don't know what this means, say yes.
-
-config LEDS_GPIO_OF
-	bool "OpenFirmware platform device bindings for GPIO LEDs"
-	depends on LEDS_GPIO && OF_DEVICE
-	default y
-	help
-	  Let the leds-gpio driver drive LEDs which have been defined as
-	  of_platform devices.  For instance, LEDs which are listed in a "dts"
-	  file.
-
 config LEDS_LP3944
 	tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
 	depends on LEDS_CLASS
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index da5db8b..d749d92 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -42,7 +42,7 @@
 	unsigned int idx_in;
 	unsigned int idx_out;
 	sector_t sector;
-	atomic_t cc_pending;
+	atomic_t pending;
 	struct ablkcipher_request *req;
 };
 
@@ -56,7 +56,7 @@
 
 	struct convert_context ctx;
 
-	atomic_t io_pending;
+	atomic_t pending;
 	int error;
 	sector_t sector;
 	struct dm_crypt_io *base_io;
@@ -740,14 +740,14 @@
 {
 	int r;
 
-	atomic_set(&ctx->cc_pending, 1);
+	atomic_set(&ctx->pending, 1);
 
 	while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
 	      ctx->idx_out < ctx->bio_out->bi_vcnt) {
 
 		crypt_alloc_req(cc, ctx);
 
-		atomic_inc(&ctx->cc_pending);
+		atomic_inc(&ctx->pending);
 
 		r = crypt_convert_block(cc, ctx, ctx->req);
 
@@ -764,14 +764,14 @@
 
 		/* sync */
 		case 0:
-			atomic_dec(&ctx->cc_pending);
+			atomic_dec(&ctx->pending);
 			ctx->sector++;
 			cond_resched();
 			continue;
 
 		/* error */
 		default:
-			atomic_dec(&ctx->cc_pending);
+			atomic_dec(&ctx->pending);
 			return r;
 		}
 	}
@@ -868,14 +868,14 @@
 	io->error = 0;
 	io->base_io = NULL;
 	io->ctx.req = NULL;
-	atomic_set(&io->io_pending, 0);
+	atomic_set(&io->pending, 0);
 
 	return io;
 }
 
 static void crypt_inc_pending(struct dm_crypt_io *io)
 {
-	atomic_inc(&io->io_pending);
+	atomic_inc(&io->pending);
 }
 
 /*
@@ -890,7 +890,7 @@
 	struct dm_crypt_io *base_io = io->base_io;
 	int error = io->error;
 
-	if (!atomic_dec_and_test(&io->io_pending))
+	if (!atomic_dec_and_test(&io->pending))
 		return;
 
 	if (io->ctx.req)
@@ -1080,7 +1080,8 @@
 		r = crypt_convert(cc, &io->ctx);
 		if (r < 0)
 			io->error = -EIO;
-		crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
+
+		crypt_finished = atomic_dec_and_test(&io->ctx.pending);
 
 		/* Encryption was already finished, submit io now */
 		if (crypt_finished) {
@@ -1151,11 +1152,10 @@
 			   io->sector);
 
 	r = crypt_convert(cc, &io->ctx);
-
 	if (r < 0)
 		io->error = -EIO;
 
-	if (atomic_dec_and_test(&io->ctx.cc_pending))
+	if (atomic_dec_and_test(&io->ctx.pending))
 		kcryptd_crypt_read_done(io);
 
 	crypt_dec_pending(io);
@@ -1182,7 +1182,7 @@
 
 	mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool);
 
-	if (!atomic_dec_and_test(&ctx->cc_pending))
+	if (!atomic_dec_and_test(&ctx->pending))
 		return;
 
 	if (bio_data_dir(io->base_bio) == READ)
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 5a61c5f..754f38f 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -770,11 +770,6 @@
 	if (!argc)
 		return 0;
 
-	if (argc > as->argc) {
-		ti->error = "not enough arguments for features";
-		return -EINVAL;
-	}
-
 	do {
 		arg_name = dm_shift_arg(as);
 		argc--;
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_platform.c b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_platform.c
index d5a8098..f0882f7 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_platform.c
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_platform.c
@@ -15,7 +15,7 @@
 #include <linux/clk.h>
 #include <mach/clk.h>
 #include <linux/io.h>
-#include <linux/android_pmem.h>
+
 #include <mach/camera.h>
 #include <mach/iommu_domains.h>
 
@@ -35,8 +35,6 @@
 	ion_unmap_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL);
 	ion_free(gemini_client, *ionhandle);
 	*ionhandle = NULL;
-#elif CONFIG_ANDROID_PMEM
-	put_pmem_file(file);
 #endif
 }
 
@@ -53,9 +51,6 @@
 
 	rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
 			SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0);
-#elif CONFIG_ANDROID_PMEM
-	unsigned long kvstart;
-	rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
 #else
 	rc = 0;
 	paddr = 0;
diff --git a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_platform.c b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_platform.c
index e6392fe..3607f2e 100644
--- a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_platform.c
+++ b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_platform.c
@@ -13,7 +13,7 @@
 #include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/android_pmem.h>
+
 #include <mach/clk.h>
 #include <mach/camera.h>
 #include <mach/msm_subsystem_map.h>
@@ -39,8 +39,6 @@
 		GEN_POOL);
 	ion_free(mercury_client, *ionhandle);
 	*ionhandle = NULL;
-#elif CONFIG_ANDROID_PMEM
-	put_pmem_file(file);
 #endif
 }
 
@@ -59,10 +57,6 @@
 	rc = ion_map_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
 		GEN_POOL, SZ_4K, 0, &paddr,
 		(unsigned long *)&size, 0, 0);
-#elif CONFIG_ANDROID_PMEM
-	unsigned long kvstart;
-	rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
-#else
 	rc = 0;
 	paddr = 0;
 	size = 0;
diff --git a/drivers/media/platform/msm/camera_v1/msm_camera.c b/drivers/media/platform/msm/camera_v1/msm_camera.c
index 622ecfd..213ccc7 100644
--- a/drivers/media/platform/msm/camera_v1/msm_camera.c
+++ b/drivers/media/platform/msm/camera_v1/msm_camera.c
@@ -28,7 +28,7 @@
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/uaccess.h>
-#include <linux/android_pmem.h>
+
 #include <linux/poll.h>
 #include <media/msm_camera.h>
 #include <mach/camera.h>
@@ -319,15 +319,6 @@
 			goto out1;
 		ion_phys(client_for_ion, region->handle,
 			&paddr, (size_t *)&len);
-#else
-	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
-	if (rc < 0) {
-		pr_err("%s: get_pmem_file fd %d error %d\n",
-			__func__,
-			info->fd, rc);
-		goto out1;
-	}
-	region->file = file;
 #endif
 	if (!info->len)
 		info->len = len;
@@ -364,8 +355,6 @@
 out2:
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	ion_free(client_for_ion, region->handle);
-#else
-	put_pmem_file(region->file);
 #endif
 out1:
 	kfree(region);
@@ -649,8 +638,6 @@
 				hlist_del(node);
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 				ion_free(client_for_ion, region->handle);
-#else
-				put_pmem_file(region->file);
 #endif
 				kfree(region);
 				CDBG("%s: type %d, vaddr  0x%p\n",
@@ -673,8 +660,6 @@
 				hlist_del(node);
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 				ion_free(client_for_ion, region->handle);
-#else
-				put_pmem_file(region->file);
 #endif
 				kfree(region);
 				CDBG("%s: type %d, vaddr  0x%p\n",
@@ -696,8 +681,6 @@
 				hlist_del(node);
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 				ion_free(client_for_ion, region->handle);
-#else
-				put_pmem_file(region->file);
 #endif
 				kfree(region);
 				CDBG("%s: type %d, vaddr  0x%p\n",
@@ -3012,8 +2995,6 @@
 			hlist_del(hnode);
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 				ion_free(client_for_ion, region->handle);
-#else
-			put_pmem_file(region->file);
 #endif
 			kfree(region);
 		}
@@ -3023,8 +3004,6 @@
 			hlist_del(hnode);
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 				ion_free(client_for_ion, region->handle);
-#else
-			put_pmem_file(region->file);
 #endif
 			kfree(region);
 		}
diff --git a/drivers/media/platform/msm/camera_v1/msm_isp.c b/drivers/media/platform/msm/camera_v1/msm_isp.c
index f646f09..59290ec 100644
--- a/drivers/media/platform/msm/camera_v1/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v1/msm_isp.c
@@ -21,7 +21,7 @@
 #include <linux/videodev2.h>
 #include <linux/proc_fs.h>
 #include <linux/vmalloc.h>
-#include <linux/android_pmem.h>
+
 
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
diff --git a/drivers/media/platform/msm/camera_v1/msm_mctl.c b/drivers/media/platform/msm/camera_v1/msm_mctl.c
index 0210d23..95e889d 100644
--- a/drivers/media/platform/msm/camera_v1/msm_mctl.c
+++ b/drivers/media/platform/msm/camera_v1/msm_mctl.c
@@ -26,7 +26,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 
-#include <linux/android_pmem.h>
+
 
 #include "msm.h"
 #include "msm_cam_server.h"
diff --git a/drivers/media/platform/msm/camera_v1/msm_mctl_buf.c b/drivers/media/platform/msm/camera_v1/msm_mctl_buf.c
index 3ccd258..041f674 100644
--- a/drivers/media/platform/msm/camera_v1/msm_mctl_buf.c
+++ b/drivers/media/platform/msm/camera_v1/msm_mctl_buf.c
@@ -23,7 +23,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 
-#include <linux/android_pmem.h>
+
 
 #include "msm.h"
 #include "msm_cam_server.h"
@@ -1015,78 +1015,6 @@
 	D("%s Frame mapped successfully ", __func__);
 	return 0;
 }
-#else
-/* Unmap using PMEM APIs */
-static int __msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
-	struct ion_client *client, int domain_num)
-{
-	int i = 0, rc = 0;
-
-	for (i = 0; i < meta_frame->frame.num_planes; i++) {
-		D("%s Plane %d handle %p", __func__, i,
-			meta_frame->map[i].handle);
-		put_pmem_file(meta_frame->map[i].file);
-	}
-}
-
-/* Map using PMEM APIs */
-static int __msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
-	struct ion_client *client, int domain_num)
-{
-	unsigned long kvstart = 0;
-	unsigned long paddr = 0;
-	struct file *file = NULL;
-	unsigned long len;
-	int i = 0, j = 0;
-
-	for (i = 0; i < meta_frame->frame.num_planes; i++) {
-		rc = get_pmem_file(meta_frame->frame.mp[i].fd,
-			&paddr, &kvstart, &len, &file);
-		if (rc < 0) {
-			pr_err("%s: get_pmem_file fd %d error %d\n",
-				__func__, meta_frame->frame.mp[i].fd, rc);
-			/* Roll back previous plane mappings, if any */
-			for (j = i-1; j >= 0; j--)
-				if (meta_frame->map[j].file)
-					put_pmem_file(meta_frame->map[j].file);
-
-			return -EACCES;
-		}
-		D("%s Got pmem file for fd %d plane %d as %p", __func__,
-			meta_frame->frame.mp[i].fd, i, file);
-		meta_frame->map[i].file = file;
-		/* Validate the offsets with the mapped length. */
-		if ((meta_frame->frame.mp[i].addr_offset > len) ||
-			(meta_frame->frame.mp[i].data_offset +
-			meta_frame->frame.mp[i].length > len)) {
-			pr_err("%s: Invalid offsets A %d D %d L %d len %ld",
-				__func__, meta_frame->frame.mp[i].addr_offset,
-				meta_frame->frame.mp[i].data_offset,
-				meta_frame->frame.mp[i].length, len);
-			/* Roll back previous plane mappings, if any */
-			for (j = i; j >= 0; j--)
-				if (meta_frame->map[j].file)
-					put_pmem_file(meta_frame->map[j].file);
-
-			return -EINVAL;
-		}
-		meta_frame->map[i].data_offset =
-			meta_frame->frame.mp[i].data_offset;
-		/* Add the addr_offset to the paddr here itself. The addr_offset
-		 * will be non-zero only if the user has allocated a buffer with
-		 * a single fd, but logically partitioned it into
-		 * multiple planes or buffers.*/
-		paddr += meta_frame->frame.mp[i].addr_offset;
-		meta_frame->map[i].paddr = paddr;
-		meta_frame->map[i].len = len;
-		D("%s Plane %d fd %d handle %p paddr %x", __func__,
-			i, meta_frame->frame.mp[i].fd,
-			meta_frame->map[i].handle,
-			(uint32_t)meta_frame->map[i].paddr);
-	}
-	D("%s Frame mapped successfully ", __func__);
-	return 0;
-}
 #endif
 
 int msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
diff --git a/drivers/media/platform/msm/camera_v1/msm_mctl_pp.c b/drivers/media/platform/msm/camera_v1/msm_mctl_pp.c
index 9267c9f..ae3ce63 100644
--- a/drivers/media/platform/msm/camera_v1/msm_mctl_pp.c
+++ b/drivers/media/platform/msm/camera_v1/msm_mctl_pp.c
@@ -25,7 +25,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 
-#include <linux/android_pmem.h>
+
 
 #include "msm.h"
 #include "msm_vpe.h"
diff --git a/drivers/media/platform/msm/camera_v1/msm_mem.c b/drivers/media/platform/msm/camera_v1/msm_mem.c
index 8144415..c9a87d7 100644
--- a/drivers/media/platform/msm/camera_v1/msm_mem.c
+++ b/drivers/media/platform/msm/camera_v1/msm_mem.c
@@ -25,7 +25,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 
-#include <linux/android_pmem.h>
+
 
 #include "msm.h"
 
@@ -71,26 +71,6 @@
 
 static DEFINE_MUTEX(hlist_mut);
 
-#ifdef CONFIG_ANDROID_PMEM
-static int check_pmem_info(struct msm_pmem_info *info, int len)
-{
-	if (info->offset < len &&
-		info->offset + info->len <= len &&
-		info->planar0_off < len &&
-		info->planar1_off < len)
-		return 0;
-
-	pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
-						__func__,
-						info->offset,
-						info->len,
-						info->planar0_off,
-						info->planar1_off,
-						len);
-	return -EINVAL;
-}
-#endif
-
 static int check_overlap(struct hlist_head *ptype,
 				unsigned long paddr,
 				unsigned long len)
@@ -138,14 +118,6 @@
 	if (ion_map_iommu(client, region->handle, domain_num, 0,
 				  SZ_4K, 0, &paddr, &len, 0, 0) < 0)
 		goto out2;
-#elif CONFIG_ANDROID_PMEM
-	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
-	if (rc < 0) {
-		pr_err("%s: get_pmem_file fd %d error %d\n",
-				__func__, info->fd, rc);
-		goto out1;
-	}
-	region->file = file;
 #else
 	paddr = 0;
 	file = NULL;
@@ -153,9 +125,6 @@
 #endif
 	if (!info->len)
 		info->len = len;
-	rc = check_pmem_info(info, len);
-	if (rc < 0)
-		goto out3;
 	paddr += info->offset;
 	len = info->len;
 
@@ -185,8 +154,6 @@
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 out2:
 	ion_free(client, region->handle);
-#elif CONFIG_ANDROID_PMEM
-	put_pmem_file(region->file);
 #endif
 out1:
 	kfree(region);
@@ -256,8 +223,6 @@
 				ion_unmap_iommu(client, region->handle,
 					domain_num, 0);
 				ion_free(client, region->handle);
-#else
-				put_pmem_file(region->file);
 #endif
 				kfree(region);
 			}
diff --git a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x.c b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x.c
index bbf9d1b..d7ec547 100644
--- a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x.c
+++ b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x.c
@@ -14,7 +14,7 @@
 #include <linux/msm_adsp.h>
 #include <linux/uaccess.h>
 #include <linux/fs.h>
-#include <linux/android_pmem.h>
+
 #include <linux/slab.h>
 #include <mach/msm_adsp.h>
 #include <mach/clk.h>
diff --git a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a.c b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a.c
index 0279c78..6b41b03 100644
--- a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a.c
+++ b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a.c
@@ -13,7 +13,7 @@
 #include <linux/msm_adsp.h>
 #include <linux/uaccess.h>
 #include <linux/fs.h>
-#include <linux/android_pmem.h>
+
 #include <linux/slab.h>
 #include <linux/pm_qos.h>
 #include <linux/delay.h>
diff --git a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a_v4l2.c
index f3388d9..3a8f1b2 100644
--- a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe7x27a_v4l2.c
@@ -13,7 +13,7 @@
 #include <linux/msm_adsp.h>
 #include <linux/uaccess.h>
 #include <linux/fs.h>
-#include <linux/android_pmem.h>
+
 #include <linux/slab.h>
 #include <linux/pm_qos.h>
 #include <linux/delay.h>
diff --git a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe_stats_buf.c b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe_stats_buf.c
index a6807ed..a550d78 100644
--- a/drivers/media/platform/msm/camera_v1/vfe/msm_vfe_stats_buf.c
+++ b/drivers/media/platform/msm/camera_v1/vfe/msm_vfe_stats_buf.c
@@ -25,7 +25,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 
-#include <linux/android_pmem.h>
+
 #include <media/msm_camera.h>
 #include <media/msm_isp.h>
 #include "msm.h"
@@ -162,25 +162,6 @@
 	return rc;
 }
 
-#ifdef CONFIG_ANDROID_PMEM
-static int msm_stats_check_pmem_info(struct msm_stats_buf_info *info, int len)
-{
-	if (info->offset < len &&
-		info->offset + info->len <= len &&
-		info->planar0_off < len && info->planar1_off < len)
-		return 0;
-
-	pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
-		   __func__,
-		   info->offset,
-		   info->len,
-		   info->planar0_off,
-		   info->planar1_off,
-		   len);
-	return -EINVAL;
-}
-#endif
-
 static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl,
 	struct msm_stats_buf_info *info, struct ion_client *client,
 	int domain_num)
@@ -226,14 +207,6 @@
 		pr_err("%s: cannot map address", __func__);
 		goto out2;
 	}
-#elif CONFIG_ANDROID_PMEM
-	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
-	if (rc < 0) {
-		pr_err("%s: get_pmem_file fd %d error %d\n",
-			   __func__, info->fd, rc);
-		goto out1;
-	}
-	stats_buf->file = file;
 #else
 	paddr = 0;
 	file = NULL;
@@ -241,11 +214,6 @@
 #endif
 	if (!info->len)
 		info->len = len;
-	rc = msm_stats_check_pmem_info(info, len);
-	if (rc < 0) {
-		pr_err("%s: msm_stats_check_pmem_info err = %d", __func__, rc);
-		goto out3;
-	}
 	paddr += info->offset;
 	len = info->len;
 	stats_buf->paddr = paddr;
@@ -256,15 +224,12 @@
 	D("%s pmem_stats address is 0x%ld\n", __func__, paddr);
 	stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
 	return 0;
-out3:
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	ion_unmap_iommu(client, stats_buf->handle, domain_num, 0);
 #endif
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 out2:
 	ion_free(client, stats_buf->handle);
-#elif CONFIG_ANDROID_PMEM
-	put_pmem_file(stats_buf->file);
 #endif
 out1:
 	return rc;
@@ -295,8 +260,6 @@
 	ion_unmap_iommu(client, stats_buf->handle,
 					domain_num, 0);
 	ion_free(client, stats_buf->handle);
-#else
-	put_pmem_file(stats_buf->file);
 #endif
 	if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
 		/* buf queued need delete from list */
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 c8873b8..3a24428 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
@@ -20,7 +20,7 @@
 #include <linux/proc_fs.h>
 #include <linux/videodev2.h>
 #include <linux/vmalloc.h>
-#include <linux/android_pmem.h>
+
 
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 69d523c..38130db 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -378,8 +378,8 @@
 	struct msm_vfe_tasklet_queue_cmd
 		tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
 
+	uint32_t vfe_hw_version;
 	struct msm_vfe_hardware_info *hw_info;
-
 	struct msm_vfe_axi_shared_data axi_data;
 	struct msm_vfe_stats_shared_data stats_data;
 	struct msm_vfe_error_info error_info;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index fc0a8b5..b136125 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -29,6 +29,9 @@
 #define CDBG(fmt, args...) do { } while (0)
 #endif
 
+#define VFE40_V1_VERSION 0x10000018
+#define VFE40_V2_VERSION 0x1001001A
+
 #define VFE40_BURST_LEN 3
 #define VFE40_STATS_BURST_LEN 2
 #define VFE40_UB_SIZE 1536
@@ -123,53 +126,99 @@
 static void msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev)
 {
 	void __iomem *vfebase = vfe_dev->vfe_base;
-	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
-	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
-	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
-	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_3);
-	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_4);
-	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
-	msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
-	msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+	if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
+		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
+		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
+		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
+		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_3);
+		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_4);
+		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
+		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
+		msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+	} else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
+		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
+		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
+		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
+		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_3);
+		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_4);
+		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
+		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
+		msm_camera_io_w(0x0001AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+	}
 }
 
-static void msm_vfe40_init_vbif_parms(
-	void __iomem *vfe_vbif_base)
+static void msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev)
 {
-	msm_camera_io_w(0x1,
-		vfe_vbif_base + VFE40_VBIF_CLKON);
-	msm_camera_io_w(0x01010101,
-		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
-	msm_camera_io_w(0x01010101,
-		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
-	msm_camera_io_w(0x10010110,
-		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
-	msm_camera_io_w(0x10101010,
-		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
-	msm_camera_io_w(0x10101010,
-		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
-	msm_camera_io_w(0x10101010,
-		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
-	msm_camera_io_w(0x00001010,
-		vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
-	msm_camera_io_w(0x00001010,
-		vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
-	msm_camera_io_w(0x00000707,
-		vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
-	msm_camera_io_w(0x00000707,
-		vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
-	msm_camera_io_w(0x00000030,
-		vfe_vbif_base + VFE40_VBIF_ARB_CTL);
-	msm_camera_io_w(0x00000FFF,
-		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
-	msm_camera_io_w(0x0FFF0FFF,
-		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
-	msm_camera_io_w(0x00000001,
-		vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
-	msm_camera_io_w(0x22222222,
-		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
-	msm_camera_io_w(0x00002222,
-		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+	void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+	if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
+		msm_camera_io_w(0x1,
+			vfe_vbif_base + VFE40_VBIF_CLKON);
+		msm_camera_io_w(0x01010101,
+			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+		msm_camera_io_w(0x01010101,
+			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+		msm_camera_io_w(0x10010110,
+			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+		msm_camera_io_w(0x10101010,
+			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+		msm_camera_io_w(0x10101010,
+			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+		msm_camera_io_w(0x10101010,
+			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+		msm_camera_io_w(0x00001010,
+			vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+		msm_camera_io_w(0x00001010,
+			vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+		msm_camera_io_w(0x00000707,
+			vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+		msm_camera_io_w(0x00000707,
+			vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
+		msm_camera_io_w(0x00000030,
+			vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+		msm_camera_io_w(0x00000FFF,
+			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+		msm_camera_io_w(0x0FFF0FFF,
+			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+		msm_camera_io_w(0x00000001,
+			vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+		msm_camera_io_w(0x22222222,
+			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+		msm_camera_io_w(0x00002222,
+			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+	} else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
+		msm_camera_io_w(0x1,
+			vfe_vbif_base + VFE40_VBIF_CLKON);
+		msm_camera_io_w(0x10101010,
+			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+		msm_camera_io_w(0x10101010,
+			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+		msm_camera_io_w(0x10101010,
+			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+		msm_camera_io_w(0x10101010,
+			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+		msm_camera_io_w(0x10101010,
+			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+		msm_camera_io_w(0x10101010,
+			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+		msm_camera_io_w(0x00000010,
+			vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+		msm_camera_io_w(0x00000010,
+			vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+		msm_camera_io_w(0x00000707,
+			vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+		msm_camera_io_w(0x00000010,
+			vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+		msm_camera_io_w(0x00000FFF,
+			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+		msm_camera_io_w(0x0FFF0FFF,
+			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+		msm_camera_io_w(0x00000003,
+			vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+		msm_camera_io_w(0x22222222,
+			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+		msm_camera_io_w(0x00002222,
+			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+	}
 }
 
 static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev)
@@ -254,7 +303,7 @@
 static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev)
 {
 	msm_vfe40_init_qos_parms(vfe_dev);
-	msm_vfe40_init_vbif_parms(vfe_dev->vfe_vbif_base);
+	msm_vfe40_init_vbif_parms(vfe_dev);
 	/* CGC_OVERRIDE */
 	msm_camera_io_w(0x3FFFFFFF, vfe_dev->vfe_base + 0x14);
 	msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 5baeb28..f337e27 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -637,6 +637,9 @@
 		mutex_unlock(&vfe_dev->mutex);
 		return -EINVAL;
 	}
+	vfe_dev->vfe_hw_version = msm_camera_io_r(vfe_dev->vfe_base);
+	ISP_DBG("%s: HW Version: 0x%x\n", __func__, vfe_dev->vfe_hw_version);
+
 	vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
 
 	for (i = 0; i < vfe_dev->hw_info->num_iommu_ctx; i++)
@@ -649,10 +652,6 @@
 		sizeof(struct msm_vfe_stats_shared_data));
 	memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
 	vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
-
-	ISP_DBG("%s: HW Version: 0x%x\n",
-		__func__, msm_camera_io_r(vfe_dev->vfe_base));
-
 	vfe_dev->vfe_open_cnt++;
 	vfe_dev->taskletq_idx = 0;
 	mutex_unlock(&vfe_dev->mutex);
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 0eb0a23..b1253fa 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -17,7 +17,7 @@
 #include <linux/clk.h>
 #include <mach/clk.h>
 #include <linux/io.h>
-#include <linux/android_pmem.h>
+
 #include <mach/camera.h>
 #include <mach/iommu_domains.h>
 #include <mach/msm_bus.h>
@@ -293,8 +293,12 @@
 	pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_8x_clk_info), 0);
 
 fail_clk:
-	regulator_put(pgmn_dev->jpeg_fs);
-	regulator_disable(pgmn_dev->jpeg_fs);
+	rc = regulator_disable(pgmn_dev->jpeg_fs);
+	if (!rc)
+		regulator_put(pgmn_dev->jpeg_fs);
+	else
+		JPEG_PR_ERR("%s:%d] regulator disable failed %d",
+			__func__, __LINE__, rc);
 	pgmn_dev->jpeg_fs = NULL;
 
 fail_fs:
@@ -330,8 +334,12 @@
 	JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__);
 
 	if (pgmn_dev->jpeg_fs) {
-		regulator_put(pgmn_dev->jpeg_fs);
-		regulator_disable(pgmn_dev->jpeg_fs);
+		result = regulator_disable(pgmn_dev->jpeg_fs);
+		if (!result)
+			regulator_put(pgmn_dev->jpeg_fs);
+		else
+			JPEG_PR_ERR("%s:%d] regulator disable failed %d",
+				__func__, __LINE__, result);
 		pgmn_dev->jpeg_fs = NULL;
 	}
 	iounmap(pgmn_dev->jpeg_vbif);
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index f8cddb2..6418f21 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -268,6 +268,8 @@
 	msm_enqueue(&session->stream_q, &stream->list);
 	session->stream_q.len++;
 
+	INIT_LIST_HEAD(&stream->queued_list);
+
 	return 0;
 }
 
@@ -852,6 +854,31 @@
 	return stream->vb2_q;
 }
 
+struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q)
+{
+	struct msm_session *session;
+	struct msm_stream *stream;
+	unsigned long flags1;
+	unsigned long flags2;
+	spin_lock_irqsave(&msm_session_q->lock, flags1);
+	list_for_each_entry(session, &(msm_session_q->list), list) {
+		spin_lock_irqsave(&(session->stream_q.lock), flags2);
+		list_for_each_entry(
+			stream, &(session->stream_q.list), list) {
+			if (stream->vb2_q == q) {
+				spin_unlock_irqrestore
+					(&(session->stream_q.lock), flags2);
+				spin_unlock_irqrestore
+					(&msm_session_q->lock, flags1);
+				return stream;
+			}
+		}
+		spin_unlock_irqrestore(&(session->stream_q.lock), flags2);
+	}
+	spin_unlock_irqrestore(&msm_session_q->lock, flags1);
+	return NULL;
+}
+
 static struct v4l2_subdev *msm_sd_find(const char *name)
 {
 	unsigned long flags;
diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h
index eb15cab..39901ad 100644
--- a/drivers/media/platform/msm/camera_v2/msm.h
+++ b/drivers/media/platform/msm/camera_v2/msm.h
@@ -51,5 +51,6 @@
 	unsigned int stream_id);
 struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id,
 	unsigned int stream_id);
+struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q);
 
 #endif /*_MSM_H */
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
index 079dbb5..29262af 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c
@@ -38,22 +38,107 @@
 
 int msm_vb2_buf_init(struct vb2_buffer *vb)
 {
+	struct msm_stream *stream;
 	struct msm_vb2_buffer *msm_vb2_buf;
 
+	stream = msm_get_stream_from_vb2q(vb->vb2_queue);
+	if (!stream) {
+		pr_err("%s: Couldn't find stream\n", __func__);
+		return -EINVAL;
+	}
 	msm_vb2_buf = container_of(vb, struct msm_vb2_buffer, vb2_buf);
 	msm_vb2_buf->in_freeq = 0;
+	msm_vb2_buf->stream = stream;
 
 	return 0;
 }
 
 static void msm_vb2_buf_queue(struct vb2_buffer *vb)
 {
+	struct msm_vb2_buffer *msm_vb2;
+	struct msm_stream *stream;
+	unsigned long flags;
+
+	msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf);
+
+	if (!msm_vb2) {
+		pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__);
+		return;
+	}
+
+	stream = msm_vb2->stream;
+	if (!stream) {
+		pr_err("%s:%d] NULL stream", __func__, __LINE__);
+		return;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	list_add_tail(&msm_vb2->list, &stream->queued_list);
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+}
+
+static int msm_vb2_buf_finish(struct vb2_buffer *vb)
+{
+	struct msm_vb2_buffer *msm_vb2;
+	struct msm_stream *stream;
+	unsigned long flags;
+	struct msm_vb2_buffer *msm_vb2_entry, *temp;
+
+	msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf);
+
+	if (!msm_vb2) {
+		pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	stream = msm_vb2->stream;
+	if (!stream) {
+		pr_err("%s:%d] NULL stream", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	list_for_each_entry_safe(msm_vb2_entry, temp, &(stream->queued_list),
+		list) {
+		if (msm_vb2_entry == msm_vb2) {
+			list_del_init(&msm_vb2_entry->list);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
+	return 0;
+}
+
+static void msm_vb2_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct msm_vb2_buffer *msm_vb2;
+	struct msm_stream *stream;
+	unsigned long flags;
+
+	msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf);
+
+	if (!msm_vb2) {
+		pr_err("%s:%d] vb2 NULL", __func__, __LINE__);
+		return;
+	}
+
+	stream = msm_vb2->stream;
+	if (!stream) {
+		pr_err("%s:%d] NULL stream", __func__, __LINE__);
+		return;
+	}
+
+	spin_lock_irqsave(&stream->stream_lock, flags);
+	INIT_LIST_HEAD(&stream->queued_list);
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
 }
 
 static struct vb2_ops msm_vb2_get_q_op = {
-	.queue_setup		= msm_vb2_queue_setup,
-	.buf_init		= msm_vb2_buf_init,
-	.buf_queue              = msm_vb2_buf_queue,
+	.queue_setup	= msm_vb2_queue_setup,
+	.buf_init	= msm_vb2_buf_init,
+	.buf_queue	= msm_vb2_buf_queue,
+	.buf_cleanup	= msm_vb2_buf_cleanup,
+	.buf_finish	= msm_vb2_buf_finish,
 };
 
 
@@ -101,7 +186,7 @@
 {
 	struct msm_stream *stream;
 	struct vb2_buffer *vb2_buf = NULL;
-	struct msm_vb2_buffer *msm_vb2;
+	struct msm_vb2_buffer *msm_vb2 = NULL;
 	unsigned long flags;
 
 	stream = msm_get_stream(session_id, stream_id);
@@ -115,18 +200,18 @@
 		goto end;
 	}
 
-	list_for_each_entry(vb2_buf, &(stream->vb2_q->queued_list),
-		queued_entry) {
+	list_for_each_entry(msm_vb2, &(stream->queued_list), list) {
+		vb2_buf = &(msm_vb2->vb2_buf);
 		if (vb2_buf->state != VB2_BUF_STATE_ACTIVE)
 			continue;
 
-		msm_vb2 = container_of(vb2_buf, struct msm_vb2_buffer, vb2_buf);
 		if (msm_vb2->in_freeq)
 			continue;
 
 		msm_vb2->in_freeq = 1;
 		goto end;
 	}
+	msm_vb2 = NULL;
 	vb2_buf = NULL;
 end:
 	spin_unlock_irqrestore(&stream->stream_lock, flags);
@@ -136,9 +221,15 @@
 static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id,
 				unsigned int stream_id)
 {
+	struct msm_stream *stream;
 	struct msm_vb2_buffer *msm_vb2;
 	int rc = 0;
+	unsigned long flags;
+	stream = msm_get_stream(session_id, stream_id);
+	if (IS_ERR_OR_NULL(stream))
+		return -EINVAL;
 
+	spin_lock_irqsave(&stream->stream_lock, flags);
 	if (vb) {
 		msm_vb2 =
 			container_of(vb, struct msm_vb2_buffer, vb2_buf);
@@ -151,6 +242,7 @@
 		pr_err("%s: VB buffer is null\n", __func__);
 		rc = -EINVAL;
 	}
+	spin_unlock_irqrestore(&stream->stream_lock, flags);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
index cecc85e..027d344 100644
--- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
+++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h
@@ -42,6 +42,7 @@
 	struct vb2_buffer vb2_buf;
 	struct list_head list;
 	int in_freeq;
+	struct msm_stream *stream;
 };
 
 struct msm_vb2_private_data {
@@ -60,6 +61,7 @@
 	/* vb2 buffer handling */
 	struct vb2_queue *vb2_q;
 	spinlock_t stream_lock;
+	struct list_head queued_list;
 };
 
 struct vb2_ops *msm_vb2_get_q_ops(void);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 41234c3..ca5e646 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -754,6 +754,9 @@
 	case VIDIOC_MSM_CPP_CFG:
 		rc = msm_cpp_cfg(cpp_dev, ioctl_ptr);
 		break;
+	case VIDIOC_MSM_CPP_FLUSH_QUEUE:
+		rc = msm_cpp_send_frame_to_hardware(cpp_dev);
+		break;
 	case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: {
 		struct msm_device_queue *queue = &cpp_dev->eventData_q;
 		struct msm_queue_cmd *event_qcmd;
diff --git a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
index 46002c3..b9fdc5e 100644
--- a/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
+++ b/drivers/media/platform/msm/dvb/video/mpq_dvb_video.c
@@ -28,7 +28,7 @@
 #include <linux/uaccess.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
 #include <linux/clk.h>
 #include <linux/timer.h>
 #include <mach/msm_subsystem_map.h>
@@ -43,8 +43,6 @@
 #define ERR(x...) pr_err(x)
 
 #define MPQ_VID_DEC_NAME "mpq_vidc_dec"
-static unsigned int vidc_mmu_subsystem[] = {
-	MSM_SUBSYSTEM_VIDEO};
 
 static char vid_thread_names[DVB_MPQ_NUM_VIDEO_DEVICES][10] = {
 				"dvb-vid-0",
@@ -1060,10 +1058,7 @@
 {
 	struct vcd_property_hdr vcd_property_hdr;
 	struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
-	struct msm_mapped_buffer *mapped_buffer = NULL;
 	u32 vcd_status = VCD_ERR_FAIL;
-	u32 len = 0, flags = 0;
-	struct file *file;
 	int rc = 0;
 	unsigned long ionflag = 0;
 	unsigned long buffer_size = 0;
@@ -1084,28 +1079,8 @@
 	vcd_h264_mv_buffer->offset = mv_data->offset;
 
 	if (!vcd_get_ion_status()) {
-		if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
-			(unsigned long *) (&(vcd_h264_mv_buffer->
-			physical_addr)),
-			(unsigned long *) (&vcd_h264_mv_buffer->
-						kernel_virtual_addr),
-			(unsigned long *) (&len), &file)) {
-			ERR("%s(): get_pmem_file failed\n", __func__);
-			return -EIO;
-		}
-		put_pmem_file(file);
-		flags = MSM_SUBSYSTEM_MAP_IOVA;
-		mapped_buffer = msm_subsystem_map_buffer(
-			(unsigned long)vcd_h264_mv_buffer->physical_addr, len,
-				flags, vidc_mmu_subsystem,
-				sizeof(vidc_mmu_subsystem)/
-				sizeof(unsigned int));
-		if (IS_ERR(mapped_buffer)) {
-			ERR("buffer map failed");
-			return PTR_ERR(mapped_buffer);
-		}
-		vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
-		vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+		pr_err("PMEM not available");
+		return -EINVAL;
 	} else {
 		client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
 					client_ctx->user_ion_client,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index e55c0f1..b71a816 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/jiffies.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <asm/div64.h>
@@ -21,7 +22,7 @@
 #include "msm_smem.h"
 #include "msm_vidc_debug.h"
 
-#define HW_RESPONSE_TIMEOUT (5 * 60 * 1000)
+#define HW_RESPONSE_TIMEOUT msecs_to_jiffies(200)
 
 #define IS_ALREADY_IN_STATE(__p, __d) ({\
 	int __rc = (__p >= __d);\
@@ -313,7 +314,7 @@
 	enum command_response cmd)
 {
 	int rc = 0;
-	rc = wait_for_completion_interruptible_timeout(
+	rc = wait_for_completion_timeout(
 		&inst->completions[SESSION_MSG_INDEX(cmd)],
 		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
 	if (!rc) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 65542bc..62158b0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -18,7 +18,7 @@
 int msm_vidc_debug = 0x3;
 int msm_fw_debug = 0x18;
 int msm_fw_debug_mode = 0x1;
-int msm_fw_low_power_mode = 0x1;
+int msm_fw_low_power_mode = 0x0;
 
 struct debug_buffer {
 	char ptr[MAX_DBG_BUF_SIZE];
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 88dc4fe..d1948d1 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1188,6 +1188,13 @@
 	return 0;
 }
 
+static int q6_hfi_get_stride_scanline(int color_fmt,
+	int width, int height, int *stride, int *scanlines) {
+	*stride = VENUS_Y_STRIDE(color_fmt, width);
+	*scanlines = VENUS_Y_SCANLINES(color_fmt, height);
+	return 0;
+}
+
 static void q6_init_hfi_callbacks(struct hfi_device *hdev)
 {
 	hdev->core_init = q6_hfi_core_init;
@@ -1223,6 +1230,7 @@
 	hdev->load_fw = q6_hfi_load_fw;
 	hdev->unload_fw = q6_hfi_unload_fw;
 	hdev->get_fw_info = q6_hfi_get_fw_info;
+	hdev->get_stride_scanline = q6_hfi_get_stride_scanline;
 }
 
 
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 8c30b6c..424af64 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -164,6 +164,11 @@
 	}
 
 	qinfo =	(struct vidc_iface_q_info *) info;
+	if (!qinfo || !qinfo->q_array.align_virtual_addr) {
+		dprintk(VIDC_WARN, "Queues have already been freed\n");
+		return -EINVAL;
+	}
+
 	venus_hfi_sim_modify_cmd_packet(packet);
 
 	queue = (struct hfi_queue_header *) qinfo->q_hdr;
@@ -282,6 +287,10 @@
 	}
 
 	qinfo =	(struct vidc_iface_q_info *) info;
+	if (!qinfo || !qinfo->q_array.align_virtual_addr) {
+		dprintk(VIDC_WARN, "Queues have already been freed\n");
+		return -EINVAL;
+	}
 	queue = (struct hfi_queue_header *) qinfo->q_hdr;
 
 	if (!queue) {
@@ -634,6 +643,8 @@
 	int num_entries = sizeof(venus_qdss_entries)/(2 * sizeof(u32));
 	int domain, partition;
 
+	mutex_lock(&device->write_lock);
+	mutex_lock(&device->read_lock);
 	if (device->qdss.mem_data) {
 		qdss = (struct hfi_mem_map_table *)
 			device->qdss.align_virtual_addr;
@@ -674,6 +685,8 @@
 
 	msm_smem_delete_client(device->hal_client);
 	device->hal_client = NULL;
+	mutex_unlock(&device->read_lock);
+	mutex_unlock(&device->write_lock);
 }
 static int venus_hfi_get_qdss_iommu_virtual_addr(struct hfi_mem_map *mem_map,
 						int domain, int partition)
@@ -937,7 +950,6 @@
 	}
 
 	dev->intr_status = 0;
-	enable_irq(dev->hal_data->irq);
 	INIT_LIST_HEAD(&dev->sess_head);
 	mutex_init(&dev->read_lock);
 	mutex_init(&dev->write_lock);
@@ -966,6 +978,7 @@
 		rc = -EEXIST;
 		goto err_core_init;
 	}
+	enable_irq(dev->hal_data->irq);
 	venus_hfi_write_register(dev->hal_data->register_base_addr,
 		VIDC_CTRL_INIT, 0x1, 0);
 	rc = venus_hfi_core_start_cpu(dev);
@@ -1989,12 +2002,8 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
-	if (device->clocks_enabled) {
-		cl = &device->resources.clock[VCODEC_CLK];
-		clk_disable_unprepare(cl->clk);
-	}
 
-	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+	for (i = 0; i < VCODEC_MAX_CLKS; i++) {
 		cl = &device->resources.clock[i];
 		clk_disable_unprepare(cl->clk);
 	}
@@ -2009,17 +2018,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-	if (!device->clocks_enabled) {
-		cl = &device->resources.clock[VCODEC_CLK];
-		rc = clk_prepare_enable(cl->clk);
-		if (rc) {
-			dprintk(VIDC_ERR, "Failed to enable clocks\n");
-			goto fail_clk_enable;
-		} else {
-			dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
-		}
-	}
-	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
+	for (i = 0; i < VCODEC_MAX_CLKS; i++) {
 		cl = &device->resources.clock[i];
 		rc = clk_prepare_enable(cl->clk);
 		if (rc) {
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 1f3dc2f..153552d 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2696,6 +2696,9 @@
 {
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
 	int retval = 0;
+	int cf0;
+	struct hci_fm_def_data_rd_req rd;
+	int lsb, msb;
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
@@ -2858,6 +2861,113 @@
 	case V4L2_CID_PRIVATE_VALID_CHANNEL:
 		ctrl->value = radio->is_station_valid;
 		break;
+	case V4L2_CID_PRIVATE_AF_RMSSI_TH:
+		rd.mode = FM_RDS_CNFG_MODE;
+		rd.length = FM_RDS_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("Get AF Jump Threshold failed %x", retval);
+			return retval;
+		}
+		lsb = radio->default_data.data[AF_RMSSI_TH_LSB_OFFSET];
+		msb = radio->default_data.data[AF_RMSSI_TH_MSB_OFFSET];
+		ctrl->value = ((msb << 8) | lsb);
+		break;
+	case V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES:
+		rd.mode = FM_RDS_CNFG_MODE;
+		rd.length = FM_RDS_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("Get AF jump rmssi samples failed %x", retval);
+			return retval;
+		}
+		ctrl->value = radio->default_data.data[AF_RMSSI_SAMPLES_OFFSET];
+		break;
+	case V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("get good channel rmssi th failed %x", retval);
+			return retval;
+		}
+		ctrl->value = radio->default_data.data[GD_CH_RMSSI_TH_OFFSET];
+		if (ctrl->value > MAX_GD_CH_RMSSI_TH)
+			ctrl->value -= 256;
+		break;
+	case V4L2_CID_PRIVATE_SRCHALGOTYPE:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("get search algo type failed %x", retval);
+			return retval;
+		}
+		ctrl->value = radio->default_data.data[SRCH_ALGO_TYPE_OFFSET];
+		break;
+	case V4L2_CID_PRIVATE_SINRFIRSTSTAGE:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		ctrl->value = radio->default_data.data[SINRFIRSTSTAGE_OFFSET];
+		if (ctrl->value > MAX_SINR_FIRSTSTAGE)
+			ctrl->value -= 256;
+		break;
+	case V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		ctrl->value = radio->default_data.data[RMSSIFIRSTSTAGE_OFFSET];
+		if (ctrl->value > MAX_RMSSI_FIRSTSTAGE)
+			ctrl->value -= 256;
+		break;
+	case V4L2_CID_PRIVATE_CF0TH12:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		ctrl->value = radio->default_data.data[CF0TH12_BYTE1_OFFSET];
+		cf0 = radio->default_data.data[CF0TH12_BYTE2_OFFSET];
+		ctrl->value |= (cf0 << 8);
+		cf0 = radio->default_data.data[CF0TH12_BYTE3_OFFSET];
+		ctrl->value |= (cf0 << 16);
+		cf0 = radio->default_data.data[CF0TH12_BYTE4_OFFSET];
+		if (cf0 > 127)
+			cf0 -= 256;
+		ctrl->value |= (cf0 << 24);
+		break;
 	default:
 		retval = -EINVAL;
 	}
@@ -3022,8 +3132,8 @@
 	unsigned long arg = 0;
 	struct hci_fm_tx_ps tx_ps = {0};
 	struct hci_fm_tx_rt tx_rt = {0};
-	struct hci_fm_def_data_rd_req rd_txgain;
-	struct hci_fm_def_data_wr_req wr_txgain;
+	struct hci_fm_def_data_rd_req rd;
+	struct hci_fm_def_data_wr_req wrd;
 	char sinr_th, sinr;
 	__u8 intf_det_low_th, intf_det_high_th, intf_det_out;
 
@@ -3325,25 +3435,25 @@
 			ctrl->value = FM_TX_PWR_LVL_MAX;
 		if (ctrl->value < FM_TX_PWR_LVL_0)
 			ctrl->value = FM_TX_PWR_LVL_0;
-		rd_txgain.mode = FM_TX_PHY_CFG_MODE;
-		rd_txgain.length = FM_TX_PHY_CFG_LEN;
-		rd_txgain.param_len = 0x00;
-		rd_txgain.param = 0x00;
+		rd.mode = FM_TX_PHY_CFG_MODE;
+		rd.length = FM_TX_PHY_CFG_LEN;
+		rd.param_len = 0x00;
+		rd.param = 0x00;
 
-		retval = hci_def_data_read(&rd_txgain, radio->fm_hdev);
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Default data read failed for PHY_CFG %d\n",
 			retval);
 			break;
 		}
-		memset(&wr_txgain, 0, sizeof(wr_txgain));
-		wr_txgain.mode = FM_TX_PHY_CFG_MODE;
-		wr_txgain.length = FM_TX_PHY_CFG_LEN;
-		memcpy(&wr_txgain.data, &radio->default_data.data,
+		memset(&wrd, 0, sizeof(wrd));
+		wrd.mode = FM_TX_PHY_CFG_MODE;
+		wrd.length = FM_TX_PHY_CFG_LEN;
+		memcpy(&wrd.data, &radio->default_data.data,
 					radio->default_data.ret_data_len);
-		wr_txgain.data[FM_TX_PWR_GAIN_OFFSET] =
+		wrd.data[FM_TX_PWR_GAIN_OFFSET] =
 				(ctrl->value) * FM_TX_PWR_LVL_STEP_SIZE;
-		retval = hci_def_data_write(&wr_txgain, radio->fm_hdev);
+		retval = hci_def_data_write(&wrd, radio->fm_hdev);
 		if (retval < 0)
 			FMDERR("Default write failed for PHY_TXGAIN %d\n",
 			retval);
@@ -3536,6 +3646,150 @@
 		else
 			radio->is_station_valid = INVALID_CHANNEL;
 		break;
+	case V4L2_CID_PRIVATE_AF_RMSSI_TH:
+		rd.mode = FM_RDS_CNFG_MODE;
+		rd.length = FM_RDS_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		wrd.mode = FM_RDS_CNFG_MODE;
+		wrd.length = FM_RDS_CNFG_LEN;
+		memcpy(&wrd.data, &radio->default_data.data,
+				radio->default_data.ret_data_len);
+		wrd.data[AF_RMSSI_TH_LSB_OFFSET] = ((ctrl->value) & 255);
+		wrd.data[AF_RMSSI_TH_MSB_OFFSET] = ((ctrl->value) >> 8);
+		retval = hci_def_data_write(&wrd, radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("set AF jump RMSSI threshold failed\n");
+		break;
+	case V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES:
+		rd.mode = FM_RDS_CNFG_MODE;
+		rd.length = FM_RDS_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		wrd.mode = FM_RDS_CNFG_MODE;
+		wrd.length = FM_RDS_CNFG_LEN;
+		memcpy(&wrd.data, &radio->default_data.data,
+				radio->default_data.ret_data_len);
+		wrd.data[AF_RMSSI_SAMPLES_OFFSET] = ctrl->value;
+		retval = hci_def_data_write(&wrd, radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("set AF jump RMSSI Samples failed\n");
+		break;
+	case V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		wrd.mode = FM_RX_CONFG_MODE;
+		wrd.length = FM_RX_CNFG_LEN;
+		memcpy(&wrd.data, &radio->default_data.data,
+				radio->default_data.ret_data_len);
+		wrd.data[GD_CH_RMSSI_TH_OFFSET] = ctrl->value;
+		retval = hci_def_data_write(&wrd, radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("set good channel RMSSI th failed\n");
+		break;
+	case V4L2_CID_PRIVATE_SRCHALGOTYPE:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		wrd.mode = FM_RX_CONFG_MODE;
+		wrd.length = FM_RX_CNFG_LEN;
+		memcpy(&wrd.data, &radio->default_data.data,
+				radio->default_data.ret_data_len);
+		wrd.data[SRCH_ALGO_TYPE_OFFSET] = ctrl->value;
+		retval = hci_def_data_write(&wrd, radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("set Search Algo Type failed\n");
+		break;
+	case V4L2_CID_PRIVATE_SINRFIRSTSTAGE:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		wrd.mode = FM_RX_CONFG_MODE;
+		wrd.length = FM_RX_CNFG_LEN;
+		memcpy(&wrd.data, &radio->default_data.data,
+				radio->default_data.ret_data_len);
+		wrd.data[SINRFIRSTSTAGE_OFFSET] = ctrl->value;
+		retval = hci_def_data_write(&wrd, radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("set SINR First Stage failed\n");
+		break;
+	case V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		wrd.mode = FM_RX_CONFG_MODE;
+		wrd.length = FM_RX_CNFG_LEN;
+		memcpy(&wrd.data, &radio->default_data.data,
+				radio->default_data.ret_data_len);
+		wrd.data[RMSSIFIRSTSTAGE_OFFSET] = ctrl->value;
+		retval = hci_def_data_write(&wrd, radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("set RMSSI First Stage failed\n");
+		break;
+	case V4L2_CID_PRIVATE_CF0TH12:
+		rd.mode = FM_RX_CONFG_MODE;
+		rd.length = FM_RX_CNFG_LEN;
+		rd.param_len = 0;
+		rd.param = 0;
+
+		retval = hci_def_data_read(&rd, radio->fm_hdev);
+		if (retval < 0) {
+			FMDERR("default data read failed %x", retval);
+			return retval;
+		}
+		wrd.mode = FM_RX_CONFG_MODE;
+		wrd.length = FM_RX_CNFG_LEN;
+		memcpy(&wrd.data, &radio->default_data.data,
+				radio->default_data.ret_data_len);
+		wrd.data[CF0TH12_BYTE1_OFFSET] = (ctrl->value & 255);
+		wrd.data[CF0TH12_BYTE2_OFFSET] = ((ctrl->value >> 8) & 255);
+		wrd.data[CF0TH12_BYTE3_OFFSET] = ((ctrl->value >> 16) & 255);
+		wrd.data[CF0TH12_BYTE4_OFFSET] = ((ctrl->value >> 24) & 255);
+		retval = hci_def_data_write(&wrd, radio->fm_hdev);
+		if (retval < 0)
+			FMDERR("set CF0 Threshold failed\n");
+		break;
 	default:
 		retval = -EINVAL;
 	}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 8a99968..f3a979b 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -41,7 +41,7 @@
 	struct rc_dev *rcdev;
 	struct pm_qos_request pm_qos_req;
 	struct timer_list gpio_ir_timer;
-	unsigned int gpio_nr;
+	int gpio_nr;
 	bool active_low;
 	int can_sleep;
 	bool can_wakeup;
@@ -52,7 +52,7 @@
 static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
 {
 	struct gpio_rc_dev *gpio_dev = dev_id;
-	unsigned int gval;
+	int gval;
 	int rc = 0;
 	enum raw_event_type type = IR_SPACE;
 
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index b2ef948..ff2cddd 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -68,15 +68,6 @@
 			goto done;
 		}
 
-		/* Prevent excessive memory consumption, as well as integer
-		 * overflows.
-		 */
-		if (xmap->menu_count == 0 ||
-		    xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
-			ret = -EINVAL;
-			goto done;
-		}
-
 		size = xmap->menu_count * sizeof(*map->menu_info);
 		map->menu_info = kmalloc(size, GFP_KERNEL);
 		if (map->menu_info == NULL) {
diff --git a/drivers/media/video/videobuf-msm-mem.c b/drivers/media/video/videobuf-msm-mem.c
index 9e2cc22..eeda13a 100644
--- a/drivers/media/video/videobuf-msm-mem.c
+++ b/drivers/media/video/videobuf-msm-mem.c
@@ -24,7 +24,7 @@
 #include <linux/pagemap.h>
 #include <linux/sched.h>
 #include <linux/io.h>
-#include <linux/android_pmem.h>
+
 #include <linux/memory_alloc.h>
 #include <media/videobuf-msm-mem.h>
 #include <media/msm_camera.h>
@@ -140,55 +140,6 @@
 	.close    = videobuf_vm_close,
 };
 
-/**
- * videobuf_pmem_contig_user_put() - reset pointer to user space buffer
- * @mem: per-buffer private videobuf-contig-pmem data
- *
- * This function resets the user space pointer
- */
-static void videobuf_pmem_contig_user_put(struct videobuf_contig_pmem *mem)
-{
-	if (mem->phyaddr) {
-		put_pmem_file(mem->file);
-		mem->is_userptr = 0;
-		mem->phyaddr = 0;
-		mem->size = 0;
-	}
-}
-
-/**
- * videobuf_pmem_contig_user_get() - setup user space memory pointer
- * @mem: per-buffer private videobuf-contig-pmem data
- * @vb: video buffer to map
- *
- * This function validates and sets up a pointer to user space memory.
- * Only physically contiguous pfn-mapped memory is accepted.
- *
- * Returns 0 if successful.
- */
-static int videobuf_pmem_contig_user_get(struct videobuf_contig_pmem *mem,
-					struct videobuf_buffer *vb)
-{
-	unsigned long kvstart;
-	unsigned long len;
-	int rc;
-
-	mem->size = PAGE_ALIGN(vb->size);
-	rc = get_pmem_file(vb->baddr, (unsigned long *)&mem->phyaddr,
-					&kvstart, &len, &mem->file);
-	if (rc < 0) {
-		pr_err("%s: get_pmem_file fd %lu error %d\n",
-					__func__, vb->baddr,
-							rc);
-		return rc;
-	}
-	mem->phyaddr += vb->boff;
-	mem->y_off = 0;
-	mem->cbcr_off = (vb->size)*2/3;
-	mem->is_userptr = 1;
-	return rc;
-}
-
 static struct videobuf_buffer *__videobuf_alloc(size_t size)
 {
 	struct videobuf_contig_pmem *mem;
@@ -229,12 +180,6 @@
 
 		/* All handling should be done by __videobuf_mmap_mapper() */
 		break;
-	case V4L2_MEMORY_USERPTR:
-		D("%s memory method USERPTR\n", __func__);
-
-		/* handle pointer from user space */
-		rc = videobuf_pmem_contig_user_get(mem, vb);
-		break;
 	case V4L2_MEMORY_OVERLAY:
 	default:
 		pr_err("%s memory method OVERLAY/unknown\n", __func__);
@@ -383,7 +328,6 @@
 
 	/* handle user space pointer case */
 	if (buf->baddr) {
-		videobuf_pmem_contig_user_put(mem);
 		return 0;
 	} else {
 		/* don't support read() method */
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index cd07db8..8dbb522 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -24,7 +24,7 @@
 #include <linux/pagemap.h>
 #include <linux/sched.h>
 #include <linux/io.h>
-#include <linux/android_pmem.h>
+
 #include <linux/memory_alloc.h>
 #include <media/videobuf2-msm-mem.h>
 #include <media/msm_camera.h>
@@ -177,15 +177,14 @@
 					struct ion_client *client,
 					int domain_num)
 {
-	unsigned long len;
 	int rc = 0;
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	unsigned long kvstart;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	unsigned long len;
 #endif
 	unsigned long paddr = 0;
 	if (mem->phyaddr != 0)
 		return 0;
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#if defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
 	mem->ion_handle = ion_import_dma_buf(client, (int)mem->vaddr);
 	if (IS_ERR_OR_NULL(mem->ion_handle)) {
 		pr_err("%s ION import failed\n", __func__);
@@ -195,17 +194,8 @@
 		SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, 0, 0);
 	if (rc < 0)
 		ion_free(client, mem->ion_handle);
-#elif CONFIG_ANDROID_PMEM
-	rc = get_pmem_file((int)mem->vaddr, (unsigned long *)&mem->phyaddr,
-					&kvstart, &len, &mem->file);
-	if (rc < 0) {
-		pr_err("%s: get_pmem_file fd %d error %d\n",
-					__func__, (int)mem->vaddr, rc);
-		return rc;
-	}
 #else
 	paddr = 0;
-	kvstart = 0;
 #endif
 	if (offset)
 		mem->offset = *offset;
@@ -224,12 +214,10 @@
 				struct ion_client *client, int domain_num)
 {
 	if (mem->is_userptr) {
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#if defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
 		ion_unmap_iommu(client, mem->ion_handle,
 				domain_num, 0);
 		ion_free(client, mem->ion_handle);
-#elif CONFIG_ANDROID_PMEM
-		put_pmem_file(mem->file);
 #endif
 	}
 	mem->is_userptr = 0;
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index ce65e3f..c99bed1 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -58,11 +58,8 @@
 
 obj-$(CONFIG_TIMPANI_CODEC)	+= timpani-codec.o
 
-ifdef CONFIG_TIMPANI_CODEC
 obj-$(CONFIG_TIMPANI_CODEC) += msm-adie-codec.o
-else ifdef CONFIG_MARIMBA_CODEC
 obj-$(CONFIG_MARIMBA_CODEC) += msm-adie-codec.o
-endif
 
 obj-$(CONFIG_TWL6030_PWM)	+= twl6030-pwm.o
 obj-$(CONFIG_TWL6040_CORE)	+= twl6040-core.o twl6040-irq.o
@@ -127,6 +124,10 @@
 obj-$(CONFIG_MFD_WL1273_CORE)	+= wl1273-core.o
 obj-$(CONFIG_MFD_CS5535)	+= cs5535-mfd.o
 obj-$(CONFIG_MFD_OMAP_USB_HOST)	+= omap-usb-host.o
+obj-$(CONFIG_MFD_PM8921_CORE) 	+= pm8921-core.o
+obj-$(CONFIG_MFD_PM8821_CORE) 	+= pm8821-core.o
+obj-$(CONFIG_MFD_PM8018_CORE) 	+= pm8018-core.o
+obj-$(CONFIG_MFD_PM8XXX_IRQ) 	+= pm8xxx-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)	+= tps65911-comparator.o
 obj-$(CONFIG_MFD_TPS65090)	+= tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE)	+= aat2870-core.o
@@ -135,11 +136,7 @@
 obj-$(CONFIG_MFD_S5M_CORE)	+= s5m-core.o s5m-irq.o
 obj-$(CONFIG_PMIC8058)		+= pmic8058.o
 obj-$(CONFIG_PMIC8901)		+= pmic8901.o
-obj-$(CONFIG_MFD_PM8921_CORE) 	+= pm8921-core.o
-obj-$(CONFIG_MFD_PM8821_CORE) 	+= pm8821-core.o
-obj-$(CONFIG_MFD_PM8018_CORE) 	+= pm8018-core.o
 obj-$(CONFIG_MFD_PM8038_CORE) 	+= pm8038-core.o
-obj-$(CONFIG_MFD_PM8XXX_IRQ) 	+= pm8xxx-irq.o
 obj-$(CONFIG_MFD_PM8821_IRQ) 	+= pm8821-irq.o
 obj-$(CONFIG_MFD_PM8XXX_DEBUG) 	+= pm8xxx-debug.o
 obj-$(CONFIG_MFD_PM8XXX_PWM) 	+= pm8xxx-pwm.o
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b0222ec..f80f3f2 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,8 +54,6 @@
 obj-$(CONFIG_MAX8997_MUIC)	+= max8997-muic.o
 obj-$(CONFIG_WL127X_RFKILL)	+= wl127x-rfkill.o
 obj-$(CONFIG_SENSORS_AK8975)	+= akm8975.o
-obj-$(CONFIG_WL127X_RFKILL)	+= wl127x-rfkill.o
-obj-$(CONFIG_SENSORS_AK8975)	+= akm8975.o
 obj-$(CONFIG_TSIF) += msm_tsif.o
 msm_tsif-objs := tsif.o
 obj-$(CONFIG_TSIF_CHRDEV) += tsif_chrdev.o
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 834e0e2..b075435 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -34,6 +34,7 @@
 #include <linux/delay.h>
 #include <linux/capability.h>
 #include <linux/compat.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/ioctl.h>
 #include <linux/mmc/card.h>
@@ -2497,6 +2498,7 @@
 #endif
 
 	if (req && !mq->mqrq_prev->req) {
+		mmc_rpm_hold(host, &card->dev);
 		/* claim host only for the first request */
 		mmc_claim_host(card->host);
 		if (card->ext_csd.bkops_en)
@@ -2558,6 +2560,7 @@
 			mmc_start_bkops(card, false);
 		/* release host only when there are no more requests */
 		mmc_release_host(card->host);
+		mmc_rpm_release(host, &card->dev);
 	}
 	return ret;
 }
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 58efd5e..96e3dc0 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -2695,6 +2695,7 @@
 	pr_info("%s: Starting tests of card %s...\n",
 		mmc_hostname(test->card->host), mmc_card_id(test->card));
 
+	mmc_rpm_hold(test->card->host, &test->card->dev);
 	mmc_claim_host(test->card->host);
 
 	for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
@@ -2778,6 +2779,7 @@
 	}
 
 	mmc_release_host(test->card->host);
+	mmc_rpm_release(test->card->host, &test->card->dev);
 
 	pr_info("%s: Tests completed.\n",
 		mmc_hostname(test->card->host));
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 169ccf1..0e024dd 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -57,7 +57,6 @@
 {
 	struct mmc_queue *mq = d;
 	struct request_queue *q = mq->queue;
-	struct request *req;
 	struct mmc_card *card = mq->card;
 
 	current->flags |= PF_MEMALLOC;
@@ -65,7 +64,7 @@
 	down(&mq->thread_sem);
 	do {
 		struct mmc_queue_req *tmp;
-		req = NULL;	/* Must be set to NULL at each iteration */
+		struct request *req = NULL;
 
 		spin_lock_irq(q->queue_lock);
 		set_current_state(TASK_INTERRUPTIBLE);
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 2f27407..7b9e133 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -26,6 +26,7 @@
 #include "bus.h"
 
 #define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv)
+#define RUNTIME_SUSPEND_DELAY_MS 10000
 
 static ssize_t mmc_type_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
@@ -144,9 +145,6 @@
 		ret = drv->resume(card);
 	return ret;
 }
-#else
-#define mmc_bus_suspend NULL
-#define mmc_bus_resume NULL
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
@@ -155,19 +153,38 @@
 {
 	struct mmc_card *card = mmc_dev_to_card(dev);
 
-	return mmc_power_save_host(card->host);
+	if (mmc_use_core_runtime_pm(card->host))
+		return 0;
+	else
+		return mmc_power_save_host(card->host);
 }
 
 static int mmc_runtime_resume(struct device *dev)
 {
 	struct mmc_card *card = mmc_dev_to_card(dev);
 
-	return mmc_power_restore_host(card->host);
+	if (mmc_use_core_runtime_pm(card->host))
+		return 0;
+	else
+		return mmc_power_restore_host(card->host);
 }
 
 static int mmc_runtime_idle(struct device *dev)
 {
-	return pm_runtime_suspend(dev);
+	struct mmc_card *card = mmc_dev_to_card(dev);
+	struct mmc_host *host = card->host;
+	int ret = 0;
+
+	if (mmc_use_core_runtime_pm(card->host)) {
+		ret = pm_schedule_suspend(dev, card->idle_timeout);
+		if (ret) {
+			pr_err("%s: %s: pm_schedule_suspend failed: err: %d\n",
+			       mmc_hostname(host), __func__, ret);
+			return ret;
+		}
+	}
+
+	return ret;
 }
 
 #endif /* !CONFIG_PM_RUNTIME */
@@ -178,6 +195,42 @@
 	SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume)
 };
 
+static ssize_t show_rpm_delay(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct mmc_card *card = mmc_dev_to_card(dev);
+
+	if (!card) {
+		pr_err("%s: %s: card is NULL\n", dev_name(dev), __func__);
+		return -EINVAL;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", card->idle_timeout);
+}
+
+static ssize_t store_rpm_delay(struct device *dev, struct device_attribute
+			       *attr, const char *buf, size_t count)
+{
+	struct mmc_card *card = mmc_dev_to_card(dev);
+	unsigned int delay;
+
+	if (!card) {
+		pr_err("%s: %s: card is NULL\n", dev_name(dev), __func__);
+		return -EINVAL;
+	}
+
+	if (!kstrtou32(buf, 0, &delay)) {
+		if (delay < 2000) {
+			pr_err("%s: %s: less than 2 sec delay is unsupported\n",
+			       mmc_hostname(card->host), __func__);
+			return -EINVAL;
+		}
+		card->idle_timeout = delay;
+	}
+
+	return count;
+}
+
 static struct bus_type mmc_bus_type = {
 	.name		= "mmc",
 	.dev_attrs	= mmc_dev_attrs,
@@ -330,10 +383,34 @@
 #endif
 	mmc_init_context_info(card->host);
 
+	if (mmc_use_core_runtime_pm(card->host)) {
+		ret = pm_runtime_set_active(&card->dev);
+		if (ret)
+			pr_err("%s: %s: failed setting runtime active: ret: %d\n",
+			       mmc_hostname(card->host), __func__, ret);
+		else
+			pm_runtime_enable(&card->dev);
+	}
+
 	ret = device_add(&card->dev);
 	if (ret)
 		return ret;
 
+	if (mmc_use_core_runtime_pm(card->host)) {
+		card->rpm_attrib.show = show_rpm_delay;
+		card->rpm_attrib.store = store_rpm_delay;
+		sysfs_attr_init(&card->rpm_attrib.attr);
+		card->rpm_attrib.attr.name = "runtime_pm_timeout";
+		card->rpm_attrib.attr.mode = S_IRUGO | S_IWUSR;
+
+		ret = device_create_file(&card->dev, &card->rpm_attrib);
+		if (ret)
+			pr_err("%s: %s: creating runtime pm sysfs entry: failed: %d\n",
+			       mmc_hostname(card->host), __func__, ret);
+		/* Default timeout is 10 seconds */
+		card->idle_timeout = RUNTIME_SUSPEND_DELAY_MS;
+	}
+
 	mmc_card_set_present(card);
 
 	return 0;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index a3c3967..bea8428 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -409,9 +409,12 @@
 		return;
 	}
 
+	mmc_rpm_hold(card->host, &card->dev);
 	/* In case of delayed bkops we might be in race with suspend. */
-	if (!mmc_try_claim_host(card->host))
+	if (!mmc_try_claim_host(card->host)) {
+		mmc_rpm_release(card->host, &card->dev);
 		return;
+	}
 
 	/*
 	 * Since the cancel_delayed_work can be changed while we are waiting
@@ -486,6 +489,7 @@
 
 out:
 	mmc_release_host(card->host);
+	mmc_rpm_release(card->host, &card->dev);
 }
 EXPORT_SYMBOL(mmc_start_bkops);
 
@@ -515,6 +519,7 @@
 	 * the host from getting into suspend
 	 */
 	do {
+		mmc_rpm_hold(card->host, &card->dev);
 		mmc_claim_host(card->host);
 
 		if (!mmc_card_doing_bkops(card))
@@ -541,6 +546,7 @@
 		}
 
 		mmc_release_host(card->host);
+		mmc_rpm_release(card->host, &card->dev);
 
 		/*
 		 * Sleep before checking the card status again to allow the
@@ -559,6 +565,7 @@
 	return;
 out:
 	mmc_release_host(card->host);
+	mmc_rpm_release(card->host, &card->dev);
 }
 
 /**
@@ -1016,7 +1023,7 @@
 	if (host->areq)
 		mmc_post_req(host, host->areq->mrq, 0);
 
-	/* Cancel a prepared request if it was not started. */
+	 /* Cancel a prepared request if it was not started. */
 	if ((err || start_err) && areq)
 		mmc_post_req(host, areq->mrq, -EINVAL);
 
@@ -2786,8 +2793,9 @@
 	if (!host->card || !host->bus_ops ||
 			!host->bus_ops->change_bus_speed ||
 			!host->clk_scaling.enable || !host->ios.clock)
-		goto out;
+		return;
 
+	mmc_rpm_hold(host, &host->card->dev);
 	if (!mmc_try_claim_host(host)) {
 		/* retry after a timer tick */
 		queue_delayed_work(system_nrt_wq, &host->clk_scaling.work, 1);
@@ -2797,6 +2805,7 @@
 	mmc_clk_scaling(host, true);
 	mmc_release_host(host);
 out:
+	mmc_rpm_release(host, &host->card->dev);
 	return;
 }
 
@@ -3020,16 +3029,8 @@
 	/* Order's important: probe SDIO, then SD, then MMC */
 	if (!mmc_attach_sdio(host))
 		return 0;
-
-	if (!host->ios.vdd)
-		mmc_power_up(host);
-
 	if (!mmc_attach_sd(host))
 		return 0;
-
-	if (!host->ios.vdd)
-		mmc_power_up(host);
-
 	if (!mmc_attach_mmc(host))
 		return 0;
 
@@ -3147,11 +3148,12 @@
 	if (host->ops->get_cd && host->ops->get_cd(host) == 0)
 		goto out;
 
+	mmc_rpm_hold(host, &host->class_dev);
 	mmc_claim_host(host);
 	if (!mmc_rescan_try_freq(host, host->f_min))
 		extend_wakelock = true;
 	mmc_release_host(host);
-
+	mmc_rpm_release(host, &host->class_dev);
  out:
 	if (extend_wakelock)
 		wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
@@ -3374,9 +3376,6 @@
 	if (mmc_bus_needs_resume(host))
 		return 0;
 
-	cancel_delayed_work(&host->detect);
-	mmc_flush_scheduled_work();
-
 	mmc_bus_get(host);
 	if (host->bus_ops && !host->bus_dead) {
 		/*
@@ -3413,7 +3412,6 @@
 				 * It will be redetected on resume.  (Calling
 				 * bus_ops->remove() with a claimed host can
 				 * deadlock.)
-				 * It will be redetected on resume.
 				 */
 				if (host->bus_ops->remove)
 					host->bus_ops->remove(host);
@@ -3588,6 +3586,37 @@
 EXPORT_SYMBOL(mmc_set_embedded_sdio_data);
 #endif
 
+void mmc_rpm_hold(struct mmc_host *host, struct device *dev)
+{
+	int ret = 0;
+
+	if (!mmc_use_core_runtime_pm(host))
+		return;
+
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		pr_err("%s: %s: %s: error resuming device: %d\n",
+		       dev_name(dev), mmc_hostname(host), __func__, ret);
+		if (pm_runtime_suspended(dev))
+			BUG_ON(1);
+	}
+}
+EXPORT_SYMBOL(mmc_rpm_hold);
+
+void mmc_rpm_release(struct mmc_host *host, struct device *dev)
+{
+	int ret = 0;
+
+	if (!mmc_use_core_runtime_pm(host))
+		return;
+
+	ret = pm_runtime_put_sync(dev);
+	if (ret < 0 && ret != -EBUSY)
+		pr_err("%s: %s: %s: put sync ret: %d\n",
+		       dev_name(dev), mmc_hostname(host), __func__, ret);
+}
+EXPORT_SYMBOL(mmc_rpm_release);
+
 /**
  * mmc_init_context_info() - init synchronization context
  * @host: mmc host
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 0cfddc4..c0a4cef 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -4,7 +4,7 @@
  *  Copyright (C) 2003 Russell King, All Rights Reserved.
  *  Copyright (C) 2007-2008 Pierre Ossman
  *  Copyright (C) 2010 Linus Walleij
- *  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 as
@@ -21,6 +21,7 @@
 #include <linux/leds.h>
 #include <linux/slab.h>
 #include <linux/suspend.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -37,9 +38,85 @@
 	kfree(host);
 }
 
+static int mmc_host_runtime_suspend(struct device *dev)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	int ret = 0;
+
+	if (!mmc_use_core_runtime_pm(host))
+		return 0;
+
+	ret = mmc_suspend_host(host);
+	if (ret < 0)
+		pr_err("%s: %s: suspend host failed: %d\n", mmc_hostname(host),
+		       __func__, ret);
+
+	return ret;
+}
+
+static int mmc_host_runtime_resume(struct device *dev)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	int ret = 0;
+
+	if (!mmc_use_core_runtime_pm(host))
+		return 0;
+
+	ret = mmc_resume_host(host);
+	if (ret < 0) {
+		pr_err("%s: %s: resume host: failed: ret: %d\n",
+		       mmc_hostname(host), __func__, ret);
+		if (pm_runtime_suspended(dev))
+			BUG_ON(1);
+	}
+
+	return ret;
+}
+
+static int mmc_host_suspend(struct device *dev)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	int ret = 0;
+
+	if (!mmc_use_core_runtime_pm(host))
+		return 0;
+
+	if (!pm_runtime_suspended(dev)) {
+		ret = mmc_suspend_host(host);
+		if (ret < 0)
+			pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
+			       __func__, ret);
+	}
+	return ret;
+}
+
+static int mmc_host_resume(struct device *dev)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	int ret = 0;
+
+	if (!mmc_use_core_runtime_pm(host))
+		return 0;
+
+	if (!pm_runtime_suspended(dev)) {
+		ret = mmc_resume_host(host);
+		if (ret < 0)
+			pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
+			       __func__, ret);
+	}
+	return ret;
+}
+
+static const struct dev_pm_ops mmc_host_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mmc_host_suspend, mmc_host_resume)
+	SET_RUNTIME_PM_OPS(mmc_host_runtime_suspend, mmc_host_runtime_resume,
+			   pm_generic_runtime_idle)
+};
+
 static struct class mmc_host_class = {
 	.name		= "mmc_host",
 	.dev_release	= mmc_host_classdev_release,
+	.pm		= &mmc_host_pm_ops,
 };
 
 int mmc_register_host_class(void)
@@ -60,8 +137,7 @@
 		struct device_attribute *attr, char *buf)
 {
 	struct mmc_host *host = cls_dev_to_mmc_host(dev);
-	return snprintf(buf, PAGE_SIZE, "%lu\n",
-			host->clkgate_delay);
+	return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
 }
 
 static ssize_t clkgate_delay_store(struct device *dev,
@@ -76,9 +152,6 @@
 	spin_lock_irqsave(&host->clk_lock, flags);
 	host->clkgate_delay = value;
 	spin_unlock_irqrestore(&host->clk_lock, flags);
-
-	pr_info("%s: clock gate delay set to %lu ms\n",
-			mmc_hostname(host), value);
 	return count;
 }
 
@@ -533,7 +606,7 @@
 static ssize_t
 show_perf(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct mmc_host *host = dev_get_drvdata(dev);
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
 	int64_t rtime_drv, wtime_drv;
 	unsigned long rbytes_drv, wbytes_drv;
 
@@ -559,8 +632,8 @@
 set_perf(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
 	int64_t value;
-	struct mmc_host *host = dev_get_drvdata(dev);
 
 	sscanf(buf, "%lld", &value);
 	spin_lock(&host->lock);
@@ -605,6 +678,14 @@
 	WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
 		!host->ops->enable_sdio_irq);
 
+	if (mmc_use_core_runtime_pm(host)) {
+		err = pm_runtime_set_active(&host->class_dev);
+		if (err)
+			pr_err("%s: %s: failed setting runtime active: err: %d\n",
+			       mmc_hostname(host), __func__, err);
+		else
+			pm_runtime_enable(&host->class_dev);
+	}
 	err = device_add(&host->class_dev);
 	if (err)
 		return err;
@@ -625,7 +706,7 @@
 		pr_err("%s: failed to create clk scale sysfs group with err %d\n",
 				__func__, err);
 
-	err = sysfs_create_group(&host->parent->kobj, &dev_attr_grp);
+	err = sysfs_create_group(&host->class_dev.kobj, &dev_attr_grp);
 	if (err)
 		pr_err("%s: failed to create sysfs group with err %d\n",
 							 __func__, err);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0e6956f..8a866cf 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -17,6 +17,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/mmc.h>
+#include <linux/pm_runtime.h>
 
 #include "core.h"
 #include "bus.h"
@@ -293,7 +294,7 @@
 
 	card->ext_csd.rev = ext_csd[EXT_CSD_REV];
 	if (card->ext_csd.rev > 7) {
-		printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
+		pr_err("%s: unrecognised EXT_CSD revision %d\n",
 			mmc_hostname(card->host), card->ext_csd.rev);
 		err = -EINVAL;
 		goto out;
@@ -1495,6 +1496,7 @@
 	BUG_ON(!host);
 	BUG_ON(!host->card);
 
+	mmc_rpm_hold(host, &host->card->dev);
 	mmc_claim_host(host);
 
 	/*
@@ -1504,6 +1506,13 @@
 
 	mmc_release_host(host);
 
+	/*
+	 * if detect fails, the device would be removed anyway;
+	 * the rpm framework would mark the device state suspended.
+	 */
+	if (!err)
+		mmc_rpm_release(host, &host->card->dev);
+
 	if (err) {
 		mmc_remove(host);
 
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 318d590..dc129f7 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -18,6 +18,7 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sd.h>
+#include <linux/pm_runtime.h>
 
 #include "core.h"
 #include "bus.h"
@@ -944,9 +945,9 @@
 		int ro = -1;
 
 		if (host->ops->get_ro) {
-			mmc_host_clk_hold(host);
+			mmc_host_clk_hold(card->host);
 			ro = host->ops->get_ro(host);
-			mmc_host_clk_release(host);
+			mmc_host_clk_release(card->host);
 		}
 
 		if (ro < 0) {
@@ -1067,9 +1068,9 @@
 		 * value registers for UHS-I cards.
 		 */
 		if (host->ops->enable_preset_value) {
-			mmc_host_clk_hold(host);
+			mmc_host_clk_hold(card->host);
 			host->ops->enable_preset_value(host, true);
-			mmc_host_clk_release(host);
+			mmc_host_clk_release(card->host);
 		}
 	} else {
 		/*
@@ -1145,7 +1146,8 @@
 
 	BUG_ON(!host);
 	BUG_ON(!host->card);
-       
+
+	mmc_rpm_hold(host, &host->card->dev);
 	mmc_claim_host(host);
 
 	/*
@@ -1170,6 +1172,13 @@
 #endif
 	mmc_release_host(host);
 
+	/*
+	 * if detect fails, the device would be removed anyway;
+	 * the rpm framework would mark the device state suspended.
+	 */
+	if (!err)
+		mmc_rpm_release(host, &host->card->dev);
+
 	if (err) {
 		mmc_sd_remove(host);
 
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index fca3274..3d8ceb4 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -215,14 +215,14 @@
 
 	card->sdio_single_irq = NULL;
 	if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
-			card->host->sdio_irqs == 1)
+	    card->host->sdio_irqs == 1)
 		for (i = 0; i < card->sdio_funcs; i++) {
-			func = card->sdio_func[i];
-			if (func && func->irq_handler) {
-				card->sdio_single_irq = func;
-				break;
-			}
-		}
+		       func = card->sdio_func[i];
+		       if (func && func->irq_handler) {
+			       card->sdio_single_irq = func;
+			       break;
+		       }
+	       }
 }
 
 /**
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 1c4697d..56d4499 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1389,8 +1389,6 @@
 			dto -= 13;
 		else
 			dto = 0;
-		/* Use the maximum timeout value allowed in the standard of 14
-		   or 0xE */
 		if (dto > 14)
 			dto = 14;
 	}
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 27e6c79..7bae401 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -32,6 +32,9 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/mmc/mmc.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/mmc/cd-gpio.h>
 #include <mach/gpio.h>
 #include <mach/msm_bus.h>
 
@@ -200,6 +203,7 @@
 	bool nonremovable;
 	struct sdhci_msm_pin_data *pin_data;
 	u32 cpu_dma_latency_us;
+	int status_gpio; /* card detection GPIO that is configured as IRQ */
 	struct sdhci_msm_bus_voting_data *voting_data;
 };
 
@@ -216,6 +220,7 @@
 struct sdhci_msm_host {
 	struct platform_device	*pdev;
 	void __iomem *core_mem;    /* MSM SDCC mapped address */
+	int	pwr_irq;	/* power irq */
 	struct clk	 *clk;     /* main SD/MMC bus clock */
 	struct clk	 *pclk;    /* SDHC peripheral bus clock */
 	struct clk	 *bus_clk; /* SDHC bus voter clock */
@@ -1075,6 +1080,8 @@
 		goto out;
 	}
 
+	pdata->status_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, 0);
+
 	of_property_read_u32(np, "qcom,bus-width", &bus_width);
 	if (bus_width == 8)
 		pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
@@ -1864,7 +1871,7 @@
 	struct sdhci_pltfm_host *pltfm_host;
 	struct sdhci_msm_host *msm_host;
 	struct resource *core_memres = NULL;
-	int ret = 0, pwr_irq = 0, dead = 0;
+	int ret = 0, dead = 0;
 	u32 vdd_max_current;
 	u32 host_version;
 
@@ -1987,18 +1994,18 @@
 	}
 
 	/* Setup PWRCTL irq */
-	pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
-	if (pwr_irq < 0) {
+	msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
+	if (msm_host->pwr_irq < 0) {
 		dev_err(&pdev->dev, "Failed to get pwr_irq by name (%d)\n",
-				pwr_irq);
+				msm_host->pwr_irq);
 		goto vreg_deinit;
 	}
-	ret = devm_request_threaded_irq(&pdev->dev, pwr_irq, NULL,
+	ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
 					sdhci_msm_pwr_irq, IRQF_ONESHOT,
 					dev_name(&pdev->dev), host);
 	if (ret) {
 		dev_err(&pdev->dev, "Request threaded irq(%d) failed (%d)\n",
-				pwr_irq, ret);
+				msm_host->pwr_irq, ret);
 		goto vreg_deinit;
 	}
 
@@ -2029,6 +2036,7 @@
 
 	msm_host->mmc->caps |= MMC_CAP_HW_RESET;
 	msm_host->mmc->caps2 |= msm_host->pdata->caps2;
+	msm_host->mmc->caps2 |= MMC_CAP2_CORE_RUNTIME_PM;
 	msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR;
 	msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
 	msm_host->mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC |
@@ -2051,10 +2059,20 @@
 		INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
 				  sdhci_msm_bus_work);
 
+	if (gpio_is_valid(msm_host->pdata->status_gpio)) {
+		ret = mmc_cd_gpio_request(msm_host->mmc,
+				msm_host->pdata->status_gpio);
+		if (ret) {
+			dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n",
+					__func__, ret);
+			goto bus_unregister;
+		}
+	}
+
 	ret = sdhci_add_host(host);
 	if (ret) {
 		dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
-		goto bus_unregister;
+		goto free_cd_gpio;
 	}
 
 	 /* Set core clk rate, optionally override from dts */
@@ -2076,12 +2094,22 @@
 	if (ret)
 		goto remove_host;
 
+	ret = pm_runtime_set_active(&pdev->dev);
+	if (ret)
+		pr_err("%s: %s: pm_runtime_set_active failed: err: %d\n",
+		       mmc_hostname(host->mmc), __func__, ret);
+	else
+		pm_runtime_enable(&pdev->dev);
+
 	/* Successful initialization */
 	goto out;
 
 remove_host:
 	dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
 	sdhci_remove_host(host, dead);
+free_cd_gpio:
+	if (gpio_is_valid(msm_host->pdata->status_gpio))
+		mmc_cd_gpio_free(msm_host->mmc);
 bus_unregister:
 	sdhci_msm_bus_unregister(msm_host);
 vreg_deinit:
@@ -2114,7 +2142,12 @@
 	pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__);
 	device_remove_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw);
 	sdhci_remove_host(host, dead);
+	pm_runtime_disable(&pdev->dev);
 	sdhci_pltfm_free(pdev);
+
+	if (gpio_is_valid(msm_host->pdata->status_gpio))
+		mmc_cd_gpio_free(msm_host->mmc);
+
 	sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
 
 	if (pdata->pin_data)
@@ -2127,6 +2160,92 @@
 	return 0;
 }
 
+static int sdhci_msm_runtime_suspend(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+	disable_irq(host->irq);
+	disable_irq(msm_host->pwr_irq);
+
+	return 0;
+}
+
+static int sdhci_msm_runtime_resume(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+	enable_irq(msm_host->pwr_irq);
+	enable_irq(host->irq);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int sdhci_msm_suspend(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	int ret = 0;
+
+	if (gpio_is_valid(msm_host->pdata->status_gpio))
+		mmc_cd_gpio_free(msm_host->mmc);
+
+	if (pm_runtime_suspended(dev)) {
+		pr_debug("%s: %s: already runtime suspended\n",
+		mmc_hostname(host->mmc), __func__);
+		goto out;
+	}
+
+	return sdhci_msm_runtime_suspend(dev);
+out:
+	return ret;
+}
+
+static int sdhci_msm_resume(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	int ret = 0;
+
+	if (gpio_is_valid(msm_host->pdata->status_gpio)) {
+		ret = mmc_cd_gpio_request(msm_host->mmc,
+				msm_host->pdata->status_gpio);
+		if (ret)
+			pr_err("%s: %s: Failed to request card detection IRQ %d\n",
+					mmc_hostname(host->mmc), __func__, ret);
+	}
+
+	if (pm_runtime_suspended(dev)) {
+		pr_debug("%s: %s: runtime suspended, defer system resume\n",
+		mmc_hostname(host->mmc), __func__);
+		goto out;
+	}
+
+	return sdhci_msm_runtime_resume(dev);
+out:
+	return ret;
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops sdhci_msm_pmops = {
+	SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
+	SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume,
+			   NULL)
+};
+
+#define SDHCI_MSM_PMOPS (&sdhci_msm_pmops)
+
+#else
+#define SDHCI_PM_OPS NULL
+#endif
 static const struct of_device_id sdhci_msm_dt_match[] = {
 	{.compatible = "qcom,sdhci-msm"},
 };
@@ -2139,6 +2258,7 @@
 		.name	= "sdhci_msm",
 		.owner	= THIS_MODULE,
 		.of_match_table = sdhci_msm_dt_match,
+		.pm = SDHCI_MSM_PMOPS,
 	},
 };
 
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index e7a3741..69ef0be 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -23,9 +23,8 @@
 #include <linux/scatterlist.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
-#include <linux/mmc/sdhci-pci-data.h>
-#include <linux/sfi.h>
 #include <linux/pm_runtime.h>
+#include <linux/mmc/sdhci-pci-data.h>
 
 #include "sdhci.h"
 
@@ -368,8 +367,6 @@
 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
 	}
 
-	slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC;
-
 	return 0;
 }
 
@@ -1452,8 +1449,6 @@
 	int i;
 	struct sdhci_pci_chip *chip;
 
-	sdhci_pci_runtime_pm_forbid(&pdev->dev);
-
 	chip = pci_get_drvdata(pdev);
 
 	if (chip) {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 97c1013..0a89ea2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -453,6 +453,44 @@
 	dataddr[0] = cpu_to_le32(addr);
 }
 
+static int sdhci_pre_dma_transfer(struct sdhci_host *host,
+				  struct mmc_data *data,
+				  struct sdhci_next *next)
+{
+	int sg_count;
+
+	if (!next && data->host_cookie &&
+	    data->host_cookie != host->next_data.cookie) {
+		printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d"
+		       " host->next_data.cookie %d\n",
+		       __func__, data->host_cookie, host->next_data.cookie);
+		data->host_cookie = 0;
+	}
+
+	/* Check if next job is already prepared */
+	if (next ||
+	    (!next && data->host_cookie != host->next_data.cookie)) {
+		sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg,
+				      data->sg_len,
+				      (data->flags & MMC_DATA_WRITE) ?
+				      DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	} else {
+		sg_count = host->next_data.sg_count;
+		host->next_data.sg_count = 0;
+	}
+
+	if (sg_count == 0)
+		return -EINVAL;
+
+	if (next) {
+		next->sg_count = sg_count;
+		data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
+	} else
+		host->sg_count = sg_count;
+
+	return sg_count;
+}
+
 static int sdhci_adma_table_pre(struct sdhci_host *host,
 	struct mmc_data *data)
 {
@@ -491,9 +529,8 @@
 		goto fail;
 	BUG_ON(host->align_addr & 0x3);
 
-	host->sg_count = dma_map_sg(mmc_dev(host->mmc),
-		data->sg, data->sg_len, direction);
-	if (host->sg_count == 0)
+	host->sg_count = sdhci_pre_dma_transfer(host, data, NULL);
+	if (host->sg_count < 0)
 		goto unmap_align;
 
 	desc = host->adma_desc;
@@ -638,8 +675,9 @@
 		}
 	}
 
-	dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-		data->sg_len, direction);
+	if (!data->host_cookie)
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+			     direction);
 }
 
 static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
@@ -819,11 +857,7 @@
 		} else {
 			int sg_cnt;
 
-			sg_cnt = dma_map_sg(mmc_dev(host->mmc),
-					data->sg, data->sg_len,
-					(data->flags & MMC_DATA_READ) ?
-						DMA_FROM_DEVICE :
-						DMA_TO_DEVICE);
+			sg_cnt = sdhci_pre_dma_transfer(host, data, NULL);
 			if (sg_cnt == 0) {
 				/*
 				 * This only happens when someone fed
@@ -927,9 +961,11 @@
 		if (host->flags & SDHCI_USE_ADMA)
 			sdhci_adma_table_post(host, data);
 		else {
-			dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-				data->sg_len, (data->flags & MMC_DATA_READ) ?
-					DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			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);
 		}
 	}
 
@@ -1304,6 +1340,35 @@
 	return 0;
 }
 
+static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+			  bool is_first_req)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+
+	if (mrq->data->host_cookie) {
+		mrq->data->host_cookie = 0;
+		return;
+	}
+
+	if (host->flags & SDHCI_REQ_USE_DMA)
+		if (sdhci_pre_dma_transfer(host, mrq->data, &host->next_data) < 0)
+			mrq->data->host_cookie = 0;
+}
+
+static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+			   int err)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct mmc_data *data = mrq->data;
+
+	if (host->flags & SDHCI_REQ_USE_DMA) {
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+			     (data->flags & MMC_DATA_WRITE) ?
+			     DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		data->host_cookie = 0;
+	}
+}
+
 static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 	struct sdhci_host *host;
@@ -2016,6 +2081,8 @@
 }
 
 static const struct mmc_host_ops sdhci_ops = {
+	.pre_req	= sdhci_pre_req,
+	.post_req	= sdhci_post_req,
 	.request	= sdhci_request,
 	.set_ios	= sdhci_set_ios,
 	.get_ro		= sdhci_get_ro,
@@ -2598,13 +2665,20 @@
 
 static int sdhci_runtime_pm_get(struct sdhci_host *host)
 {
-	return pm_runtime_get_sync(host->mmc->parent);
+	if (!mmc_use_core_runtime_pm(host->mmc))
+		return pm_runtime_get_sync(host->mmc->parent);
+	else
+		return 0;
 }
 
 static int sdhci_runtime_pm_put(struct sdhci_host *host)
 {
-	pm_runtime_mark_last_busy(host->mmc->parent);
-	return pm_runtime_put_autosuspend(host->mmc->parent);
+	if (!mmc_use_core_runtime_pm(host->mmc)) {
+		pm_runtime_mark_last_busy(host->mmc->parent);
+		return pm_runtime_put_autosuspend(host->mmc->parent);
+	} else {
+		return 0;
+	}
 }
 
 int sdhci_runtime_suspend_host(struct sdhci_host *host)
@@ -2805,6 +2879,8 @@
 		}
 	}
 
+	host->next_data.cookie = 1;
+
 	/*
 	 * If we use DMA, then it's up to the caller to set the DMA
 	 * mask, but PIO does not need the hw shim so we set a new
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 315efbb..47b19c0 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3219,44 +3219,6 @@
 }
 EXPORT_SYMBOL(nand_scan_ident);
 
-static void nand_panic_wait(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = mtd->priv;
-	int i;
-
-	if (chip->state != FL_READY)
-		for (i = 0; i < 40; i++) {
-			if (chip->dev_ready(mtd))
-				break;
-			mdelay(10);
-		}
-	chip->state = FL_READY;
-}
-
-static int nand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
-			    size_t *retlen, const u_char *buf)
-{
-	struct nand_chip *chip = mtd->priv;
-	int ret;
-
-	/* Do not allow reads past end of device */
-	if ((to + len) > mtd->size)
-		return -EINVAL;
-	if (!len)
-		return 0;
-
-	nand_panic_wait(mtd);
-
-	chip->ops.len = len;
-	chip->ops.datbuf = (uint8_t *)buf;
-	chip->ops.oobbuf = NULL;
-
-	ret = nand_do_write_ops(mtd, to, &chip->ops);
-
-	*retlen = chip->ops.retlen;
-	return ret;
-}
-
 
 /**
  * nand_scan_tail - [NAND Interface] Scan for the NAND device
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 28ba41a..41dd6e7 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -118,8 +118,8 @@
 
 static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
 		const void *dst_mac, const void *src_mac);
-static int ecm_ipa_register_tx(struct ecm_ipa_dev *dev);
-static void ecm_ipa_deregister_tx(struct ecm_ipa_dev *dev);
+static int ecm_ipa_register_properties(void);
+static void ecm_ipa_deregister_properties(void);
 static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
 static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
 static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file);
@@ -262,13 +262,13 @@
 	strlcpy(ipv4_hdr->name, ECM_IPA_IPV4_HDR_NAME, IPA_RESOURCE_NAME_MAX);
 	memcpy(eth_ipv4->h_dest, dst_mac, ETH_ALEN);
 	memcpy(eth_ipv4->h_source, src_mac, ETH_ALEN);
-	eth_ipv4->h_proto = ETH_P_IP;
+	eth_ipv4->h_proto = htons(ETH_P_IP);
 	ipv4_hdr->hdr_len = ETH_HLEN;
 	ipv4_hdr->is_partial = 0;
 	strlcpy(ipv6_hdr->name, ECM_IPA_IPV6_HDR_NAME, IPA_RESOURCE_NAME_MAX);
 	memcpy(eth_ipv6->h_dest, dst_mac, ETH_ALEN);
 	memcpy(eth_ipv6->h_source, src_mac, ETH_ALEN);
-	eth_ipv6->h_proto = ETH_P_IPV6;
+	eth_ipv6->h_proto = htons(ETH_P_IPV6);
 	ipv6_hdr->hdr_len = ETH_HLEN;
 	ipv6_hdr->is_partial = 0;
 	hdrs->commit = 1;
@@ -320,14 +320,29 @@
 		ECM_IPA_ERROR("ipa_del_hdr failed");
 }
 
-static int ecm_ipa_register_tx(struct ecm_ipa_dev *dev)
+/* ecm_ipa_register_properties() - set Tx/Rx properties for ipacm
+ *
+ * Register ecm0 interface with 2 Tx properties and 2 Rx properties:
+ * The 2 Tx properties are for data flowing from IPA to USB, they
+ * have Header-Insertion properties both for Ipv4 and Ipv6 Ethernet framing.
+ * The 2 Rx properties are for data flowing from USB to IPA, they have
+ * simple rule which always "hit".
+ *
+ */
+static int ecm_ipa_register_properties(void)
 {
 	struct ipa_tx_intf tx_properties = {0};
 	struct ipa_ioc_tx_intf_prop properties[2] = { {0}, {0} };
 	struct ipa_ioc_tx_intf_prop *ipv4_property;
 	struct ipa_ioc_tx_intf_prop *ipv6_property;
+	struct ipa_ioc_rx_intf_prop rx_ioc_properties[2] = { {0}, {0} };
+	struct ipa_rx_intf rx_properties = {0};
+	struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
+	struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
 	int result = 0;
+
 	ECM_IPA_LOG_ENTRY();
+
 	tx_properties.prop = properties;
 	ipv4_property = &tx_properties.prop[0];
 	ipv4_property->ip = IPA_IP_v4;
@@ -340,18 +355,32 @@
 	strlcpy(ipv6_property->hdr_name, ECM_IPA_IPV6_HDR_NAME,
 			IPA_RESOURCE_NAME_MAX);
 	tx_properties.num_props = 2;
-	result = ipa_register_intf("ecm0", &tx_properties, NULL);
+
+	rx_properties.prop = rx_ioc_properties;
+	rx_ipv4_property = &rx_properties.prop[0];
+	rx_ipv4_property->ip = IPA_IP_v4;
+	rx_ipv4_property->attrib.attrib_mask = 0;
+	rx_ipv4_property->src_pipe = IPA_CLIENT_USB_PROD;
+	rx_ipv6_property = &rx_properties.prop[1];
+	rx_ipv6_property->ip = IPA_IP_v6;
+	rx_ipv6_property->attrib.attrib_mask = 0;
+	rx_ipv6_property->src_pipe = IPA_CLIENT_USB_PROD;
+	rx_properties.num_props = 2;
+
+	result = ipa_register_intf("ecm0", &tx_properties, &rx_properties);
 	if (result)
-		ECM_IPA_ERROR("fail on Tx_prop registration\n");
+		ECM_IPA_ERROR("fail on Tx/Rx properties registration\n");
+
 	ECM_IPA_LOG_EXIT();
+
 	return result;
 }
 
-static void ecm_ipa_deregister_tx(struct ecm_ipa_dev *dev)
+static void ecm_ipa_deregister_properties(void)
 {
 	int result;
 	ECM_IPA_LOG_ENTRY();
-	result = ipa_deregister_intf(dev->net->name);
+	result = ipa_deregister_intf("ecm0");
 	if (result)
 		ECM_IPA_DEBUG("Fail on Tx prop deregister\n");
 	ECM_IPA_LOG_EXIT();
@@ -407,12 +436,12 @@
 		goto fail_set_device_ethernet;
 	}
 	ECM_IPA_DEBUG("Ethernet header insertion was set\n");
-	result = ecm_ipa_register_tx(dev);
+	result = ecm_ipa_register_properties();
 	if (result) {
 		ECM_IPA_ERROR("fail on properties set\n");
 		goto fail_register_tx;
 	}
-	ECM_IPA_DEBUG("ECM Tx properties were registered\n");
+	ECM_IPA_DEBUG("ECM 2 Tx and 2 Rx properties were registered\n");
 	result = register_netdev(net);
 	if (result) {
 		ECM_IPA_ERROR("register_netdev failed: %d\n", result);
@@ -422,7 +451,7 @@
 	ECM_IPA_LOG_EXIT();
 	return 0;
 fail_register_netdev:
-	ecm_ipa_deregister_tx(dev);
+	ecm_ipa_deregister_properties();
 fail_register_tx:
 fail_set_device_ethernet:
 	ecm_ipa_rules_destroy(dev);
diff --git a/drivers/net/pppolac.c b/drivers/net/pppolac.c
deleted file mode 100644
index a5d3d63..0000000
--- a/drivers/net/pppolac.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/* drivers/net/pppolac.c
- *
- * Driver for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661)
- *
- * Copyright (C) 2009 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/* This driver handles L2TP data packets between a UDP socket and a PPP channel.
- * The socket must keep connected, and only one session per socket is permitted.
- * Sequencing of outgoing packets is controlled by LNS. Incoming packets with
- * sequences are reordered within a sliding window of one second. Currently
- * reordering only happens when a packet is received. It is done for simplicity
- * since no additional locks or threads are required. This driver only works on
- * IPv4 due to the lack of UDP encapsulation support in IPv6. */
-
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-#include <linux/skbuff.h>
-#include <linux/file.h>
-#include <linux/netdevice.h>
-#include <linux/net.h>
-#include <linux/udp.h>
-#include <linux/ppp_defs.h>
-#include <linux/if_ppp.h>
-#include <linux/if_pppox.h>
-#include <linux/ppp_channel.h>
-#include <net/tcp_states.h>
-#include <asm/uaccess.h>
-
-#define L2TP_CONTROL_BIT	0x80
-#define L2TP_LENGTH_BIT		0x40
-#define L2TP_SEQUENCE_BIT	0x08
-#define L2TP_OFFSET_BIT		0x02
-#define L2TP_VERSION		0x02
-#define L2TP_VERSION_MASK	0x0F
-
-#define PPP_ADDR	0xFF
-#define PPP_CTRL	0x03
-
-union unaligned {
-	__u32 u32;
-} __attribute__((packed));
-
-static inline union unaligned *unaligned(void *ptr)
-{
-	return (union unaligned *)ptr;
-}
-
-struct meta {
-	__u32 sequence;
-	__u32 timestamp;
-};
-
-static inline struct meta *skb_meta(struct sk_buff *skb)
-{
-	return (struct meta *)skb->cb;
-}
-
-/******************************************************************************/
-
-static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb)
-{
-	struct sock *sk = (struct sock *)sk_udp->sk_user_data;
-	struct pppolac_opt *opt = &pppox_sk(sk)->proto.lac;
-	struct meta *meta = skb_meta(skb);
-	__u32 now = jiffies;
-	__u8 bits;
-	__u8 *ptr;
-
-	/* Drop the packet if L2TP header is missing. */
-	if (skb->len < sizeof(struct udphdr) + 6)
-		goto drop;
-
-	/* Put it back if it is a control packet. */
-	if (skb->data[sizeof(struct udphdr)] & L2TP_CONTROL_BIT)
-		return opt->backlog_rcv(sk_udp, skb);
-
-	/* Skip UDP header. */
-	skb_pull(skb, sizeof(struct udphdr));
-
-	/* Check the version. */
-	if ((skb->data[1] & L2TP_VERSION_MASK) != L2TP_VERSION)
-		goto drop;
-	bits = skb->data[0];
-	ptr = &skb->data[2];
-
-	/* Check the length if it is present. */
-	if (bits & L2TP_LENGTH_BIT) {
-		if ((ptr[0] << 8 | ptr[1]) != skb->len)
-			goto drop;
-		ptr += 2;
-	}
-
-	/* Skip all fields including optional ones. */
-	if (!skb_pull(skb, 6 + (bits & L2TP_SEQUENCE_BIT ? 4 : 0) +
-			(bits & L2TP_LENGTH_BIT ? 2 : 0) +
-			(bits & L2TP_OFFSET_BIT ? 2 : 0)))
-		goto drop;
-
-	/* Skip the offset padding if it is present. */
-	if (bits & L2TP_OFFSET_BIT &&
-			!skb_pull(skb, skb->data[-2] << 8 | skb->data[-1]))
-		goto drop;
-
-	/* Check the tunnel and the session. */
-	if (unaligned(ptr)->u32 != opt->local)
-		goto drop;
-
-	/* Check the sequence if it is present. */
-	if (bits & L2TP_SEQUENCE_BIT) {
-		meta->sequence = ptr[4] << 8 | ptr[5];
-		if ((__s16)(meta->sequence - opt->recv_sequence) < 0)
-			goto drop;
-	}
-
-	/* Skip PPP address and control if they are present. */
-	if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
-			skb->data[1] == PPP_CTRL)
-		skb_pull(skb, 2);
-
-	/* Fix PPP protocol if it is compressed. */
-	if (skb->len >= 1 && skb->data[0] & 1)
-		skb_push(skb, 1)[0] = 0;
-
-	/* Drop the packet if PPP protocol is missing. */
-	if (skb->len < 2)
-		goto drop;
-
-	/* Perform reordering if sequencing is enabled. */
-	atomic_set(&opt->sequencing, bits & L2TP_SEQUENCE_BIT);
-	if (bits & L2TP_SEQUENCE_BIT) {
-		struct sk_buff *skb1;
-
-		/* Insert the packet into receive queue in order. */
-		skb_set_owner_r(skb, sk);
-		skb_queue_walk(&sk->sk_receive_queue, skb1) {
-			struct meta *meta1 = skb_meta(skb1);
-			__s16 order = meta->sequence - meta1->sequence;
-			if (order == 0)
-				goto drop;
-			if (order < 0) {
-				meta->timestamp = meta1->timestamp;
-				skb_insert(skb1, skb, &sk->sk_receive_queue);
-				skb = NULL;
-				break;
-			}
-		}
-		if (skb) {
-			meta->timestamp = now;
-			skb_queue_tail(&sk->sk_receive_queue, skb);
-		}
-
-		/* Remove packets from receive queue as long as
-		 * 1. the receive buffer is full,
-		 * 2. they are queued longer than one second, or
-		 * 3. there are no missing packets before them. */
-		skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) {
-			meta = skb_meta(skb);
-			if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
-					now - meta->timestamp < HZ &&
-					meta->sequence != opt->recv_sequence)
-				break;
-			skb_unlink(skb, &sk->sk_receive_queue);
-			opt->recv_sequence = (__u16)(meta->sequence + 1);
-			skb_orphan(skb);
-			ppp_input(&pppox_sk(sk)->chan, skb);
-		}
-		return NET_RX_SUCCESS;
-	}
-
-	/* Flush receive queue if sequencing is disabled. */
-	skb_queue_purge(&sk->sk_receive_queue);
-	skb_orphan(skb);
-	ppp_input(&pppox_sk(sk)->chan, skb);
-	return NET_RX_SUCCESS;
-drop:
-	kfree_skb(skb);
-	return NET_RX_DROP;
-}
-
-static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb)
-{
-	sock_hold(sk_udp);
-	sk_receive_skb(sk_udp, skb, 0);
-	return 0;
-}
-
-static struct sk_buff_head delivery_queue;
-
-static void pppolac_xmit_core(struct work_struct *delivery_work)
-{
-	mm_segment_t old_fs = get_fs();
-	struct sk_buff *skb;
-
-	set_fs(KERNEL_DS);
-	while ((skb = skb_dequeue(&delivery_queue))) {
-		struct sock *sk_udp = skb->sk;
-		struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
-		struct msghdr msg = {
-			.msg_iov = (struct iovec *)&iov,
-			.msg_iovlen = 1,
-			.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
-		};
-		sk_udp->sk_prot->sendmsg(NULL, sk_udp, &msg, skb->len);
-		kfree_skb(skb);
-	}
-	set_fs(old_fs);
-}
-
-static DECLARE_WORK(delivery_work, pppolac_xmit_core);
-
-static int pppolac_xmit(struct ppp_channel *chan, struct sk_buff *skb)
-{
-	struct sock *sk_udp = (struct sock *)chan->private;
-	struct pppolac_opt *opt = &pppox_sk(sk_udp->sk_user_data)->proto.lac;
-
-	/* Install PPP address and control. */
-	skb_push(skb, 2);
-	skb->data[0] = PPP_ADDR;
-	skb->data[1] = PPP_CTRL;
-
-	/* Install L2TP header. */
-	if (atomic_read(&opt->sequencing)) {
-		skb_push(skb, 10);
-		skb->data[0] = L2TP_SEQUENCE_BIT;
-		skb->data[6] = opt->xmit_sequence >> 8;
-		skb->data[7] = opt->xmit_sequence;
-		skb->data[8] = 0;
-		skb->data[9] = 0;
-		opt->xmit_sequence++;
-	} else {
-		skb_push(skb, 6);
-		skb->data[0] = 0;
-	}
-	skb->data[1] = L2TP_VERSION;
-	unaligned(&skb->data[2])->u32 = opt->remote;
-
-	/* Now send the packet via the delivery queue. */
-	skb_set_owner_w(skb, sk_udp);
-	skb_queue_tail(&delivery_queue, skb);
-	schedule_work(&delivery_work);
-	return 1;
-}
-
-/******************************************************************************/
-
-static struct ppp_channel_ops pppolac_channel_ops = {
-	.start_xmit = pppolac_xmit,
-};
-
-static int pppolac_connect(struct socket *sock, struct sockaddr *useraddr,
-	int addrlen, int flags)
-{
-	struct sock *sk = sock->sk;
-	struct pppox_sock *po = pppox_sk(sk);
-	struct sockaddr_pppolac *addr = (struct sockaddr_pppolac *)useraddr;
-	struct socket *sock_udp = NULL;
-	struct sock *sk_udp;
-	int error;
-
-	if (addrlen != sizeof(struct sockaddr_pppolac) ||
-			!addr->local.tunnel || !addr->local.session ||
-			!addr->remote.tunnel || !addr->remote.session) {
-		return -EINVAL;
-	}
-
-	lock_sock(sk);
-	error = -EALREADY;
-	if (sk->sk_state != PPPOX_NONE)
-		goto out;
-
-	sock_udp = sockfd_lookup(addr->udp_socket, &error);
-	if (!sock_udp)
-		goto out;
-	sk_udp = sock_udp->sk;
-	lock_sock(sk_udp);
-
-	/* Remove this check when IPv6 supports UDP encapsulation. */
-	error = -EAFNOSUPPORT;
-	if (sk_udp->sk_family != AF_INET)
-		goto out;
-	error = -EPROTONOSUPPORT;
-	if (sk_udp->sk_protocol != IPPROTO_UDP)
-		goto out;
-	error = -EDESTADDRREQ;
-	if (sk_udp->sk_state != TCP_ESTABLISHED)
-		goto out;
-	error = -EBUSY;
-	if (udp_sk(sk_udp)->encap_type || sk_udp->sk_user_data)
-		goto out;
-	if (!sk_udp->sk_bound_dev_if) {
-		struct dst_entry *dst = sk_dst_get(sk_udp);
-		error = -ENODEV;
-		if (!dst)
-			goto out;
-		sk_udp->sk_bound_dev_if = dst->dev->ifindex;
-		dst_release(dst);
-	}
-
-	po->chan.hdrlen = 12;
-	po->chan.private = sk_udp;
-	po->chan.ops = &pppolac_channel_ops;
-	po->chan.mtu = PPP_MRU - 80;
-	po->proto.lac.local = unaligned(&addr->local)->u32;
-	po->proto.lac.remote = unaligned(&addr->remote)->u32;
-	atomic_set(&po->proto.lac.sequencing, 1);
-	po->proto.lac.backlog_rcv = sk_udp->sk_backlog_rcv;
-
-	error = ppp_register_channel(&po->chan);
-	if (error)
-		goto out;
-
-	sk->sk_state = PPPOX_CONNECTED;
-	udp_sk(sk_udp)->encap_type = UDP_ENCAP_L2TPINUDP;
-	udp_sk(sk_udp)->encap_rcv = pppolac_recv;
-	sk_udp->sk_backlog_rcv = pppolac_recv_core;
-	sk_udp->sk_user_data = sk;
-out:
-	if (sock_udp) {
-		release_sock(sk_udp);
-		if (error)
-			sockfd_put(sock_udp);
-	}
-	release_sock(sk);
-	return error;
-}
-
-static int pppolac_release(struct socket *sock)
-{
-	struct sock *sk = sock->sk;
-
-	if (!sk)
-		return 0;
-
-	lock_sock(sk);
-	if (sock_flag(sk, SOCK_DEAD)) {
-		release_sock(sk);
-		return -EBADF;
-	}
-
-	if (sk->sk_state != PPPOX_NONE) {
-		struct sock *sk_udp = (struct sock *)pppox_sk(sk)->chan.private;
-		lock_sock(sk_udp);
-		skb_queue_purge(&sk->sk_receive_queue);
-		pppox_unbind_sock(sk);
-		udp_sk(sk_udp)->encap_type = 0;
-		udp_sk(sk_udp)->encap_rcv = NULL;
-		sk_udp->sk_backlog_rcv = pppox_sk(sk)->proto.lac.backlog_rcv;
-		sk_udp->sk_user_data = NULL;
-		release_sock(sk_udp);
-		sockfd_put(sk_udp->sk_socket);
-	}
-
-	sock_orphan(sk);
-	sock->sk = NULL;
-	release_sock(sk);
-	sock_put(sk);
-	return 0;
-}
-
-/******************************************************************************/
-
-static struct proto pppolac_proto = {
-	.name = "PPPOLAC",
-	.owner = THIS_MODULE,
-	.obj_size = sizeof(struct pppox_sock),
-};
-
-static struct proto_ops pppolac_proto_ops = {
-	.family = PF_PPPOX,
-	.owner = THIS_MODULE,
-	.release = pppolac_release,
-	.bind = sock_no_bind,
-	.connect = pppolac_connect,
-	.socketpair = sock_no_socketpair,
-	.accept = sock_no_accept,
-	.getname = sock_no_getname,
-	.poll = sock_no_poll,
-	.ioctl = pppox_ioctl,
-	.listen = sock_no_listen,
-	.shutdown = sock_no_shutdown,
-	.setsockopt = sock_no_setsockopt,
-	.getsockopt = sock_no_getsockopt,
-	.sendmsg = sock_no_sendmsg,
-	.recvmsg = sock_no_recvmsg,
-	.mmap = sock_no_mmap,
-};
-
-static int pppolac_create(struct net *net, struct socket *sock)
-{
-	struct sock *sk;
-
-	sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppolac_proto);
-	if (!sk)
-		return -ENOMEM;
-
-	sock_init_data(sock, sk);
-	sock->state = SS_UNCONNECTED;
-	sock->ops = &pppolac_proto_ops;
-	sk->sk_protocol = PX_PROTO_OLAC;
-	sk->sk_state = PPPOX_NONE;
-	return 0;
-}
-
-/******************************************************************************/
-
-static struct pppox_proto pppolac_pppox_proto = {
-	.create = pppolac_create,
-	.owner = THIS_MODULE,
-};
-
-static int __init pppolac_init(void)
-{
-	int error;
-
-	error = proto_register(&pppolac_proto, 0);
-	if (error)
-		return error;
-
-	error = register_pppox_proto(PX_PROTO_OLAC, &pppolac_pppox_proto);
-	if (error)
-		proto_unregister(&pppolac_proto);
-	else
-		skb_queue_head_init(&delivery_queue);
-	return error;
-}
-
-static void __exit pppolac_exit(void)
-{
-	unregister_pppox_proto(PX_PROTO_OLAC);
-	proto_unregister(&pppolac_proto);
-}
-
-module_init(pppolac_init);
-module_exit(pppolac_exit);
-
-MODULE_DESCRIPTION("PPP on L2TP Access Concentrator (PPPoLAC)");
-MODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/pppopns.c b/drivers/net/pppopns.c
deleted file mode 100644
index 6016d29..0000000
--- a/drivers/net/pppopns.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/* drivers/net/pppopns.c
- *
- * Driver for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637)
- *
- * Copyright (C) 2009 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/* This driver handles PPTP data packets between a RAW socket and a PPP channel.
- * The socket is created in the kernel space and connected to the same address
- * of the control socket. Outgoing packets are always sent with sequences but
- * without acknowledgements. Incoming packets with sequences are reordered
- * within a sliding window of one second. Currently reordering only happens when
- * a packet is received. It is done for simplicity since no additional locks or
- * threads are required. This driver should work on both IPv4 and IPv6. */
-
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-#include <linux/skbuff.h>
-#include <linux/file.h>
-#include <linux/netdevice.h>
-#include <linux/net.h>
-#include <linux/ppp_defs.h>
-#include <linux/if.h>
-#include <linux/if_ppp.h>
-#include <linux/if_pppox.h>
-#include <linux/ppp_channel.h>
-#include <asm/uaccess.h>
-
-#define GRE_HEADER_SIZE		8
-
-#define PPTP_GRE_BITS		htons(0x2001)
-#define PPTP_GRE_BITS_MASK	htons(0xEF7F)
-#define PPTP_GRE_SEQ_BIT	htons(0x1000)
-#define PPTP_GRE_ACK_BIT	htons(0x0080)
-#define PPTP_GRE_TYPE		htons(0x880B)
-
-#define PPP_ADDR	0xFF
-#define PPP_CTRL	0x03
-
-struct header {
-	__u16	bits;
-	__u16	type;
-	__u16	length;
-	__u16	call;
-	__u32	sequence;
-} __attribute__((packed));
-
-struct meta {
-	__u32 sequence;
-	__u32 timestamp;
-};
-
-static inline struct meta *skb_meta(struct sk_buff *skb)
-{
-	return (struct meta *)skb->cb;
-}
-
-/******************************************************************************/
-
-static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb)
-{
-	struct sock *sk = (struct sock *)sk_raw->sk_user_data;
-	struct pppopns_opt *opt = &pppox_sk(sk)->proto.pns;
-	struct meta *meta = skb_meta(skb);
-	__u32 now = jiffies;
-	struct header *hdr;
-
-	/* Skip transport header */
-	skb_pull(skb, skb_transport_header(skb) - skb->data);
-
-	/* Drop the packet if GRE header is missing. */
-	if (skb->len < GRE_HEADER_SIZE)
-		goto drop;
-	hdr = (struct header *)skb->data;
-
-	/* Check the header. */
-	if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local ||
-			(hdr->bits & PPTP_GRE_BITS_MASK) != PPTP_GRE_BITS)
-		goto drop;
-
-	/* Skip all fields including optional ones. */
-	if (!skb_pull(skb, GRE_HEADER_SIZE +
-			(hdr->bits & PPTP_GRE_SEQ_BIT ? 4 : 0) +
-			(hdr->bits & PPTP_GRE_ACK_BIT ? 4 : 0)))
-		goto drop;
-
-	/* Check the length. */
-	if (skb->len != ntohs(hdr->length))
-		goto drop;
-
-	/* Check the sequence if it is present. */
-	if (hdr->bits & PPTP_GRE_SEQ_BIT) {
-		meta->sequence = ntohl(hdr->sequence);
-		if ((__s32)(meta->sequence - opt->recv_sequence) < 0)
-			goto drop;
-	}
-
-	/* Skip PPP address and control if they are present. */
-	if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
-			skb->data[1] == PPP_CTRL)
-		skb_pull(skb, 2);
-
-	/* Fix PPP protocol if it is compressed. */
-	if (skb->len >= 1 && skb->data[0] & 1)
-		skb_push(skb, 1)[0] = 0;
-
-	/* Drop the packet if PPP protocol is missing. */
-	if (skb->len < 2)
-		goto drop;
-
-	/* Perform reordering if sequencing is enabled. */
-	if (hdr->bits & PPTP_GRE_SEQ_BIT) {
-		struct sk_buff *skb1;
-
-		/* Insert the packet into receive queue in order. */
-		skb_set_owner_r(skb, sk);
-		skb_queue_walk(&sk->sk_receive_queue, skb1) {
-			struct meta *meta1 = skb_meta(skb1);
-			__s32 order = meta->sequence - meta1->sequence;
-			if (order == 0)
-				goto drop;
-			if (order < 0) {
-				meta->timestamp = meta1->timestamp;
-				skb_insert(skb1, skb, &sk->sk_receive_queue);
-				skb = NULL;
-				break;
-			}
-		}
-		if (skb) {
-			meta->timestamp = now;
-			skb_queue_tail(&sk->sk_receive_queue, skb);
-		}
-
-		/* Remove packets from receive queue as long as
-		 * 1. the receive buffer is full,
-		 * 2. they are queued longer than one second, or
-		 * 3. there are no missing packets before them. */
-		skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) {
-			meta = skb_meta(skb);
-			if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
-					now - meta->timestamp < HZ &&
-					meta->sequence != opt->recv_sequence)
-				break;
-			skb_unlink(skb, &sk->sk_receive_queue);
-			opt->recv_sequence = meta->sequence + 1;
-			skb_orphan(skb);
-			ppp_input(&pppox_sk(sk)->chan, skb);
-		}
-		return NET_RX_SUCCESS;
-	}
-
-	/* Flush receive queue if sequencing is disabled. */
-	skb_queue_purge(&sk->sk_receive_queue);
-	skb_orphan(skb);
-	ppp_input(&pppox_sk(sk)->chan, skb);
-	return NET_RX_SUCCESS;
-drop:
-	kfree_skb(skb);
-	return NET_RX_DROP;
-}
-
-static void pppopns_recv(struct sock *sk_raw, int length)
-{
-	struct sk_buff *skb;
-	while ((skb = skb_dequeue(&sk_raw->sk_receive_queue))) {
-		sock_hold(sk_raw);
-		sk_receive_skb(sk_raw, skb, 0);
-	}
-}
-
-static struct sk_buff_head delivery_queue;
-
-static void pppopns_xmit_core(struct work_struct *delivery_work)
-{
-	mm_segment_t old_fs = get_fs();
-	struct sk_buff *skb;
-
-	set_fs(KERNEL_DS);
-	while ((skb = skb_dequeue(&delivery_queue))) {
-		struct sock *sk_raw = skb->sk;
-		struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
-		struct msghdr msg = {
-			.msg_iov = (struct iovec *)&iov,
-			.msg_iovlen = 1,
-			.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
-		};
-		sk_raw->sk_prot->sendmsg(NULL, sk_raw, &msg, skb->len);
-		kfree_skb(skb);
-	}
-	set_fs(old_fs);
-}
-
-static DECLARE_WORK(delivery_work, pppopns_xmit_core);
-
-static int pppopns_xmit(struct ppp_channel *chan, struct sk_buff *skb)
-{
-	struct sock *sk_raw = (struct sock *)chan->private;
-	struct pppopns_opt *opt = &pppox_sk(sk_raw->sk_user_data)->proto.pns;
-	struct header *hdr;
-	__u16 length;
-
-	/* Install PPP address and control. */
-	skb_push(skb, 2);
-	skb->data[0] = PPP_ADDR;
-	skb->data[1] = PPP_CTRL;
-	length = skb->len;
-
-	/* Install PPTP GRE header. */
-	hdr = (struct header *)skb_push(skb, 12);
-	hdr->bits = PPTP_GRE_BITS | PPTP_GRE_SEQ_BIT;
-	hdr->type = PPTP_GRE_TYPE;
-	hdr->length = htons(length);
-	hdr->call = opt->remote;
-	hdr->sequence = htonl(opt->xmit_sequence);
-	opt->xmit_sequence++;
-
-	/* Now send the packet via the delivery queue. */
-	skb_set_owner_w(skb, sk_raw);
-	skb_queue_tail(&delivery_queue, skb);
-	schedule_work(&delivery_work);
-	return 1;
-}
-
-/******************************************************************************/
-
-static struct ppp_channel_ops pppopns_channel_ops = {
-	.start_xmit = pppopns_xmit,
-};
-
-static int pppopns_connect(struct socket *sock, struct sockaddr *useraddr,
-	int addrlen, int flags)
-{
-	struct sock *sk = sock->sk;
-	struct pppox_sock *po = pppox_sk(sk);
-	struct sockaddr_pppopns *addr = (struct sockaddr_pppopns *)useraddr;
-	struct sockaddr_storage ss;
-	struct socket *sock_tcp = NULL;
-	struct socket *sock_raw = NULL;
-	struct sock *sk_tcp;
-	struct sock *sk_raw;
-	int error;
-
-	if (addrlen != sizeof(struct sockaddr_pppopns))
-		return -EINVAL;
-
-	lock_sock(sk);
-	error = -EALREADY;
-	if (sk->sk_state != PPPOX_NONE)
-		goto out;
-
-	sock_tcp = sockfd_lookup(addr->tcp_socket, &error);
-	if (!sock_tcp)
-		goto out;
-	sk_tcp = sock_tcp->sk;
-	error = -EPROTONOSUPPORT;
-	if (sk_tcp->sk_protocol != IPPROTO_TCP)
-		goto out;
-	addrlen = sizeof(struct sockaddr_storage);
-	error = kernel_getpeername(sock_tcp, (struct sockaddr *)&ss, &addrlen);
-	if (error)
-		goto out;
-	if (!sk_tcp->sk_bound_dev_if) {
-		struct dst_entry *dst = sk_dst_get(sk_tcp);
-		error = -ENODEV;
-		if (!dst)
-			goto out;
-		sk_tcp->sk_bound_dev_if = dst->dev->ifindex;
-		dst_release(dst);
-	}
-
-	error = sock_create(ss.ss_family, SOCK_RAW, IPPROTO_GRE, &sock_raw);
-	if (error)
-		goto out;
-	sk_raw = sock_raw->sk;
-	sk_raw->sk_bound_dev_if = sk_tcp->sk_bound_dev_if;
-	error = kernel_connect(sock_raw, (struct sockaddr *)&ss, addrlen, 0);
-	if (error)
-		goto out;
-
-	po->chan.hdrlen = 14;
-	po->chan.private = sk_raw;
-	po->chan.ops = &pppopns_channel_ops;
-	po->chan.mtu = PPP_MRU - 80;
-	po->proto.pns.local = addr->local;
-	po->proto.pns.remote = addr->remote;
-	po->proto.pns.data_ready = sk_raw->sk_data_ready;
-	po->proto.pns.backlog_rcv = sk_raw->sk_backlog_rcv;
-
-	error = ppp_register_channel(&po->chan);
-	if (error)
-		goto out;
-
-	sk->sk_state = PPPOX_CONNECTED;
-	lock_sock(sk_raw);
-	sk_raw->sk_data_ready = pppopns_recv;
-	sk_raw->sk_backlog_rcv = pppopns_recv_core;
-	sk_raw->sk_user_data = sk;
-	release_sock(sk_raw);
-out:
-	if (sock_tcp)
-		sockfd_put(sock_tcp);
-	if (error && sock_raw)
-		sock_release(sock_raw);
-	release_sock(sk);
-	return error;
-}
-
-static int pppopns_release(struct socket *sock)
-{
-	struct sock *sk = sock->sk;
-
-	if (!sk)
-		return 0;
-
-	lock_sock(sk);
-	if (sock_flag(sk, SOCK_DEAD)) {
-		release_sock(sk);
-		return -EBADF;
-	}
-
-	if (sk->sk_state != PPPOX_NONE) {
-		struct sock *sk_raw = (struct sock *)pppox_sk(sk)->chan.private;
-		lock_sock(sk_raw);
-		skb_queue_purge(&sk->sk_receive_queue);
-		pppox_unbind_sock(sk);
-		sk_raw->sk_data_ready = pppox_sk(sk)->proto.pns.data_ready;
-		sk_raw->sk_backlog_rcv = pppox_sk(sk)->proto.pns.backlog_rcv;
-		sk_raw->sk_user_data = NULL;
-		release_sock(sk_raw);
-		sock_release(sk_raw->sk_socket);
-	}
-
-	sock_orphan(sk);
-	sock->sk = NULL;
-	release_sock(sk);
-	sock_put(sk);
-	return 0;
-}
-
-/******************************************************************************/
-
-static struct proto pppopns_proto = {
-	.name = "PPPOPNS",
-	.owner = THIS_MODULE,
-	.obj_size = sizeof(struct pppox_sock),
-};
-
-static struct proto_ops pppopns_proto_ops = {
-	.family = PF_PPPOX,
-	.owner = THIS_MODULE,
-	.release = pppopns_release,
-	.bind = sock_no_bind,
-	.connect = pppopns_connect,
-	.socketpair = sock_no_socketpair,
-	.accept = sock_no_accept,
-	.getname = sock_no_getname,
-	.poll = sock_no_poll,
-	.ioctl = pppox_ioctl,
-	.listen = sock_no_listen,
-	.shutdown = sock_no_shutdown,
-	.setsockopt = sock_no_setsockopt,
-	.getsockopt = sock_no_getsockopt,
-	.sendmsg = sock_no_sendmsg,
-	.recvmsg = sock_no_recvmsg,
-	.mmap = sock_no_mmap,
-};
-
-static int pppopns_create(struct net *net, struct socket *sock)
-{
-	struct sock *sk;
-
-	sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppopns_proto);
-	if (!sk)
-		return -ENOMEM;
-
-	sock_init_data(sock, sk);
-	sock->state = SS_UNCONNECTED;
-	sock->ops = &pppopns_proto_ops;
-	sk->sk_protocol = PX_PROTO_OPNS;
-	sk->sk_state = PPPOX_NONE;
-	return 0;
-}
-
-/******************************************************************************/
-
-static struct pppox_proto pppopns_pppox_proto = {
-	.create = pppopns_create,
-	.owner = THIS_MODULE,
-};
-
-static int __init pppopns_init(void)
-{
-	int error;
-
-	error = proto_register(&pppopns_proto, 0);
-	if (error)
-		return error;
-
-	error = register_pppox_proto(PX_PROTO_OPNS, &pppopns_pppox_proto);
-	if (error)
-		proto_unregister(&pppopns_proto);
-	else
-		skb_queue_head_init(&delivery_queue);
-	return error;
-}
-
-static void __exit pppopns_exit(void)
-{
-	unregister_pppox_proto(PX_PROTO_OPNS);
-	proto_unregister(&pppopns_proto);
-}
-
-module_init(pppopns_init);
-module_exit(pppopns_exit);
-
-MODULE_DESCRIPTION("PPP on PPTP Network Server (PPPoPNS)");
-MODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index e9130f6..fa0c568 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -35,7 +35,6 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/if_arp.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ctype.h>
@@ -362,9 +361,6 @@
 		return -ENOMEM;
 	}
 
-	if (dev->net->type != ARPHRD_RAWIP)
-		skb_reserve(skb, NET_IP_ALIGN);
-
 	entry = (struct skb_data *) skb->cb;
 	entry->urb = urb;
 	entry->dev = dev;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 4f96a69..fa84e37 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -538,17 +538,6 @@
 	ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
 			 AR_WA_ASPM_TIMER_BASED_DISABLE);
 
-	/*
-	 * Read back AR_WA into a permanent copy and set bits 14 and 17.
-	 * We need to do this to avoid RMW of this register. We cannot
-	 * read the reg when chip is asleep.
-	 */
-	ah->WARegVal = REG_READ(ah, AR_WA);
-	ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
-			 AR_WA_ASPM_TIMER_BASED_DISABLE);
-
-	ath9k_hw_read_revisions(ah);
-
 	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
 		ath_err(common, "Couldn't reset chip\n");
 		return -EIO;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 740f09b..cb00645 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -621,10 +621,8 @@
 static void ath9k_init_txpower_limits(struct ath_softc *sc)
 {
 	struct ath_hw *ah = sc->sc_ah;
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath9k_channel *curchan = ah->curchan;
 
-	ah->txchainmask = common->tx_chainmask;
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
 		ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ);
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 5e66310..77dc327 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -148,31 +148,6 @@
 	}
 }
 
-static void ath_pci_aspm_init(struct ath_common *common)
-{
-	struct ath_softc *sc = (struct ath_softc *) common->priv;
-	struct ath_hw *ah = sc->sc_ah;
-	struct pci_dev *pdev = to_pci_dev(sc->dev);
-	struct pci_dev *parent;
-	int pos;
-	u8 aspm;
-
-	if (!pci_is_pcie(pdev))
-		return;
-
-	parent = pdev->bus->self;
-	if (WARN_ON(!parent))
-		return;
-
-	pos = pci_pcie_cap(parent);
-	pci_read_config_byte(parent, pos +  PCI_EXP_LNKCTL, &aspm);
-	if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
-		ah->aspm_enabled = true;
-		/* Initialize PCIe PM and SERDES registers. */
-		ath9k_hw_configpcipowersave(ah, 0, 0);
-	}
-}
-
 static const struct ath_bus_ops ath_pci_bus_ops = {
 	.ath_bus_type = ATH_PCI,
 	.read_cachesize = ath_pci_read_cachesize,
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 0cd9f47..e4d6dc2 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2527,13 +2527,6 @@
 		b43_print_fw_helptext(dev->wl, 1);
 		err = -EOPNOTSUPP;
 		goto error;
-	} else if (fwrev >= 598) {
-		b43err(dev->wl, "YOUR FIRMWARE IS TOO NEW. Support for "
-		       "firmware 598 and up requires kernel 3.2 or newer. You "
-		       "have to install older firmware or upgrade kernel.\n");
-		b43_print_fw_helptext(dev->wl, 1);
-		err = -EOPNOTSUPP;
-		goto error;
 	}
 	dev->fw.rev = fwrev;
 	dev->fw.patch = fwpatch;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index 826dd3e..2e1a317 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -551,9 +551,6 @@
 
 	mutex_lock(&priv->mutex);
 
-	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-		goto out;
-
 	if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
 		IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
 		goto out;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index 4763426..506b9a0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -104,7 +104,7 @@
 			tx_agc[RF90_PATH_A] = 0x10101010;
 			tx_agc[RF90_PATH_B] = 0x10101010;
 		} else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
-			   TXHIGHPWRLEVEL_LEVEL2) {
+			   TXHIGHPWRLEVEL_LEVEL1) {
 			tx_agc[RF90_PATH_A] = 0x00000000;
 			tx_agc[RF90_PATH_B] = 0x00000000;
 		} else{
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 46b4651..88e8d43 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -91,6 +91,16 @@
 	  in the kernel log along with the PMIC option status. The PMIC
 	  type is mapped to a Qualcomm chip part number and logged as well.
 
+config QPNP_COINCELL
+	tristate "Qualcomm QPNP coincell charger support"
+	depends on SPMI && OF_SPMI
+	help
+	  This driver supports the QPNP coincell peripheral found inside of
+	  Qualcomm QPNP PMIC devices.  The coincell charger provides a means to
+	  charge a coincell battery or backup capacitor which is used to
+	  maintain PMIC register state when the main battery is removed from the
+	  mobile device.
+
 config IPA
 	tristate "IPA support"
 	depends on SPS
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 6b9c5ad..efb78e5 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_QPNP_POWER_ON) += qpnp-power-on.o
 obj-$(CONFIG_QPNP_VIBRATOR) += qpnp-vibrator.o
 obj-$(CONFIG_QPNP_CLKDIV) += qpnp-clkdiv.o
+obj-$(CONFIG_QPNP_COINCELL) += qpnp-coincell.o
 obj-$(CONFIG_MSM_AVTIMER) += avtimer.o
 obj-$(CONFIG_SSM) += ssm.o
 obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 1142094..42a0016 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -1919,22 +1919,26 @@
 	ipa_ctx->aggregation_byte_limit = 1;
 	ipa_ctx->aggregation_time_limit = 0;
 
-	/* Initialize IPA RM (resource manager) */
-	result = ipa_rm_initialize();
-	if (result) {
-		IPAERR(":cdev_add err=%d\n", -result);
-		result = -ENODEV;
-		goto fail_ipa_rm_init;
+	if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_PCIE) {
+		/* Initialize IPA RM (resource manager) */
+		result = ipa_rm_initialize();
+		if (result) {
+			IPAERR(":cdev_add err=%d\n", -result);
+			result = -ENODEV;
+			goto fail_ipa_rm_init;
+		}
 	}
 
-	a2_mux_init();
+	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL) {
+		a2_mux_init();
 
-	/* Initialize the tethering bridge driver */
-	result = teth_bridge_driver_init();
-	if (result) {
-		IPAERR(":teth_bridge_driver_init() failed\n");
-		result = -ENODEV;
-		goto fail_cdev_add;
+		/* Initialize the tethering bridge driver */
+		result = teth_bridge_driver_init();
+		if (result) {
+			IPAERR(":teth_bridge_driver_init() failed\n");
+			result = -ENODEV;
+			goto fail_cdev_add;
+		}
 	}
 
 	/* gate IPA clocks */
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 76e2eee..29253cd 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -69,6 +69,11 @@
 	bool device_mac_addr_known;
 };
 
+struct stats {
+	u64 a2_to_usb_num_sw_tx_packets;
+	u64 usb_to_a2_num_sw_tx_packets;
+};
+
 struct teth_bridge_ctx {
 	struct class *class;
 	dev_t dev_num;
@@ -90,6 +95,7 @@
 	struct work_struct comp_hw_bridge_work;
 	bool comp_hw_bridge_in_progress;
 	struct teth_aggr_capabilities *aggr_caps;
+	struct stats stats;
 };
 
 static struct teth_bridge_ctx *teth_ctx;
@@ -806,6 +812,7 @@
 				&teth_ctx->mac_addresses.device_mac_addr_known);
 
 		/* Send the packet to A2, using a2_service driver API */
+		teth_ctx->stats.usb_to_a2_num_sw_tx_packets++;
 		res = a2_mux_write(A2_MUX_TETHERED_0, skb);
 		if (res) {
 			TETH_ERR("Packet send failure, dropping packet !\n");
@@ -843,6 +850,7 @@
 				mac_addresses.host_pc_mac_addr_known);
 
 		/* Send the packet to USB */
+		teth_ctx->stats.a2_to_usb_num_sw_tx_packets++;
 		res = ipa_tx_dp(IPA_CLIENT_USB_CONS, skb, NULL);
 		if (res) {
 			TETH_ERR("Packet send failure, dropping packet !\n");
@@ -1216,6 +1224,8 @@
 static struct dentry *dfile_link_protocol;
 static struct dentry *dfile_get_aggr_params;
 static struct dentry *dfile_set_aggr_protocol;
+static struct dentry *dfile_stats;
+static struct dentry *dfile_is_hw_bridge_complete;
 
 static ssize_t teth_debugfs_read_link_protocol(struct file *file,
 					       char __user *ubuf,
@@ -1351,6 +1361,43 @@
 	return count;
 }
 
+static ssize_t teth_debugfs_stats(struct file *file,
+				  char __user *ubuf,
+				  size_t count,
+				  loff_t *ppos)
+{
+	int nbytes = 0;
+
+	nbytes += scnprintf(&dbg_buff[nbytes],
+			    TETH_MAX_MSG_LEN - nbytes,
+			   "USB to A2 SW Tx packets: %lld\n",
+			    teth_ctx->stats.usb_to_a2_num_sw_tx_packets);
+	nbytes += scnprintf(&dbg_buff[nbytes],
+			    TETH_MAX_MSG_LEN - nbytes,
+			   "A2 to USB SW Tx packets: %lld\n",
+			    teth_ctx->stats.a2_to_usb_num_sw_tx_packets);
+	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t teth_debugfs_hw_bridge_status(struct file *file,
+					     char __user *ubuf,
+					     size_t count,
+					     loff_t *ppos)
+{
+	int nbytes = 0;
+
+	if (teth_ctx->is_hw_bridge_complete)
+		nbytes += scnprintf(&dbg_buff[nbytes],
+				    TETH_MAX_MSG_LEN - nbytes,
+				   "HW bridge is in use.\n");
+	else
+		nbytes += scnprintf(&dbg_buff[nbytes],
+				    TETH_MAX_MSG_LEN - nbytes,
+				   "SW bridge is in use. HW bridge not complete yet.\n");
+
+	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
 const struct file_operations teth_link_protocol_ops = {
 	.read = teth_debugfs_read_link_protocol,
 	.write = teth_debugfs_write_link_protocol,
@@ -1364,6 +1411,14 @@
 	.write = teth_debugfs_set_aggr_protocol,
 };
 
+const struct file_operations teth_stats_ops = {
+	.read = teth_debugfs_stats,
+};
+
+const struct file_operations teth_hw_bridge_status_ops = {
+	.read = teth_debugfs_hw_bridge_status,
+};
+
 void teth_debugfs_init(void)
 {
 	const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
@@ -1400,6 +1455,23 @@
 		goto fail;
 	}
 
+	dfile_stats =
+		debugfs_create_file("stats", read_only_mode, dent,
+				    0, &teth_stats_ops);
+	if (!dfile_stats || IS_ERR(dfile_stats)) {
+		IPAERR("fail to create file stats\n");
+		goto fail;
+	}
+
+	dfile_is_hw_bridge_complete =
+		debugfs_create_file("is_hw_bridge_complete", read_only_mode,
+				    dent, 0, &teth_hw_bridge_status_ops);
+	if (!dfile_is_hw_bridge_complete ||
+	    IS_ERR(dfile_is_hw_bridge_complete)) {
+		IPAERR("fail to create file is_hw_bridge_complete\n");
+		goto fail;
+	}
+
 	return;
 fail:
 	debugfs_remove_recursive(dent);
diff --git a/drivers/platform/msm/qpnp-coincell.c b/drivers/platform/msm/qpnp-coincell.c
new file mode 100644
index 0000000..e08fd7d
--- /dev/null
+++ b/drivers/platform/msm/qpnp-coincell.c
@@ -0,0 +1,266 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#define QPNP_COINCELL_DRIVER_NAME "qcom,qpnp-coincell"
+
+struct qpnp_coincell {
+	struct spmi_device	*spmi_dev;
+	u16			base_addr;
+};
+
+#define QPNP_COINCELL_REG_TYPE		0x04
+#define QPNP_COINCELL_REG_SUBTYPE	0x05
+#define QPNP_COINCELL_REG_RSET		0x44
+#define QPNP_COINCELL_REG_VSET		0x45
+#define QPNP_COINCELL_REG_ENABLE	0x46
+
+#define QPNP_COINCELL_TYPE		0x02
+#define QPNP_COINCELL_SUBTYPE		0x20
+#define QPNP_COINCELL_ENABLE		0x80
+#define QPNP_COINCELL_DISABLE		0x00
+
+static const int qpnp_rset_map[] = {2100, 1700, 1200, 800};
+static const int qpnp_vset_map[] = {2500, 3200, 3100, 3000};
+
+static int qpnp_coincell_set_resistance(struct qpnp_coincell *chip, int rset)
+{
+	int i, rc;
+	u8 reg;
+
+	for (i = 0; i < ARRAY_SIZE(qpnp_rset_map); i++)
+		if (rset == qpnp_rset_map[i])
+			break;
+
+	if (i >= ARRAY_SIZE(qpnp_rset_map)) {
+		pr_err("invalid rset=%d value\n", rset);
+		return -EINVAL;
+	}
+
+	reg = i;
+	rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+		chip->base_addr + QPNP_COINCELL_REG_RSET, &reg, 1);
+	if (rc)
+		dev_err(&chip->spmi_dev->dev, "%s: could not write to RSET register, rc=%d\n",
+			__func__, rc);
+
+	return rc;
+}
+
+static int qpnp_coincell_set_voltage(struct qpnp_coincell *chip, int vset)
+{
+	int i, rc;
+	u8 reg;
+
+	for (i = 0; i < ARRAY_SIZE(qpnp_vset_map); i++)
+		if (vset == qpnp_vset_map[i])
+			break;
+
+	if (i >= ARRAY_SIZE(qpnp_vset_map)) {
+		pr_err("invalid vset=%d value\n", vset);
+		return -EINVAL;
+	}
+
+	reg = i;
+	rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+		chip->base_addr + QPNP_COINCELL_REG_VSET, &reg, 1);
+	if (rc)
+		dev_err(&chip->spmi_dev->dev, "%s: could not write to VSET register, rc=%d\n",
+			__func__, rc);
+
+	return rc;
+}
+
+static int qpnp_coincell_set_charge(struct qpnp_coincell *chip, bool enabled)
+{
+	int rc;
+	u8 reg;
+
+	reg = enabled ? QPNP_COINCELL_ENABLE : QPNP_COINCELL_DISABLE;
+	rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+		chip->base_addr + QPNP_COINCELL_REG_ENABLE, &reg, 1);
+	if (rc)
+		dev_err(&chip->spmi_dev->dev, "%s: could not write to ENABLE register, rc=%d\n",
+			__func__, rc);
+
+	return rc;
+}
+
+static void qpnp_coincell_charger_show_state(struct qpnp_coincell *chip)
+{
+	int rc, rset, vset, temp;
+	bool enabled;
+	u8 reg[QPNP_COINCELL_REG_ENABLE - QPNP_COINCELL_REG_RSET + 1];
+
+	rc = spmi_ext_register_readl(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+		chip->base_addr + QPNP_COINCELL_REG_RSET, reg, ARRAY_SIZE(reg));
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: could not read RSET register, rc=%d\n",
+			__func__, rc);
+		return;
+	}
+
+	temp = reg[QPNP_COINCELL_REG_RSET - QPNP_COINCELL_REG_RSET];
+	if (temp >= ARRAY_SIZE(qpnp_rset_map)) {
+		dev_err(&chip->spmi_dev->dev, "unknown RSET=0x%02X register value\n",
+			temp);
+		return;
+	}
+	rset = qpnp_rset_map[temp];
+
+	temp = reg[QPNP_COINCELL_REG_VSET - QPNP_COINCELL_REG_RSET];
+	if (temp >= ARRAY_SIZE(qpnp_vset_map)) {
+		dev_err(&chip->spmi_dev->dev, "unknown VSET=0x%02X register value\n",
+			temp);
+		return;
+	}
+	vset = qpnp_vset_map[temp];
+
+	temp = reg[QPNP_COINCELL_REG_ENABLE - QPNP_COINCELL_REG_RSET];
+	enabled = temp & QPNP_COINCELL_ENABLE;
+
+	pr_info("enabled=%c, voltage=%d mV, resistance=%d ohm\n",
+		(enabled ? 'Y' : 'N'), vset, rset);
+}
+
+static int qpnp_coincell_check_type(struct qpnp_coincell *chip)
+{
+	int rc;
+	u8 type[2];
+
+	rc = spmi_ext_register_readl(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+		chip->base_addr + QPNP_COINCELL_REG_TYPE, type, 2);
+	if (rc) {
+		dev_err(&chip->spmi_dev->dev, "%s: could not read type register, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	if (type[0] != QPNP_COINCELL_TYPE || type[1] != QPNP_COINCELL_SUBTYPE) {
+		dev_err(&chip->spmi_dev->dev, "%s: invalid type=0x%02X or subtype=0x%02X register value\n",
+			__func__, type[0], type[1]);
+		return -ENODEV;
+	}
+
+	return rc;
+}
+
+static int qpnp_coincell_probe(struct spmi_device *spmi)
+{
+	struct device_node *node = spmi->dev.of_node;
+	struct qpnp_coincell *chip;
+	struct resource *res;
+	u32 temp;
+	int rc = 0;
+
+	if (!node) {
+		dev_err(&spmi->dev, "%s: device node missing\n", __func__);
+		return -ENODEV;
+	}
+
+	chip = devm_kzalloc(&spmi->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip) {
+		dev_err(&spmi->dev, "%s: cannot allocate qpnp_coincell\n",
+			__func__);
+		return -ENOMEM;
+	}
+	chip->spmi_dev = spmi;
+
+	res = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&spmi->dev, "%s: node is missing base address\n",
+			__func__);
+		return -EINVAL;
+	}
+	chip->base_addr = res->start;
+
+	rc = qpnp_coincell_check_type(chip);
+	if (rc)
+		return rc;
+
+	rc = of_property_read_u32(node, "qcom,rset-ohms", &temp);
+	if (!rc) {
+		rc = qpnp_coincell_set_resistance(chip, temp);
+		if (rc)
+			return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,vset-millivolts", &temp);
+	if (!rc) {
+		rc = qpnp_coincell_set_voltage(chip, temp);
+		if (rc)
+			return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,charge-enable", &temp);
+	if (!rc) {
+		rc = qpnp_coincell_set_charge(chip, temp);
+		if (rc)
+			return rc;
+	}
+
+	qpnp_coincell_charger_show_state(chip);
+
+	return 0;
+}
+
+static int __devexit qpnp_coincell_remove(struct spmi_device *spmi)
+{
+	return 0;
+}
+
+static struct of_device_id qpnp_coincell_match_table[] = {
+	{ .compatible = QPNP_COINCELL_DRIVER_NAME, },
+	{}
+};
+
+static const struct spmi_device_id qpnp_coincell_id[] = {
+	{ QPNP_COINCELL_DRIVER_NAME, 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(spmi, qpnp_coincell_id);
+
+static struct spmi_driver qpnp_coincell_driver = {
+	.driver	= {
+		.name		= QPNP_COINCELL_DRIVER_NAME,
+		.of_match_table	= qpnp_coincell_match_table,
+		.owner		= THIS_MODULE,
+	},
+	.probe		= qpnp_coincell_probe,
+	.remove		= __devexit_p(qpnp_coincell_remove),
+	.id_table	= qpnp_coincell_id,
+};
+
+static int __init qpnp_coincell_init(void)
+{
+	return spmi_driver_register(&qpnp_coincell_driver);
+}
+
+static void __exit qpnp_coincell_exit(void)
+{
+	spmi_driver_unregister(&qpnp_coincell_driver);
+}
+
+MODULE_DESCRIPTION("QPNP PMIC coincell charger driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(qpnp_coincell_init);
+module_exit(qpnp_coincell_exit);
diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c
index c57bb91..3afb954 100644
--- a/drivers/platform/msm/ssm.c
+++ b/drivers/platform/msm/ssm.c
@@ -66,7 +66,7 @@
 	struct device *dev;
 	smd_channel_t *ch;
 	ion_phys_addr_t buff_phys;
-	ion_virt_addr_t buff_virt;
+	void *buff_virt;
 	dev_t ssm_device_no;
 	struct work_struct ipc_work;
 	struct mutex mutex;
@@ -401,7 +401,7 @@
 	const struct elf32_phdr *phdr;
 	struct ion_handle *ion_handle;
 	ion_phys_addr_t buff_phys;
-	ion_virt_addr_t buff_virt;
+	void *buff_virt;
 
 	/* Check if TZ app already loaded */
 	app_req.cmd_id = APP_LOOKUP_COMMAND;
@@ -509,8 +509,7 @@
 		goto ion_free;
 	}
 
-	buff_virt =
-		(ion_virt_addr_t)ion_map_kernel(ssm_drv->ssm_ion_client,
+	buff_virt = ion_map_kernel(ssm_drv->ssm_ion_client,
 				ion_handle);
 	if (IS_ERR_OR_NULL((void *)buff_virt)) {
 		rc = PTR_ERR((void *)buff_virt);
@@ -605,8 +604,7 @@
 		goto ion_free;
 	}
 
-	ssm->buff_virt =
-		(ion_virt_addr_t)ion_map_kernel(ssm->ssm_ion_client,
+	ssm->buff_virt = ion_map_kernel(ssm->ssm_ion_client,
 				ssm->ssm_ion_handle);
 	if (IS_ERR_OR_NULL((void *)ssm->buff_virt)) {
 		rc = PTR_ERR((void *)ssm->buff_virt);
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index a9a850c..f9ae3c2 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -28,34 +28,8 @@
 #include <linux/dma-mapping.h>
 #include <mach/msm_smsm.h>
 
-#define USB_SUMMING_THRESHOLD 512
-#define CONNECTIONS_NUM	8
-
-static struct sps_bam_props usb_props;
-static struct sps_pipe *sps_pipes[CONNECTIONS_NUM][2];
-static struct sps_connect sps_connections[CONNECTIONS_NUM][2];
-static struct sps_mem_buffer data_mem_buf[CONNECTIONS_NUM][2];
-static struct sps_mem_buffer desc_mem_buf[CONNECTIONS_NUM][2];
-static struct platform_device *usb_bam_pdev;
-static struct workqueue_struct *usb_bam_wq;
-static u32 h_bam;
-static spinlock_t usb_bam_lock;
-
-struct usb_bam_event_info {
-	struct sps_register_event event;
-	int (*callback)(void *);
-	void *param;
-	struct work_struct event_w;
-};
-
-struct usb_bam_connect_info {
-	u8 idx;
-	u32 *src_pipe;
-	u32 *dst_pipe;
-	struct usb_bam_event_info wake_event;
-	bool src_enabled;
-	bool dst_enabled;
-};
+#define USB_THRESHOLD 512
+#define USB_BAM_MAX_STR_LEN 50
 
 enum usb_bam_sm {
 	USB_BAM_SM_INIT = 0,
@@ -64,7 +38,7 @@
 	USB_BAM_SM_UNPLUG_NOTIFIED,
 };
 
-struct usb_bam_peer_handhskae_info {
+struct usb_bam_peer_handshake_info {
 	enum usb_bam_sm state;
 	bool client_ready;
 	bool ack_received;
@@ -72,26 +46,79 @@
 	struct usb_bam_event_info reset_event;
 };
 
-static struct usb_bam_connect_info usb_bam_connections[CONNECTIONS_NUM];
-static struct usb_bam_pipe_connect ***msm_usb_bam_connections_info;
-static struct usb_bam_pipe_connect *bam_connection_arr;
-void __iomem *qscratch_ram1_reg;
-struct clk *mem_clk;
-struct clk *mem_iface_clk;
-struct usb_bam_peer_handhskae_info peer_handhskae_info;
+struct usb_bam_sps_type {
+	struct sps_bam_props usb_props;
+	struct sps_pipe **sps_pipes;
+	struct sps_connect *sps_connections;
+};
 
-static int connect_pipe(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
-						u32 *usb_pipe_idx)
+struct usb_bam_ctx_type {
+	struct usb_bam_sps_type usb_bam_sps;
+	struct platform_device *usb_bam_pdev;
+	struct workqueue_struct *usb_bam_wq;
+	void __iomem *qscratch_ram1_reg;
+	u8 max_connections;
+	struct clk *mem_clk;
+	struct clk *mem_iface_clk;
+	char qdss_core_name[USB_BAM_MAX_STR_LEN];
+	char bam_enabled_list[USB_BAM_MAX_STR_LEN];
+	u32 h_bam[MAX_BAMS];
+};
+
+static char *bam_enable_strings[3] = {
+	[SSUSB_BAM] = "ssusb",
+	[HSUSB_BAM] = "hsusb",
+	[HSIC_BAM]  = "hsic",
+};
+
+static spinlock_t usb_bam_lock;
+static struct usb_bam_peer_handshake_info peer_handshake_info;
+static struct usb_bam_pipe_connect *usb_bam_connections;
+static struct usb_bam_ctx_type ctx;
+
+static int get_bam_type_from_core_name(const char *name)
+{
+	if (strnstr(name, bam_enable_strings[SSUSB_BAM],
+			USB_BAM_MAX_STR_LEN) ||
+		strnstr(name, "dwc3", USB_BAM_MAX_STR_LEN))
+		return SSUSB_BAM;
+	else if (strnstr(name, bam_enable_strings[HSIC_BAM],
+			USB_BAM_MAX_STR_LEN))
+		return HSIC_BAM;
+	else if (strnstr(name, bam_enable_strings[HSUSB_BAM],
+			USB_BAM_MAX_STR_LEN) ||
+		strnstr(name, "ci", USB_BAM_MAX_STR_LEN))
+		return HSUSB_BAM;
+
+	pr_err("%s: invalid BAM name(%s)\n", __func__, name);
+	return -EINVAL;
+}
+
+static bool bam_use_private_mem(enum usb_bam bam)
+{
+	int i;
+
+	for (i = 0; i < ctx.max_connections; i++)
+		if (usb_bam_connections[i].bam_type == bam &&
+			usb_bam_connections[i].mem_type == USB_PRIVATE_MEM)
+				return true;
+
+	return false;
+}
+
+static int connect_pipe(u8 idx, u32 *usb_pipe_idx)
 {
 	int ret, ram1_value;
-	struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
-	struct sps_connect *connection =
-		&sps_connections[conn_idx][pipe_dir];
+	enum usb_bam bam;
+	struct usb_bam_sps_type usb_bam_sps = ctx.usb_bam_sps;
+	struct sps_pipe **pipe = &(usb_bam_sps.sps_pipes[idx]);
+	struct sps_connect *sps_connection = &usb_bam_sps.sps_connections[idx];
 	struct msm_usb_bam_platform_data *pdata =
-		usb_bam_pdev->dev.platform_data;
-	struct usb_bam_pipe_connect *pipe_connection =
-				&msm_usb_bam_connections_info
-				[pdata->usb_active_bam][conn_idx][pipe_dir];
+		ctx.usb_bam_pdev->dev.platform_data;
+	struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
+	enum usb_bam_pipe_dir dir = pipe_connect->dir;
+	struct sps_mem_buffer *data_buf = &(pipe_connect->data_mem_buf);
+	struct sps_mem_buffer *desc_buf = &(pipe_connect->desc_mem_buf);
 
 	*pipe = sps_alloc_endpoint();
 	if (*pipe == NULL) {
@@ -99,42 +126,42 @@
 		return -ENOMEM;
 	}
 
-	ret = sps_get_config(*pipe, connection);
+	ret = sps_get_config(*pipe, sps_connection);
 	if (ret) {
 		pr_err("%s: tx get config failed %d\n", __func__, ret);
 		goto free_sps_endpoint;
 	}
 
-	ret = sps_phy2h(pipe_connection->src_phy_addr, &(connection->source));
+	ret = sps_phy2h(pipe_connect->src_phy_addr, &(sps_connection->source));
 	if (ret) {
 		pr_err("%s: sps_phy2h failed (src BAM) %d\n", __func__, ret);
 		goto free_sps_endpoint;
 	}
 
-	connection->src_pipe_index = pipe_connection->src_pipe_index;
-	ret = sps_phy2h(pipe_connection->dst_phy_addr,
-					&(connection->destination));
+	sps_connection->src_pipe_index = pipe_connect->src_pipe_index;
+	ret = sps_phy2h(pipe_connect->dst_phy_addr,
+		&(sps_connection->destination));
 	if (ret) {
 		pr_err("%s: sps_phy2h failed (dst BAM) %d\n", __func__, ret);
 		goto free_sps_endpoint;
 	}
-	connection->dest_pipe_index = pipe_connection->dst_pipe_index;
+	sps_connection->dest_pipe_index = pipe_connect->dst_pipe_index;
 
-	if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
-		connection->mode = SPS_MODE_SRC;
-		*usb_pipe_idx = connection->src_pipe_index;
+	if (dir == USB_TO_PEER_PERIPHERAL) {
+		sps_connection->mode = SPS_MODE_SRC;
+		*usb_pipe_idx = pipe_connect->src_pipe_index;
 	} else {
-		connection->mode = SPS_MODE_DEST;
-		*usb_pipe_idx = connection->dest_pipe_index;
+		sps_connection->mode = SPS_MODE_DEST;
+		*usb_pipe_idx = pipe_connect->dst_pipe_index;
 	}
 
 	/* If BAM is using dedicated SPS pipe memory, get it */
-	if (pipe_connection->mem_type == SPS_PIPE_MEM) {
+	if (pipe_connect->mem_type == SPS_PIPE_MEM) {
 		pr_debug("%s: USB BAM using SPS pipe memory\n", __func__);
 		ret = sps_setup_bam2bam_fifo(
-				&data_mem_buf[conn_idx][pipe_dir],
-				pipe_connection->data_fifo_base_offset,
-				pipe_connection->data_fifo_size, 1);
+			data_buf,
+			pipe_connect->data_fifo_base_offset,
+			pipe_connect->data_fifo_size, 1);
 		if (ret) {
 			pr_err("%s: data fifo setup failure %d\n", __func__,
 				ret);
@@ -142,90 +169,84 @@
 		}
 
 		ret = sps_setup_bam2bam_fifo(
-				&desc_mem_buf[conn_idx][pipe_dir],
-				pipe_connection->desc_fifo_base_offset,
-				pipe_connection->desc_fifo_size, 1);
+			desc_buf,
+			pipe_connect->desc_fifo_base_offset,
+			pipe_connect->desc_fifo_size, 1);
 		if (ret) {
 			pr_err("%s: desc. fifo setup failure %d\n", __func__,
 				ret);
 			goto free_sps_endpoint;
 		}
-	} else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+	} else if (pipe_connect->mem_type == USB_PRIVATE_MEM) {
 		pr_debug("%s: USB BAM using private memory\n", __func__);
 
-		if (IS_ERR(mem_clk) || IS_ERR(mem_iface_clk)) {
+		if (IS_ERR(ctx.mem_clk) || IS_ERR(ctx.mem_iface_clk)) {
 			pr_err("%s: Failed to enable USB mem_clk\n", __func__);
-			ret = IS_ERR(mem_clk);
+			ret = IS_ERR(ctx.mem_clk);
 			goto free_sps_endpoint;
 		}
 
-		clk_prepare_enable(mem_clk);
-		clk_prepare_enable(mem_iface_clk);
+		clk_prepare_enable(ctx.mem_clk);
+		clk_prepare_enable(ctx.mem_iface_clk);
 
 		/*
 		 * Enable USB PRIVATE RAM to be used for BAM FIFOs
 		 * HSUSB: Only RAM13 is used for BAM FIFOs
 		 * SSUSB: RAM11, 12, 13 are used for BAM FIFOs
 		 */
-		if (pdata->usb_active_bam == HSUSB_BAM)
+		bam = pipe_connect->bam_type;
+		if (bam < 0)
+			goto free_sps_endpoint;
+
+		if (bam == HSUSB_BAM)
 			ram1_value = 0x4;
 		else
 			ram1_value = 0x7;
 
 		pr_debug("Writing 0x%x to QSCRATCH_RAM1\n", ram1_value);
-		writel_relaxed(ram1_value, qscratch_ram1_reg);
+		writel_relaxed(ram1_value, ctx.qscratch_ram1_reg);
 
-		data_mem_buf[conn_idx][pipe_dir].phys_base =
-			pipe_connection->data_fifo_base_offset +
+		data_buf->phys_base =
+			pipe_connect->data_fifo_base_offset +
 				pdata->usb_base_address;
-		data_mem_buf[conn_idx][pipe_dir].size =
-			pipe_connection->data_fifo_size;
-		data_mem_buf[conn_idx][pipe_dir].base =
-			ioremap(data_mem_buf[conn_idx][pipe_dir].phys_base,
-				data_mem_buf[conn_idx][pipe_dir].size);
-		memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
-			data_mem_buf[conn_idx][pipe_dir].size);
+		data_buf->size = pipe_connect->data_fifo_size;
+		data_buf->base =
+			ioremap(data_buf->phys_base, data_buf->size);
+		memset(data_buf->base, 0, data_buf->size);
 
-		desc_mem_buf[conn_idx][pipe_dir].phys_base =
-			pipe_connection->desc_fifo_base_offset +
+		desc_buf->phys_base =
+			pipe_connect->desc_fifo_base_offset +
 				pdata->usb_base_address;
-		desc_mem_buf[conn_idx][pipe_dir].size =
-			pipe_connection->desc_fifo_size;
-		desc_mem_buf[conn_idx][pipe_dir].base =
-			ioremap(desc_mem_buf[conn_idx][pipe_dir].phys_base,
-				desc_mem_buf[conn_idx][pipe_dir].size);
-		memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
-			desc_mem_buf[conn_idx][pipe_dir].size);
+		desc_buf->size = pipe_connect->desc_fifo_size;
+		desc_buf->base =
+			ioremap(desc_buf->phys_base, desc_buf->size);
+		memset(desc_buf->base, 0, desc_buf->size);
 	} else {
 		pr_debug("%s: USB BAM using system memory\n", __func__);
 		/* BAM would use system memory, allocate FIFOs */
-		data_mem_buf[conn_idx][pipe_dir].size =
-					pipe_connection->data_fifo_size;
-		data_mem_buf[conn_idx][pipe_dir].base =
-			dma_alloc_coherent(&usb_bam_pdev->dev,
-				    pipe_connection->data_fifo_size,
-				    &data_mem_buf[conn_idx][pipe_dir].phys_base,
-				    0);
-		memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
-					pipe_connection->data_fifo_size);
+		data_buf->size = pipe_connect->data_fifo_size;
+		data_buf->base =
+			dma_alloc_coherent(&ctx.usb_bam_pdev->dev,
+			pipe_connect->data_fifo_size,
+			&(data_buf->phys_base),
+			0);
+		memset(data_buf->base, 0, pipe_connect->data_fifo_size);
 
-		desc_mem_buf[conn_idx][pipe_dir].size =
-					pipe_connection->desc_fifo_size;
-		desc_mem_buf[conn_idx][pipe_dir].base =
-			dma_alloc_coherent(&usb_bam_pdev->dev,
-				    pipe_connection->desc_fifo_size,
-				    &desc_mem_buf[conn_idx][pipe_dir].phys_base,
-				    0);
-		memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
-					pipe_connection->desc_fifo_size);
+		desc_buf->size = pipe_connect->desc_fifo_size;
+		desc_buf->base =
+			dma_alloc_coherent(&ctx.usb_bam_pdev->dev,
+			pipe_connect->desc_fifo_size,
+			&(desc_buf->phys_base),
+			0);
+		memset(desc_buf->base, 0, pipe_connect->desc_fifo_size);
 	}
 
-	connection->data = data_mem_buf[conn_idx][pipe_dir];
-	connection->desc = desc_mem_buf[conn_idx][pipe_dir];
-	connection->event_thresh = 16;
-	connection->options = SPS_O_AUTO_ENABLE;
+	sps_connection->data = *data_buf;
+	sps_connection->desc = *desc_buf;
+	sps_connection->event_thresh = 16;
+	sps_connection->options = SPS_O_AUTO_ENABLE;
 
-	ret = sps_connect(*pipe, connection);
+	ret = sps_connect(*pipe, sps_connection);
 	if (ret < 0) {
 		pr_err("%s: sps_connect failed %d\n", __func__, ret);
 		goto error;
@@ -239,20 +260,15 @@
 	return ret;
 }
 
-static int connect_pipe_ipa(
-			struct usb_bam_connect_ipa_params *connection_params)
+static int connect_pipe_ipa(u8 idx,
+			struct usb_bam_connect_ipa_params *ipa_params)
 {
 	int ret;
-	u8 conn_idx = connection_params->idx;
-	enum usb_bam_pipe_dir pipe_dir = connection_params->dir;
-	struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
-	struct sps_connect *connection =
-		&sps_connections[conn_idx][pipe_dir];
-	struct msm_usb_bam_platform_data *pdata =
-		usb_bam_pdev->dev.platform_data;
-	struct usb_bam_pipe_connect *pipe_connection =
-				&msm_usb_bam_connections_info
-				[pdata->usb_active_bam][conn_idx][pipe_dir];
+	struct usb_bam_sps_type usb_bam_sps = ctx.usb_bam_sps;
+	enum usb_bam_pipe_dir dir = ipa_params->dir;
+	struct sps_pipe **pipe = &(usb_bam_sps.sps_pipes[idx]);
+	struct sps_connect *sps_connection = &usb_bam_sps.sps_connections[idx];
+	struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
 
 	struct ipa_connect_params ipa_in_params;
 	struct ipa_sps_params sps_out_params;
@@ -262,12 +278,12 @@
 	memset(&ipa_in_params, 0, sizeof(ipa_in_params));
 	memset(&sps_out_params, 0, sizeof(sps_out_params));
 
-	if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
-		usb_phy_addr = pipe_connection->src_phy_addr;
-		ipa_in_params.client_ep_idx = pipe_connection->src_pipe_index;
+	if (dir == USB_TO_PEER_PERIPHERAL) {
+		usb_phy_addr = pipe_connect->src_phy_addr;
+		ipa_in_params.client_ep_idx = pipe_connect->src_pipe_index;
 	} else {
-		usb_phy_addr = pipe_connection->dst_phy_addr;
-		ipa_in_params.client_ep_idx = pipe_connection->dst_pipe_index;
+		usb_phy_addr = pipe_connect->dst_phy_addr;
+		ipa_in_params.client_ep_idx = pipe_connect->dst_pipe_index;
 	}
 	/* Get HSUSB / HSIC bam handle */
 	ret = sps_phy2h(usb_phy_addr, &usb_handle);
@@ -279,46 +295,41 @@
 
 	/* IPA input parameters */
 	ipa_in_params.client_bam_hdl = usb_handle;
-	ipa_in_params.desc_fifo_sz = pipe_connection->desc_fifo_size;
-	ipa_in_params.data_fifo_sz = pipe_connection->data_fifo_size;
-	ipa_in_params.notify = connection_params->notify;
-	ipa_in_params.priv = connection_params->priv;
-	ipa_in_params.client = connection_params->client;
+	ipa_in_params.desc_fifo_sz = pipe_connect->desc_fifo_size;
+	ipa_in_params.data_fifo_sz = pipe_connect->data_fifo_size;
+	ipa_in_params.notify = ipa_params->notify;
+	ipa_in_params.priv = ipa_params->priv;
+	ipa_in_params.client = ipa_params->client;
 
 	/* If BAM is using dedicated SPS pipe memory, get it */
 
-	if (pipe_connection->mem_type == SPS_PIPE_MEM) {
+	if (pipe_connect->mem_type == SPS_PIPE_MEM) {
 		pr_debug("%s: USB BAM using SPS pipe memory\n", __func__);
 		ret = sps_setup_bam2bam_fifo(
-			&data_mem_buf[conn_idx][pipe_dir],
-			pipe_connection->data_fifo_base_offset,
-			pipe_connection->data_fifo_size, 1);
+			&pipe_connect->data_mem_buf,
+			pipe_connect->data_fifo_base_offset,
+			pipe_connect->data_fifo_size, 1);
 		if (ret) {
-			pr_err("%s: data fifo setup failure %d\n", __func__,
-				ret);
+			pr_err("%s: data fifo setup failure %d\n",
+				__func__, ret);
 			return ret;
 		}
 
 		ret = sps_setup_bam2bam_fifo(
-			&desc_mem_buf[conn_idx][pipe_dir],
-			pipe_connection->desc_fifo_base_offset,
-			pipe_connection->desc_fifo_size, 1);
+			&pipe_connect->desc_mem_buf,
+			pipe_connect->desc_fifo_base_offset,
+			pipe_connect->desc_fifo_size, 1);
 		if (ret) {
-			pr_err("%s: desc. fifo setup failure %d\n", __func__,
-				ret);
+			pr_err("%s: desc. fifo setup failure %d\n",
+				__func__, ret);
 			return ret;
 		}
 
-	} else {
-		pr_err("%s: unsupported memory type(%d)\n",
-			__func__, pipe_connection->mem_type);
-		return -EINVAL;
+		ipa_in_params.desc = pipe_connect->desc_mem_buf;
+		ipa_in_params.data = pipe_connect->data_mem_buf;
 	}
 
-	ipa_in_params.desc = desc_mem_buf[conn_idx][pipe_dir];
-	ipa_in_params.data = data_mem_buf[conn_idx][pipe_dir];
-
-	memcpy(&ipa_in_params.ipa_ep_cfg, &connection_params->ipa_ep_cfg,
+	memcpy(&ipa_in_params.ipa_ep_cfg, &ipa_params->ipa_ep_cfg,
 		   sizeof(struct ipa_ep_cfg));
 
 	ret = ipa_connect(&ipa_in_params, &sps_out_params, &clnt_hdl);
@@ -334,38 +345,48 @@
 		goto disconnect_ipa;
 	}
 
-	ret = sps_get_config(*pipe, connection);
+	ret = sps_get_config(*pipe, sps_connection);
 	if (ret) {
 		pr_err("%s: tx get config failed %d\n", __func__, ret);
 		goto free_sps_endpoints;
 	}
 
-	if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
+	if (dir == USB_TO_PEER_PERIPHERAL) {
 		/* USB src IPA dest */
-		connection->mode = SPS_MODE_SRC;
-		connection_params->cons_clnt_hdl = clnt_hdl;
-		connection->source = usb_handle;
-		connection->destination = sps_out_params.ipa_bam_hdl;
-		connection->src_pipe_index = pipe_connection->src_pipe_index;
-		connection->dest_pipe_index = sps_out_params.ipa_ep_idx;
-		*(connection_params->src_pipe) = connection->src_pipe_index;
+		sps_connection->mode = SPS_MODE_SRC;
+		ipa_params->cons_clnt_hdl = clnt_hdl;
+		sps_connection->source = usb_handle;
+		sps_connection->destination = sps_out_params.ipa_bam_hdl;
+		sps_connection->src_pipe_index = pipe_connect->src_pipe_index;
+		sps_connection->dest_pipe_index = sps_out_params.ipa_ep_idx;
+		*(ipa_params->src_pipe) = sps_connection->src_pipe_index;
+		pipe_connect->dst_pipe_index = sps_out_params.ipa_ep_idx;
+		pr_debug("%s: BAM pipe usb[%x]->ipa[%x] connection\n",
+			__func__,
+			pipe_connect->src_pipe_index,
+			pipe_connect->dst_pipe_index);
 	} else {
 		/* IPA src, USB dest */
-		connection->mode = SPS_MODE_DEST;
-		connection_params->prod_clnt_hdl = clnt_hdl;
-		connection->source = sps_out_params.ipa_bam_hdl;
-		connection->destination = usb_handle;
-		connection->src_pipe_index = sps_out_params.ipa_ep_idx;
-		connection->dest_pipe_index = pipe_connection->dst_pipe_index;
-		*(connection_params->dst_pipe) = connection->dest_pipe_index;
+		sps_connection->mode = SPS_MODE_DEST;
+		ipa_params->prod_clnt_hdl = clnt_hdl;
+		sps_connection->source = sps_out_params.ipa_bam_hdl;
+		sps_connection->destination = usb_handle;
+		sps_connection->src_pipe_index = sps_out_params.ipa_ep_idx;
+		sps_connection->dest_pipe_index = pipe_connect->dst_pipe_index;
+		*(ipa_params->dst_pipe) = sps_connection->dest_pipe_index;
+		pipe_connect->src_pipe_index = sps_out_params.ipa_ep_idx;
+		pr_debug("%s: BAM pipe ipa[%x]->usb[%x] connection\n",
+			__func__,
+			pipe_connect->src_pipe_index,
+			pipe_connect->dst_pipe_index);
 	}
 
-	connection->data = sps_out_params.data;
-	connection->desc = sps_out_params.desc;
-	connection->event_thresh = 16;
-	connection->options = SPS_O_AUTO_ENABLE;
+	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;
 
-	ret = sps_connect(*pipe, connection);
+	ret = sps_connect(*pipe, sps_connection);
 	if (ret < 0) {
 		pr_err("%s: sps_connect failed %d\n", __func__, ret);
 		goto error;
@@ -382,92 +403,85 @@
 	return ret;
 }
 
-static int disconnect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir)
+static int disconnect_pipe(u8 idx)
 {
-	struct msm_usb_bam_platform_data *pdata =
-				usb_bam_pdev->dev.platform_data;
-	struct usb_bam_pipe_connect *pipe_connection =
-			&msm_usb_bam_connections_info
-			[pdata->usb_active_bam][connection_idx][pipe_dir];
-	struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
-	struct sps_connect *connection =
-		&sps_connections[connection_idx][pipe_dir];
+	struct usb_bam_pipe_connect *pipe_connect =
+		&usb_bam_connections[idx];
+	struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx];
+	struct sps_connect *sps_connection =
+		&ctx.usb_bam_sps.sps_connections[idx];
 
 	sps_disconnect(pipe);
 	sps_free_endpoint(pipe);
 
-	if (pipe_connection->mem_type == SYSTEM_MEM) {
+	if (pipe_connect->mem_type == SYSTEM_MEM) {
 		pr_debug("%s: Freeing system memory used by PIPE\n", __func__);
-		dma_free_coherent(&usb_bam_pdev->dev, connection->data.size,
-			  connection->data.base, connection->data.phys_base);
-		dma_free_coherent(&usb_bam_pdev->dev, connection->desc.size,
-			  connection->desc.base, connection->desc.phys_base);
-	} else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+		if (sps_connection->data.phys_base)
+			dma_free_coherent(&ctx.usb_bam_pdev->dev,
+					sps_connection->data.size,
+					sps_connection->data.base,
+					sps_connection->data.phys_base);
+		if (sps_connection->desc.phys_base)
+			dma_free_coherent(&ctx.usb_bam_pdev->dev,
+					sps_connection->desc.size,
+					sps_connection->desc.base,
+					sps_connection->desc.phys_base);
+	} else if (pipe_connect->mem_type == USB_PRIVATE_MEM) {
 		pr_debug("Freeing USB private memory used by BAM PIPE\n");
-		writel_relaxed(0x0, qscratch_ram1_reg);
-		iounmap(connection->data.base);
-		iounmap(connection->desc.base);
-		clk_disable_unprepare(mem_clk);
-		clk_disable_unprepare(mem_iface_clk);
+		writel_relaxed(0x0, ctx.qscratch_ram1_reg);
+		iounmap(sps_connection->data.base);
+		iounmap(sps_connection->desc.base);
+		clk_disable_unprepare(ctx.mem_clk);
+		clk_disable_unprepare(ctx.mem_iface_clk);
 	}
 
-	connection->options &= ~SPS_O_AUTO_ENABLE;
+	sps_connection->options &= ~SPS_O_AUTO_ENABLE;
 	return 0;
 }
 
-int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
+int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
 {
-	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
-	struct msm_usb_bam_platform_data *pdata =
-				usb_bam_pdev->dev.platform_data;
-	int usb_active_bam = pdata->usb_active_bam;
 	int ret;
+	enum usb_bam bam;
+	struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
+	struct msm_usb_bam_platform_data *pdata;
 
-	if (!usb_bam_pdev) {
+	if (!ctx.usb_bam_pdev) {
 		pr_err("%s: usb_bam device not found\n", __func__);
 		return -ENODEV;
 	}
 
-	if (idx >= CONNECTIONS_NUM) {
-		pr_err("%s: Invalid connection index\n",
-			__func__);
-		return -EINVAL;
-	}
+	pdata = ctx.usb_bam_pdev->dev.platform_data;
 
-	if (connection->src_enabled && connection->dst_enabled) {
+	if (pipe_connect->enabled) {
 		pr_debug("%s: connection %d was already established\n",
 			__func__, idx);
 		return 0;
 	}
-	connection->src_pipe = src_pipe_idx;
-	connection->dst_pipe = dst_pipe_idx;
-	connection->idx = idx;
+
+	if (!bam_pipe_idx) {
+		pr_err("%s: invalid bam_pipe_idx\n", __func__);
+		return -EINVAL;
+	}
+	if (idx < 0 || idx > ctx.max_connections) {
+		pr_err("idx is wrong %d", idx);
+		return -EINVAL;
+	}
+	bam = pipe_connect->bam_type;
+	if (bam < 0)
+		return -EINVAL;
 
 	/* Check if BAM requires RESET before connect */
-	if (pdata->reset_on_connect[usb_active_bam] == true)
-		sps_device_reset(h_bam);
+	if (pdata->reset_on_connect[bam] == true)
+		sps_device_reset(ctx.h_bam[bam]);
 
-	if (src_pipe_idx) {
-		/* open USB -> Peripheral pipe */
-		ret = connect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
-						   connection->src_pipe);
-		if (ret) {
-			pr_err("%s: src pipe connection failure\n", __func__);
-			return ret;
-		}
-		connection->src_enabled = 1;
+	ret = connect_pipe(idx, bam_pipe_idx);
+	if (ret) {
+		pr_err("%s: pipe connection[%d] failure\n", __func__, idx);
+		return ret;
 	}
 
-	if (dst_pipe_idx) {
-		/* open Peripheral -> USB pipe */
-		ret = connect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
-						   connection->dst_pipe);
-		if (ret) {
-			pr_err("%s: dst pipe connection failure\n", __func__);
-			return ret;
-		}
-		connection->dst_enabled = 1;
-	}
+	pipe_connect->enabled = 1;
 
 	return 0;
 }
@@ -531,64 +545,65 @@
 
 int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
 {
-	u8 idx = ipa_params->idx;
-	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+	u8 idx;
+	struct usb_bam_pipe_connect *pipe_connect;
 	int ret;
 
-	if (idx >= CONNECTIONS_NUM) {
-		pr_err("%s: Invalid connection index\n",
+	if (!ipa_params) {
+		pr_err("%s: Invalid ipa params\n",
 			__func__);
 		return -EINVAL;
 	}
 
-	if ((connection->src_enabled &&
-		 ipa_params->dir == USB_TO_PEER_PERIPHERAL) ||
-		 (connection->dst_enabled &&
-		  ipa_params->dir == PEER_PERIPHERAL_TO_USB)) {
+	if (ipa_params->dir == USB_TO_PEER_PERIPHERAL)
+		idx = ipa_params->src_idx;
+	else
+		idx = ipa_params->dst_idx;
+
+	if (idx >= ctx.max_connections) {
+		pr_err("%s: Invalid connection index\n",
+			__func__);
+		return -EINVAL;
+	}
+	pipe_connect = &usb_bam_connections[idx];
+
+	if (pipe_connect->enabled) {
 		pr_debug("%s: connection %d was already established\n",
 			__func__, idx);
 		return 0;
 	}
 
-	if (ipa_params->dir == USB_TO_PEER_PERIPHERAL)
-		connection->src_pipe = ipa_params->src_pipe;
-	else
-		connection->dst_pipe = ipa_params->dst_pipe;
-
-	connection->idx = idx;
-
+	ret = connect_pipe_ipa(idx, ipa_params);
 	ipa_rm_request_resource(IPA_CLIENT_USB_PROD);
 
-	ret = connect_pipe_ipa(ipa_params);
 	if (ret) {
 		pr_err("%s: dst pipe connection failure\n", __func__);
 		return ret;
 	}
 
-	if (ipa_params->dir == USB_TO_PEER_PERIPHERAL)
-		connection->src_enabled = 1;
-	else
-		connection->dst_enabled = 1;
+	pipe_connect->enabled = 1;
 
 	return 0;
 }
+EXPORT_SYMBOL(usb_bam_connect_ipa);
 
 int usb_bam_client_ready(bool ready)
 {
 	spin_lock(&usb_bam_lock);
-	if (peer_handhskae_info.client_ready == ready) {
+	if (peer_handshake_info.client_ready == ready) {
 		pr_debug("%s: client state is already %d\n",
 			__func__, ready);
 		spin_unlock(&usb_bam_lock);
 		return 0;
 	}
 
-	peer_handhskae_info.client_ready = ready;
+	peer_handshake_info.client_ready = ready;
 
 	spin_unlock(&usb_bam_lock);
-	if (!queue_work(usb_bam_wq, &peer_handhskae_info.reset_event.event_w)) {
+	if (!queue_work(ctx.usb_bam_wq,
+			&peer_handshake_info.reset_event.event_w)) {
 		spin_lock(&usb_bam_lock);
-		peer_handhskae_info.pending_work++;
+		peer_handshake_info.pending_work++;
 		spin_unlock(&usb_bam_lock);
 	}
 
@@ -608,65 +623,65 @@
 	struct usb_bam_event_info *wake_event_info =
 		(struct usb_bam_event_info *)notify->user;
 
-	queue_work(usb_bam_wq, &wake_event_info->event_w);
+	queue_work(ctx.usb_bam_wq, &wake_event_info->event_w);
 }
 
 static void usb_bam_sm_work(struct work_struct *w)
 {
 	pr_debug("%s: current state: %d\n", __func__,
-		peer_handhskae_info.state);
+		peer_handshake_info.state);
 
 	spin_lock(&usb_bam_lock);
 
-	switch (peer_handhskae_info.state) {
+	switch (peer_handshake_info.state) {
 	case USB_BAM_SM_INIT:
-		if (peer_handhskae_info.client_ready) {
+		if (peer_handshake_info.client_ready) {
 			spin_unlock(&usb_bam_lock);
 			smsm_change_state(SMSM_APPS_STATE, 0,
 				SMSM_USB_PLUG_UNPLUG);
 			spin_lock(&usb_bam_lock);
-			peer_handhskae_info.state = USB_BAM_SM_PLUG_NOTIFIED;
+			peer_handshake_info.state = USB_BAM_SM_PLUG_NOTIFIED;
 		}
 		break;
 	case USB_BAM_SM_PLUG_NOTIFIED:
-		if (peer_handhskae_info.ack_received) {
-			peer_handhskae_info.state = USB_BAM_SM_PLUG_ACKED;
-			peer_handhskae_info.ack_received = 0;
+		if (peer_handshake_info.ack_received) {
+			peer_handshake_info.state = USB_BAM_SM_PLUG_ACKED;
+			peer_handshake_info.ack_received = 0;
 		}
 		break;
 	case USB_BAM_SM_PLUG_ACKED:
-		if (!peer_handhskae_info.client_ready) {
+		if (!peer_handshake_info.client_ready) {
 			spin_unlock(&usb_bam_lock);
 			smsm_change_state(SMSM_APPS_STATE,
 				SMSM_USB_PLUG_UNPLUG, 0);
 			spin_lock(&usb_bam_lock);
-			peer_handhskae_info.state = USB_BAM_SM_UNPLUG_NOTIFIED;
+			peer_handshake_info.state = USB_BAM_SM_UNPLUG_NOTIFIED;
 		}
 		break;
 	case USB_BAM_SM_UNPLUG_NOTIFIED:
-		if (peer_handhskae_info.ack_received) {
+		if (peer_handshake_info.ack_received) {
 			spin_unlock(&usb_bam_lock);
-			peer_handhskae_info.reset_event.
-				callback(peer_handhskae_info.reset_event.param);
+			peer_handshake_info.reset_event.
+				callback(peer_handshake_info.reset_event.param);
 			spin_lock(&usb_bam_lock);
-			peer_handhskae_info.state = USB_BAM_SM_INIT;
-			peer_handhskae_info.ack_received = 0;
+			peer_handshake_info.state = USB_BAM_SM_INIT;
+			peer_handshake_info.ack_received = 0;
 		}
 		break;
 	}
 
-	if (peer_handhskae_info.pending_work) {
-		peer_handhskae_info.pending_work--;
+	if (peer_handshake_info.pending_work) {
+		peer_handshake_info.pending_work--;
 		spin_unlock(&usb_bam_lock);
-		queue_work(usb_bam_wq,
-			&peer_handhskae_info.reset_event.event_w);
+		queue_work(ctx.usb_bam_wq,
+			&peer_handshake_info.reset_event.event_w);
 		spin_lock(&usb_bam_lock);
 	}
 	spin_unlock(&usb_bam_lock);
 }
 
-static void usb_bam_ack_toggle_cb(void *priv, uint32_t old_state,
-	uint32_t new_state)
+static void usb_bam_ack_toggle_cb(void *priv,
+	uint32_t old_state, uint32_t new_state)
 {
 	static int last_processed_state;
 	int current_state;
@@ -681,27 +696,35 @@
 	}
 
 	last_processed_state = current_state;
-	peer_handhskae_info.ack_received = true;
+	peer_handshake_info.ack_received = true;
 
 	spin_unlock(&usb_bam_lock);
-	if (!queue_work(usb_bam_wq, &peer_handhskae_info.reset_event.event_w)) {
+	if (!queue_work(ctx.usb_bam_wq,
+			&peer_handshake_info.reset_event.event_w)) {
 		spin_lock(&usb_bam_lock);
-		peer_handhskae_info.pending_work++;
+		peer_handshake_info.pending_work++;
 		spin_unlock(&usb_bam_lock);
 	}
 }
 
-int usb_bam_register_wake_cb(u8 idx,
-	int (*callback)(void *user), void* param)
+int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
+	void *param)
 {
-	struct sps_pipe *pipe = sps_pipes[idx][PEER_PERIPHERAL_TO_USB];
-	struct sps_connect *sps_connection =
-		&sps_connections[idx][PEER_PERIPHERAL_TO_USB];
-	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
-	struct usb_bam_event_info *wake_event_info =
-		&connection->wake_event;
+	struct sps_pipe *pipe = ctx.usb_bam_sps.sps_pipes[idx];
+	struct sps_connect *sps_connection;
+	struct usb_bam_pipe_connect *pipe_connect;
+	struct usb_bam_event_info *wake_event_info;
 	int ret;
 
+	if (idx < 0 || idx > ctx.max_connections) {
+		pr_err("%s:idx is wrong %d", __func__, idx);
+		return -EINVAL;
+	}
+	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->param = param;
 	wake_event_info->callback = callback;
 	wake_event_info->event.mode = SPS_TRIGGER_CALLBACK;
@@ -717,7 +740,7 @@
 
 	sps_connection->options = callback ?
 		(SPS_O_AUTO_ENABLE | SPS_O_WAKEUP | SPS_O_WAKEUP_IS_ONESHOT) :
-			SPS_O_AUTO_ENABLE;
+		SPS_O_AUTO_ENABLE;
 	ret = sps_set_config(pipe, sps_connection);
 	if (ret) {
 		pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
@@ -727,14 +750,13 @@
 	return 0;
 }
 
-int usb_bam_register_peer_reset_cb(u8 idx,
-	 int (*callback)(void *), void *param)
+int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param)
 {
 	u32 ret = 0;
 
 	if (callback) {
-		peer_handhskae_info.reset_event.param = param;
-		peer_handhskae_info.reset_event.callback = callback;
+		peer_handshake_info.reset_event.param = param;
+		peer_handshake_info.reset_event.callback = callback;
 
 		ret = smsm_state_cb_register(SMSM_MODEM_STATE,
 			SMSM_USB_PLUG_UNPLUG, usb_bam_ack_toggle_cb, NULL);
@@ -748,8 +770,8 @@
 					SMSM_USB_PLUG_UNPLUG);
 		}
 	} else {
-		peer_handhskae_info.reset_event.param = NULL;
-		peer_handhskae_info.reset_event.callback = NULL;
+		peer_handshake_info.reset_event.param = NULL;
+		peer_handshake_info.reset_event.callback = NULL;
 		smsm_state_cb_deregister(SMSM_MODEM_STATE,
 			SMSM_USB_PLUG_UNPLUG, usb_bam_ack_toggle_cb, NULL);
 	}
@@ -759,126 +781,129 @@
 
 int usb_bam_disconnect_pipe(u8 idx)
 {
-	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+	struct usb_bam_pipe_connect *pipe_connect;
 	int ret;
 
-	if (idx >= CONNECTIONS_NUM) {
-		pr_err("%s: Invalid connection index\n",
-			__func__);
-		return -EINVAL;
-	}
+	pipe_connect = &usb_bam_connections[idx];
 
-	if (!connection->src_enabled && !connection->dst_enabled) {
+	if (!pipe_connect->enabled) {
 		pr_debug("%s: connection %d isn't enabled\n",
 			__func__, idx);
 		return 0;
 	}
 
-	if (connection->src_enabled) {
-		/* close USB -> Peripheral pipe */
-		ret = disconnect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL);
-		if (ret) {
-			pr_err("%s: src pipe connection failure\n", __func__);
-			return ret;
-		}
-		connection->src_enabled = 0;
-	}
-	if (connection->dst_enabled) {
-		/* close Peripheral -> USB pipe */
-		ret = disconnect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB);
-		if (ret) {
-			pr_err("%s: dst pipe connection failure\n", __func__);
-			return ret;
-		}
-		connection->dst_enabled = 0;
+	ret = disconnect_pipe(idx);
+	if (ret) {
+		pr_err("%s: src pipe connection failure\n", __func__);
+		return ret;
 	}
 
-	connection->src_pipe = 0;
-	connection->dst_pipe = 0;
+	pipe_connect->enabled = 0;
 
 	return 0;
 }
 
-int usb_bam_disconnect_ipa(u8 idx,
-		struct usb_bam_connect_ipa_params *ipa_params)
+int usb_bam_disconnect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
 {
-	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
 	int ret;
+	u8 idx;
+	struct usb_bam_pipe_connect *pipe_connect;
+	struct sps_connect *sps_connection;
 
-	if (!usb_bam_pdev) {
-		pr_err("%s: usb_bam device not found\n", __func__);
-		return -ENODEV;
-	}
-
-	if (idx >= CONNECTIONS_NUM) {
-		pr_err("%s: Invalid connection index\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	/* Currently just calls ipa_disconnect, no sps pipes
-	   disconenction support */
-
-	/* close IPA -> USB pipe */
-	if (connection->dst_pipe) {
+	if (ipa_params->prod_clnt_hdl) {
+		/* close USB -> IPA pipe */
+		idx = ipa_params->dst_idx;
 		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;
+
+		ret = usb_bam_disconnect_pipe(idx);
+		if (ret) {
+			pr_err("%s: failure to disconnect pipe %d\n",
+				__func__, idx);
+			return ret;
+		}
 	}
-	/* close USB -> IPA pipe */
-	if (connection->src_pipe) {
+	if (ipa_params->cons_clnt_hdl) {
+		/* close IPA -> USB pipe */
+		idx = ipa_params->src_idx;
 		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;
+
+		ret = usb_bam_disconnect_pipe(idx);
+		if (ret) {
+			pr_err("%s: failure to disconnect pipe %d\n",
+				__func__, idx);
+			return ret;
+		}
 	}
 
 	ipa_rm_release_resource(IPA_CLIENT_USB_PROD);
 	return 0;
-
 }
+EXPORT_SYMBOL(usb_bam_disconnect_ipa);
 
-int usb_bam_reset(void)
+int usb_bam_a2_reset(void)
 {
-	struct usb_bam_connect_info *connection;
+	struct usb_bam_pipe_connect *pipe_connect;
 	int i;
 	int ret = 0, ret_int;
-	bool reconnect[CONNECTIONS_NUM];
-	u32 *reconnect_src_pipe[CONNECTIONS_NUM];
-	u32 *reconnect_dst_pipe[CONNECTIONS_NUM];
+	u8 bam = -1;
+	int reconnect_pipe_idx[ctx.max_connections];
 
-	/* Disconnect all pipes */
-	for (i = 0; i < CONNECTIONS_NUM; i++) {
-		connection = &usb_bam_connections[i];
-		reconnect[i] = connection->src_enabled ||
-			connection->dst_enabled;
-		reconnect_src_pipe[i] = connection->src_pipe;
-		reconnect_dst_pipe[i] = connection->dst_pipe;
+	for (i = 0; i < ctx.max_connections; i++)
+		reconnect_pipe_idx[i] = -1;
 
-		ret_int = usb_bam_disconnect_pipe(i);
-		if (ret_int) {
-			pr_err("%s: failure to connect pipe %d\n",
-				__func__, i);
-			ret = ret_int;
-			continue;
+	/* Disconnect a2 pipes */
+	for (i = 0; i < ctx.max_connections; i++) {
+		pipe_connect = &usb_bam_connections[i];
+		if (strnstr(pipe_connect->name, "a2", USB_BAM_MAX_STR_LEN) &&
+				pipe_connect->enabled) {
+			if (pipe_connect->dir == USB_TO_PEER_PERIPHERAL)
+				reconnect_pipe_idx[i] =
+					pipe_connect->src_pipe_index;
+			else
+				reconnect_pipe_idx[i] =
+					pipe_connect->dst_pipe_index;
+
+			bam = pipe_connect->bam_type;
+			if (bam < 0) {
+				ret = -EINVAL;
+				continue;
+			}
+			ret_int = usb_bam_disconnect_pipe(i);
+			if (ret_int) {
+				pr_err("%s: failure to connect pipe %d\n",
+					__func__, i);
+				ret = ret_int;
+				continue;
+			}
 		}
 	}
-
-	/* Reset USB/HSIC BAM */
-	if (sps_device_reset(h_bam))
+	/* Reset A2 (USB/HSIC) BAM */
+	if (bam != -1 && sps_device_reset(ctx.h_bam[bam]))
 		pr_err("%s: BAM reset failed\n", __func__);
 
-	/* Reconnect all pipes */
-	for (i = 0; i < CONNECTIONS_NUM; i++) {
-		connection = &usb_bam_connections[i];
-		if (reconnect[i]) {
-			ret_int = usb_bam_connect(i, reconnect_src_pipe[i],
-				reconnect_dst_pipe[i]);
+	/* Reconnect A2 pipes */
+	for (i = 0; i < ctx.max_connections; i++) {
+		pipe_connect = &usb_bam_connections[i];
+		if (reconnect_pipe_idx[i] != -1) {
+			ret_int = usb_bam_connect(i, &reconnect_pipe_idx[i]);
 			if (ret_int) {
 				pr_err("%s: failure to reconnect pipe %d\n",
 					__func__, i);
@@ -891,134 +916,23 @@
 	return ret;
 }
 
-static int update_connections_info(struct device_node *node, int bam,
-	int conn_num, int dir, enum usb_pipe_mem_type mem_type)
-{
-	u32 rc;
-	char *key = NULL;
-	uint32_t val = 0;
-
-	struct usb_bam_pipe_connect *pipe_connection;
-
-	pipe_connection = &msm_usb_bam_connections_info[bam][conn_num][dir];
-
-	pipe_connection->mem_type = mem_type;
-
-	key = "qcom,src-bam-physical-address";
-	rc = of_property_read_u32(node, key, &val);
-	if (!rc)
-		pipe_connection->src_phy_addr = val;
-
-	key = "qcom,src-bam-pipe-index";
-	rc = of_property_read_u32(node, key, &val);
-	if (!rc)
-		pipe_connection->src_pipe_index = val;
-
-	key = "qcom,dst-bam-physical-address";
-	rc = of_property_read_u32(node, key, &val);
-	if (!rc)
-		pipe_connection->dst_phy_addr = val;
-
-	key = "qcom,dst-bam-pipe-index";
-	rc = of_property_read_u32(node, key, &val);
-	if (!rc)
-		pipe_connection->dst_pipe_index = val;
-
-	key = "qcom,data-fifo-offset";
-	rc = of_property_read_u32(node, key, &val);
-	if (!rc)
-		pipe_connection->data_fifo_base_offset = val;
-
-	key = "qcom,data-fifo-size";
-	rc = of_property_read_u32(node, key, &val);
-	if (rc)
-		goto err;
-	pipe_connection->data_fifo_size = val;
-
-	key = "qcom,descriptor-fifo-offset";
-	rc = of_property_read_u32(node, key, &val);
-	if (!rc)
-		pipe_connection->desc_fifo_base_offset = val;
-
-	key = "qcom,descriptor-fifo-size";
-	rc = of_property_read_u32(node, key, &val);
-	if (rc)
-		goto err;
-	pipe_connection->desc_fifo_size = val;
-
-	return 0;
-
-err:
-	pr_err("%s: Error in name %s key %s\n", __func__,
-		node->full_name, key);
-	return -EFAULT;
-}
-
-static int usb_bam_update_conn_array_index(struct platform_device *pdev,
-		void *buff, int bam_max, int conn_max, int pipe_dirs)
-{
-	int bam_num, conn_num;
-	struct usb_bam_pipe_connect *bam_connection_arr = buff;
-
-	msm_usb_bam_connections_info = devm_kzalloc(&pdev->dev,
-		bam_max * sizeof(struct usb_bam_pipe_connect **),
-		GFP_KERNEL);
-
-	if (!msm_usb_bam_connections_info)
-		return -ENOMEM;
-
-	for (bam_num = 0; bam_num < bam_max; bam_num++) {
-		msm_usb_bam_connections_info[bam_num] =
-			devm_kzalloc(&pdev->dev, conn_max *
-			sizeof(struct usb_bam_pipe_connect *),
-			GFP_KERNEL);
-		if (!msm_usb_bam_connections_info[bam_num])
-			return -ENOMEM;
-
-		for (conn_num = 0; conn_num < conn_max; conn_num++)
-			msm_usb_bam_connections_info[bam_num][conn_num] =
-				bam_connection_arr +
-				(bam_num * conn_max * pipe_dirs) +
-				(conn_num * pipe_dirs);
-	}
-
-	return 0;
-}
-
 static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
 	struct platform_device *pdev)
 {
 	struct msm_usb_bam_platform_data *pdata;
 	struct device_node *node = pdev->dev.of_node;
-	int conn_num, bam;
-	u8 dir;
-	u8 ncolumns = 2;
-	int bam_amount, rc = 0;
-	u32 pipe_entry = 0;
-	char *key = NULL;
-	enum usb_pipe_mem_type mem_type;
+	int rc = 0;
+	u8 i = 0;
 	bool reset_bam;
+	enum usb_bam bam;
 
+	ctx.max_connections = 0;
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
 		pr_err("unable to allocate platform data\n");
 		return NULL;
 	}
 
-	rc = of_property_read_u32(node, "qcom,usb-active-bam",
-		&pdata->usb_active_bam);
-	if (rc) {
-		pr_err("Invalid usb active bam property\n");
-		return NULL;
-	}
-
-	rc = of_property_read_u32(node, "qcom,usb-total-bam-num",
-		&pdata->total_bam_num);
-	if (rc) {
-		pr_err("Invalid usb total bam num property\n");
-		return NULL;
-	}
-
 	rc = of_property_read_u32(node, "qcom,usb-bam-num-pipes",
 		&pdata->usb_bam_num_pipes);
 	if (rc) {
@@ -1032,91 +946,113 @@
 		pr_debug("%s: Invalid usb base address property\n", __func__);
 
 	pdata->ignore_core_reset_ack = of_property_read_bool(node,
-					"qcom,ignore-core-reset-ack");
+		"qcom,ignore-core-reset-ack");
 
 	pdata->disable_clk_gating = of_property_read_bool(node,
-					"qcom,disable-clk-gating");
+		"qcom,disable-clk-gating");
 
 	for_each_child_of_node(pdev->dev.of_node, node)
-		pipe_entry++;
+		ctx.max_connections++;
 
-	/*
-	 * we need to know the number of connection, so we will know
-	 * how much memory to allocate
-	 */
-	conn_num = pipe_entry / 2;
-	bam_amount = pdata->total_bam_num;
-
-	if (conn_num <= 0 || conn_num >= pdata->usb_bam_num_pipes)
+	if (!ctx.max_connections) {
+		pr_err("%s: error: max_connections is zero\n", __func__);
 		goto err;
+	}
 
-
-	/* alloc msm_usb_bam_connections_info */
-	bam_connection_arr = devm_kzalloc(&pdev->dev, bam_amount *
-		conn_num * ncolumns *
+	usb_bam_connections = devm_kzalloc(&pdev->dev, ctx.max_connections *
 		sizeof(struct usb_bam_pipe_connect), GFP_KERNEL);
 
-	if (!bam_connection_arr)
-		goto err;
-
-	rc = usb_bam_update_conn_array_index(pdev, bam_connection_arr,
-					bam_amount, conn_num, ncolumns);
-	if (rc)
-		goto err;
+	if (!usb_bam_connections) {
+		pr_err("%s: devm_kzalloc failed(%d)\n", __func__,  __LINE__);
+		return NULL;
+	}
 
 	/* retrieve device tree parameters */
 	for_each_child_of_node(pdev->dev.of_node, node) {
-		const char *str;
-
-		key = "qcom,usb-bam-type";
-		rc = of_property_read_u32(node, key, &bam);
+		rc = of_property_read_string(node, "label",
+			&usb_bam_connections[i].name);
 		if (rc)
 			goto err;
 
-		key = "qcom,usb-bam-mem-type";
-		rc = of_property_read_u32(node, key, &mem_type);
+		rc = of_property_read_u32(node, "qcom,usb-bam-mem-type",
+			&usb_bam_connections[i].mem_type);
 		if (rc)
 			goto err;
 
-		if (mem_type == USB_PRIVATE_MEM &&
-			!pdata->usb_base_address)
-			goto err;
-
-		rc = of_property_read_string(node, "label", &str);
-		if (rc) {
-			pr_err("Cannot read string\n");
+		if (usb_bam_connections[i].mem_type == USB_PRIVATE_MEM &&
+			!pdata->usb_base_address) {
+			pr_err("%s: base address is missing for private mem\n",
+				__func__);
 			goto err;
 		}
+
+		rc = of_property_read_u32(node, "qcom,bam-type",
+			&usb_bam_connections[i].bam_type);
+		if (rc) {
+			pr_err("%s: bam type is missing in device tree\n",
+				__func__);
+			goto err;
+		}
+
+		rc = of_property_read_u32(node, "qcom,peer-bam",
+			&usb_bam_connections[i].peer_bam);
+		if (rc) {
+			pr_err("%s: peer bam is missing in device tree\n",
+				__func__);
+			goto err;
+		}
+		rc = of_property_read_u32(node, "qcom,dir",
+			&usb_bam_connections[i].dir);
+		if (rc) {
+			pr_err("%s: direction is missing in device tree\n",
+				__func__);
+			goto err;
+		}
+
+		rc = of_property_read_u32(node, "qcom,pipe-num",
+			&usb_bam_connections[i].pipe_num);
+		if (rc) {
+			pr_err("%s: pipe num is missing in device tree\n",
+				__func__);
+			goto err;
+		}
+
 		reset_bam = of_property_read_bool(node,
-					"qcom,reset-bam-on-connect");
+			"qcom,reset-bam-on-connect");
 		if (reset_bam)
 			pdata->reset_on_connect[bam] = true;
 
-		if (strnstr(str, "usb-to", 30))
-			dir = USB_TO_PEER_PERIPHERAL;
-		else if (strnstr(str, "to-usb", 30))
-			dir = PEER_PERIPHERAL_TO_USB;
-		else
-			goto err;
+		of_property_read_u32(node, "qcom,src-bam-physical-address",
+			&usb_bam_connections[i].src_phy_addr);
 
-		/* Check if connection type is supported */
-		if (!strcmp(str, "usb-to-peri-qdss-dwc3") ||
-			!strcmp(str, "peri-to-usb-qdss-dwc3") ||
-			!strcmp(str, "usb-to-ipa") ||
-			!strcmp(str, "ipa-to-usb") ||
-			!strcmp(str, "usb-to-peri-qdss-hsusb") ||
-			!strcmp(str, "peri-to-usb-qdss-hsusb"))
-				conn_num = 0;
-		else
-			goto err;
+		of_property_read_u32(node, "qcom,src-bam-pipe-index",
+			&usb_bam_connections[i].src_pipe_index);
 
-		rc = update_connections_info(node, bam, conn_num,
-						dir, mem_type);
+		of_property_read_u32(node, "qcom,dst-bam-physical-address",
+			&usb_bam_connections[i].dst_phy_addr);
+
+		of_property_read_u32(node, "qcom,dst-bam-pipe-index",
+			&usb_bam_connections[i].dst_pipe_index);
+
+		of_property_read_u32(node, "qcom,data-fifo-offset",
+			&usb_bam_connections[i].data_fifo_base_offset);
+
+		rc = of_property_read_u32(node, "qcom,data-fifo-size",
+			&usb_bam_connections[i].data_fifo_size);
 		if (rc)
 			goto err;
+
+		of_property_read_u32(node, "qcom,descriptor-fifo-offset",
+			&usb_bam_connections[i].desc_fifo_base_offset);
+
+		rc = of_property_read_u32(node, "qcom,descriptor-fifo-size",
+			&usb_bam_connections[i].desc_fifo_size);
+		if (rc)
+			goto err;
+		i++;
 	}
 
-	pdata->connections = &msm_usb_bam_connections_info[0][0][0];
+	pdata->connections = usb_bam_connections;
 
 	return pdata;
 err:
@@ -1124,83 +1060,78 @@
 	return NULL;
 }
 
-static char *bam_enable_strings[3] = {
-	[SSUSB_BAM] = "ssusb",
-	[HSUSB_BAM] = "hsusb",
-	[HSIC_BAM]  = "hsic",
-};
-
-static int usb_bam_init(void)
+static int usb_bam_init(int bam_idx)
 {
-	int ret;
+	int ret, irq;
 	void *usb_virt_addr;
 	struct msm_usb_bam_platform_data *pdata =
-		usb_bam_pdev->dev.platform_data;
-	struct usb_bam_pipe_connect *pipe_connection =
-		&msm_usb_bam_connections_info[pdata->usb_active_bam][0][0];
+		ctx.usb_bam_pdev->dev.platform_data;
 	struct resource *res, *ram_resource;
-	int irq;
+	struct sps_bam_props props = ctx.usb_bam_sps.usb_props;
 
-	res = platform_get_resource_byname(usb_bam_pdev, IORESOURCE_MEM,
-				bam_enable_strings[pdata->usb_active_bam]);
+	pr_debug("%s: usb_bam_init - %s\n", __func__,
+		bam_enable_strings[bam_idx]);
+	res = platform_get_resource_byname(ctx.usb_bam_pdev, IORESOURCE_MEM,
+		bam_enable_strings[bam_idx]);
 	if (!res) {
-		dev_err(&usb_bam_pdev->dev, "Unable to get memory resource\n");
-		return -ENODEV;
+		dev_dbg(&ctx.usb_bam_pdev->dev, "bam not initialized\n");
+		return 0;
 	}
 
-	irq = platform_get_irq_byname(usb_bam_pdev,
-				bam_enable_strings[pdata->usb_active_bam]);
+	irq = platform_get_irq_byname(ctx.usb_bam_pdev,
+		bam_enable_strings[bam_idx]);
 	if (irq < 0) {
-		dev_err(&usb_bam_pdev->dev, "Unable to get IRQ resource\n");
+		dev_err(&ctx.usb_bam_pdev->dev, "Unable to get IRQ resource\n");
 		return irq;
 	}
 
-	usb_virt_addr = devm_ioremap(&usb_bam_pdev->dev, res->start,
-							 resource_size(res));
+	usb_virt_addr = devm_ioremap(&ctx.usb_bam_pdev->dev, res->start,
+		resource_size(res));
 	if (!usb_virt_addr) {
 		pr_err("%s: ioremap failed\n", __func__);
 		return -ENOMEM;
 	}
 
 	/* Check if USB3 pipe memory needs to be enabled */
-	if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+	if (bam_idx == SSUSB_BAM && bam_use_private_mem(bam_idx)) {
 		pr_debug("%s: Enabling USB private memory for: %s\n", __func__,
-				bam_enable_strings[pdata->usb_active_bam]);
+			bam_enable_strings[bam_idx]);
 
-		ram_resource = platform_get_resource_byname(usb_bam_pdev,
-					 IORESOURCE_MEM, "qscratch_ram1_reg");
+		ram_resource = platform_get_resource_byname(ctx.usb_bam_pdev,
+			IORESOURCE_MEM, "qscratch_ram1_reg");
 		if (!res) {
-			dev_err(&usb_bam_pdev->dev, "Unable to get qscratch\n");
+			dev_err(&ctx.usb_bam_pdev->dev, "Unable to get qscratch\n");
 			ret = -ENODEV;
 			goto free_bam_regs;
 		}
 
-		qscratch_ram1_reg = devm_ioremap(&usb_bam_pdev->dev,
-						ram_resource->start,
-						resource_size(ram_resource));
-		if (!qscratch_ram1_reg) {
+		ctx.qscratch_ram1_reg = devm_ioremap(&ctx.usb_bam_pdev->dev,
+			ram_resource->start,
+			resource_size(ram_resource));
+		if (!ctx.qscratch_ram1_reg) {
 			pr_err("%s: ioremap failed for qscratch\n", __func__);
 			ret = -ENOMEM;
 			goto free_bam_regs;
 		}
 	}
-	usb_props.phys_addr = res->start;
-	usb_props.virt_addr = usb_virt_addr;
-	usb_props.virt_size = resource_size(res);
-	usb_props.irq = irq;
-	usb_props.summing_threshold = USB_SUMMING_THRESHOLD;
-	usb_props.event_threshold = 512;
-	usb_props.num_pipes = pdata->usb_bam_num_pipes;
+	props.phys_addr = res->start;
+	props.virt_addr = usb_virt_addr;
+	props.virt_size = resource_size(res);
+	props.irq = irq;
+	props.summing_threshold = USB_THRESHOLD;
+	props.event_threshold = USB_THRESHOLD;
+	props.num_pipes = pdata->usb_bam_num_pipes;
 	/*
-	 * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
-	 * Hence, let BAM to ignore acknowledge from USB while resetting PIPE
-	 */
-	if (pdata->ignore_core_reset_ack && pdata->usb_active_bam != SSUSB_BAM)
-		usb_props.options = SPS_BAM_NO_EXT_P_RST;
-	if (pdata->disable_clk_gating)
-		usb_props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
+	* HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
+	* Hence, let BAM to ignore acknowledge from USB while resetting PIPE
+	*/
+	if (pdata->ignore_core_reset_ack && bam_idx != SSUSB_BAM)
+		props.options = SPS_BAM_NO_EXT_P_RST;
 
-	ret = sps_register_bam_device(&usb_props, &h_bam);
+	if (pdata->disable_clk_gating)
+		props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
+
+	ret = sps_register_bam_device(&props, &(ctx.h_bam[bam_idx]));
 	if (ret < 0) {
 		pr_err("%s: register bam error %d\n", __func__, ret);
 		ret = -EFAULT;
@@ -1210,61 +1141,46 @@
 	return 0;
 
 free_qscratch_reg:
-	iounmap(qscratch_ram1_reg);
+	iounmap(ctx.qscratch_ram1_reg);
 free_bam_regs:
 	iounmap(usb_virt_addr);
 
 	return ret;
 }
 
-static ssize_t
-usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
-		    char *buf)
+static int enable_usb_bams(struct platform_device *pdev)
 {
-	struct msm_usb_bam_platform_data *pdata = dev->platform_data;
-
-	if (!pdata)
-		return 0;
-	return scnprintf(buf, PAGE_SIZE, "%s\n",
-			 bam_enable_strings[pdata->usb_active_bam]);
-}
-
-static ssize_t usb_bam_store_enable(struct device *dev,
-				     struct device_attribute *attr,
-				     const char *buf, size_t count)
-{
-	struct msm_usb_bam_platform_data *pdata = dev->platform_data;
-	char str[10], *pstr;
 	int ret, i;
 
-	if (!pdata) {
-		dev_err(dev, "no usb_bam pdata found\n");
-		return -ENODEV;
-	}
-
-	strlcpy(str, buf, sizeof(str));
-	pstr = strim(str);
-
 	for (i = 0; i < ARRAY_SIZE(bam_enable_strings); i++) {
-		if (!strncmp(pstr, bam_enable_strings[i], sizeof(str)))
-			pdata->usb_active_bam = i;
+		ret = usb_bam_init(i);
+		if (ret) {
+			pr_err("failed to init usb bam %s\n",
+				bam_enable_strings[i]);
+			return ret;
+		}
 	}
 
-	dev_dbg(dev, "active_bam=%s\n",
-		bam_enable_strings[pdata->usb_active_bam]);
+	ctx.usb_bam_sps.sps_pipes = devm_kzalloc(&pdev->dev,
+		ctx.max_connections * sizeof(struct sps_pipe *),
+		GFP_KERNEL);
 
-	ret = usb_bam_init();
-	if (ret) {
-		dev_err(dev, "failed to initialize usb bam\n");
-		return ret;
+	if (!ctx.usb_bam_sps.sps_pipes) {
+		pr_err("%s: failed to allocate sps_pipes\n", __func__);
+		return -ENOMEM;
 	}
 
-	return count;
+	ctx.usb_bam_sps.sps_connections = devm_kzalloc(&pdev->dev,
+		ctx.max_connections * sizeof(struct sps_connect),
+		GFP_KERNEL);
+	if (!ctx.usb_bam_sps.sps_connections) {
+		pr_err("%s: failed to allocate sps_connections\n", __func__);
+		return -ENOMEM;
+	}
+
+	return 0;
 }
 
-static DEVICE_ATTR(enable, S_IWUSR | S_IRUSR, usb_bam_show_enable,
-		   usb_bam_store_enable);
-
 static int usb_bam_probe(struct platform_device *pdev)
 {
 	int ret, i;
@@ -1272,89 +1188,126 @@
 
 	dev_dbg(&pdev->dev, "usb_bam_probe\n");
 
-	for (i = 0; i < CONNECTIONS_NUM; i++) {
-		usb_bam_connections[i].src_enabled = 0;
-		usb_bam_connections[i].dst_enabled = 0;
-		INIT_WORK(&usb_bam_connections[i].wake_event.event_w,
-			usb_bam_work);
-	}
+	ctx.mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
+	if (IS_ERR(ctx.mem_clk))
 
-	spin_lock_init(&usb_bam_lock);
-	INIT_WORK(&peer_handhskae_info.reset_event.event_w, usb_bam_sm_work);
 
-	mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
-	if (IS_ERR(mem_clk))
 		dev_dbg(&pdev->dev, "failed to get mem_clock\n");
 
-	mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
-	if (IS_ERR(mem_iface_clk))
+	ctx.mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
+	if (IS_ERR(ctx.mem_iface_clk))
 		dev_dbg(&pdev->dev, "failed to get mem_iface_clock\n");
 
 	if (pdev->dev.of_node) {
 		dev_dbg(&pdev->dev, "device tree enabled\n");
 		pdata = usb_bam_dt_to_pdata(pdev);
 		if (!pdata)
-			return -ENOMEM;
+			return -EINVAL;
 		pdev->dev.platform_data = pdata;
 	} else if (!pdev->dev.platform_data) {
 		dev_err(&pdev->dev, "missing platform_data\n");
 		return -ENODEV;
 	} else {
 		pdata = pdev->dev.platform_data;
-		ret = usb_bam_update_conn_array_index(pdev, pdata->connections,
-				MAX_BAMS, CONNECTIONS_NUM, 2);
-		if (ret) {
-			pr_err("usb_bam_update_conn_array_index failed\n");
-			return ret;
-		}
+		usb_bam_connections = pdata->connections;
+		ctx.max_connections = pdata->max_connections;
 	}
-	usb_bam_pdev = pdev;
+	ctx.usb_bam_pdev = pdev;
 
-	ret = device_create_file(&pdev->dev, &dev_attr_enable);
-	if (ret)
-		dev_err(&pdev->dev, "failed to create device file\n");
+	for (i = 0; i < ctx.max_connections; i++) {
+		usb_bam_connections[i].enabled = 0;
+		INIT_WORK(&usb_bam_connections[i].wake_event.event_w,
+			usb_bam_work);
+	}
 
-	usb_bam_wq = alloc_workqueue("usb_bam_wq",
+	spin_lock_init(&usb_bam_lock);
+	INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
+
+	ctx.usb_bam_wq = alloc_workqueue("usb_bam_wq",
 		WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
-	if (!usb_bam_wq) {
+	if (!ctx.usb_bam_wq) {
 		pr_err("unable to create workqueue usb_bam_wq\n");
 		return -ENOMEM;
 	}
 
+	ret = enable_usb_bams(pdev);
+	if (ret) {
+		destroy_workqueue(ctx.usb_bam_wq);
+		return ret;
+	}
 	usb_bam_ipa_create_resources();
 
 	return ret;
 }
 
-void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
-	u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+int usb_bam_get_qdss_idx(u8 num)
+{
+	return usb_bam_get_connection_idx(ctx.qdss_core_name, QDSS_P_BAM,
+		PEER_PERIPHERAL_TO_USB, num);
+}
+EXPORT_SYMBOL(usb_bam_get_qdss_idx);
+
+void usb_bam_set_qdss_core(const char *qdss_core)
+{
+	strlcpy(ctx.qdss_core_name, qdss_core, USB_BAM_MAX_STR_LEN);
+}
+
+int get_bam2bam_connection_info(u8 idx, u32 *usb_bam_handle,
+	u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
 	struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
 {
-	struct sps_connect *connection =
-		&sps_connections[conn_idx][pipe_dir];
+	struct usb_bam_pipe_connect *pipe_connect = &usb_bam_connections[idx];
+	enum usb_bam_pipe_dir dir = pipe_connect->dir;
+	struct sps_connect *sps_connection =
+		&ctx.usb_bam_sps.sps_connections[idx];
 
-
-	if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
-		*usb_bam_handle = connection->source;
-		*usb_bam_pipe_idx = connection->src_pipe_index;
-		*peer_pipe_idx = connection->dest_pipe_index;
+	if (dir == USB_TO_PEER_PERIPHERAL) {
+		*usb_bam_handle = sps_connection->source;
+		*usb_bam_pipe_idx = sps_connection->src_pipe_index;
+		*peer_pipe_idx = sps_connection->dest_pipe_index;
 	} else {
-		*usb_bam_handle = connection->destination;
-		*usb_bam_pipe_idx = connection->dest_pipe_index;
-		*peer_pipe_idx = connection->src_pipe_index;
+		*usb_bam_handle = sps_connection->destination;
+		*usb_bam_pipe_idx = sps_connection->dest_pipe_index;
+		*peer_pipe_idx = sps_connection->src_pipe_index;
 	}
 	if (data_fifo)
-		memcpy(data_fifo, &data_mem_buf[conn_idx][pipe_dir],
-			sizeof(struct sps_mem_buffer));
+		memcpy(data_fifo, &pipe_connect->data_mem_buf,
+		sizeof(struct sps_mem_buffer));
 	if (desc_fifo)
-		memcpy(desc_fifo, &desc_mem_buf[conn_idx][pipe_dir],
-			sizeof(struct sps_mem_buffer));
+		memcpy(desc_fifo, &pipe_connect->desc_mem_buf,
+		sizeof(struct sps_mem_buffer));
+	return 0;
 }
 EXPORT_SYMBOL(get_bam2bam_connection_info);
 
+
+int usb_bam_get_connection_idx(const char *core_name, enum peer_bam client,
+	enum usb_bam_pipe_dir dir, u32 num)
+{
+	u8 i;
+	int bam_type;
+
+	bam_type = get_bam_type_from_core_name(core_name);
+	if (bam_type < 0)
+		return -EINVAL;
+
+	for (i = 0; i < ctx.max_connections; i++)
+		if (usb_bam_connections[i].bam_type == bam_type &&
+				usb_bam_connections[i].peer_bam == client &&
+				usb_bam_connections[i].dir == dir &&
+				usb_bam_connections[i].pipe_num == num) {
+			pr_debug("%s: index %d was found\n", __func__, i);
+			return i;
+		}
+
+	pr_err("%s: failed for %s\n", __func__, core_name);
+	return -ENODEV;
+}
+EXPORT_SYMBOL(usb_bam_get_connection_idx);
+
 static int usb_bam_remove(struct platform_device *pdev)
 {
-	destroy_workqueue(usb_bam_wq);
+	destroy_workqueue(ctx.usb_bam_wq);
 
 	return 0;
 }
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index bc2e2ae..e42337f 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -294,6 +294,13 @@
 	help
 	  Say Y to enable support for the battery in Qualcomm MSM.
 
+config BATTERY_MSM_FAKE
+	tristate "Fake MSM battery"
+	depends on ARCH_MSM && BATTERY_MSM
+	default n
+	help
+	  Say Y to bypass actual battery queries.
+
 config BATTERY_MSM8X60
 	tristate "MSM8X60 battery"
 	select PMIC8XXX_BATTALARM
@@ -365,13 +372,6 @@
 	  The driver reports the charger status via the power supply framework.
 	  A charger status change triggers an IRQ via the device STAT pin.
 
-config BATTERY_MSM_FAKE
-	tristate "Fake MSM battery"
-	depends on ARCH_MSM && BATTERY_MSM
-	default n
-	help
-	  Say Y to bypass actual battery queries.
-
 config PM8058_FIX_USB
 	tristate "pmic8058 software workaround for usb removal"
 	depends on PMIC8058
@@ -396,13 +396,6 @@
 	help
 	  Say Y here to enable support for batteries with BQ27520 (I2C) chips.
 
-config BATTERY_BQ27541
-	tristate "BQ27541 battery driver"
-	depends on I2C
-	default n
-	help
-	  Say Y here to enable support for batteries with BQ27541 (I2C) chips.
-
 config BQ27520_TEST_ENABLE
 	bool "Enable BQ27520 Fuel Gauge Chip Test"
 	depends on BATTERY_BQ27520
@@ -410,6 +403,13 @@
 	help
 	  Say Y here to enable Test sysfs Interface for BQ27520 Drivers.
 
+config BATTERY_BQ27541
+	tristate "BQ27541 battery driver"
+	depends on I2C
+	default n
+	help
+	  Say Y here to enable support for batteries with BQ27541 (I2C) chips.
+
 config BATTERY_BQ28400
 	tristate "BQ28400 battery driver"
 	depends on I2C
@@ -432,6 +432,7 @@
 	tristate "QPNP Charger driver"
 	depends on SPMI
 	depends on OF_SPMI
+	depends on THERMAL_QPNP_ADC_TM
 	help
 	  Say Y here to enable the switch mode battery charger
 	  and boost device which supports USB detection and charging. The driver
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 0fdadb9..bc6f289 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -115,8 +115,7 @@
 
 	u8				revision1;
 	u8				revision2;
-	int				charger_status;
-	bool				online;
+	int				battery_present;
 	/* platform data */
 	int				r_sense_uohm;
 	unsigned int			v_cutoff_uv;
@@ -149,6 +148,9 @@
 	int				shutdown_soc;
 	int				shutdown_iavg_ma;
 
+	struct wake_lock		low_voltage_wake_lock;
+	bool				low_voltage_wake_lock_held;
+	int				low_voltage_threshold;
 	int				low_soc_calc_threshold;
 	int				low_soc_calculate_soc_ms;
 	int				calculate_soc_ms;
@@ -204,8 +206,7 @@
 };
 
 static enum power_supply_property msm_bms_power_props[] = {
-	POWER_SUPPLY_PROP_STATUS,
-	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_CAPACITY,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -1141,7 +1142,11 @@
 		pr_err("vadc read failed with rc: %d\n", rc);
 		return rc;
 	}
-	*ibat_ua = (int)i_result.result_ua;
+	/*
+	 * reverse the current read by the iadc, since the bms uses
+	 * flipped battery current polarity.
+	 */
+	*ibat_ua = -1 * (int)i_result.result_ua;
 	*vbat_uv = (int)v_result.physical;
 
 	return 0;
@@ -1285,6 +1290,25 @@
 	return chip->prev_chg_soc;
 }
 
+static void very_low_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv)
+{
+	/*
+	 * if battery is very low (v_cutoff voltage + 20mv) hold
+	 * a wakelock untill soc = 0%
+	 */
+	if (vbat_uv <= chip->low_voltage_threshold
+			&& !chip->low_voltage_wake_lock_held) {
+		pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
+		wake_lock(&chip->low_voltage_wake_lock);
+		chip->low_voltage_wake_lock_held = 1;
+	} else if (vbat_uv > chip->low_voltage_threshold
+			&& chip->low_voltage_wake_lock_held) {
+		pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
+		chip->low_voltage_wake_lock_held = 0;
+		wake_unlock(&chip->low_voltage_wake_lock);
+	}
+}
+
 static int adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
 							int soc, int batt_temp)
 {
@@ -1305,6 +1329,8 @@
 		goto out;
 	}
 
+	very_low_voltage_check(chip, vbat_uv);
+
 	delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
 
 	ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt_mohm)/1000;
@@ -1620,7 +1646,8 @@
 				calculate_soc_delayed_work.work);
 	int soc = recalculate_soc(chip);
 
-	if (soc < chip->low_soc_calc_threshold)
+	if (soc < chip->low_soc_calc_threshold
+			|| chip->low_voltage_wake_lock_held)
 		schedule_delayed_work(&chip->calculate_soc_delayed_work,
 			round_jiffies_relative(msecs_to_jiffies
 			(chip->low_soc_calculate_soc_ms)));
@@ -1838,24 +1865,15 @@
 	return chip->fcc;
 }
 
-static bool get_prop_bms_online(struct qpnp_bms_chip *chip)
+static int get_prop_bms_present(struct qpnp_bms_chip *chip)
 {
-	return chip->online;
+	return chip->battery_present;
 }
 
-static int get_prop_bms_status(struct qpnp_bms_chip *chip)
+static void set_prop_bms_present(struct qpnp_bms_chip *chip, int present)
 {
-	return chip->charger_status;
-}
-
-static void set_prop_bms_online(struct qpnp_bms_chip *chip, bool online)
-{
-	chip->online = online;
-}
-
-static void set_prop_bms_status(struct qpnp_bms_chip *chip, int status)
-{
-	chip->charger_status = status;
+	if (chip->battery_present != present)
+		chip->battery_present = present;
 }
 
 static void qpnp_bms_external_power_changed(struct power_supply *psy)
@@ -1882,11 +1900,8 @@
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 		val->intval = get_prop_bms_charge_full_design(chip);
 		break;
-	case POWER_SUPPLY_PROP_STATUS:
-		val->intval = get_prop_bms_status(chip);
-		break;
-	case POWER_SUPPLY_PROP_ONLINE:
-		val->intval = get_prop_bms_online(chip);
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = get_prop_bms_present(chip);
 		break;
 	default:
 		return -EINVAL;
@@ -1902,11 +1917,8 @@
 								bms_psy);
 
 	switch (psp) {
-	case POWER_SUPPLY_PROP_ONLINE:
-		set_prop_bms_online(chip, val->intval);
-		break;
-	case POWER_SUPPLY_PROP_STATUS:
-		set_prop_bms_status(chip, (bool)val->intval);
+	case POWER_SUPPLY_PROP_PRESENT:
+		set_prop_bms_present(chip, val->intval);
 		break;
 	default:
 		return -EINVAL;
@@ -2121,6 +2133,7 @@
 			"ocv-voltage-high-threshold-uv", rc);
 	SPMI_PROP_READ(ocv_low_threshold_uv,
 			"ocv-voltage-low-threshold-uv", rc);
+	SPMI_PROP_READ(low_voltage_threshold, "low-voltage-threshold", rc);
 
 	if (chip->adjust_soc_low_threshold >= 45)
 		chip->adjust_soc_low_threshold = 45;
@@ -2294,6 +2307,7 @@
 static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
 {
 	struct qpnp_bms_chip *chip;
+	union power_supply_propval retval = {0,};
 	int rc, vbatt;
 
 	chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -2373,6 +2387,8 @@
 
 	wake_lock_init(&chip->soc_wake_lock, WAKE_LOCK_SUSPEND,
 			"qpnp_soc_lock");
+	wake_lock_init(&chip->low_voltage_wake_lock, WAKE_LOCK_SUSPEND,
+			"qpnp_low_voltage_lock");
 	INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
 			calculate_soc_work);
 
@@ -2381,6 +2397,14 @@
 	dev_set_drvdata(&spmi->dev, chip);
 	device_init_wakeup(&spmi->dev, 1);
 
+	if (!chip->batt_psy)
+		chip->batt_psy = power_supply_get_by_name("battery");
+	if (chip->batt_psy) {
+		chip->batt_psy->get_property(chip->batt_psy,
+					POWER_SUPPLY_PROP_PRESENT, &retval);
+		chip->battery_present = retval.intval;
+	}
+
 	calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
 
 	/* setup & register the battery power supply */
@@ -2417,6 +2441,7 @@
 
 unregister_dc:
 	wake_lock_destroy(&chip->soc_wake_lock);
+	wake_lock_destroy(&chip->low_voltage_wake_lock);
 	power_supply_unregister(&chip->bms_psy);
 	dev_set_drvdata(&spmi->dev, NULL);
 error_resource:
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 7833afa..eb0d6d4 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013 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
@@ -171,17 +171,27 @@
  * @boost_base:			boost peripheral base address
  * @misc_base:			misc peripheral base address
  * @freq_base:			freq peripheral base address
+ * @bat_is_cool:		indicates that battery is cool
+ * @bat_is_warm:		indicates that battery is warm
  * @chg_done:			indicates that charging is completed
  * @usb_present:		present status of usb
  * @dc_present:			present status of dc
+ * @batt_present:		present status of battery
  * @use_default_batt_values:	flag to report default battery properties
  * @max_voltage_mv:		the max volts the batt should be charged up to
  * @min_voltage_mv:		min battery voltage before turning the FET on
- * @resume_voltage_mv:		voltage at which the battery resumes charging
+ * @max_bat_chg_current:	maximum battery charge current in mA
+ * @warm_bat_chg_ma:	warm battery maximum charge current in mA
+ * @cool_bat_chg_ma:	cool battery maximum charge current in mA
+ * @warm_bat_mv:		warm temperature battery target voltage
+ * @cool_bat_mv:		cool temperature battery target voltage
+ * @resume_delta_mv:		voltage delta at which battery resumes charging
  * @term_current:		the charging based term current
  * @safe_current:		battery safety current setting
  * @maxinput_usb_ma:		Maximum Input current USB
  * @maxinput_dc_ma:		Maximum Input current DC
+ * @warm_bat_degc		Warm battery temperature in degree Celsius
+ * @cool_bat_degc		Cool battery temperature in degree Celsius
  * @revision:			PMIC revision
  * @thermal_levels		amount of thermal mitigation levels
  * @thermal_mitigation		thermal mitigation level values
@@ -208,20 +218,32 @@
 	unsigned int			usbin_valid_irq;
 	unsigned int			dcin_valid_irq;
 	unsigned int			chg_done_irq;
+	unsigned int			chg_fastchg_irq;
+	unsigned int			chg_trklchg_irq;
 	unsigned int			chg_failed_irq;
+	unsigned int			batt_pres_irq;
+	bool				bat_is_cool;
+	bool				bat_is_warm;
 	bool				chg_done;
 	bool				usb_present;
 	bool				dc_present;
+	bool				batt_present;
 	bool				charging_disabled;
 	bool				use_default_batt_values;
 	unsigned int			max_bat_chg_current;
+	unsigned int			warm_bat_chg_ma;
+	unsigned int			cool_bat_chg_ma;
 	unsigned int			safe_voltage_mv;
 	unsigned int			max_voltage_mv;
 	unsigned int			min_voltage_mv;
-	unsigned int			resume_voltage_mv;
+	unsigned int			warm_bat_mv;
+	unsigned int			cool_bat_mv;
+	unsigned int			resume_delta_mv;
 	unsigned int			term_current;
 	unsigned int			maxinput_usb_ma;
 	unsigned int			maxinput_dc_ma;
+	unsigned int			warm_bat_degc;
+	unsigned int			cool_bat_degc;
 	unsigned int			safe_current;
 	unsigned int			revision;
 	unsigned int			thermal_levels;
@@ -232,6 +254,7 @@
 	struct power_supply		*bms_psy;
 	struct power_supply		batt_psy;
 	uint32_t			flags;
+	struct qpnp_adc_tm_btm_param	adc_param;
 };
 
 static struct of_device_id qpnp_charger_match_table[] = {
@@ -323,6 +346,23 @@
 	return (usb_otg_en & USB_OTG_EN_BIT) ? 1 : 0;
 }
 
+static int
+qpnp_chg_is_batt_present(struct qpnp_chg_chip *chip)
+{
+	u8 batt_pres_rt_sts;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &batt_pres_rt_sts,
+				 INT_RT_STS(chip->bat_if_base), 1);
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+				INT_RT_STS(chip->bat_if_base), rc);
+		return rc;
+	}
+
+	return (batt_pres_rt_sts & BATT_PRES_IRQ) ? 1 : 0;
+}
+
 #define USB_VALID_BIT	BIT(7)
 static int
 qpnp_chg_is_usb_chg_plugged_in(struct qpnp_chg_chip *chip)
@@ -493,6 +533,26 @@
 }
 
 static irqreturn_t
+qpnp_chg_bat_if_batt_pres_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_chg_chip *chip = _chip;
+	int batt_present;
+
+	batt_present = qpnp_chg_is_batt_present(chip);
+	pr_debug("batt-pres triggered: %d\n", batt_present);
+
+	if (chip->batt_present ^ batt_present) {
+		chip->batt_present = batt_present;
+		power_supply_changed(&chip->batt_psy);
+	}
+
+	if (chip->bms_psy)
+		power_supply_set_present(chip->bms_psy, batt_present);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
 qpnp_chg_dc_dcin_valid_irq_handler(int irq, void *_chip)
 {
 	struct qpnp_chg_chip *chip = _chip;
@@ -527,12 +587,47 @@
 }
 
 static irqreturn_t
-qpnp_chg_chgr_chg_done_irq_handler(int irq, void *_chip)
+qpnp_chg_chgr_chg_trklchg_irq_handler(int irq, void *_chip)
 {
 	struct qpnp_chg_chip *chip = _chip;
 
+	pr_debug("TRKL IRQ triggered\n");
+
+	chip->chg_done = false;
+	power_supply_changed(&chip->batt_psy);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_chg_chip *chip = _chip;
+
+	pr_debug("FAST_CHG IRQ triggered\n");
+
+	chip->chg_done = false;
+	power_supply_changed(&chip->batt_psy);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+qpnp_chg_chgr_chg_done_irq_handler(int irq, void *_chip)
+{
+	struct qpnp_chg_chip *chip = _chip;
+	u8 chgr_sts;
+	int rc;
+
 	pr_debug("CHG_DONE IRQ triggered\n");
+
+	rc = qpnp_chg_read(chip, &chgr_sts,
+				INT_RT_STS(chip->chgr_base), 1);
+	if (rc)
+		pr_err("failed to read interrupt sts %d\n", rc);
+
 	chip->chg_done = true;
+	power_supply_changed(&chip->batt_psy);
 
 	return IRQ_HANDLED;
 }
@@ -597,8 +692,8 @@
 	return rc;
 }
 
-static
-int switch_usb_to_charge_mode(struct qpnp_chg_chip *chip)
+static int
+switch_usb_to_charge_mode(struct qpnp_chg_chip *chip)
 {
 	int rc;
 
@@ -625,8 +720,8 @@
 	return 0;
 }
 
-static
-int switch_usb_to_host_mode(struct qpnp_chg_chip *chip)
+static int
+switch_usb_to_host_mode(struct qpnp_chg_chip *chip)
 {
 	int rc;
 
@@ -791,19 +886,16 @@
 	int rc;
 	u8 chgr_sts;
 
+	if (chip->chg_done)
+		return POWER_SUPPLY_STATUS_FULL;
+
 	rc = qpnp_chg_read(chip, &chgr_sts,
 				INT_RT_STS(chip->chgr_base), 1);
 	if (rc) {
 		pr_err("failed to read interrupt sts %d\n", rc);
-		return POWER_SUPPLY_STATUS_DISCHARGING;
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
 	}
 
-	pr_debug("chgr sts 0x%x\n", chgr_sts);
-	if (chgr_sts & CHG_DONE_IRQ || chip->chg_done)
-		return POWER_SUPPLY_STATUS_FULL;
-	else
-		chip->chg_done = false;
-
 	if (chgr_sts & TRKL_CHG_ON_IRQ)
 		return POWER_SUPPLY_STATUS_CHARGING;
 	if (chgr_sts & FAST_CHG_ON_IRQ)
@@ -1147,8 +1239,33 @@
 	temp = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
 
 	pr_debug("voltage=%d setting %02x\n", voltage, temp);
-	return qpnp_chg_write(chip, &temp,
-		chip->chgr_base + CHGR_VDD_MAX, 1);
+	return qpnp_chg_write(chip, &temp, chip->chgr_base + CHGR_VDD_MAX, 1);
+}
+
+/* JEITA compliance logic */
+static void
+qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
+{
+	if (chip->bat_is_cool)
+		qpnp_chg_vddmax_set(chip, chip->cool_bat_mv);
+	else if (chip->bat_is_warm)
+		qpnp_chg_vddmax_set(chip, chip->warm_bat_mv);
+	else
+		qpnp_chg_vddmax_set(chip, chip->max_voltage_mv);
+}
+
+static void
+qpnp_chg_set_appropriate_vbatdet(struct qpnp_chg_chip *chip)
+{
+	if (chip->bat_is_cool)
+		qpnp_chg_vbatdet_set(chip, chip->cool_bat_mv
+			- chip->resume_delta_mv);
+	else if (chip->bat_is_warm)
+		qpnp_chg_vbatdet_set(chip, chip->warm_bat_mv
+			- chip->resume_delta_mv);
+	else
+		qpnp_chg_vbatdet_set(chip, chip->max_voltage_mv
+			- chip->resume_delta_mv);
 }
 
 static void
@@ -1156,6 +1273,12 @@
 {
 	unsigned int chg_current = chip->max_bat_chg_current;
 
+	if (chip->bat_is_cool)
+		chg_current = min(chg_current, chip->cool_bat_chg_ma);
+
+	if (chip->bat_is_warm)
+		chg_current = min(chg_current, chip->warm_bat_chg_ma);
+
 	if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
 		chg_current = min(chg_current,
 			chip->thermal_mitigation[chip->therm_lvl_sel]);
@@ -1181,6 +1304,58 @@
 	}
 }
 
+#define TEMP_HYSTERISIS_DEGC 2
+static void
+qpnp_chg_adc_notification(enum qpnp_tm_state state, void *ctx)
+{
+	struct qpnp_chg_chip *chip = ctx;
+	bool bat_warm = 0, bat_cool = 0;
+
+	if (state >= ADC_TM_STATE_NUM) {
+		pr_err("invalid notification %d\n", state);
+		return;
+	}
+
+	pr_debug("state = %s\n", state == ADC_TM_HIGH_STATE ? "high" : "low");
+
+	if (state == ADC_TM_HIGH_STATE) {
+		if (!chip->bat_is_warm) {
+			bat_warm = true;
+			bat_cool = false;
+			chip->adc_param.low_temp =
+				chip->warm_bat_degc - TEMP_HYSTERISIS_DEGC;
+		} else if (chip->bat_is_cool) {
+			bat_warm = false;
+			bat_cool = false;
+			chip->adc_param.high_temp = chip->warm_bat_degc;
+		}
+	} else {
+		if (!chip->bat_is_cool) {
+			bat_cool = true;
+			bat_warm = false;
+			chip->adc_param.high_temp =
+				chip->cool_bat_degc + TEMP_HYSTERISIS_DEGC;
+		} else if (chip->bat_is_warm) {
+			bat_cool = false;
+			bat_warm = false;
+			chip->adc_param.low_temp = chip->cool_bat_degc;
+		}
+	}
+
+	if (chip->bat_is_cool ^ bat_cool || chip->bat_is_warm ^ bat_warm) {
+		/* set appropriate voltages and currents */
+		qpnp_chg_set_appropriate_vddmax(chip);
+		qpnp_chg_set_appropriate_battery_current(chip);
+		qpnp_chg_set_appropriate_vbatdet(chip);
+
+		chip->bat_is_cool = bat_cool;
+		chip->bat_is_warm = bat_warm;
+	}
+
+	/* re-arm ADC interrupt */
+	qpnp_adc_tm_btm_configure(&chip->adc_param);
+}
+
 static int
 qpnp_batt_power_set_property(struct power_supply *psy,
 				  enum power_supply_property psp,
@@ -1231,20 +1406,37 @@
 			return -ENXIO;
 		}
 
+		chip->chg_fastchg_irq = spmi_get_irq_byname(chip->spmi,
+						spmi_resource, "fast-chg-on");
+		if (chip->chg_fastchg_irq < 0) {
+			pr_err("Unable to get fast-chg-on irq\n");
+			return -ENXIO;
+		}
+
+		chip->chg_trklchg_irq = spmi_get_irq_byname(chip->spmi,
+						spmi_resource, "trkl-chg-on");
+		if (chip->chg_trklchg_irq < 0) {
+			pr_err("Unable to get trkl-chg-on irq\n");
+			return -ENXIO;
+		}
+
 		chip->chg_failed_irq = spmi_get_irq_byname(chip->spmi,
 						spmi_resource, "chg-failed");
 		if (chip->chg_failed_irq < 0) {
 			pr_err("Unable to get chg_failed irq\n");
 			return -ENXIO;
 		}
+
 		rc |= devm_request_irq(chip->dev, chip->chg_done_irq,
 				qpnp_chg_chgr_chg_done_irq_handler,
-				IRQF_TRIGGER_RISING, "chg_done", chip);
+				IRQF_TRIGGER_RISING,
+				"chg_done", chip);
 		if (rc < 0) {
 			pr_err("Can't request %d chg_done for chg: %d\n",
 						chip->chg_done_irq, rc);
 			return -ENXIO;
 		}
+
 		rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
 				qpnp_chg_chgr_chg_failed_irq_handler,
 				IRQF_TRIGGER_RISING, "chg_failed", chip);
@@ -1254,6 +1446,26 @@
 			return -ENXIO;
 		}
 
+		rc |= devm_request_irq(chip->dev, chip->chg_fastchg_irq,
+				qpnp_chg_chgr_chg_fastchg_irq_handler,
+				IRQF_TRIGGER_RISING,
+				"fast-chg-on", chip);
+		if (rc < 0) {
+			pr_err("Can't request %d fast-chg-on for chg: %d\n",
+						chip->chg_fastchg_irq, rc);
+			return -ENXIO;
+		}
+
+		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);
+		if (rc < 0) {
+			pr_err("Can't request %d trkl-chg-on for chg: %d\n",
+						chip->chg_trklchg_irq, rc);
+			return -ENXIO;
+		}
+
 		rc = qpnp_chg_vinmin_set(chip, chip->min_voltage_mv);
 		if (rc) {
 			pr_debug("failed setting  min_voltage rc=%d\n", rc);
@@ -1269,7 +1481,8 @@
 			pr_debug("failed setting safe_voltage rc=%d\n", rc);
 			return rc;
 		}
-		rc = qpnp_chg_vbatdet_set(chip, chip->resume_voltage_mv);
+		rc = qpnp_chg_vbatdet_set(chip,
+				chip->max_voltage_mv - chip->resume_delta_mv);
 		if (rc) {
 			pr_debug("failed setting resume_voltage rc=%d\n", rc);
 			return rc;
@@ -1279,10 +1492,12 @@
 			pr_debug("failed setting ibatmax rc=%d\n", rc);
 			return rc;
 		}
-		rc = qpnp_chg_ibatterm_set(chip, chip->term_current);
-		if (rc) {
-			pr_debug("failed setting ibatterm rc=%d\n", rc);
-			return rc;
+		if (chip->term_current) {
+			rc = qpnp_chg_ibatterm_set(chip, chip->term_current);
+			if (rc) {
+				pr_debug("failed setting ibatterm rc=%d\n", rc);
+				return rc;
+			}
 		}
 		rc = qpnp_chg_ibatsafe_set(chip, chip->safe_current);
 		if (rc) {
@@ -1293,11 +1508,14 @@
 		rc = qpnp_chg_masked_write(chip, chip->chgr_base + 0x62,
 			0xFF, 0xA0, 1);
 
-		/* HACK: use analog EOC */
+		/* HACK: use digital EOC */
 		rc = qpnp_chg_masked_write(chip, chip->chgr_base +
 			CHGR_IBAT_TERM_CHGR,
-			0x80, 0x80, 1);
+			0x88, 0x80, 1);
 
+		enable_irq_wake(chip->chg_fastchg_irq);
+		enable_irq_wake(chip->chg_trklchg_irq);
+		enable_irq_wake(chip->chg_failed_irq);
 		enable_irq_wake(chip->chg_done_irq);
 		break;
 	case SMBB_BUCK_SUBTYPE:
@@ -1313,6 +1531,23 @@
 		break;
 	case SMBB_BAT_IF_SUBTYPE:
 	case SMBBP_BAT_IF_SUBTYPE:
+		chip->batt_pres_irq = spmi_get_irq_byname(chip->spmi,
+						spmi_resource, "batt-pres");
+		if (chip->batt_pres_irq < 0) {
+			pr_err("Unable to get batt-pres irq\n");
+			return -ENXIO;
+		}
+		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);
+		if (rc < 0) {
+			pr_err("Can't request %d batt-pres irq for chg: %d\n",
+						chip->batt_pres_irq, rc);
+			return -ENXIO;
+		}
+
+		enable_irq_wake(chip->batt_pres_irq);
 		break;
 	case SMBB_USB_CHGPTH_SUBTYPE:
 	case SMBBP_USB_CHGPTH_SUBTYPE:
@@ -1406,6 +1641,7 @@
 	struct qpnp_chg_chip	*chip;
 	struct resource *resource;
 	struct spmi_resource *spmi_resource;
+	bool present;
 	int rc = 0;
 
 	chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -1427,7 +1663,7 @@
 	/* Get the vddmax property */
 	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddmax-mv",
 						&chip->max_voltage_mv);
-	if (rc && rc != -EINVAL) {
+	if (rc) {
 		pr_err("Error reading vddmax property %d\n", rc);
 		goto fail_chg_enable;
 	}
@@ -1435,7 +1671,7 @@
 	/* Get the vinmin property */
 	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vinmin-mv",
 						&chip->min_voltage_mv);
-	if (rc && rc != -EINVAL) {
+	if (rc) {
 		pr_err("Error reading vddmax property %d\n", rc);
 		goto fail_chg_enable;
 	}
@@ -1443,17 +1679,17 @@
 	/* Get the vddmax property */
 	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddsafe-mv",
 						&chip->safe_voltage_mv);
-	if (rc && rc != -EINVAL) {
+	if (rc) {
 		pr_err("Error reading vddsave property %d\n", rc);
 		goto fail_chg_enable;
 	}
 
-	/* Get the ibatsafe property */
+	/* Get the vbatdet-delta property */
 	rc = of_property_read_u32(spmi->dev.of_node,
-				"qcom,chg-vbatdet-mv",
-				&chip->resume_voltage_mv);
-	if (rc) {
-		pr_err("Error reading vbatdet property %d\n", rc);
+				"qcom,chg-vbatdet-delta-mv",
+				&chip->resume_delta_mv);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading vbatdet-delta property %d\n", rc);
 		goto fail_chg_enable;
 	}
 
@@ -1478,17 +1714,8 @@
 	/* Get the ibatmax property */
 	rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-ibatmax-ma",
 						&chip->max_bat_chg_current);
-	if (rc && rc != -EINVAL) {
-		pr_err("Error reading ibatmax property %d\n", rc);
-		goto fail_chg_enable;
-	}
-
-	/* Get the ibatsafe property */
-	rc = of_property_read_u32(spmi->dev.of_node,
-				"qcom,chg-vbatdet-mv",
-				&chip->resume_voltage_mv);
 	if (rc) {
-		pr_err("Error reading vbatdet property %d\n", rc);
+		pr_err("Error reading ibatmax property %d\n", rc);
 		goto fail_chg_enable;
 	}
 
@@ -1514,6 +1741,67 @@
 	chip->charging_disabled = of_property_read_bool(spmi->dev.of_node,
 					"qcom,chg-charging-disabled");
 
+	/* Get the warm-bat-degc property */
+	rc = of_property_read_u32(spmi->dev.of_node,
+				"qcom,chg-warm-bat-degc",
+				&chip->warm_bat_degc);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading warm-bat-degc property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	/* Get the cool-bat-degc property */
+	rc = of_property_read_u32(spmi->dev.of_node,
+				"qcom,chg-cool-bat-degc",
+				&chip->cool_bat_degc);
+	if (rc && rc != -EINVAL) {
+		pr_err("Error reading cool-bat-degc property %d\n", rc);
+		goto fail_chg_enable;
+	}
+
+	if (chip->cool_bat_degc && chip->warm_bat_degc) {
+		rc = qpnp_adc_tm_is_ready();
+		if (rc) {
+			pr_err("tm not ready %d\n", rc);
+			goto fail_chg_enable;
+		}
+
+		/* Get the ibatmax-warm property */
+		rc = of_property_read_u32(spmi->dev.of_node,
+					"qcom,chg-ibatmax-warm-ma",
+					&chip->warm_bat_chg_ma);
+		if (rc) {
+			pr_err("Error reading ibatmax-warm-ma %d\n", rc);
+			goto fail_chg_enable;
+		}
+
+		/* Get the ibatmax-cool property */
+		rc = of_property_read_u32(spmi->dev.of_node,
+					"qcom,chg-ibatmax-cool-ma",
+					&chip->cool_bat_chg_ma);
+		if (rc) {
+			pr_err("Error reading ibatmax-cool-ma %d\n", rc);
+			goto fail_chg_enable;
+		}
+		/* Get the cool-bat-mv property */
+		rc = of_property_read_u32(spmi->dev.of_node,
+					"qcom,chg-cool-bat-mv",
+					&chip->cool_bat_mv);
+		if (rc) {
+			pr_err("Error reading cool-bat-mv property %d\n", rc);
+			goto fail_chg_enable;
+		}
+
+		/* Get the warm-bat-mv property */
+		rc = of_property_read_u32(spmi->dev.of_node,
+					"qcom,chg-warm-bat-mv",
+					&chip->warm_bat_mv);
+		if (rc) {
+			pr_err("Error reading warm-bat-mv property %d\n", rc);
+			goto fail_chg_enable;
+		}
+	}
+
 	/* Get the fake-batt-values property */
 	chip->use_default_batt_values = of_property_read_bool(spmi->dev.of_node,
 					"qcom,chg-use-default-batt-values");
@@ -1652,6 +1940,14 @@
 		if (rc)
 			goto fail_chg_enable;
 
+		/* if bms exists, notify it of the presence of the battery */
+		if (!chip->bms_psy)
+			chip->bms_psy = power_supply_get_by_name("bms");
+		if (chip->bms_psy) {
+			present = get_prop_batt_present(chip);
+			power_supply_set_present(chip->bms_psy, present);
+		}
+
 		chip->batt_psy.name = "battery";
 		chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
 		chip->batt_psy.properties = msm_batt_power_props;
@@ -1701,6 +1997,22 @@
 		}
 	}
 
+	if (chip->cool_bat_degc && chip->warm_bat_degc) {
+		chip->adc_param.low_temp = chip->cool_bat_degc;
+		chip->adc_param.high_temp = chip->warm_bat_degc;
+		chip->adc_param.timer_interval = ADC_MEAS2_INTERVAL_1S;
+		chip->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+		chip->adc_param.btm_ctx = chip;
+		chip->adc_param.threshold_notification =
+						qpnp_chg_adc_notification;
+
+		rc = qpnp_adc_tm_btm_configure(&chip->adc_param);
+		if (rc) {
+			pr_err("request ADC error %d\n", rc);
+			goto fail_chg_enable;
+		}
+	}
+
 	qpnp_chg_charge_en(chip, !chip->charging_disabled);
 	qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
 
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8f924d6..fe5af3a 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -436,4 +436,6 @@
 	  comply with QPNP.  QPNP is a SPMI based PMIC implementation.  These
 	  chips provide several different varieties of LDO and switching
 	  regulators.  They also provide voltage switches and boost regulators.
+
 endif
+
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 054ce42..eb07c97 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -45,7 +45,6 @@
 obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
-obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
 obj-$(CONFIG_REGULATOR_PMIC8058) += pmic8058-regulator.o
 obj-$(CONFIG_REGULATOR_PMIC8901) += pmic8901-regulator.o
 obj-$(CONFIG_REGULATOR_MSM_GPIO) += msm-gpio-regulator.o
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 1849118..7a559a6 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -123,24 +123,6 @@
 	  clock several times per second, please enable this option
 	  only if you know that you really need it.
 
-config RTC_INTF_ALARM
-	bool "Android alarm driver"
-	depends on RTC_CLASS
-	default y
-	help
-	  Provides non-wakeup and rtc backed wakeup alarms based on rtc or
-	  elapsed realtime, and a non-wakeup alarm on the monotonic clock.
-	  Also provides an interface to set the wall time which must be used
-	  for elapsed realtime to work.
-
-config RTC_INTF_ALARM_DEV
-	bool "Android alarm device"
-	depends on RTC_INTF_ALARM
-	default y
-	help
-	  Exports the alarm interface to user-space.
-
-
 config RTC_DRV_TEST
 	tristate "Test driver/device"
 	help
@@ -804,13 +786,6 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-davinci.
 
-config RTC_DRV_MSM7X00A
-	tristate "MSM7X00A"
-	depends on ARCH_MSM
-	default y
-	help
-	  RTC driver for Qualcomm MSM7K chipsets
-
 config RTC_DRV_OMAP
 	tristate "TI OMAP1"
 	depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX
@@ -1150,15 +1125,6 @@
 	  This drive can also be built as a module. If so, the module
 	  will be called rtc-puv3.
 
-config RTC_DRV_PM8XXX
-	tristate "Qualcomm PMIC8XXX RTC"
-	depends on MFD_PM8XXX
-	help
-	  Say Y here if you want to support the Qualcomm PMIC8XXX RTC.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called rtc-pm8xxx.
-
 config RTC_DRV_LOONGSON1
 	tristate "loongson1 RTC support"
 	depends on MACH_LOONGSON1
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 295f927..c6a0362 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -81,7 +81,6 @@
 obj-$(CONFIG_RTC_DRV_PCF8583)	+= rtc-pcf8583.o
 obj-$(CONFIG_RTC_DRV_PCF2123)	+= rtc-pcf2123.o
 obj-$(CONFIG_RTC_DRV_PCF50633)	+= rtc-pcf50633.o
-obj-$(CONFIG_RTC_DRV_PM8XXX)    += rtc-pm8xxx.o
 obj-$(CONFIG_RTC_DRV_PL030)	+= rtc-pl030.o
 obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031.o
 obj-$(CONFIG_RTC_DRV_PM8XXX)	+= rtc-pm8xxx.o
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index aea91ef..8097e69 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -15,31 +15,37 @@
 #include <linux/rtc.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
-#include<linux/spinlock.h>
+#include <linux/spinlock.h>
 
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/mfd/pm8xxx/rtc.h>
 
 
 /* RTC Register offsets from RTC CTRL REG */
-#define PM8XXX_ALARM_CTRL_OFFSET 0x01
-#define PM8XXX_RTC_WRITE_OFFSET 0x02
-#define PM8XXX_RTC_READ_OFFSET 0x06
-#define PM8XXX_ALARM_RW_OFFSET 0x0A
+#define PM8XXX_ALARM_CTRL_OFFSET	0x01
+#define PM8XXX_RTC_WRITE_OFFSET		0x02
+#define PM8XXX_RTC_READ_OFFSET		0x06
+#define PM8XXX_ALARM_RW_OFFSET		0x0A
 
 /* RTC_CTRL register bit fields */
-#define PM8xxx_RTC_ENABLE	BIT(7)
-#define PM8xxx_RTC_ALARM_ENABLE	BIT(1)
-#define PM8xxx_RTC_ABORT_ENABLE BIT(0)
+#define PM8xxx_RTC_ENABLE		BIT(7)
+#define PM8xxx_RTC_ALARM_ENABLE		BIT(1)
+#define PM8xxx_RTC_ALARM_CLEAR		BIT(0)
+#define PM8xxx_RTC_ABORT_ENABLE		BIT(0)
 
-#define PM8xxx_RTC_ALARM_CLEAR  BIT(0)
-
-#define NUM_8_BIT_RTC_REGS	0x4
+#define NUM_8_BIT_RTC_REGS		0x4
 
 /**
- * struct pm8xxx_rtc - rtc driver internal structure
- * @rtc: rtc device for this driver
- * @rtc_alarm_irq: rtc alarm irq number
+ * struct pm8xxx_rtc -  rtc driver internal structure
+ * @rtc:		rtc device for this driver.
+ * @rtc_alarm_irq:	rtc alarm irq number.
+ * @rtc_base:		address of rtc control register.
+ * @rtc_read_base:	base address of read registers.
+ * @rtc_write_base:	base address of write registers.
+ * @alarm_rw_base:	base address of alarm registers.
+ * @ctrl_reg:		rtc control register.
+ * @rtc_dev:		device structure.
+ * @ctrl_reg_lock:	spinlock protecting access to ctrl_reg.
  */
 struct pm8xxx_rtc {
 	struct rtc_device *rtc;
@@ -57,9 +63,8 @@
  * The RTC registers need to be read/written one byte at a time. This is a
  * hardware limitation.
  */
-
 static int pm8xxx_read_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
-			int base, int count)
+		int base, int count)
 {
 	int i, rc;
 	struct device *parent = rtc_dd->rtc_dev->parent;
@@ -67,7 +72,7 @@
 	for (i = 0; i < count; i++) {
 		rc = pm8xxx_readb(parent, base + i, &rtc_val[i]);
 		if (rc < 0) {
-			dev_err(rtc_dd->rtc_dev, "PM8xxx read failed\n");
+			dev_err(rtc_dd->rtc_dev, "PMIC read failed\n");
 			return rc;
 		}
 	}
@@ -76,7 +81,7 @@
 }
 
 static int pm8xxx_write_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
-			int base, int count)
+		int base, int count)
 {
 	int i, rc;
 	struct device *parent = rtc_dd->rtc_dev->parent;
@@ -84,7 +89,7 @@
 	for (i = 0; i < count; i++) {
 		rc = pm8xxx_writeb(parent, base + i, rtc_val[i]);
 		if (rc < 0) {
-			dev_err(rtc_dd->rtc_dev, "PM8xxx write failed\n");
+			dev_err(rtc_dd->rtc_dev, "PMIC write failed\n");
 			return rc;
 		}
 	}
@@ -92,7 +97,6 @@
 	return 0;
 }
 
-
 /*
  * Steps to write the RTC registers.
  * 1. Disable alarm if enabled.
@@ -100,20 +104,19 @@
  * 3. Write Byte[1], Byte[2], Byte[3] then Byte[0].
  * 4. Enable alarm if disabled in step 1.
  */
-static int
-pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
-	int rc;
+	int rc, i;
 	unsigned long secs, irq_flags;
-	u8 value[4], reg = 0, alarm_enabled = 0, ctrl_reg;
+	u8 value[NUM_8_BIT_RTC_REGS], reg = 0, alarm_enabled = 0, ctrl_reg;
 	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
 
 	rtc_tm_to_time(tm, &secs);
 
-	value[0] = secs & 0xFF;
-	value[1] = (secs >> 8) & 0xFF;
-	value[2] = (secs >> 16) & 0xFF;
-	value[3] = (secs >> 24) & 0xFF;
+	for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
+		value[i] = secs & 0xFF;
+		secs >>= 8;
+	}
 
 	dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
 
@@ -124,20 +127,21 @@
 		alarm_enabled = 1;
 		ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
 		rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
-									1);
+				1);
 		if (rc < 0) {
-			dev_err(dev, "PM8xxx write failed\n");
+			dev_err(dev, "Write to RTC control register "
+								"failed\n");
 			goto rtc_rw_fail;
 		}
+		rtc_dd->ctrl_reg = ctrl_reg;
 	} else
 		spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
 
-	/* Write Byte[1], Byte[2], Byte[3], Byte[0] */
 	/* Write 0 to Byte[0] */
 	reg = 0;
 	rc = pm8xxx_write_wrapper(rtc_dd, &reg, rtc_dd->rtc_write_base, 1);
 	if (rc < 0) {
-		dev_err(dev, "PM8xxx write failed\n");
+		dev_err(dev, "Write to RTC write data register failed\n");
 		goto rtc_rw_fail;
 	}
 
@@ -145,14 +149,14 @@
 	rc = pm8xxx_write_wrapper(rtc_dd, value + 1,
 					rtc_dd->rtc_write_base + 1, 3);
 	if (rc < 0) {
-		dev_err(dev, "Write to RTC registers failed\n");
+		dev_err(dev, "Write to RTC write data register failed\n");
 		goto rtc_rw_fail;
 	}
 
 	/* Write Byte[0] */
 	rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->rtc_write_base, 1);
 	if (rc < 0) {
-		dev_err(dev, "Write to RTC register failed\n");
+		dev_err(dev, "Write to RTC write data register failed\n");
 		goto rtc_rw_fail;
 	}
 
@@ -161,13 +165,13 @@
 		rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
 									1);
 		if (rc < 0) {
-			dev_err(dev, "PM8xxx write failed\n");
+			dev_err(dev, "Write to RTC control register "
+								"failed\n");
 			goto rtc_rw_fail;
 		}
+		rtc_dd->ctrl_reg = ctrl_reg;
 	}
 
-	rtc_dd->ctrl_reg = ctrl_reg;
-
 rtc_rw_fail:
 	if (alarm_enabled)
 		spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
@@ -175,18 +179,17 @@
 	return rc;
 }
 
-static int
-pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
 	int rc;
-	u8 value[4], reg;
+	u8 value[NUM_8_BIT_RTC_REGS], reg;
 	unsigned long secs;
 	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
 
 	rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->rtc_read_base,
 							NUM_8_BIT_RTC_REGS);
 	if (rc < 0) {
-		dev_err(dev, "RTC time read failed\n");
+		dev_err(dev, "RTC read data register failed\n");
 		return rc;
 	}
 
@@ -196,7 +199,7 @@
 	 */
 	rc = pm8xxx_read_wrapper(rtc_dd, &reg, rtc_dd->rtc_read_base, 1);
 	if (rc < 0) {
-		dev_err(dev, "PM8xxx read failed\n");
+		dev_err(dev, "RTC read data register failed\n");
 		return rc;
 	}
 
@@ -204,96 +207,76 @@
 		rc = pm8xxx_read_wrapper(rtc_dd, value,
 				rtc_dd->rtc_read_base, NUM_8_BIT_RTC_REGS);
 		if (rc < 0) {
-			dev_err(dev, "RTC time read failed\n");
+			dev_err(dev, "RTC read data register failed\n");
 			return rc;
 		}
 	}
 
-	secs = value[0] | (value[1] << 8) | (value[2] << 16) \
-						| (value[3] << 24);
+	secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
 
 	rtc_time_to_tm(secs, tm);
 
 	rc = rtc_valid_tm(tm);
 	if (rc < 0) {
-		dev_err(dev, "Invalid time read from PM8xxx\n");
+		dev_err(dev, "Invalid time read from RTC\n");
 		return rc;
 	}
 
 	dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n",
-			secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
-			tm->tm_mday, tm->tm_mon, tm->tm_year);
+				secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
+				tm->tm_mday, tm->tm_mon, tm->tm_year);
 
 	return 0;
 }
 
-static int
-pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
-	int rc;
-	u8 value[4], ctrl_reg;
-	unsigned long secs, secs_rtc, irq_flags;
+	int rc, i;
+	u8 value[NUM_8_BIT_RTC_REGS], ctrl_reg;
+	unsigned long secs, irq_flags;
 	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
-	struct rtc_time rtc_tm;
 
 	rtc_tm_to_time(&alarm->time, &secs);
 
-	/*
-	 * Read the current RTC time and verify if the alarm time is in the
-	 * past. If yes, return invalid.
-	 */
-	rc = pm8xxx_rtc_read_time(dev, &rtc_tm);
-	if (rc < 0) {
-		dev_err(dev, "Unamble to read RTC time\n");
-		return -EINVAL;
+	for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
+		value[i] = secs & 0xFF;
+		secs >>= 8;
 	}
 
-	rtc_tm_to_time(&rtc_tm, &secs_rtc);
-	if (secs < secs_rtc) {
-		dev_err(dev, "Trying to set alarm in the past\n");
-		return -EINVAL;
-	}
-
-	value[0] = secs & 0xFF;
-	value[1] = (secs >> 8) & 0xFF;
-	value[2] = (secs >> 16) & 0xFF;
-	value[3] = (secs >> 24) & 0xFF;
-
 	spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
 
 	rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
 							NUM_8_BIT_RTC_REGS);
 	if (rc < 0) {
-		dev_err(dev, "Write to RTC ALARM registers failed\n");
+		dev_err(dev, "Write to RTC ALARM register failed\n");
 		goto rtc_rw_fail;
 	}
 
 	ctrl_reg = rtc_dd->ctrl_reg;
-	ctrl_reg = (alarm->enabled) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
+	ctrl_reg = alarm->enabled ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
 					(ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
 
 	rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
 	if (rc < 0) {
-		dev_err(dev, "PM8xxx write failed\n");
+		dev_err(dev, "Write to RTC control register failed\n");
 		goto rtc_rw_fail;
 	}
 
 	rtc_dd->ctrl_reg = ctrl_reg;
 
 	dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
-			alarm->time.tm_hour, alarm->time.tm_min,
-			alarm->time.tm_sec, alarm->time.tm_mday,
-			alarm->time.tm_mon, alarm->time.tm_year);
+				alarm->time.tm_hour, alarm->time.tm_min,
+				alarm->time.tm_sec, alarm->time.tm_mday,
+				alarm->time.tm_mon, alarm->time.tm_year);
 rtc_rw_fail:
 	spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
 	return rc;
 }
 
-static int
-pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
 	int rc;
-	u8 value[4];
+	u8 value[NUM_8_BIT_RTC_REGS];
 	unsigned long secs;
 	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
 
@@ -304,28 +287,25 @@
 		return rc;
 	}
 
-	secs = value[0] | (value[1] << 8) | (value[2] << 16) | \
-						 (value[3] << 24);
+	secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
 
 	rtc_time_to_tm(secs, &alarm->time);
 
 	rc = rtc_valid_tm(&alarm->time);
 	if (rc < 0) {
-		dev_err(dev, "Invalid time read from PM8xxx\n");
+		dev_err(dev, "Invalid alarm time read from RTC\n");
 		return rc;
 	}
 
 	dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
-		alarm->time.tm_hour, alarm->time.tm_min,
+				alarm->time.tm_hour, alarm->time.tm_min,
 				alarm->time.tm_sec, alarm->time.tm_mday,
 				alarm->time.tm_mon, alarm->time.tm_year);
 
 	return 0;
 }
 
-
-static int
-pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
 {
 	int rc;
 	unsigned long irq_flags;
@@ -334,12 +314,12 @@
 
 	spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
 	ctrl_reg = rtc_dd->ctrl_reg;
-	ctrl_reg = (enabled) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
+	ctrl_reg = (enable) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
 				(ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
 
 	rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
 	if (rc < 0) {
-		dev_err(dev, "PM8xxx write failed\n");
+		dev_err(dev, "Write to RTC control register failed\n");
 		goto rtc_rw_fail;
 	}
 
@@ -375,7 +355,8 @@
 	rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
 	if (rc < 0) {
 		spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
-		dev_err(rtc_dd->rtc_dev, "PM8xxx write failed!\n");
+		dev_err(rtc_dd->rtc_dev, "Write to RTC control register "
+								"failed\n");
 		goto rtc_alarm_handled;
 	}
 
@@ -386,7 +367,8 @@
 	rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
 						PM8XXX_ALARM_CTRL_OFFSET, 1);
 	if (rc < 0) {
-		dev_err(rtc_dd->rtc_dev, "PM8xxx write failed!\n");
+		dev_err(rtc_dd->rtc_dev, "RTC Alarm control register read "
+								"failed\n");
 		goto rtc_alarm_handled;
 	}
 
@@ -394,7 +376,8 @@
 	rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
 						PM8XXX_ALARM_CTRL_OFFSET, 1);
 	if (rc < 0)
-		dev_err(rtc_dd->rtc_dev, "PM8xxx write failed!\n");
+		dev_err(rtc_dd->rtc_dev, "Write to RTC Alarm control register"
+								" failed\n");
 
 rtc_alarm_handled:
 	return IRQ_HANDLED;
@@ -408,7 +391,7 @@
 	struct pm8xxx_rtc *rtc_dd;
 	struct resource *rtc_resource;
 	const struct pm8xxx_rtc_platform_data *pdata =
-		pdev->dev.platform_data;
+						dev_get_platdata(&pdev->dev);
 
 	if (pdata != NULL)
 		rtc_write_enable = pdata->rtc_write_enable;
@@ -419,7 +402,7 @@
 		return -ENOMEM;
 	}
 
-	/* Initialise spinlock to protect RTC cntrol register */
+	/* Initialise spinlock to protect RTC control register */
 	spin_lock_init(&rtc_dd->ctrl_reg_lock);
 
 	rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
@@ -444,12 +427,12 @@
 	rtc_dd->rtc_read_base = rtc_dd->rtc_base + PM8XXX_RTC_READ_OFFSET;
 	rtc_dd->alarm_rw_base = rtc_dd->rtc_base + PM8XXX_ALARM_RW_OFFSET;
 
-	rtc_dd->rtc_dev = &(pdev->dev);
+	rtc_dd->rtc_dev = &pdev->dev;
 
 	/* Check if the RTC is on, else turn it on */
 	rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
 	if (rc < 0) {
-		dev_err(&pdev->dev, "PM8xxx read failed!\n");
+		dev_err(&pdev->dev, "RTC control register read failed!\n");
 		goto fail_rtc_enable;
 	}
 
@@ -458,7 +441,8 @@
 		rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
 									1);
 		if (rc < 0) {
-			dev_err(&pdev->dev, "PM8xxx write failed!\n");
+			dev_err(&pdev->dev, "Write to RTC control register "
+								"failed\n");
 			goto fail_rtc_enable;
 		}
 	}
@@ -510,7 +494,20 @@
 	return rc;
 }
 
-#ifdef CONFIG_PM
+static int __devexit pm8xxx_rtc_remove(struct platform_device *pdev)
+{
+	struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
+
+	device_init_wakeup(&pdev->dev, 0);
+	free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
+	rtc_device_unregister(rtc_dd->rtc);
+	platform_set_drvdata(pdev, NULL);
+	kfree(rtc_dd);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
 static int pm8xxx_rtc_resume(struct device *dev)
 {
 	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
@@ -530,24 +527,9 @@
 
 	return 0;
 }
-
-static const struct dev_pm_ops pm8xxx_rtc_pm_ops = {
-	.suspend = pm8xxx_rtc_suspend,
-	.resume = pm8xxx_rtc_resume,
-};
 #endif
-static int __devexit pm8xxx_rtc_remove(struct platform_device *pdev)
-{
-	struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
 
-	device_init_wakeup(&pdev->dev, 0);
-	free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
-	rtc_device_unregister(rtc_dd->rtc);
-	platform_set_drvdata(pdev, NULL);
-	kfree(rtc_dd);
-
-	return 0;
-}
+static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
 
 static void pm8xxx_rtc_shutdown(struct platform_device *pdev)
 {
@@ -572,7 +554,7 @@
 		reg &= ~PM8xxx_RTC_ALARM_ENABLE;
 		rc = pm8xxx_write_wrapper(rtc_dd, &reg, rtc_dd->rtc_base, 1);
 		if (rc < 0) {
-			dev_err(rtc_dd->rtc_dev, "PM8xxx write failed\n");
+			dev_err(rtc_dd->rtc_dev, "Disabling alarm failed\n");
 			goto fail_alarm_disable;
 		}
 
@@ -580,7 +562,7 @@
 		rc = pm8xxx_write_wrapper(rtc_dd, value,
 				rtc_dd->alarm_rw_base, NUM_8_BIT_RTC_REGS);
 		if (rc < 0)
-			dev_err(rtc_dd->rtc_dev, "PM8xxx write failed\n");
+			dev_err(rtc_dd->rtc_dev, "Clearing alarm failed\n");
 
 fail_alarm_disable:
 		spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
@@ -594,23 +576,11 @@
 	.driver	= {
 		.name	= PM8XXX_RTC_DEV_NAME,
 		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
 		.pm	= &pm8xxx_rtc_pm_ops,
-#endif
 	},
 };
 
-static int __init pm8xxx_rtc_init(void)
-{
-	return platform_driver_register(&pm8xxx_rtc_driver);
-}
-module_init(pm8xxx_rtc_init);
-
-static void __exit pm8xxx_rtc_exit(void)
-{
-	platform_driver_unregister(&pm8xxx_rtc_driver);
-}
-module_exit(pm8xxx_rtc_exit);
+module_platform_driver(pm8xxx_rtc_driver);
 
 MODULE_ALIAS("platform:rtc-pm8xxx");
 MODULE_DESCRIPTION("PMIC8xxx RTC driver");
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index ef9c77d..fab3586 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -293,18 +293,6 @@
 
 	writel(sp_timeouts, &llr->sas_phy_timeouts);
 
-	sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts);
-
-	/* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */
-	sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF);
-
-	/* Set RATE_CHANGE timeout value to 0x3B (59us).  This ensures SCU can
-	 * lock with 3Gb drive when SCU max rate is set to 1.5Gb.
-	 */
-	sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B);
-
-	writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts);
-
 	if (is_a2(ihost->pdev)) {
 		/* Program the max ARB time for the PHY to 700us so we
 		 * inter-operate with the PMC expander which shuts down
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 1756897..706fba7 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -2,51 +2,61 @@
 # Kernel configuration file for the UFS Host Controller
 #
 # This code is based on drivers/scsi/ufs/Kconfig
-# Copyright (C) 2011  Samsung Samsung India Software Operations
+# Copyright (C) 2011-2013 Samsung India Software Operations
 #
-# Santosh Yaraganavi <santosh.sy@samsung.com>
-# Vinayak Holikatti <h.vinayak@samsung.com>
-
+# Authors:
+#	Santosh Yaraganavi <santosh.sy@samsung.com>
+#	Vinayak Holikatti <h.vinayak@samsung.com>
+#
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; either version 2
 # of the License, or (at your option) any later version.
-
+# See the COPYING file in the top-level directory or visit
+# <http://www.gnu.org/licenses/gpl-2.0.html>
+#
 # 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.
-
-# NO WARRANTY
-# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
-# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
-# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
-# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
-# solely responsible for determining the appropriateness of using and
-# distributing the Program and assumes all risks associated with its
-# exercise of rights under this Agreement, including but not limited to
-# the risks and costs of program errors, damage to or loss of data,
-# programs or equipment, and unavailability or interruption of operations.
-
-# DISCLAIMER OF LIABILITY
-# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
-# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
-# USA.
+#
+# This program is provided "AS IS" and "WITH ALL FAULTS" and
+# without warranty of any kind. You are solely responsible for
+# determining the appropriateness of using and distributing
+# the program and assume all risks associated with your exercise
+# of rights with respect to the program, including but not limited
+# to infringement of third party rights, the risks and costs of
+# program errors, damage to or loss of data, programs or equipment,
+# and unavailability or interruption of operations. Under no
+# circumstances will the contributor of this Program be liable for
+# any damages of any kind arising from your use or distribution of
+# this program.
 
 config SCSI_UFSHCD
-	tristate "Universal Flash Storage host controller driver"
-	depends on PCI && SCSI
+	tristate "Universal Flash Storage Controller Driver Core"
+	depends on SCSI
 	---help---
-	This is a generic driver which supports PCIe UFS Host controllers.
+	This selects the support for UFS devices in Linux, say Y and make
+	  sure that you know the name of your UFS host adapter (the card
+	  inside your computer that "speaks" the UFS protocol, also
+	  called UFS Host Controller), because you will be asked for it.
+	  The module will be called ufshcd.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/scsi/ufs.txt>.
+	  However, do not compile this as a module if your root file system
+	  (the one containing the directory /) is located on a UFS device.
+
+config SCSI_UFSHCD_PCI
+	tristate "PCI bus based UFS Controller support"
+	depends on SCSI_UFSHCD && PCI
+	---help---
+	This selects the PCI UFS Host Controller Interface. Select this if
+	you have UFS Host Controller with PCI Interface.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
 
 config SCSI_UFS_TEST
 	tristate "Universal Flash Storage host controller driver unit-tests"
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 489058d..bbcc202 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -1,3 +1,4 @@
 # UFSHCD makefile
 obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
+obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
 obj-$(CONFIG_SCSI_UFS_TEST) += ufs_test.o
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index b207529..139bc06 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -2,45 +2,35 @@
  * Universal Flash Storage Host controller driver
  *
  * This code is based on drivers/scsi/ufs/ufs.h
- * Copyright (C) 2011-2012 Samsung India Software Operations
+ * Copyright (C) 2011-2013 Samsung India Software Operations
  *
- * Santosh Yaraganavi <santosh.sy@samsung.com>
- * Vinayak Holikatti <h.vinayak@samsung.com>
+ * Authors:
+ *	Santosh Yaraganavi <santosh.sy@samsung.com>
+ *	Vinayak Holikatti <h.vinayak@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
  *
  * 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.
  *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
- * USA.
+ * This program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
  */
 
 #ifndef _UFS_H
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
new file mode 100644
index 0000000..5cb1d75
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -0,0 +1,211 @@
+/*
+ * Universal Flash Storage Host controller PCI glue driver
+ *
+ * This code is based on drivers/scsi/ufs/ufshcd-pci.c
+ * Copyright (C) 2011-2013 Samsung India Software Operations
+ *
+ * Authors:
+ *	Santosh Yaraganavi <santosh.sy@samsung.com>
+ *	Vinayak Holikatti <h.vinayak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ *
+ * 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.
+ *
+ * This program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
+ */
+
+#include "ufshcd.h"
+#include <linux/pci.h>
+
+#ifdef CONFIG_PM
+/**
+ * ufshcd_pci_suspend - suspend power management function
+ * @pdev: pointer to PCI device handle
+ * @state: power state
+ *
+ * Returns -ENOSYS
+ */
+static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	/*
+	 * TODO:
+	 * 1. Call ufshcd_suspend
+	 * 2. Do bus specific power management
+	 */
+
+	return -ENOSYS;
+}
+
+/**
+ * ufshcd_pci_resume - resume power management function
+ * @pdev: pointer to PCI device handle
+ *
+ * Returns -ENOSYS
+ */
+static int ufshcd_pci_resume(struct pci_dev *pdev)
+{
+	/*
+	 * TODO:
+	 * 1. Call ufshcd_resume.
+	 * 2. Do bus specific wake up
+	 */
+
+	return -ENOSYS;
+}
+#endif /* CONFIG_PM */
+
+/**
+ * ufshcd_pci_shutdown - main function to put the controller in reset state
+ * @pdev: pointer to PCI device handle
+ */
+static void ufshcd_pci_shutdown(struct pci_dev *pdev)
+{
+	ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev));
+}
+
+/**
+ * ufshcd_pci_remove - de-allocate PCI/SCSI host and host memory space
+ *		data structure memory
+ * @pdev - pointer to PCI handle
+ */
+static void ufshcd_pci_remove(struct pci_dev *pdev)
+{
+	struct ufs_hba *hba = pci_get_drvdata(pdev);
+
+	disable_irq(pdev->irq);
+	free_irq(pdev->irq, hba);
+	ufshcd_remove(hba);
+	pci_release_regions(pdev);
+	pci_set_drvdata(pdev, NULL);
+	pci_clear_master(pdev);
+	pci_disable_device(pdev);
+}
+
+/**
+ * ufshcd_set_dma_mask - Set dma mask based on the controller
+ *			 addressing capability
+ * @pdev: PCI device structure
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+static int ufshcd_set_dma_mask(struct pci_dev *pdev)
+{
+	int err;
+
+	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+		&& !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
+		return 0;
+	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (!err)
+		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+	return err;
+}
+
+/**
+ * ufshcd_pci_probe - probe routine of the driver
+ * @pdev: pointer to PCI device handle
+ * @id: PCI device id
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int
+ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct ufs_hba *hba;
+	void __iomem *mmio_base;
+	int err;
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "pci_enable_device failed\n");
+		goto out_error;
+	}
+
+	pci_set_master(pdev);
+
+
+	err = pci_request_regions(pdev, UFSHCD);
+	if (err < 0) {
+		dev_err(&pdev->dev, "request regions failed\n");
+		goto out_disable;
+	}
+
+	mmio_base = pci_ioremap_bar(pdev, 0);
+	if (!mmio_base) {
+		dev_err(&pdev->dev, "memory map failed\n");
+		err = -ENOMEM;
+		goto out_release_regions;
+	}
+
+	err = ufshcd_set_dma_mask(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "set dma mask failed\n");
+		goto out_iounmap;
+	}
+
+	err = ufshcd_init(&pdev->dev, &hba, mmio_base, pdev->irq);
+	if (err) {
+		dev_err(&pdev->dev, "Initialization failed\n");
+		goto out_iounmap;
+	}
+
+	pci_set_drvdata(pdev, hba);
+
+	return 0;
+
+out_iounmap:
+	iounmap(mmio_base);
+out_release_regions:
+	pci_release_regions(pdev);
+out_disable:
+	pci_clear_master(pdev);
+	pci_disable_device(pdev);
+out_error:
+	return err;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
+	{ PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ }	/* terminate list */
+};
+
+MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl);
+
+static struct pci_driver ufshcd_pci_driver = {
+	.name = UFSHCD,
+	.id_table = ufshcd_pci_tbl,
+	.probe = ufshcd_pci_probe,
+	.remove = ufshcd_pci_remove,
+	.shutdown = ufshcd_pci_shutdown,
+#ifdef CONFIG_PM
+	.suspend = ufshcd_pci_suspend,
+	.resume = ufshcd_pci_resume,
+#endif
+};
+
+module_pci_driver(ufshcd_pci_driver);
+
+MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
+MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
+MODULE_DESCRIPTION("UFS host controller PCI glue driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 58f4ba6..60fd40c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1,77 +1,39 @@
 /*
- * Universal Flash Storage Host controller driver
+ * Universal Flash Storage Host controller driver Core
  *
  * This code is based on drivers/scsi/ufs/ufshcd.c
- * Copyright (C) 2011-2012 Samsung India Software Operations
+ * Copyright (C) 2011-2013 Samsung India Software Operations
  *
- * Santosh Yaraganavi <santosh.sy@samsung.com>
- * Vinayak Holikatti <h.vinayak@samsung.com>
+ * Authors:
+ *	Santosh Yaraganavi <santosh.sy@samsung.com>
+ *	Vinayak Holikatti <h.vinayak@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
  *
  * 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.
  *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
- * USA.
+ * This program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_eh.h>
-
-#include "ufs.h"
-#include "ufshci.h"
-
-#define UFSHCD "ufshcd"
-#define UFSHCD_DRIVER_VERSION "0.1"
+#include "ufshcd.h"
 
 enum {
 	UFSHCD_MAX_CHANNEL	= 0,
@@ -102,121 +64,6 @@
 };
 
 /**
- * struct uic_command - UIC command structure
- * @command: UIC command
- * @argument1: UIC command argument 1
- * @argument2: UIC command argument 2
- * @argument3: UIC command argument 3
- * @cmd_active: Indicate if UIC command is outstanding
- * @result: UIC command result
- */
-struct uic_command {
-	u32 command;
-	u32 argument1;
-	u32 argument2;
-	u32 argument3;
-	int cmd_active;
-	int result;
-};
-
-/**
- * struct ufs_hba - per adapter private structure
- * @mmio_base: UFSHCI base register address
- * @ucdl_base_addr: UFS Command Descriptor base address
- * @utrdl_base_addr: UTP Transfer Request Descriptor base address
- * @utmrdl_base_addr: UTP Task Management Descriptor base address
- * @ucdl_dma_addr: UFS Command Descriptor DMA address
- * @utrdl_dma_addr: UTRDL DMA address
- * @utmrdl_dma_addr: UTMRDL DMA address
- * @host: Scsi_Host instance of the driver
- * @pdev: PCI device handle
- * @lrb: local reference block
- * @outstanding_tasks: Bits representing outstanding task requests
- * @outstanding_reqs: Bits representing outstanding transfer requests
- * @capabilities: UFS Controller Capabilities
- * @nutrs: Transfer Request Queue depth supported by controller
- * @nutmrs: Task Management Queue depth supported by controller
- * @active_uic_cmd: handle of active UIC command
- * @ufshcd_tm_wait_queue: wait queue for task management
- * @tm_condition: condition variable for task management
- * @ufshcd_state: UFSHCD states
- * @int_enable_mask: Interrupt Mask Bits
- * @uic_workq: Work queue for UIC completion handling
- * @feh_workq: Work queue for fatal controller error handling
- * @errors: HBA errors
- */
-struct ufs_hba {
-	void __iomem *mmio_base;
-
-	/* Virtual memory reference */
-	struct utp_transfer_cmd_desc *ucdl_base_addr;
-	struct utp_transfer_req_desc *utrdl_base_addr;
-	struct utp_task_req_desc *utmrdl_base_addr;
-
-	/* DMA memory reference */
-	dma_addr_t ucdl_dma_addr;
-	dma_addr_t utrdl_dma_addr;
-	dma_addr_t utmrdl_dma_addr;
-
-	struct Scsi_Host *host;
-	struct pci_dev *pdev;
-
-	struct ufshcd_lrb *lrb;
-
-	unsigned long outstanding_tasks;
-	unsigned long outstanding_reqs;
-
-	u32 capabilities;
-	int nutrs;
-	int nutmrs;
-	u32 ufs_version;
-
-	struct uic_command active_uic_cmd;
-	wait_queue_head_t ufshcd_tm_wait_queue;
-	unsigned long tm_condition;
-
-	u32 ufshcd_state;
-	u32 int_enable_mask;
-
-	/* Work Queues */
-	struct work_struct uic_workq;
-	struct work_struct feh_workq;
-
-	/* HBA Errors */
-	u32 errors;
-};
-
-/**
- * struct ufshcd_lrb - local reference block
- * @utr_descriptor_ptr: UTRD address of the command
- * @ucd_cmd_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
- * @sense_buffer: pointer to sense buffer address of the SCSI command
- * @sense_bufflen: Length of the sense buffer
- * @scsi_status: SCSI status of the command
- * @command_type: SCSI, UFS, Query.
- * @task_tag: Task tag of the command
- * @lun: LUN of the command
- */
-struct ufshcd_lrb {
-	struct utp_transfer_req_desc *utr_descriptor_ptr;
-	struct utp_upiu_cmd *ucd_cmd_ptr;
-	struct utp_upiu_rsp *ucd_rsp_ptr;
-	struct ufshcd_sg_entry *ucd_prdt_ptr;
-
-	struct scsi_cmnd *cmd;
-	u8 *sense_buffer;
-	unsigned int sense_bufflen;
-	int scsi_status;
-
-	int command_type;
-	int task_tag;
-	unsigned int lun;
-};
-
-/**
  * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
  * @hba - Pointer to adapter instance
  *
@@ -335,21 +182,21 @@
 
 	if (hba->utmrdl_base_addr) {
 		utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
-		dma_free_coherent(&hba->pdev->dev, utmrdl_size,
+		dma_free_coherent(hba->dev, utmrdl_size,
 				  hba->utmrdl_base_addr, hba->utmrdl_dma_addr);
 	}
 
 	if (hba->utrdl_base_addr) {
 		utrdl_size =
 		(sizeof(struct utp_transfer_req_desc) * hba->nutrs);
-		dma_free_coherent(&hba->pdev->dev, utrdl_size,
+		dma_free_coherent(hba->dev, utrdl_size,
 				  hba->utrdl_base_addr, hba->utrdl_dma_addr);
 	}
 
 	if (hba->ucdl_base_addr) {
 		ucdl_size =
 		(sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
-		dma_free_coherent(&hba->pdev->dev, ucdl_size,
+		dma_free_coherent(hba->dev, ucdl_size,
 				  hba->ucdl_base_addr, hba->ucdl_dma_addr);
 	}
 }
@@ -429,15 +276,6 @@
 }
 
 /**
- * ufshcd_hba_stop - Send controller to reset state
- * @hba: per adapter instance
- */
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
-{
-	writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
-}
-
-/**
  * ufshcd_hba_start - Start controller initialization sequence
  * @hba: per adapter instance
  */
@@ -724,7 +562,7 @@
 
 	/* Allocate memory for UTP command descriptors */
 	ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
-	hba->ucdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+	hba->ucdl_base_addr = dma_alloc_coherent(hba->dev,
 						 ucdl_size,
 						 &hba->ucdl_dma_addr,
 						 GFP_KERNEL);
@@ -737,7 +575,7 @@
 	 */
 	if (!hba->ucdl_base_addr ||
 	    WARN_ON(hba->ucdl_dma_addr & (PAGE_SIZE - 1))) {
-		dev_err(&hba->pdev->dev,
+		dev_err(hba->dev,
 			"Command Descriptor Memory allocation failed\n");
 		goto out;
 	}
@@ -747,13 +585,13 @@
 	 * UFSHCI requires 1024 byte alignment of UTRD
 	 */
 	utrdl_size = (sizeof(struct utp_transfer_req_desc) * hba->nutrs);
-	hba->utrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+	hba->utrdl_base_addr = dma_alloc_coherent(hba->dev,
 						  utrdl_size,
 						  &hba->utrdl_dma_addr,
 						  GFP_KERNEL);
 	if (!hba->utrdl_base_addr ||
 	    WARN_ON(hba->utrdl_dma_addr & (PAGE_SIZE - 1))) {
-		dev_err(&hba->pdev->dev,
+		dev_err(hba->dev,
 			"Transfer Descriptor Memory allocation failed\n");
 		goto out;
 	}
@@ -763,13 +601,13 @@
 	 * UFSHCI requires 1024 byte alignment of UTMRD
 	 */
 	utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs;
-	hba->utmrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev,
+	hba->utmrdl_base_addr = dma_alloc_coherent(hba->dev,
 						   utmrdl_size,
 						   &hba->utmrdl_dma_addr,
 						   GFP_KERNEL);
 	if (!hba->utmrdl_base_addr ||
 	    WARN_ON(hba->utmrdl_dma_addr & (PAGE_SIZE - 1))) {
-		dev_err(&hba->pdev->dev,
+		dev_err(hba->dev,
 		"Task Management Descriptor Memory allocation failed\n");
 		goto out;
 	}
@@ -777,7 +615,7 @@
 	/* Allocate memory for local reference block */
 	hba->lrb = kcalloc(hba->nutrs, sizeof(struct ufshcd_lrb), GFP_KERNEL);
 	if (!hba->lrb) {
-		dev_err(&hba->pdev->dev, "LRB Memory allocation failed\n");
+		dev_err(hba->dev, "LRB Memory allocation failed\n");
 		goto out;
 	}
 	return 0;
@@ -867,7 +705,7 @@
 	/* check if controller is ready to accept UIC commands */
 	if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
 	    UIC_COMMAND_READY) == 0x0) {
-		dev_err(&hba->pdev->dev,
+		dev_err(hba->dev,
 			"Controller not ready"
 			" to accept UIC commands\n");
 		return -EIO;
@@ -912,7 +750,7 @@
 	/* check if device present */
 	reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
 	if (!ufshcd_is_device_present(reg)) {
-		dev_err(&hba->pdev->dev, "cc: Device not present\n");
+		dev_err(hba->dev, "cc: Device not present\n");
 		err = -ENXIO;
 		goto out;
 	}
@@ -924,7 +762,7 @@
 	if (!(ufshcd_get_lists_status(reg))) {
 		ufshcd_enable_run_stop_reg(hba);
 	} else {
-		dev_err(&hba->pdev->dev,
+		dev_err(hba->dev,
 			"Host controller not ready to process requests");
 		err = -EIO;
 		goto out;
@@ -1005,7 +843,7 @@
 		if (retry) {
 			retry--;
 		} else {
-			dev_err(&hba->pdev->dev,
+			dev_err(hba->dev,
 				"Controller enable failed\n");
 			return -EIO;
 		}
@@ -1084,7 +922,7 @@
 
 	/* start the initialization process */
 	if (ufshcd_initialize_hba(hba)) {
-		dev_err(&hba->pdev->dev,
+		dev_err(hba->dev,
 			"Reset: Controller initialization failed\n");
 		return FAILED;
 	}
@@ -1167,7 +1005,7 @@
 			task_result = SUCCESS;
 	} else {
 		task_result = FAILED;
-		dev_err(&hba->pdev->dev,
+		dev_err(hba->dev,
 			"trc: Invalid ocs = %x\n", ocs_value);
 	}
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -1281,7 +1119,7 @@
 		/* check if the returned transfer response is valid */
 		result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
 		if (result) {
-			dev_err(&hba->pdev->dev,
+			dev_err(hba->dev,
 				"Invalid response = %x\n", result);
 			break;
 		}
@@ -1310,7 +1148,7 @@
 	case OCS_FATAL_ERROR:
 	default:
 		result |= DID_ERROR << 16;
-		dev_err(&hba->pdev->dev,
+		dev_err(hba->dev,
 		"OCS error from controller = %x\n", ocs);
 		break;
 	} /* end of switch */
@@ -1374,7 +1212,7 @@
 	    !(ufshcd_get_uic_cmd_result(hba))) {
 
 		if (ufshcd_make_hba_operational(hba))
-			dev_err(&hba->pdev->dev,
+			dev_err(hba->dev,
 				"cc: hba not operational state\n");
 		return;
 	}
@@ -1509,7 +1347,7 @@
 	free_slot = ufshcd_get_tm_free_slot(hba);
 	if (free_slot >= hba->nutmrs) {
 		spin_unlock_irqrestore(host->host_lock, flags);
-		dev_err(&hba->pdev->dev, "Task management queue full\n");
+		dev_err(hba->dev, "Task management queue full\n");
 		err = FAILED;
 		goto out;
 	}
@@ -1552,7 +1390,7 @@
 					 &hba->tm_condition) != 0),
 					 60 * HZ);
 	if (!err) {
-		dev_err(&hba->pdev->dev,
+		dev_err(hba->dev,
 			"Task management command timed-out\n");
 		err = FAILED;
 		goto out;
@@ -1688,23 +1526,13 @@
 };
 
 /**
- * ufshcd_shutdown - main function to put the controller in reset state
- * @pdev: pointer to PCI device handle
- */
-static void ufshcd_shutdown(struct pci_dev *pdev)
-{
-	ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev));
-}
-
-#ifdef CONFIG_PM
-/**
  * ufshcd_suspend - suspend power management function
- * @pdev: pointer to PCI device handle
+ * @hba: per adapter instance
  * @state: power state
  *
  * Returns -ENOSYS
  */
-static int ufshcd_suspend(struct pci_dev *pdev, pm_message_t state)
+int ufshcd_suspend(struct ufs_hba *hba, pm_message_t state)
 {
 	/*
 	 * TODO:
@@ -1717,14 +1545,15 @@
 
 	return -ENOSYS;
 }
+EXPORT_SYMBOL_GPL(ufshcd_suspend);
 
 /**
  * ufshcd_resume - resume power management function
- * @pdev: pointer to PCI device handle
+ * @hba: per adapter instance
  *
  * Returns -ENOSYS
  */
-static int ufshcd_resume(struct pci_dev *pdev)
+int ufshcd_resume(struct ufs_hba *hba)
 {
 	/*
 	 * TODO:
@@ -1737,7 +1566,7 @@
 
 	return -ENOSYS;
 }
-#endif /* CONFIG_PM */
+EXPORT_SYMBOL_GPL(ufshcd_resume);
 
 /**
  * ufshcd_hba_free - free allocated memory for
@@ -1748,108 +1577,67 @@
 {
 	iounmap(hba->mmio_base);
 	ufshcd_free_hba_memory(hba);
-	pci_release_regions(hba->pdev);
 }
 
 /**
- * ufshcd_remove - de-allocate PCI/SCSI host and host memory space
+ * ufshcd_remove - de-allocate SCSI host and host memory space
  *		data structure memory
- * @pdev - pointer to PCI handle
+ * @hba - per adapter instance
  */
-static void ufshcd_remove(struct pci_dev *pdev)
+void ufshcd_remove(struct ufs_hba *hba)
 {
-	struct ufs_hba *hba = pci_get_drvdata(pdev);
-
 	/* disable interrupts */
 	ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
-	free_irq(pdev->irq, hba);
 
 	ufshcd_hba_stop(hba);
 	ufshcd_hba_free(hba);
 
 	scsi_remove_host(hba->host);
 	scsi_host_put(hba->host);
-	pci_set_drvdata(pdev, NULL);
-	pci_clear_master(pdev);
-	pci_disable_device(pdev);
 }
+EXPORT_SYMBOL_GPL(ufshcd_remove);
 
 /**
- * ufshcd_set_dma_mask - Set dma mask based on the controller
- *			 addressing capability
- * @pdev: PCI device structure
- *
- * Returns 0 for success, non-zero for failure
- */
-static int ufshcd_set_dma_mask(struct ufs_hba *hba)
-{
-	int err;
-	u64 dma_mask;
-
-	/*
-	 * If controller supports 64 bit addressing mode, then set the DMA
-	 * mask to 64-bit, else set the DMA mask to 32-bit
-	 */
-	if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT)
-		dma_mask = DMA_BIT_MASK(64);
-	else
-		dma_mask = DMA_BIT_MASK(32);
-
-	err = pci_set_dma_mask(hba->pdev, dma_mask);
-	if (err)
-		return err;
-
-	err = pci_set_consistent_dma_mask(hba->pdev, dma_mask);
-
-	return err;
-}
-
-/**
- * ufshcd_probe - probe routine of the driver
- * @pdev: pointer to PCI device handle
- * @id: PCI device id
- *
+ * ufshcd_init - Driver initialization routine
+ * @dev: pointer to device handle
+ * @hba_handle: driver private handle
+ * @mmio_base: base register address
+ * @irq: Interrupt line of device
  * Returns 0 on success, non-zero value on failure
  */
-static int __devinit
-ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
+		 void __iomem *mmio_base, unsigned int irq)
 {
 	struct Scsi_Host *host;
 	struct ufs_hba *hba;
 	int err;
 
-	err = pci_enable_device(pdev);
-	if (err) {
-		dev_err(&pdev->dev, "pci_enable_device failed\n");
+	if (!dev) {
+		dev_err(dev,
+		"Invalid memory reference for dev is NULL\n");
+		err = -ENODEV;
 		goto out_error;
 	}
 
-	pci_set_master(pdev);
+	if (!mmio_base) {
+		dev_err(dev,
+		"Invalid memory reference for mmio_base is NULL\n");
+		err = -ENODEV;
+		goto out_error;
+	}
 
 	host = scsi_host_alloc(&ufshcd_driver_template,
 				sizeof(struct ufs_hba));
 	if (!host) {
-		dev_err(&pdev->dev, "scsi_host_alloc failed\n");
+		dev_err(dev, "scsi_host_alloc failed\n");
 		err = -ENOMEM;
-		goto out_disable;
+		goto out_error;
 	}
 	hba = shost_priv(host);
-
-	err = pci_request_regions(pdev, UFSHCD);
-	if (err < 0) {
-		dev_err(&pdev->dev, "request regions failed\n");
-		goto out_host_put;
-	}
-
-	hba->mmio_base = pci_ioremap_bar(pdev, 0);
-	if (!hba->mmio_base) {
-		dev_err(&pdev->dev, "memory map failed\n");
-		err = -ENOMEM;
-		goto out_release_regions;
-	}
-
 	hba->host = host;
-	hba->pdev = pdev;
+	hba->dev = dev;
+	hba->mmio_base = mmio_base;
+	hba->irq = irq;
 
 	/* Read capabilities registers */
 	ufshcd_hba_capabilities(hba);
@@ -1857,17 +1645,11 @@
 	/* Get UFS version supported by the controller */
 	hba->ufs_version = ufshcd_get_ufs_version(hba);
 
-	err = ufshcd_set_dma_mask(hba);
-	if (err) {
-		dev_err(&pdev->dev, "set dma mask failed\n");
-		goto out_iounmap;
-	}
-
 	/* Allocate memory for host memory space */
 	err = ufshcd_memory_alloc(hba);
 	if (err) {
-		dev_err(&pdev->dev, "Memory allocation failed\n");
-		goto out_iounmap;
+		dev_err(hba->dev, "Memory allocation failed\n");
+		goto out_disable;
 	}
 
 	/* Configure LRB */
@@ -1889,76 +1671,50 @@
 	INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
 
 	/* IRQ registration */
-	err = request_irq(pdev->irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
+	err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
 	if (err) {
-		dev_err(&pdev->dev, "request irq failed\n");
+		dev_err(hba->dev, "request irq failed\n");
 		goto out_lrb_free;
 	}
 
 	/* Enable SCSI tag mapping */
 	err = scsi_init_shared_tag_map(host, host->can_queue);
 	if (err) {
-		dev_err(&pdev->dev, "init shared queue failed\n");
+		dev_err(hba->dev, "init shared queue failed\n");
 		goto out_free_irq;
 	}
 
-	pci_set_drvdata(pdev, hba);
-
-	err = scsi_add_host(host, &pdev->dev);
+	err = scsi_add_host(host, hba->dev);
 	if (err) {
-		dev_err(&pdev->dev, "scsi_add_host failed\n");
+		dev_err(hba->dev, "scsi_add_host failed\n");
 		goto out_free_irq;
 	}
 
 	/* Initialization routine */
 	err = ufshcd_initialize_hba(hba);
 	if (err) {
-		dev_err(&pdev->dev, "Initialization failed\n");
-		goto out_free_irq;
+		dev_err(hba->dev, "Initialization failed\n");
+		goto out_remove_scsi_host;
 	}
+	*hba_handle = hba;
 
 	return 0;
 
+out_remove_scsi_host:
+	scsi_remove_host(hba->host);
 out_free_irq:
-	free_irq(pdev->irq, hba);
+	free_irq(irq, hba);
 out_lrb_free:
 	ufshcd_free_hba_memory(hba);
-out_iounmap:
-	iounmap(hba->mmio_base);
-out_release_regions:
-	pci_release_regions(pdev);
-out_host_put:
-	scsi_host_put(host);
 out_disable:
-	pci_clear_master(pdev);
-	pci_disable_device(pdev);
+	scsi_host_put(host);
 out_error:
 	return err;
 }
+EXPORT_SYMBOL_GPL(ufshcd_init);
 
-static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
-	{ PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ }	/* terminate list */
-};
-
-MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl);
-
-static struct pci_driver ufshcd_pci_driver = {
-	.name = UFSHCD,
-	.id_table = ufshcd_pci_tbl,
-	.probe = ufshcd_probe,
-	.remove = __devexit_p(ufshcd_remove),
-	.shutdown = ufshcd_shutdown,
-#ifdef CONFIG_PM
-	.suspend = ufshcd_suspend,
-	.resume = ufshcd_resume,
-#endif
-};
-
-module_pci_driver(ufshcd_pci_driver);
-
-MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>, "
-	      "Vinayak Holikatti <h.vinayak@samsung.com>");
-MODULE_DESCRIPTION("Generic UFS host controller driver");
+MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
+MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
+MODULE_DESCRIPTION("Generic UFS host controller driver Core");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
new file mode 100644
index 0000000..6b99a42
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -0,0 +1,202 @@
+/*
+ * Universal Flash Storage Host controller driver
+ *
+ * This code is based on drivers/scsi/ufs/ufshcd.h
+ * Copyright (C) 2011-2013 Samsung India Software Operations
+ *
+ * Authors:
+ *	Santosh Yaraganavi <santosh.sy@samsung.com>
+ *	Vinayak Holikatti <h.vinayak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ *
+ * 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.
+ *
+ * This program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
+ */
+
+#ifndef _UFSHCD_H
+#define _UFSHCD_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+
+#include "ufs.h"
+#include "ufshci.h"
+
+#define UFSHCD "ufshcd"
+#define UFSHCD_DRIVER_VERSION "0.2"
+
+/**
+ * struct uic_command - UIC command structure
+ * @command: UIC command
+ * @argument1: UIC command argument 1
+ * @argument2: UIC command argument 2
+ * @argument3: UIC command argument 3
+ * @cmd_active: Indicate if UIC command is outstanding
+ * @result: UIC command result
+ */
+struct uic_command {
+	u32 command;
+	u32 argument1;
+	u32 argument2;
+	u32 argument3;
+	int cmd_active;
+	int result;
+};
+
+/**
+ * struct ufshcd_lrb - local reference block
+ * @utr_descriptor_ptr: UTRD address of the command
+ * @ucd_cmd_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
+ * @sense_buffer: pointer to sense buffer address of the SCSI command
+ * @sense_bufflen: Length of the sense buffer
+ * @scsi_status: SCSI status of the command
+ * @command_type: SCSI, UFS, Query.
+ * @task_tag: Task tag of the command
+ * @lun: LUN of the command
+ */
+struct ufshcd_lrb {
+	struct utp_transfer_req_desc *utr_descriptor_ptr;
+	struct utp_upiu_cmd *ucd_cmd_ptr;
+	struct utp_upiu_rsp *ucd_rsp_ptr;
+	struct ufshcd_sg_entry *ucd_prdt_ptr;
+
+	struct scsi_cmnd *cmd;
+	u8 *sense_buffer;
+	unsigned int sense_bufflen;
+	int scsi_status;
+
+	int command_type;
+	int task_tag;
+	unsigned int lun;
+};
+
+
+/**
+ * struct ufs_hba - per adapter private structure
+ * @mmio_base: UFSHCI base register address
+ * @ucdl_base_addr: UFS Command Descriptor base address
+ * @utrdl_base_addr: UTP Transfer Request Descriptor base address
+ * @utmrdl_base_addr: UTP Task Management Descriptor base address
+ * @ucdl_dma_addr: UFS Command Descriptor DMA address
+ * @utrdl_dma_addr: UTRDL DMA address
+ * @utmrdl_dma_addr: UTMRDL DMA address
+ * @host: Scsi_Host instance of the driver
+ * @dev: device handle
+ * @lrb: local reference block
+ * @outstanding_tasks: Bits representing outstanding task requests
+ * @outstanding_reqs: Bits representing outstanding transfer requests
+ * @capabilities: UFS Controller Capabilities
+ * @nutrs: Transfer Request Queue depth supported by controller
+ * @nutmrs: Task Management Queue depth supported by controller
+ * @ufs_version: UFS Version to which controller complies
+ * @irq: Irq number of the controller
+ * @active_uic_cmd: handle of active UIC command
+ * @ufshcd_tm_wait_queue: wait queue for task management
+ * @tm_condition: condition variable for task management
+ * @ufshcd_state: UFSHCD states
+ * @int_enable_mask: Interrupt Mask Bits
+ * @uic_workq: Work queue for UIC completion handling
+ * @feh_workq: Work queue for fatal controller error handling
+ * @errors: HBA errors
+ */
+struct ufs_hba {
+	void __iomem *mmio_base;
+
+	/* Virtual memory reference */
+	struct utp_transfer_cmd_desc *ucdl_base_addr;
+	struct utp_transfer_req_desc *utrdl_base_addr;
+	struct utp_task_req_desc *utmrdl_base_addr;
+
+	/* DMA memory reference */
+	dma_addr_t ucdl_dma_addr;
+	dma_addr_t utrdl_dma_addr;
+	dma_addr_t utmrdl_dma_addr;
+
+	struct Scsi_Host *host;
+	struct device *dev;
+
+	struct ufshcd_lrb *lrb;
+
+	unsigned long outstanding_tasks;
+	unsigned long outstanding_reqs;
+
+	u32 capabilities;
+	int nutrs;
+	int nutmrs;
+	u32 ufs_version;
+	unsigned int irq;
+
+	struct uic_command active_uic_cmd;
+	wait_queue_head_t ufshcd_tm_wait_queue;
+	unsigned long tm_condition;
+
+	u32 ufshcd_state;
+	u32 int_enable_mask;
+
+	/* Work Queues */
+	struct work_struct uic_workq;
+	struct work_struct feh_workq;
+
+	/* HBA Errors */
+	u32 errors;
+};
+
+int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
+			unsigned int);
+void ufshcd_remove(struct ufs_hba *);
+
+/**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+	writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 6e3510f..0c16484 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -2,45 +2,35 @@
  * Universal Flash Storage Host controller driver
  *
  * This code is based on drivers/scsi/ufs/ufshci.h
- * Copyright (C) 2011-2012 Samsung India Software Operations
+ * Copyright (C) 2011-2013 Samsung India Software Operations
  *
- * Santosh Yaraganavi <santosh.sy@samsung.com>
- * Vinayak Holikatti <h.vinayak@samsung.com>
+ * Authors:
+ *	Santosh Yaraganavi <santosh.sy@samsung.com>
+ *	Vinayak Holikatti <h.vinayak@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
+ * See the COPYING file in the top-level directory or visit
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
  *
  * 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.
  *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
- * USA.
+ * This program is provided "AS IS" and "WITH ALL FAULTS" and
+ * without warranty of any kind. You are solely responsible for
+ * determining the appropriateness of using and distributing
+ * the program and assume all risks associated with your exercise
+ * of rights with respect to the program, including but not limited
+ * to infringement of third party rights, the risks and costs of
+ * program errors, damage to or loss of data, programs or equipment,
+ * and unavailability or interruption of operations. Under no
+ * circumstances will the contributor of this Program be liable for
+ * any damages of any kind arising from your use or distribution of
+ * this program.
  */
 
 #ifndef _UFSHCI_H
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index bec0399..e9f056e 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2568,11 +2568,12 @@
 					struct slim_pending_ch, pending);
 		struct slim_ich *slc = &ctrl->chans[pch->chan];
 		u32 sl = slc->seglen << slc->rootexp;
-		if (revert) {
+		if (revert || slc->def > 0) {
 			if (slc->coeff == SLIM_COEFF_3)
 				sl *= 3;
 			ctrl->sched.usedslots += sl;
-			slc->def = 1;
+			if (revert)
+				slc->def++;
 			slc->state = SLIM_CH_ACTIVE;
 		} else
 			slim_remove_ch(ctrl, slc);
@@ -2635,7 +2636,11 @@
 			/* Disconnect source port to free it up */
 			if (SLIM_HDL_TO_LA(slc->srch) == sb->laddr)
 				slc->srch = 0;
-			if (slc->def != 0) {
+			/*
+			 * If controller overrides BW allocation,
+			 * delete this in remove channel itself
+			 */
+			if (slc->def != 0 && !ctrl->allocbw) {
 				list_del(&pch->pending);
 				kfree(pch);
 			}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 7f60128..b89f608 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -276,13 +276,12 @@
 		if (dd->input_block_size == 4 || dd->output_block_size == 4)
 			dd->use_dma = 0;
 
-		/* DM mode is currently unsupported for different block sizes */
-		if (dd->input_block_size != dd->output_block_size)
-			dd->use_dma = 0;
-
-		if (dd->use_dma)
-			dd->burst_size = max(dd->input_block_size,
-							DM_BURST_SIZE);
+		if (dd->use_dma) {
+			dd->input_burst_size = max(dd->input_block_size,
+						DM_BURST_SIZE);
+			dd->output_burst_size = max(dd->output_block_size,
+						DM_BURST_SIZE);
+		}
 	}
 
 	return;
@@ -646,7 +645,8 @@
 static void msm_spi_setup_dm_transfer(struct msm_spi *dd)
 {
 	dmov_box *box;
-	int bytes_to_send, num_rows, bytes_sent;
+	int bytes_to_send, bytes_sent;
+	int tx_num_rows, rx_num_rows;
 	u32 num_transfers;
 
 	atomic_set(&dd->rx_irq_called, 0);
@@ -678,64 +678,80 @@
 			      dd->max_trfr_len);
 
 	num_transfers = DIV_ROUND_UP(bytes_to_send, dd->bytes_per_word);
-	dd->unaligned_len = bytes_to_send % dd->burst_size;
-	num_rows = bytes_to_send / dd->burst_size;
+	dd->tx_unaligned_len = bytes_to_send % dd->output_burst_size;
+	dd->rx_unaligned_len = bytes_to_send % dd->input_burst_size;
+	tx_num_rows = bytes_to_send / dd->output_burst_size;
+	rx_num_rows = bytes_to_send / dd->input_burst_size;
 
 	dd->mode = SPI_DMOV_MODE;
 
-	if (num_rows) {
+	if (tx_num_rows) {
 		/* src in 16 MSB, dst in 16 LSB */
 		box = &dd->tx_dmov_cmd->box;
 		box->src_row_addr = dd->cur_transfer->tx_dma + bytes_sent;
-		box->src_dst_len = (dd->burst_size << 16) | dd->burst_size;
-		box->num_rows = (num_rows << 16) | num_rows;
-		box->row_offset = (dd->burst_size << 16) | 0;
+		box->src_dst_len
+			= (dd->output_burst_size << 16) | dd->output_burst_size;
+		box->num_rows = (tx_num_rows << 16) | tx_num_rows;
+		box->row_offset = (dd->output_burst_size << 16) | 0;
 
+		dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+				   DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
+				   offsetof(struct spi_dmov_cmd, box));
+	} else {
+		dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
+				   DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
+				   offsetof(struct spi_dmov_cmd, single_pad));
+	}
+
+	if (rx_num_rows) {
+		/* src in 16 MSB, dst in 16 LSB */
 		box = &dd->rx_dmov_cmd->box;
 		box->dst_row_addr = dd->cur_transfer->rx_dma + bytes_sent;
-		box->src_dst_len = (dd->burst_size << 16) | dd->burst_size;
-		box->num_rows = (num_rows << 16) | num_rows;
-		box->row_offset = (0 << 16) | dd->burst_size;
+		box->src_dst_len
+			= (dd->input_burst_size << 16) | dd->input_burst_size;
+		box->num_rows = (rx_num_rows << 16) | rx_num_rows;
+		box->row_offset = (0 << 16) | dd->input_burst_size;
 
-		dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
-				   DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
-				   offsetof(struct spi_dmov_cmd, box));
 		dd->rx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
 				   DMOV_CMD_ADDR(dd->rx_dmov_cmd_dma +
 				   offsetof(struct spi_dmov_cmd, box));
 	} else {
-		dd->tx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
-				   DMOV_CMD_ADDR(dd->tx_dmov_cmd_dma +
-				   offsetof(struct spi_dmov_cmd, single_pad));
 		dd->rx_dmov_cmd->cmd_ptr = CMD_PTR_LP |
 				   DMOV_CMD_ADDR(dd->rx_dmov_cmd_dma +
 				   offsetof(struct spi_dmov_cmd, single_pad));
 	}
 
-	if (!dd->unaligned_len) {
+	if (!dd->tx_unaligned_len) {
 		dd->tx_dmov_cmd->box.cmd |= CMD_LC;
-		dd->rx_dmov_cmd->box.cmd |= CMD_LC;
 	} else {
 		dmov_s *tx_cmd = &(dd->tx_dmov_cmd->single_pad);
-		dmov_s *rx_cmd = &(dd->rx_dmov_cmd->single_pad);
-		u32 offset = dd->cur_transfer->len - dd->unaligned_len;
+		u32 tx_offset = dd->cur_transfer->len - dd->tx_unaligned_len;
 
 		if ((dd->multi_xfr) && (dd->read_len <= 0))
-			offset = dd->cur_msg_len - dd->unaligned_len;
+			tx_offset = dd->cur_msg_len - dd->tx_unaligned_len;
 
 		dd->tx_dmov_cmd->box.cmd &= ~CMD_LC;
-		dd->rx_dmov_cmd->box.cmd &= ~CMD_LC;
 
-		memset(dd->tx_padding, 0, dd->burst_size);
-		memset(dd->rx_padding, 0, dd->burst_size);
+		memset(dd->tx_padding, 0, dd->output_burst_size);
 		if (dd->write_buf)
-			memcpy(dd->tx_padding, dd->write_buf + offset,
-			       dd->unaligned_len);
+			memcpy(dd->tx_padding, dd->write_buf + tx_offset,
+			       dd->tx_unaligned_len);
 
 		tx_cmd->src = dd->tx_padding_dma;
-		rx_cmd->dst = dd->rx_padding_dma;
-		tx_cmd->len = rx_cmd->len = dd->burst_size;
+		tx_cmd->len = dd->output_burst_size;
 	}
+
+	if (!dd->rx_unaligned_len) {
+		dd->rx_dmov_cmd->box.cmd |= CMD_LC;
+	} else {
+		dmov_s *rx_cmd = &(dd->rx_dmov_cmd->single_pad);
+		dd->rx_dmov_cmd->box.cmd &= ~CMD_LC;
+
+		memset(dd->rx_padding, 0, dd->input_burst_size);
+		rx_cmd->dst = dd->rx_padding_dma;
+		rx_cmd->len = dd->input_burst_size;
+	}
+
 	/* This also takes care of the padding dummy buf
 	   Since this is set to the correct length, the
 	   dummy bytes won't be actually sent */
@@ -893,7 +909,7 @@
 		if ((!dd->read_buf || op & SPI_OP_MAX_INPUT_DONE_FLAG) &&
 		    (!dd->write_buf || op & SPI_OP_MAX_OUTPUT_DONE_FLAG)) {
 			msm_spi_ack_transfer(dd);
-			if (dd->unaligned_len == 0) {
+			if (dd->rx_unaligned_len == 0) {
 				if (atomic_inc_return(&dd->rx_irq_called) == 1)
 					return IRQ_HANDLED;
 			}
@@ -1145,11 +1161,11 @@
 						 prev_xfr->len,
 						 DMA_TO_DEVICE);
 			}
-			if (dd->unaligned_len && dd->read_buf) {
-				offset = dd->cur_msg_len - dd->unaligned_len;
+			if (dd->rx_unaligned_len && dd->read_buf) {
+				offset = dd->cur_msg_len - dd->rx_unaligned_len;
 				dma_coherent_post_ops();
 				memcpy(dd->read_buf + offset, dd->rx_padding,
-				       dd->unaligned_len);
+				       dd->rx_unaligned_len);
 				memcpy(dd->cur_transfer->rx_buf,
 				       dd->read_buf + prev_xfr->len,
 				       dd->cur_transfer->len);
@@ -1171,11 +1187,11 @@
 
 unmap_end:
 	/* If we padded the transfer, we copy it from the padding buf */
-	if (dd->unaligned_len && dd->read_buf) {
-		offset = dd->cur_transfer->len - dd->unaligned_len;
+	if (dd->rx_unaligned_len && dd->read_buf) {
+		offset = dd->cur_transfer->len - dd->rx_unaligned_len;
 		dma_coherent_post_ops();
 		memcpy(dd->read_buf + offset, dd->rx_padding,
-		       dd->unaligned_len);
+		       dd->rx_unaligned_len);
 	}
 }
 
@@ -1960,7 +1976,8 @@
 			"use_dma ?    %s\n"
 			"rx block size = %d bytes\n"
 			"tx block size = %d bytes\n"
-			"burst size = %d bytes\n"
+			"input burst size = %d bytes\n"
+			"output burst size = %d bytes\n"
 			"DMA configuration:\n"
 			"tx_ch=%d, rx_ch=%d, tx_crci= %d, rx_crci=%d\n"
 			"--statistics--\n"
@@ -1975,7 +1992,8 @@
 			dd->use_dma ? "yes" : "no",
 			dd->input_block_size,
 			dd->output_block_size,
-			dd->burst_size,
+			dd->input_burst_size,
+			dd->output_burst_size,
 			dd->tx_dma_chan,
 			dd->rx_dma_chan,
 			dd->tx_dma_crci,
@@ -2104,12 +2122,15 @@
 	}
 }
 
-static inline u32 get_chunk_size(struct msm_spi *dd)
+static inline u32 get_chunk_size(struct msm_spi *dd, int input_burst_size,
+			int output_burst_size)
 {
 	u32 cache_line = dma_get_cache_alignment();
+	int burst_size = (input_burst_size > output_burst_size) ?
+		input_burst_size : output_burst_size;
 
 	return (roundup(sizeof(struct spi_dmov_cmd), DM_BYTE_ALIGN) +
-			  roundup(dd->burst_size, cache_line))*2;
+			  roundup(burst_size, cache_line))*2;
 }
 
 static void msm_spi_dmov_teardown(struct msm_spi *dd)
@@ -2125,8 +2146,10 @@
 		msleep(10);
 	}
 
-	dma_free_coherent(NULL, get_chunk_size(dd), dd->tx_dmov_cmd,
-			  dd->tx_dmov_cmd_dma);
+	dma_free_coherent(NULL,
+		get_chunk_size(dd, dd->input_burst_size, dd->output_burst_size),
+		dd->tx_dmov_cmd,
+		dd->tx_dmov_cmd_dma);
 	dd->tx_dmov_cmd = dd->rx_dmov_cmd = NULL;
 	dd->tx_padding = dd->rx_padding = NULL;
 }
@@ -2304,8 +2327,11 @@
 
 	/* We send NULL device, since it requires coherent_dma_mask id
 	   device definition, we're okay with using system pool */
-	dd->tx_dmov_cmd = dma_alloc_coherent(NULL, get_chunk_size(dd),
-					     &dd->tx_dmov_cmd_dma, GFP_KERNEL);
+	dd->tx_dmov_cmd
+		= dma_alloc_coherent(NULL,
+			get_chunk_size(dd, dd->input_burst_size,
+				dd->output_burst_size),
+			&dd->tx_dmov_cmd_dma, GFP_KERNEL);
 	if (dd->tx_dmov_cmd == NULL)
 		return -ENOMEM;
 
@@ -2319,9 +2345,9 @@
 	dd->tx_padding = (u8 *)ALIGN((size_t)&dd->rx_dmov_cmd[1], cache_line);
 	dd->tx_padding_dma = ALIGN(dd->rx_dmov_cmd_dma +
 			      sizeof(struct spi_dmov_cmd), cache_line);
-	dd->rx_padding = (u8 *)ALIGN((size_t)(dd->tx_padding + dd->burst_size),
-				     cache_line);
-	dd->rx_padding_dma = ALIGN(dd->tx_padding_dma + dd->burst_size,
+	dd->rx_padding = (u8 *)ALIGN((size_t)(dd->tx_padding +
+		dd->output_burst_size), cache_line);
+	dd->rx_padding_dma = ALIGN(dd->tx_padding_dma + dd->output_burst_size,
 				      cache_line);
 
 	/* Setup DM commands */
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index 7f5b726..b749cc0 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -318,7 +318,8 @@
 	struct msm_dmov_cmd      rx_hdr;
 	int                      input_block_size;
 	int                      output_block_size;
-	int                      burst_size;
+	int                      input_burst_size;
+	int                      output_burst_size;
 	atomic_t                 rx_irq_called;
 	atomic_t                 tx_irq_called;
 	/* Used to pad messages unaligned to block size */
@@ -326,7 +327,8 @@
 	dma_addr_t               tx_padding_dma;
 	u8                       *rx_padding;
 	dma_addr_t               rx_padding_dma;
-	u32                      unaligned_len;
+	u32                      tx_unaligned_len;
+	u32                      rx_unaligned_len;
 	/* DMA statistics */
 	int                      stat_dmov_tx_err;
 	int                      stat_dmov_rx_err;
diff --git a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h
deleted file mode 100644
index e69de29..0000000
--- a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h
+++ /dev/null
diff --git a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
deleted file mode 100644
index e69de29..0000000
--- a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
+++ /dev/null
diff --git a/drivers/staging/dream/Kconfig b/drivers/staging/dream/Kconfig
deleted file mode 100644
index 0c30b19..0000000
--- a/drivers/staging/dream/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-config DREAM
-	tristate "HTC Dream support"
-	depends on MACH_TROUT
-
-if DREAM
-
-source "drivers/staging/dream/camera/Kconfig"
-
-config INPUT_GPIO
-	tristate "GPIO driver support"
-	help
-	  Say Y here if you want to support gpio based keys, wheels etc...
-endif
diff --git a/drivers/staging/dream/Makefile b/drivers/staging/dream/Makefile
deleted file mode 100644
index fbea0ab..0000000
--- a/drivers/staging/dream/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-EXTRA_CFLAGS=-Idrivers/staging/dream/include
-obj-$(CONFIG_MSM_ADSP)		+= qdsp5/
-obj-$(CONFIG_MSM_CAMERA)	+= camera/
-obj-$(CONFIG_INPUT_GPIO)	+= gpio_axis.o gpio_event.o gpio_input.o gpio_matrix.o gpio_output.o
-
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index b04213c..7d3664a 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -54,6 +54,7 @@
 #define TSENS_SW_RST			BIT(1)
 #define TSENS_ADC_CLK_SEL		BIT(2)
 #define TSENS_SENSOR0_SHIFT		3
+#define TSENS_62_5_MS_MEAS_PERIOD	1
 #define TSENS_312_5_MS_MEAS_PERIOD	2
 #define TSENS_MEAS_PERIOD_SHIFT		18
 
@@ -239,6 +240,7 @@
 	struct platform_device		*pdev;
 	bool				prev_reading_avail;
 	bool				calibration_less_mode;
+	bool				tsens_local_init;
 	int				tsens_factor;
 	uint32_t			tsens_num_sensor;
 	int				tsens_irq;
@@ -570,24 +572,28 @@
 	unsigned int reg_cntl = 0;
 	unsigned int i;
 
-	reg_cntl = readl_relaxed(TSENS_CTRL_ADDR(tmdev->tsens_addr));
-	writel_relaxed(reg_cntl | TSENS_SW_RST,
+	if (tmdev->tsens_local_init) {
+		writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
+		writel_relaxed(reg_cntl | TSENS_SW_RST,
 			TSENS_CTRL_ADDR(tmdev->tsens_addr));
-	reg_cntl |= ((TSENS_312_5_MS_MEAS_PERIOD << TSENS_MEAS_PERIOD_SHIFT) |
+		reg_cntl |= ((TSENS_62_5_MS_MEAS_PERIOD <<
+		TSENS_MEAS_PERIOD_SHIFT) |
 		(((1 << tmdev->tsens_num_sensor) - 1) << TSENS_SENSOR0_SHIFT) |
 		TSENS_EN);
-	writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
-	writel_relaxed(TSENS_GLOBAL_INIT_DATA,
+		writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
+		writel_relaxed(TSENS_GLOBAL_INIT_DATA,
 			TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
-	writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
+		writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
 			TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
-	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
-		writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
+		for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+			writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
 			TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
 				+ (i * TSENS_SN_ADDR_OFFSET));
-		writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
+			writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
 			TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
 				+ (i * TSENS_SN_ADDR_OFFSET));
+		}
+		pr_debug("Local TSENS control initialization\n");
 	}
 	writel_relaxed(TSENS_INTERRUPT_EN,
 		TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
@@ -1156,6 +1162,8 @@
 	tmdev->calibration_less_mode = of_property_read_bool(of_node,
 				"qcom,calibration-less-mode");
 	tmdev->calib_mode = calib_type;
+	tmdev->tsens_local_init = of_property_read_bool(of_node,
+				"qcom,tsens_local_init");
 
 	tmdev->tsens_irq = platform_get_irq(pdev, 0);
 	if (tmdev->tsens_irq < 0) {
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 0348145..8760603 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -1719,7 +1719,7 @@
  */
 static int smux_handle_rx_power_cmd(struct smux_pkt_t *pkt)
 {
-	struct smux_pkt_t *ack_pkt = NULL;
+	struct smux_pkt_t *ack_pkt;
 	int power_down = 0;
 	unsigned long flags;
 
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 9274c17..5c8645a 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -988,14 +988,6 @@
 	  Choose M here to compile it as a module. The module will be
 	  called msm_serial_hs.
 
-config SERIAL_MSM_CLOCK_CONTROL
-	bool "Allow tty clients to make clock requests to msm uarts."
-	depends on SERIAL_MSM=y
-	default y
-	help
-	 Provides an interface for tty clients to request the msm uart clock
-	 to be turned on or off for power savings.
-
 config SERIAL_MSM_RX_WAKEUP
 	bool "Wakeup the msm uart clock on GPIO activity."
 	depends on SERIAL_MSM_CLOCK_CONTROL
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index c982587..63acde1 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -218,6 +218,7 @@
 	u32 bus_perf_client;
 	/* BLSP UART required BUS Scaling data */
 	struct msm_bus_scale_pdata *bus_scale_table;
+	bool rx_discard_flush_issued;
 };
 
 #define MSM_UARTDM_BURST_SIZE 16   /* DM burst size (in bytes) */
@@ -229,6 +230,7 @@
 #define BAM_PIPE_MAX 11
 #define BUS_SCALING 1
 #define BUS_RESET 0
+#define RX_FLUSH_COMPLETE_TIMEOUT 300 /* In jiffies */
 
 static struct dentry *debug_base;
 static struct msm_hs_port q_uart_port[UARTDM_NR];
@@ -849,6 +851,7 @@
 {
 	unsigned int bps;
 	unsigned long data;
+	int ret;
 	unsigned int c_cflag = termios->c_cflag;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	struct msm_hs_rx *rx = &msm_uport->rx;
@@ -969,8 +972,17 @@
 			msm_hs_spsconnect_rx(uport);
 			msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
 		} else {
+			msm_uport->rx_discard_flush_issued = true;
 			/* do discard flush */
 			msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+			pr_debug("%s(): wainting for flush completion.\n",
+								__func__);
+			ret = wait_event_timeout(msm_uport->rx.wait,
+				msm_uport->rx_discard_flush_issued == false,
+				RX_FLUSH_COMPLETE_TIMEOUT);
+			if (!ret)
+				pr_err("%s(): Discard flush pending.\n",
+								__func__);
 		}
 	}
 
@@ -1514,8 +1526,23 @@
 					struct msm_dmov_errdata *err)
 {
 	struct msm_hs_port *msm_uport;
+	struct uart_port *uport;
+	unsigned long flags;
 
 	msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer);
+	uport = &(msm_uport->uport);
+
+	pr_debug("%s(): called result:%x\n", __func__, result);
+	if (!(result & DMOV_RSLT_ERROR)) {
+		if (result & DMOV_RSLT_FLUSH) {
+			if (msm_uport->rx_discard_flush_issued) {
+				spin_lock_irqsave(&uport->lock, flags);
+				msm_uport->rx_discard_flush_issued = false;
+				spin_unlock_irqrestore(&uport->lock, flags);
+				wake_up(&msm_uport->rx.wait);
+			}
+		}
+	}
 
 	tasklet_schedule(&msm_uport->rx.tlet);
 }
@@ -1661,6 +1688,7 @@
 {
 	unsigned long sr_status;
 	unsigned long flags;
+	int ret;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	struct circ_buf *tx_buf = &uport->state->xmit;
 
@@ -1716,10 +1744,24 @@
 	}
 
 	if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
-		if (msm_uport->rx.flush == FLUSH_NONE)
+		if (msm_uport->rx.flush == FLUSH_NONE) {
 			msm_hs_stop_rx_locked(uport);
+			if (!is_blsp_uart(msm_uport))
+				msm_uport->rx_discard_flush_issued = true;
+		}
 
 		spin_unlock_irqrestore(&uport->lock, flags);
+		if (msm_uport->rx_discard_flush_issued) {
+			pr_debug("%s(): wainting for flush completion.\n",
+								__func__);
+			ret = wait_event_timeout(msm_uport->rx.wait,
+				msm_uport->rx_discard_flush_issued == false,
+				RX_FLUSH_COMPLETE_TIMEOUT);
+			if (!ret)
+				pr_err("%s(): Flush complete pending.\n",
+								__func__);
+		}
+
 		mutex_unlock(&msm_uport->clk_mutex);
 		return 0;  /* come back later to really clock off */
 	}
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 3e15ea7..fddb4fe 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -134,6 +134,8 @@
 
 source "drivers/usb/musb/Kconfig"
 
+source "drivers/usb/renesas_usbhs/Kconfig"
+
 source "drivers/usb/class/Kconfig"
 
 source "drivers/usb/storage/Kconfig"
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 9dd9c40..5b97148 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -516,6 +516,82 @@
 /*-------------------------------------------------------------------------*/
 /* Supported functions initialization */
 
+/* ACM */
+static char acm_transports[32];	/*enabled ACM ports - "tty[,sdio]"*/
+static ssize_t acm_transports_store(
+		struct device *device, struct device_attribute *attr,
+		const char *buff, size_t size)
+{
+	strlcpy(acm_transports, buff, sizeof(acm_transports));
+
+	return size;
+}
+
+static DEVICE_ATTR(acm_transports, S_IWUSR, NULL, acm_transports_store);
+static struct device_attribute *acm_function_attributes[] = {
+		&dev_attr_acm_transports,
+		NULL
+};
+
+static void acm_function_cleanup(struct android_usb_function *f)
+{
+	gserial_cleanup();
+}
+
+static int
+acm_function_bind_config(struct android_usb_function *f,
+		struct usb_configuration *c)
+{
+	char *name;
+	char buf[32], *b;
+	int err = -1, i;
+	static int acm_initialized, ports;
+
+	if (acm_initialized)
+		goto bind_config;
+
+	acm_initialized = 1;
+	strlcpy(buf, acm_transports, sizeof(buf));
+	b = strim(buf);
+
+	while (b) {
+		name = strsep(&b, ",");
+
+		if (name) {
+			err = acm_init_port(ports, name);
+			if (err) {
+				pr_err("acm: Cannot open port '%s'", name);
+				goto out;
+			}
+			ports++;
+		}
+	}
+	err = acm_port_setup(c);
+	if (err) {
+		pr_err("acm: Cannot setup transports");
+		goto out;
+	}
+
+bind_config:
+	for (i = 0; i < ports; i++) {
+		err = acm_bind_config(c, i);
+		if (err) {
+			pr_err("acm: bind_config failed for port %d", i);
+			goto out;
+		}
+	}
+
+out:
+	return err;
+}
+
+static struct android_usb_function acm_function = {
+	.name		= "acm",
+	.cleanup	= acm_function_cleanup,
+	.bind_config	= acm_function_bind_config,
+	.attributes	= acm_function_attributes,
+};
+
 /* RMNET_SMD */
 static int rmnet_smd_function_bind_config(struct android_usb_function *f,
 					  struct usb_configuration *c)
@@ -996,78 +1072,6 @@
 	.attributes	= serial_function_attributes,
 };
 
-/* ACM */
-static char acm_transports[32];	/*enabled ACM ports - "tty[,sdio]"*/
-static ssize_t acm_transports_store(
-		struct device *device, struct device_attribute *attr,
-		const char *buff, size_t size)
-{
-	strlcpy(acm_transports, buff, sizeof(acm_transports));
-
-	return size;
-}
-
-static DEVICE_ATTR(acm_transports, S_IWUSR, NULL, acm_transports_store);
-static struct device_attribute *acm_function_attributes[] = {
-		&dev_attr_acm_transports, NULL };
-
-static void acm_function_cleanup(struct android_usb_function *f)
-{
-	gserial_cleanup();
-}
-
-static int acm_function_bind_config(struct android_usb_function *f,
-					struct usb_configuration *c)
-{
-	char *name;
-	char buf[32], *b;
-	int err = -1, i;
-	static int acm_initialized, ports;
-
-	if (acm_initialized)
-		goto bind_config;
-
-	acm_initialized = 1;
-	strlcpy(buf, acm_transports, sizeof(buf));
-	b = strim(buf);
-
-	while (b) {
-		name = strsep(&b, ",");
-
-		if (name) {
-			err = acm_init_port(ports, name);
-			if (err) {
-				pr_err("acm: Cannot open port '%s'", name);
-				goto out;
-			}
-			ports++;
-		}
-	}
-	err = acm_port_setup(c);
-	if (err) {
-		pr_err("acm: Cannot setup transports");
-		goto out;
-	}
-
-bind_config:
-	for (i = 0; i < ports; i++) {
-		err = acm_bind_config(c, i);
-		if (err) {
-			pr_err("acm: bind_config failed for port %d", i);
-			goto out;
-		}
-	}
-
-out:
-	return err;
-}
-static struct android_usb_function acm_function = {
-	.name		= "acm",
-	.cleanup	= acm_function_cleanup,
-	.bind_config	= acm_function_bind_config,
-	.attributes	= acm_function_attributes,
-};
-
 /* CCID */
 static int ccid_function_init(struct android_usb_function *f,
 					struct usb_composite_dev *cdev)
@@ -1093,7 +1097,8 @@
 	.bind_config	= ccid_function_bind_config,
 };
 
-static int mtp_function_init(struct android_usb_function *f,
+static int
+mtp_function_init(struct android_usb_function *f,
 		struct usb_composite_dev *cdev)
 {
 	return mtp_setup();
@@ -1104,13 +1109,16 @@
 	mtp_cleanup();
 }
 
-static int mtp_function_bind_config(struct android_usb_function *f,
+static int
+mtp_function_bind_config(struct android_usb_function *f,
 		struct usb_configuration *c)
 {
 	return mtp_bind_config(c, false);
 }
 
-static int ptp_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
+static int
+ptp_function_init(struct android_usb_function *f,
+		struct usb_composite_dev *cdev)
 {
 	/* nothing to do - initialization is handled by mtp_function_init */
 	return 0;
@@ -1121,7 +1129,9 @@
 	/* nothing to do - cleanup is handled by mtp_function_cleanup */
 }
 
-static int ptp_function_bind_config(struct android_usb_function *f, struct usb_configuration *c)
+static int
+ptp_function_bind_config(struct android_usb_function *f,
+		struct usb_configuration *c)
 {
 	return mtp_bind_config(c, true);
 }
@@ -2083,6 +2093,7 @@
 	bool audio_enabled = false;
 	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
 
+
 	if (!cdev)
 		return -ENODEV;
 
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index ccede0c..569f200 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -3,12 +3,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
  * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
  */
 
 #include <linux/module.h>
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index c02c8e4..e0255ce 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1391,9 +1391,6 @@
 		dev_err(dev, "[%s] EINVAL\n", __func__);
 		return 0;
 	}
-	dump = kmalloc(2048, GFP_KERNEL);
-	if (dump == NULL)
-		return -ENOMEM;
 
 	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
 	if (!dump) {
@@ -3283,6 +3280,7 @@
 static int ci13xxx_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *));
 static int ci13xxx_stop(struct usb_gadget_driver *driver);
+
 /**
  * Device operations part of the API to the USB controller hardware,
  * which don't involve endpoints (or i/o)
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 76028b2..3145418 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -137,10 +137,10 @@
 #define CI13XXX_CONTROLLER_RESET_EVENT			0
 #define CI13XXX_CONTROLLER_CONNECT_EVENT		1
 #define CI13XXX_CONTROLLER_SUSPEND_EVENT		2
-#define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT	3
-#define CI13XXX_CONTROLLER_RESUME_EVENT	        4
-#define CI13XXX_CONTROLLER_DISCONNECT_EVENT	    5
-#define CI13XXX_CONTROLLER_UDC_STARTED_EVENT	    6
+#define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT		3
+#define CI13XXX_CONTROLLER_RESUME_EVENT		4
+#define CI13XXX_CONTROLLER_DISCONNECT_EVENT		5
+#define CI13XXX_CONTROLLER_UDC_STARTED_EVENT		6
 
 	void	(*notify_event) (struct ci13xxx *udc, unsigned event);
 };
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4bc0da2..de4a233 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -176,13 +176,12 @@
 	_ep->comp_desc = comp_desc;
 	if (g->speed == USB_SPEED_SUPER) {
 		switch (usb_endpoint_type(_ep->desc)) {
-		case USB_ENDPOINT_XFER_BULK:
-		case USB_ENDPOINT_XFER_INT:
-			_ep->maxburst = comp_desc->bMaxBurst + 1;
-			break;
 		case USB_ENDPOINT_XFER_ISOC:
 			/* mult: bits 1:0 of bmAttributes */
 			_ep->mult = comp_desc->bmAttributes & 0x3;
+		case USB_ENDPOINT_XFER_BULK:
+		case USB_ENDPOINT_XFER_INT:
+			_ep->maxburst = comp_desc->bMaxBurst + 1;
 			break;
 		default:
 			if (comp_desc->bMaxBurst != 0)
@@ -693,7 +692,6 @@
 			CONFIG_USB_GADGET_VBUS_DRAW;
 done:
 	usb_gadget_vbus_draw(gadget, power);
-
 	if (result >= 0 && cdev->delayed_status)
 		result = USB_GADGET_DELAYED_STATUS;
 	return result;
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 0752188..de54714 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
-#include <linux/usb/android_composite.h>
 #include <mach/usb_gadget_xport.h>
 
 #include "u_serial.h"
diff --git a/drivers/usb/gadget/f_ccid.c b/drivers/usb/gadget/f_ccid.c
index 4e28d34..6888935 100644
--- a/drivers/usb/gadget/f_ccid.c
+++ b/drivers/usb/gadget/f_ccid.c
@@ -16,7 +16,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
-#include <linux/usb/android_composite.h>
 #include <linux/fs.h>
 #include <linux/usb/ccid_desc.h>
 #include <linux/miscdevice.h>
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 245a972..bac8b68 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -3200,7 +3200,7 @@
 	if (unlikely(!fsg))
 		return -ENOMEM;
 
-	fsg->function.name        = "mass_storage";
+	fsg->function.name        = FSG_DRIVER_DESC;
 	fsg->function.strings     = fsg_strings_array;
 	fsg->function.bind        = fsg_bind;
 	fsg->function.unbind      = fsg_unbind;
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index a32dd15..893f315 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -662,19 +662,30 @@
 static int mbim_bam_connect(struct f_mbim *dev)
 {
 	int ret;
+	u8 src_connection_idx, dst_connection_idx;
+	struct usb_gadget *gadget = dev->cdev->gadget;
 
 	pr_info("dev:%p portno:%d\n", dev, dev->port_num);
 
+	src_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+		USB_TO_PEER_PERIPHERAL, dev->port_num);
+	dst_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+		PEER_PERIPHERAL_TO_USB, dev->port_num);
+	if (src_connection_idx < 0 || dst_connection_idx < 0) {
+		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+		return ret;
+	}
+
 	ret = bam_data_connect(&dev->bam_port, dev->port_num,
-		USB_GADGET_XPORT_BAM2BAM, dev->port_num, USB_FUNC_MBIM);
+		USB_GADGET_XPORT_BAM2BAM, src_connection_idx,
+		dst_connection_idx, USB_FUNC_MBIM);
 	if (ret) {
 		pr_err("bam_data_setup failed: err:%d\n",
 				ret);
 		return ret;
-	} else {
-		pr_info("mbim bam connected\n");
 	}
 
+	pr_info("mbim bam connected\n");
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 559fd04..51f0e50 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -390,14 +390,27 @@
 static int ecm_qc_bam_connect(struct f_ecm_qc *dev)
 {
 	int ret;
+	u8 src_connection_idx, dst_connection_idx;
+	struct usb_composite_dev *cdev = dev->port.func.config->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
+	enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
+		IPA_P_BAM : A2_P_BAM;
 
-	ecm_qc_bam_port.cdev = dev->port.func.config->cdev;
+	ecm_qc_bam_port.cdev = cdev;
 	ecm_qc_bam_port.in = dev->port.in_ep;
 	ecm_qc_bam_port.out = dev->port.out_ep;
 
 	/* currently we use the first connection */
+	src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
+		USB_TO_PEER_PERIPHERAL, 0);
+	dst_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
+		PEER_PERIPHERAL_TO_USB, 0);
+	if (src_connection_idx < 0 || dst_connection_idx < 0) {
+		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+		return ret;
+	}
 	ret = bam_data_connect(&ecm_qc_bam_port, 0, dev->xport,
-					0, USB_FUNC_ECM);
+		src_connection_idx, dst_connection_idx, USB_FUNC_ECM);
 	if (ret) {
 		pr_err("bam_data_connect failed: err:%d\n", ret);
 		return ret;
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 51d7bc1..8b01176 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -421,22 +421,33 @@
 static int rndis_qc_bam_connect(struct f_rndis_qc *dev)
 {
 	int ret;
+	u8 src_connection_idx, dst_connection_idx;
+	struct usb_composite_dev *cdev = dev->port.func.config->cdev;
+	struct usb_gadget *gadget = cdev->gadget;
 
-	dev->bam_port.cdev = dev->port.func.config->cdev;
+	dev->bam_port.cdev = cdev;
 	dev->bam_port.in = dev->port.in_ep;
 	dev->bam_port.out = dev->port.out_ep;
 
 	/* currently we use the first connection */
+	src_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+		USB_TO_PEER_PERIPHERAL, 0);
+	dst_connection_idx = usb_bam_get_connection_idx(gadget->name, A2_P_BAM,
+		PEER_PERIPHERAL_TO_USB, 0);
+	if (src_connection_idx < 0 || dst_connection_idx < 0) {
+		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+		return ret;
+	}
 	ret = bam_data_connect(&dev->bam_port, 0, USB_GADGET_XPORT_BAM2BAM,
-			0, USB_FUNC_RNDIS);
+		src_connection_idx, dst_connection_idx, USB_FUNC_RNDIS);
 	if (ret) {
 		pr_err("bam_data_connect failed: err:%d\n",
 				ret);
 		return ret;
-	} else {
-		pr_info("rndis bam connected\n");
 	}
 
+	pr_info("rndis bam connected\n");
+
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index 3069bcb..6518095 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -1,7 +1,7 @@
 /*
  * f_qdss.c -- QDSS function Driver
  *
- * 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
@@ -447,8 +447,8 @@
 		qdss->ch.notify(qdss->ch.priv, USB_QDSS_DISCONNECT, NULL,
 			NULL);
 		/* If the app was never started, we can skip USB BAM reset */
-		status = set_qdss_data_connection(qdss->data,
-			qdss->data->address, 0);
+		status = set_qdss_data_connection(qdss->cdev->gadget,
+			qdss->data, qdss->data->address, 0);
 		if (status)
 			pr_err("qdss_disconnect error");
 	}
@@ -490,7 +490,7 @@
 		return;
 	}
 
-	status = set_qdss_data_connection(qdss->data,
+	status = set_qdss_data_connection(qdss->cdev->gadget, qdss->data,
 		qdss->data->address, 1);
 	if (status) {
 		pr_err("set_qdss_data_connection error");
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 0d8fa0f..4b9dfbf 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -14,7 +14,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
-#include <linux/usb/android_composite.h>
 #include <linux/spinlock.h>
 
 #include <mach/usb_gadget_xport.h>
@@ -388,6 +387,8 @@
 	unsigned		port_num;
 	enum transport_type	cxport = rmnet_ports[dev->port_num].ctrl_xport;
 	enum transport_type	dxport = rmnet_ports[dev->port_num].data_xport;
+	u8			src_connection_idx, dst_connection_idx;
+	struct usb_gadget	*gadget = dev->cdev->gadget;
 
 	pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
 			__func__, xport_to_str(cxport), xport_to_str(dxport),
@@ -436,12 +437,42 @@
 	}
 
 	port_num = rmnet_ports[dev->port_num].data_xport_num;
+
 	switch (dxport) {
 	case USB_GADGET_XPORT_BAM:
 	case USB_GADGET_XPORT_BAM2BAM:
-	case USB_GADGET_XPORT_BAM2BAM_IPA:
+		src_connection_idx = usb_bam_get_connection_idx(gadget->name,
+			A2_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
+		dst_connection_idx = usb_bam_get_connection_idx(gadget->name,
+			A2_P_BAM, PEER_PERIPHERAL_TO_USB, port_num);
+		if (dst_connection_idx < 0 || src_connection_idx < 0) {
+			pr_err("%s: usb_bam_get_connection_idx failed\n",
+				__func__);
+			gsmd_ctrl_disconnect(&dev->port, port_num);
+			return ret;
+		}
 		ret = gbam_connect(&dev->port, port_num,
-						   dxport, port_num);
+			dxport, src_connection_idx, dst_connection_idx);
+		if (ret) {
+			pr_err("%s: gbam_connect failed: err:%d\n",
+				__func__, ret);
+			gsmd_ctrl_disconnect(&dev->port, port_num);
+			return ret;
+		}
+		break;
+	case USB_GADGET_XPORT_BAM2BAM_IPA:
+		src_connection_idx = usb_bam_get_connection_idx(gadget->name,
+			IPA_P_BAM, USB_TO_PEER_PERIPHERAL, port_num);
+		dst_connection_idx = usb_bam_get_connection_idx(gadget->name,
+			IPA_P_BAM, PEER_PERIPHERAL_TO_USB, port_num);
+		if (dst_connection_idx < 0 || src_connection_idx < 0) {
+			pr_err("%s: usb_bam_get_connection_idx failed\n",
+				__func__);
+			gsmd_ctrl_disconnect(&dev->port, port_num);
+			return ret;
+		}
+		ret = gbam_connect(&dev->port, port_num,
+			dxport, src_connection_idx, dst_connection_idx);
 		if (ret) {
 			pr_err("%s: gbam_connect failed: err:%d\n",
 					__func__, ret);
diff --git a/drivers/usb/gadget/qcom_maemo.c b/drivers/usb/gadget/qcom_maemo.c
deleted file mode 100644
index 2fb8be0..0000000
--- a/drivers/usb/gadget/qcom_maemo.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Qualcomm Maemo Composite driver
- *
- * Copyright (C) 2008 David Brownell
- * Copyright (C) 2008 Nokia Corporation
- * Copyright (C) 2009 Samsung Electronics
- * Copyright (c) 2010, The Linux Foundation. All rights reserved.
- *
- * This program from The Linux Foundation is free software; you can
- * redistribute it and/or modify it under the GNU General Public License
- * version 2 and only version 2 as published by the Free Software Foundation.
- * The original work available from [git.kernel.org ] is subject to the
- * notice below.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/kernel.h>
-#include <linux/utsname.h>
-#include <linux/kdev_t.h>
-#include <linux/delay.h>
-
-
-#define DRIVER_DESC		"Qcom Maemo Composite Gadget"
-#define VENDOR_ID		0x05c6
-#define PRODUCT_ID		0x902E
-
-/*
- * kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module.  So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
-#define USB_ETH
-
-#define USB_ETH_RNDIS
-#ifdef USB_ETH_RNDIS
-#  include "f_rndis.c"
-#  include "rndis.c"
-#endif
-
-
-#include "u_serial.c"
-#include "f_serial.c"
-
-#include "u_ether.c"
-
-#undef DBG     /* u_ether.c has broken idea about macros */
-#undef VDBG    /* so clean up after it */
-#undef ERROR
-#undef INFO
-
-#include "f_mass_storage.c"
-#include "f_diag.c"
-#include "f_rmnet.c"
-
-/*-------------------------------------------------------------------------*/
-/* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX         0
-#define STRING_PRODUCT_IDX              1
-#define STRING_SERIAL_IDX               2
-
-/* String Table */
-static struct usb_string strings_dev[] = {
-	/* These dummy values should be overridden by platform data */
-	[STRING_MANUFACTURER_IDX].s = "Qualcomm Incorporated",
-	[STRING_PRODUCT_IDX].s = "Usb composition",
-	[STRING_SERIAL_IDX].s = "0123456789ABCDEF",
-	{  }                    /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-	.language       = 0x0409,       /* en-us */
-	.strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-	&stringtab_dev,
-	NULL,
-};
-
-static struct usb_device_descriptor device_desc = {
-	.bLength              = sizeof(device_desc),
-	.bDescriptorType      = USB_DT_DEVICE,
-	.bcdUSB               = __constant_cpu_to_le16(0x0200),
-	.bDeviceClass         = USB_CLASS_PER_INTERFACE,
-	.bDeviceSubClass      =      0,
-	.bDeviceProtocol      =      0,
-	.idVendor             = __constant_cpu_to_le16(VENDOR_ID),
-	.idProduct            = __constant_cpu_to_le16(PRODUCT_ID),
-	.bcdDevice            = __constant_cpu_to_le16(0xffff),
-	.bNumConfigurations   = 1,
-};
-
-static u8 hostaddr[ETH_ALEN];
-static struct usb_diag_ch *diag_ch;
-static struct usb_diag_platform_data usb_diag_pdata = {
-	.ch_name = DIAG_LEGACY,
-};
-
-/****************************** Configurations ******************************/
-static struct fsg_module_parameters mod_data = {
-	.stall = 0
-};
-FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
-
-static struct fsg_common *fsg_common;
-static int maemo_setup_config(struct usb_configuration *c,
-			const struct usb_ctrlrequest *ctrl);
-
-static int maemo_do_config(struct usb_configuration *c)
-{
-	int ret;
-
-	ret = rndis_bind_config(c, hostaddr);
-	if (ret < 0)
-		return ret;
-
-	ret = diag_function_add(c);
-	if (ret < 0)
-		return ret;
-
-	ret = gser_bind_config(c, 0);
-	if (ret < 0)
-		return ret;
-
-	ret = gser_bind_config(c, 1);
-	if (ret < 0)
-		return ret;
-
-	ret = rmnet_function_add(c);
-	if (ret < 0)
-		return ret;
-
-	ret = fsg_add(c->cdev, c, fsg_common);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static struct usb_configuration maemo_config_driver = {
-	.label			= "Qcom Maemo Gadget",
-	.bind			= maemo_do_config,
-	.setup			= maemo_setup_config,
-	.bConfigurationValue	= 1,
-	.bMaxPower		= 0xFA,
-};
-static int maemo_setup_config(struct usb_configuration *c,
-		const struct usb_ctrlrequest *ctrl)
-{
-	int i;
-	int ret = -EOPNOTSUPP;
-
-	for (i = 0; i < maemo_config_driver.next_interface_id; i++) {
-		if (maemo_config_driver.interface[i]->setup) {
-			ret = maemo_config_driver.interface[i]->setup(
-				maemo_config_driver.interface[i], ctrl);
-			if (ret >= 0)
-				return ret;
-		}
-	}
-
-	return ret;
-}
-
-static int maemo_bind(struct usb_composite_dev *cdev)
-{
-	struct usb_gadget *gadget = cdev->gadget;
-	int status, gcnum;
-
-	/* set up diag channel */
-	diag_ch = diag_setup(&usb_diag_pdata);
-	if (IS_ERR(diag_ch))
-		return PTR_ERR(diag_ch);
-
-	/* set up network link layer */
-	status = gether_setup(cdev->gadget, hostaddr);
-	if (status < 0)
-		goto diag_clean;
-
-	/* set up serial link layer */
-	status = gserial_setup(cdev->gadget, 2);
-	if (status < 0)
-		goto fail0;
-
-	/* set up mass storage function */
-	fsg_common = fsg_common_from_params(0, cdev, &mod_data);
-	if (IS_ERR(fsg_common)) {
-		status = PTR_ERR(fsg_common);
-		goto fail1;
-	}
-
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0)
-		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-	else {
-		/* gadget zero is so simple (for now, no altsettings) that
-		 * it SHOULD NOT have problems with bulk-capable hardware.
-		 * so just warn about unrcognized controllers -- don't panic.
-		 *
-		 * things like configuration and altsetting numbering
-		 * can need hardware-specific attention though.
-		 */
-		WARNING(cdev, "controller '%s' not recognized\n",
-			gadget->name);
-		device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
-	}
-
-	/* Allocate string descriptor numbers ... note that string
-	 * contents can be overridden by the composite_dev glue.
-	*/
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto fail2;
-	strings_dev[STRING_MANUFACTURER_IDX].id = status;
-	device_desc.iManufacturer = status;
-
-	status = usb_string_id(cdev);
-	if (status < 0)
-		goto fail2;
-	strings_dev[STRING_PRODUCT_IDX].id = status;
-	device_desc.iProduct = status;
-
-	if (!usb_gadget_set_selfpowered(gadget))
-		maemo_config_driver.bmAttributes |= USB_CONFIG_ATT_SELFPOWER;
-
-	if (gadget->ops->wakeup)
-		maemo_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-
-	/* register our first configuration */
-	status = usb_add_config(cdev, &maemo_config_driver);
-	if (status < 0)
-		goto fail2;
-
-	usb_gadget_set_selfpowered(gadget);
-	dev_info(&gadget->dev, DRIVER_DESC "\n");
-	fsg_common_put(fsg_common);
-	return 0;
-
-fail2:
-	fsg_common_put(fsg_common);
-fail1:
-	gserial_cleanup();
-fail0:
-	gether_cleanup();
-diag_clean:
-	diag_cleanup(diag_ch);
-
-	return status;
-}
-
-static int __exit maemo_unbind(struct usb_composite_dev *cdev)
-{
-	gserial_cleanup();
-	gether_cleanup();
-	diag_cleanup(diag_ch);
-	return 0;
-}
-
-static struct usb_composite_driver qcom_maemo_driver = {
-	.name		= "Qcom Maemo Gadget",
-	.dev		= &device_desc,
-	.strings	= dev_strings,
-	.bind		= maemo_bind,
-	.unbind		= __exit_p(maemo_unbind),
-};
-
-static int __init qcom_maemo_usb_init(void)
-{
-	return usb_composite_register(&qcom_maemo_driver);
-}
-module_init(qcom_maemo_usb_init);
-
-static void __exit qcom_maemo_usb_cleanup(void)
-{
-	usb_composite_unregister(&qcom_maemo_driver);
-}
-module_exit(qcom_maemo_usb_cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("1.0");
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 5a6faf2..3c3fbca 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -100,7 +100,8 @@
 
 	u32					src_pipe_idx;
 	u32					dst_pipe_idx;
-	u8					connection_idx;
+	u8					src_connection_idx;
+	u8					dst_connection_idx;
 	enum transport_type trans;
 	struct usb_bam_connect_ipa_params ipa_params;
 
@@ -663,7 +664,7 @@
 	int ret;
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
-		ret = usb_bam_disconnect_ipa(d->connection_idx, &d->ipa_params);
+		ret = usb_bam_disconnect_ipa(&d->ipa_params);
 		if (ret)
 			pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
 				__func__, ret);
@@ -715,10 +716,15 @@
 	int ret;
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
-		ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
-							  &d->dst_pipe_idx);
+		ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
 		if (ret) {
-			pr_err("%s: usb_bam_connect failed: err:%d\n",
+			pr_err("%s: usb_bam_connect (src) failed: err:%d\n",
+				__func__, ret);
+			return;
+		}
+		ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
+		if (ret) {
+			pr_err("%s: usb_bam_connect (dst) failed: err:%d\n",
 				__func__, ret);
 			return;
 		}
@@ -787,8 +793,7 @@
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM && port->port_num == 0) {
 		/* Register for peer reset callback */
-		usb_bam_register_peer_reset_cb(d->connection_idx,
-			gbam_peer_reset_cb, port);
+		usb_bam_register_peer_reset_cb(gbam_peer_reset_cb, port);
 
 		ret = usb_bam_client_ready(true);
 		if (ret) {
@@ -832,7 +837,7 @@
 	msm_hw_bam_disable(1);
 
 	/* Reset BAM */
-	ret = usb_bam_reset();
+	ret = usb_bam_a2_reset();
 	if (ret) {
 		pr_err("%s: BAM reset failed %d\n", __func__, ret);
 		goto reenable_eps;
@@ -867,7 +872,7 @@
 
 	/* Unregister the peer reset callback */
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM && port->port_num == 0)
-		usb_bam_register_peer_reset_cb(d->connection_idx, NULL, NULL);
+		usb_bam_register_peer_reset_cb(NULL, NULL);
 
 	return 0;
 }
@@ -1216,7 +1221,8 @@
 }
 
 int gbam_connect(struct grmnet *gr, u8 port_num,
-				 enum transport_type trans, u8 connection_idx)
+		enum transport_type trans, u8 src_connection_idx,
+		u8 dst_connection_idx)
 {
 	struct gbam_port	*port;
 	struct bam_ch_info	*d;
@@ -1283,12 +1289,14 @@
 
 	if (trans == USB_GADGET_XPORT_BAM2BAM) {
 		port->gr = gr;
-		d->connection_idx = connection_idx;
+		d->src_connection_idx = src_connection_idx;
+		d->dst_connection_idx = dst_connection_idx;
 	} else if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
 		port->gr = gr;
 		d->ipa_params.src_pipe = &(d->src_pipe_idx);
 		d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
-		d->ipa_params.idx = connection_idx;
+		d->ipa_params.src_idx = src_connection_idx;
+		d->ipa_params.dst_idx = dst_connection_idx;
 	}
 
 	d->trans = trans;
@@ -1379,7 +1387,7 @@
 
 	pr_debug("%s: suspended port %d\n", __func__, port_num);
 
-	usb_bam_register_wake_cb(d->connection_idx, gbam_wake_cb, port);
+	usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
 }
 
 void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1396,5 +1404,5 @@
 
 	pr_debug("%s: resumed port %d\n", __func__, port_num);
 
-	usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+	usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
 }
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 700d07f..83f885a 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -47,7 +47,8 @@
 
 	u32			src_pipe_idx;
 	u32			dst_pipe_idx;
-	u8			connection_idx;
+	u8			src_connection_idx;
+	u8			dst_connection_idx;
 
 	enum function_type			func_type;
 	enum transport_type			trans;
@@ -135,7 +136,7 @@
 	msm_hw_bam_disable(1);
 
 	/* Reset BAM */
-	ret = usb_bam_reset();
+	ret = usb_bam_a2_reset();
 	if (ret) {
 		pr_err("%s: BAM reset failed %d\n", __func__, ret);
 		goto reenable_eps;
@@ -169,7 +170,7 @@
 	}
 
 	/* Unregister the peer reset callback */
-	usb_bam_register_peer_reset_cb(d->connection_idx, NULL, NULL);
+	usb_bam_register_peer_reset_cb(NULL, NULL);
 
 	return 0;
 }
@@ -184,7 +185,7 @@
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
 		if (d->func_type == USB_FUNC_ECM)
 			ecm_ipa_disconnect(d->ipa_params.priv);
-		ret = usb_bam_disconnect_ipa(d->connection_idx, &d->ipa_params);
+		ret = usb_bam_disconnect_ipa(&d->ipa_params);
 		if (ret)
 			pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret);
 	}
@@ -237,13 +238,17 @@
 			}
 		}
 	} else { /* transport type is USB_GADGET_XPORT_BAM2BAM */
-		ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
-						  &d->dst_pipe_idx);
-		if (ret) {
-			pr_err("usb_bam_connect failed: err:%d\n", ret);
-			return;
-		}
+	ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
+	if (ret) {
+		pr_err("usb_bam_connect (src) failed: err:%d\n", ret);
+		return;
 	}
+	ret = usb_bam_connect(d->dst_connection_idx, &d->dst_pipe_idx);
+	if (ret) {
+		pr_err("usb_bam_connect (dst) failed: err:%d\n", ret);
+		return;
+	}
+}
 
 	if (!port->port_usb) {
 		pr_err("port_usb is NULL");
@@ -282,8 +287,7 @@
 
 	/* Register for peer reset callback if USB_GADGET_XPORT_BAM2BAM */
 	if (d->trans != USB_GADGET_XPORT_BAM2BAM_IPA) {
-		usb_bam_register_peer_reset_cb(d->connection_idx,
-			bam_data_peer_reset_cb, port);
+		usb_bam_register_peer_reset_cb(bam_data_peer_reset_cb, port);
 
 		ret = usb_bam_client_ready(true);
 		if (ret) {
@@ -369,7 +373,8 @@
 }
 
 int bam_data_connect(struct data_port *gr, u8 port_num,
-	enum transport_type trans, u8 connection_idx, enum function_type func)
+	enum transport_type trans, u8 src_connection_idx,
+	u8 dst_connection_idx, enum function_type func)
 {
 	struct bam_data_port	*port;
 	struct bam_data_ch_info	*d;
@@ -408,14 +413,16 @@
 
 	port->port_usb = gr;
 
-	d->connection_idx = connection_idx;
+	d->src_connection_idx = src_connection_idx;
+	d->dst_connection_idx = dst_connection_idx;
 
 	d->trans = trans;
 
 	if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
 		d->ipa_params.src_pipe = &(d->src_pipe_idx);
 		d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
-		d->ipa_params.idx = connection_idx;
+		d->ipa_params.src_idx = src_connection_idx;
+		d->ipa_params.dst_idx = dst_connection_idx;
 	}
 
 	d->func_type = func;
@@ -499,7 +506,7 @@
 	d = &port->data_ch;
 
 	pr_debug("%s: suspended port %d\n", __func__, port_num);
-	usb_bam_register_wake_cb(d->connection_idx, bam_data_wake_cb, port);
+	usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
 }
 
 void bam_data_resume(u8 port_num)
@@ -512,6 +519,6 @@
 	d = &port->data_ch;
 
 	pr_debug("%s: resumed port %d\n", __func__, port_num);
-	usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+	usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
 }
 
diff --git a/drivers/usb/gadget/u_bam_data.h b/drivers/usb/gadget/u_bam_data.h
index 71a01b9..486191b5 100644
--- a/drivers/usb/gadget/u_bam_data.h
+++ b/drivers/usb/gadget/u_bam_data.h
@@ -30,7 +30,8 @@
 void bam_data_disconnect(struct data_port *gr, u8 port_num);
 
 int bam_data_connect(struct data_port *gr, u8 port_num,
-	enum transport_type trans, u8 connection_idx, enum function_type func);
+	enum transport_type trans, u8 src_connection_idx,
+	u8 dst_connection_idx, enum function_type func);
 
 int bam_data_setup(unsigned int no_bam2bam_port);
 
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index 028d5e6..e241e29 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,8 +15,6 @@
 #include <linux/usb/msm_hsusb.h>
 #include <mach/usb_bam.h>
 
-#define BAM_CONNC_IDX 0 /* USB bam connection index */
-
 struct  usb_qdss_bam_connect_info {
 	u32 usb_bam_pipe_idx;
 	u32 peer_pipe_idx;
@@ -60,28 +58,33 @@
 	return 0;
 }
 
-int set_qdss_data_connection(struct usb_ep *data_ep, u8 data_addr, int enable)
+static int set_qdss_data_connection(struct usb_gadget *gadget,
+	struct usb_ep *data_ep, u8 data_addr, int enable)
 {
 	int res = 0;
+	u8 idx;
 
 	pr_debug("set_qdss_data_connection\n");
 
-	if (enable) {
-		res = usb_bam_connect(BAM_CONNC_IDX, NULL,
-			&(bam_info.usb_bam_pipe_idx));
-		if (res) {
-			pr_err("usb_bam_connection error\n");
-			return res;
-		}
+	/* There is only one qdss pipe, so the pipe number can be set to 0 */
+	idx = usb_bam_get_connection_idx(gadget->name, QDSS_P_BAM,
+		PEER_PERIPHERAL_TO_USB, 0);
+	if (idx < 0) {
+		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
+		return idx;
+	}
 
+	if (enable) {
+		res = usb_bam_connect(idx, &(bam_info.usb_bam_pipe_idx));
 		bam_info.data_fifo =
 			kzalloc(sizeof(struct sps_mem_buffer *), GFP_KERNEL);
 		if (!bam_info.data_fifo) {
 			pr_err("qdss_data_connection: memory alloc failed\n");
 			return -ENOMEM;
 		}
-		get_bam2bam_connection_info(BAM_CONNC_IDX,
-			PEER_PERIPHERAL_TO_USB, &bam_info.usb_bam_handle,
+		usb_bam_set_qdss_core(gadget->name);
+		get_bam2bam_connection_info(idx,
+			&bam_info.usb_bam_handle,
 			&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
 			NULL, bam_info.data_fifo);
 
@@ -89,13 +92,13 @@
 			bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
 	} else {
 		kfree(bam_info.data_fifo);
-		res = usb_bam_disconnect_pipe(BAM_CONNC_IDX);
+		res = usb_bam_disconnect_pipe(idx);
 		if (res) {
 			pr_err("usb_bam_disconnection error\n");
 			return res;
 		}
-
 	}
+
 	return res;
 }
 
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index cea9369..a9cca50 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -48,8 +48,10 @@
 
 int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
 int gbam_connect(struct grmnet *gr, u8 port_num,
-				 enum transport_type trans, u8 connection_idx);
-void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans);
+	enum transport_type trans, u8 src_connection_idx,
+	u8 dst_connection_idx);
+void gbam_disconnect(struct grmnet *gr, u8 port_num,
+	enum transport_type trans);
 void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
 void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
 int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index c71685d..350e723 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -448,6 +448,8 @@
 		prev_len = req->length;
 		port->nbytes_from_tty += req->length;
 
+		port->write_started++;
+
 	}
 
 	if (do_tty_wake && port->port_tty)
@@ -1046,6 +1048,13 @@
 	struct gs_port		*port = tty->driver_data;
 	unsigned long		flags;
 
+	/*
+	 * tty's driver data is set to NULL during port close.  Nothing
+	 * to do here.
+	 */
+	if (!port)
+		return;
+
 	spin_lock_irqsave(&port->port_lock, flags);
 	if (port->port_usb) {
 		/* Kickstart read queue processing.  We don't do xon/xoff,
@@ -1381,7 +1390,6 @@
 	/* export the driver ... */
 	status = tty_register_driver(gs_tty_driver);
 	if (status) {
-		put_tty_driver(gs_tty_driver);
 		pr_err("%s: cannot register, err %d\n",
 				__func__, status);
 		goto fail;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index ea5484b..ca4b01a 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -49,6 +49,7 @@
 #include <linux/spinlock.h>
 #include <linux/cpu.h>
 #include <mach/rpm-regulator.h>
+#include "hbm.c"
 
 #define MSM_USB_BASE (hcd->regs)
 #define USB_REG_START_OFFSET 0x90
@@ -105,6 +106,7 @@
 	int			reset_again;
 
 	struct pm_qos_request pm_qos_req_dma;
+	unsigned		enable_hbm:1;
 };
 
 struct msm_hsic_hcd *__mehci;
@@ -622,6 +624,15 @@
 	int ret;
 	void __iomem *reg;
 
+	if (pdata && pdata->resume_gpio) {
+		ret = gpio_request(pdata->resume_gpio, "HSIC_RESUME_GPIO");
+		if (ret < 0) {
+			dev_err(mehci->dev,
+				"gpio req failed for hsic resume:%d\n", ret);
+			pdata->resume_gpio = 0;
+		}
+	}
+
 	/* HSIC init sequence when HSIC signals (Strobe/Data) are
 	routed via GPIOs */
 	if (pdata && pdata->strobe && pdata->data) {
@@ -643,7 +654,7 @@
 		ret = msm_hsic_config_gpios(mehci, 1);
 		if (ret) {
 			dev_err(mehci->dev, " gpio configuarion failed\n");
-			return ret;
+			goto free_resume_gpio;
 		}
 		if (pdata->strobe_pad_offset) {
 			/* Set CORE_CTL_EN in STROBE GPIO PAD_CTL register */
@@ -692,6 +703,12 @@
 	ulpi_write(mehci, ULPI_IFC_CTRL_AUTORESUME, ULPI_CLR(ULPI_IFC_CTRL));
 
 	return 0;
+
+free_resume_gpio:
+	if (pdata && pdata->resume_gpio)
+		gpio_free(pdata->resume_gpio);
+
+	return ret;
 }
 
 #define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)
@@ -1310,6 +1327,10 @@
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 	u32			temp;
 	struct task_struct	*resume_thread = NULL;
+	struct msm_hsic_host_platform_data *pdata =  mehci->dev->platform_data;
+
+	if (pdata->resume_gpio)
+		gpio_direction_output(pdata->resume_gpio, 1);
 
 	mehci->resume_status = 0;
 	resume_thread = kthread_run(msm_hsic_resume_thread,
@@ -1349,6 +1370,9 @@
 
 	spin_unlock_irq(&ehci->lock);
 
+	if (pdata->resume_gpio)
+		gpio_direction_output(pdata->resume_gpio, 0);
+
 	return 0;
 }
 
@@ -1367,6 +1391,18 @@
 		pm_runtime_set_autosuspend_delay(&dev->dev, 200);
 }
 
+static int ehci_msm_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+				gfp_t mem_flags)
+{
+	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+	struct usb_host_bam_type *usb_host_bam =
+			(struct usb_host_bam_type *)urb->priv_data;
+
+	if (usb_host_bam && mehci && mehci->enable_hbm)
+		return hbm_urb_enqueue(hcd, urb, mem_flags);
+	return ehci_urb_enqueue(hcd, urb, mem_flags);
+}
+
 static struct hc_driver msm_hsic_driver = {
 	.description		= hcd_name,
 	.product_desc		= "Qualcomm EHCI Host Controller using HSIC",
@@ -1387,7 +1423,7 @@
 	/*
 	 * managing i/o requests and associated device resources
 	 */
-	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_enqueue		= ehci_msm_urb_enqueue,
 	.urb_dequeue		= ehci_urb_dequeue,
 	.endpoint_disable	= ehci_endpoint_disable,
 	.endpoint_reset		= ehci_endpoint_reset,
@@ -1767,6 +1803,11 @@
 		res_gpio = 0;
 	pdata->data = res_gpio;
 
+	res_gpio = of_get_named_gpio(node, "hsic,resume-gpio", 0);
+	if (res_gpio < 0)
+		res_gpio = 0;
+	pdata->resume_gpio = res_gpio;
+
 	pdata->ignore_cal_pad_config = of_property_read_bool(node,
 					"hsic,ignore-cal-pad-config");
 	of_property_read_u32(node, "hsic,strobe-pad-offset",
@@ -1778,6 +1819,8 @@
 
 	pdata->pool_64_bit_align = of_property_read_bool(node,
 				"qcom,pool-64-bit-align");
+	pdata->enable_hbm = of_property_read_bool(node,
+				"qcom,enable-hbm");
 
 	return pdata;
 }
@@ -1789,6 +1832,7 @@
 	struct resource *res;
 	struct msm_hsic_hcd *mehci;
 	struct msm_hsic_host_platform_data *pdata;
+	unsigned long wakeup_irq_flags = 0;
 	int ret;
 
 	dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");
@@ -1797,6 +1841,9 @@
 		dev_dbg(&pdev->dev, "device tree enabled\n");
 		pdev->dev.platform_data = msm_hsic_dt_to_pdata(pdev);
 		dev_set_name(&pdev->dev, ehci_msm_hsic_driver.driver.name);
+	} else {
+		/* explicitly pass wakeup_irq flag for !DT */
+		wakeup_irq_flags = IRQF_TRIGGER_HIGH;
 	}
 	if (!pdev->dev.platform_data)
 		dev_dbg(&pdev->dev, "No platform data given\n");
@@ -1857,6 +1904,7 @@
 
 	mehci->ehci.resume_sof_bug = 1;
 	mehci->ehci.pool_64_bit_align = pdata->pool_64_bit_align;
+	mehci->enable_hbm = pdata->enable_hbm;
 
 	if (pdata)
 		mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
@@ -1944,7 +1992,7 @@
 		 */
 		irq_set_status_flags(mehci->wakeup_irq, IRQ_NOAUTOEN);
 		ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
-				IRQF_TRIGGER_HIGH,
+				wakeup_irq_flags,
 				"msm_hsic_wakeup", mehci);
 		if (ret) {
 			dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
@@ -1963,7 +2011,8 @@
 		if (ret) {
 			dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
 			mehci->async_irq = 0;
-		} else {
+		} else if (!mehci->wakeup_irq) {
+			/* Async IRQ is used only in absence of dedicated irq */
 			enable_irq_wake(mehci->async_irq);
 		}
 	}
@@ -2006,6 +2055,9 @@
 	if (pdev->dev.parent)
 		pm_runtime_put_sync(pdev->dev.parent);
 
+	if (mehci->enable_hbm)
+		hbm_init(hcd);
+
 	return 0;
 
 destroy_wq:
@@ -2035,6 +2087,9 @@
 
 	pm_runtime_set_suspended(&pdev->dev);
 
+	if (mehci->enable_hbm)
+		hbm_uninit();
+
 	/* Remove the HCD prior to releasing our resources. */
 	usb_remove_hcd(hcd);
 
@@ -2071,6 +2126,10 @@
 	destroy_workqueue(ehci_wq);
 
 	msm_hsic_config_gpios(mehci, 0);
+
+	if (pdata && pdata->resume_gpio)
+		gpio_free(pdata->resume_gpio);
+
 	msm_hsic_init_vddcx(mehci, 0);
 	msm_hsic_init_gdsc(mehci, 0);
 
@@ -2093,12 +2152,12 @@
 
 	dbg_log_event(NULL, "PM Suspend", 0);
 
-	if (device_may_wakeup(dev))
+	if (device_may_wakeup(dev) && !mehci->async_irq)
 		enable_irq_wake(hcd->irq);
 
 	ret = msm_hsic_suspend(mehci);
 
-	if (ret && device_may_wakeup(dev))
+	if (ret && device_may_wakeup(dev) && !mehci->async_irq)
 		disable_irq_wake(hcd->irq);
 
 	return ret;
@@ -2126,7 +2185,7 @@
 	dev_dbg(dev, "ehci-msm-hsic PM resume\n");
 	dbg_log_event(NULL, "PM Resume", 0);
 
-	if (device_may_wakeup(dev))
+	if (device_may_wakeup(dev) && !mehci->async_irq)
 		disable_irq_wake(hcd->irq);
 
 	/*
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index cd17421..edf2a73 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -754,23 +754,6 @@
 
 #endif
 
-/*
- * Writing to dma coherent memory on ARM may be delayed via L2
- * writing buffer, so introduce the helper which can flush L2 writing
- * buffer into memory immediately, especially used to flush ehci
- * descriptor to memory.
- * */
-#ifdef	CONFIG_ARM_DMA_MEM_BUFFERABLE
-static inline void ehci_sync_mem(void)
-{
-	mb();
-}
-#else
-static inline void ehci_sync_mem(void)
-{
-}
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 #ifdef CONFIG_PCI
diff --git a/drivers/usb/host/hbm.c b/drivers/usb/host/hbm.c
index f516ad8..d48a631 100644
--- a/drivers/usb/host/hbm.c
+++ b/drivers/usb/host/hbm.c
@@ -194,12 +194,6 @@
 		pr_err("%s: hbm_ctx alloc failed\n", __func__);
 		return;
 	}
-	hbm_ctx->base = kzalloc(sizeof(u32), GFP_KERNEL);
-	if (!hbm_ctx->base) {
-		pr_err("%s: hbm_ctx base alloc failed\n", __func__);
-		kfree(hbm_ctx);
-		return;
-	}
 
 	hbm_ctx->base = hcd->regs;
 	hbm_ctx->hcd = hcd;
@@ -214,7 +208,7 @@
 
 void hbm_uninit(void)
 {
-	kfree(hbm_ctx->base);
+	hbm_config(false);
 	kfree(hbm_ctx);
 }
 
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 1c7d928..7760d28 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -151,8 +151,8 @@
 		rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
 				USB_PHY_1P8_VOL_MAX);
 		if (rc) {
-			dev_err(motg->phy.dev, "unable to set voltage level for"
-					"hsusb 1p8\n");
+			dev_err(motg->phy.dev, "unable to set voltage level "
+					"for hsusb 1p8\n");
 			goto put_1p8;
 		}
 
@@ -207,7 +207,7 @@
 		ret = regulator_set_optimum_mode(hsusb_1p8,
 				USB_PHY_1P8_HPM_LOAD);
 		if (ret < 0) {
-			pr_err("%s: Unable to set HPM of the regulator:"
+			pr_err("%s: Unable to set HPM of the regulator "
 				"HSUSB_1p8\n", __func__);
 			return ret;
 		}
@@ -223,7 +223,7 @@
 		ret = regulator_set_optimum_mode(hsusb_3p3,
 				USB_PHY_3P3_HPM_LOAD);
 		if (ret < 0) {
-			pr_err("%s: Unable to set HPM of the regulator:"
+			pr_err("%s: Unable to set HPM of the regulator "
 				"HSUSB_3p3\n", __func__);
 			regulator_set_optimum_mode(hsusb_1p8, 0);
 			regulator_disable(hsusb_1p8);
@@ -252,7 +252,7 @@
 
 		ret = regulator_set_optimum_mode(hsusb_1p8, 0);
 		if (ret < 0)
-			pr_err("%s: Unable to set LPM of the regulator:"
+			pr_err("%s: Unable to set LPM of the regulator "
 				"HSUSB_1p8\n", __func__);
 
 		ret = regulator_disable(hsusb_3p3);
@@ -263,7 +263,7 @@
 		}
 		ret = regulator_set_optimum_mode(hsusb_3p3, 0);
 		if (ret < 0)
-			pr_err("%s: Unable to set LPM of the regulator:"
+			pr_err("%s: Unable to set LPM of the regulator "
 				"HSUSB_3p3\n", __func__);
 
 		break;
@@ -1575,7 +1575,7 @@
 }
 
 static int msm_otg_set_peripheral(struct usb_otg *otg,
-			struct usb_gadget *gadget)
+					struct usb_gadget *gadget)
 {
 	struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
 
@@ -3017,10 +3017,10 @@
 
 	if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
 		if (otgsc & OTGSC_ID) {
-			pr_debug("Id set\n");
+			dev_dbg(otg->phy->dev, "ID set\n");
 			set_bit(ID, &motg->inputs);
 		} else {
-			pr_debug("Id clear\n");
+			dev_dbg(otg->phy->dev, "ID clear\n");
 			/*
 			 * Assert a_bus_req to supply power on
 			 * VBUS when Micro/Mini-A cable is connected
@@ -3049,10 +3049,10 @@
 			!test_bit(ID_A, &motg->inputs))
 			return IRQ_HANDLED;
 		if (otgsc & OTGSC_BSV) {
-			pr_debug("BSV set\n");
+			dev_dbg(otg->phy->dev, "BSV set\n");
 			set_bit(B_SESS_VLD, &motg->inputs);
 		} else {
-			pr_debug("BSV clear\n");
+			dev_dbg(otg->phy->dev, "BSV clear\n");
 			clear_bit(B_SESS_VLD, &motg->inputs);
 			clear_bit(A_BUS_SUSPEND, &motg->inputs);
 
@@ -3245,9 +3245,9 @@
 static int msm_otg_mode_show(struct seq_file *s, void *unused)
 {
 	struct msm_otg *motg = s->private;
-	struct usb_phy *phy = &motg->phy;
+	struct usb_otg *otg = motg->phy.otg;
 
-	switch (phy->state) {
+	switch (otg->phy->state) {
 	case OTG_STATE_A_HOST:
 		seq_printf(s, "host\n");
 		break;
@@ -4228,10 +4228,10 @@
 static int __devexit msm_otg_remove(struct platform_device *pdev)
 {
 	struct msm_otg *motg = platform_get_drvdata(pdev);
-	struct usb_otg *otg = motg->phy.otg;
+	struct usb_phy *phy = &motg->phy;
 	int cnt = 0;
 
-	if (otg->host || otg->gadget)
+	if (phy->otg->host || phy->otg->gadget)
 		return -EBUSY;
 
 	if (pdev->dev.of_node)
@@ -4264,8 +4264,8 @@
 	/*
 	 * Put PHY in low power mode.
 	 */
-	ulpi_read(otg->phy, 0x14);
-	ulpi_write(otg->phy, 0x08, 0x09);
+	ulpi_read(phy, 0x14);
+	ulpi_write(phy, 0x08, 0x09);
 
 	writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
 	while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
@@ -4275,7 +4275,7 @@
 		cnt++;
 	}
 	if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
-		dev_err(otg->phy->dev, "Unable to suspend PHY\n");
+		dev_err(phy->dev, "Unable to suspend PHY\n");
 
 	clk_disable_unprepare(motg->pclk);
 	clk_disable_unprepare(motg->core_clk);
diff --git a/drivers/usb/otg/otg_id.c b/drivers/usb/otg/otg_id.c
deleted file mode 100644
index 7c38390..0000000
--- a/drivers/usb/otg/otg_id.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2011 Google, Inc.
- *
- * Author:
- *	Colin Cross <ccross@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/notifier.h>
-#include <linux/usb/otg_id.h>
-
-static DEFINE_MUTEX(otg_id_lock);
-static struct plist_head otg_id_plist =
-	PLIST_HEAD_INIT(otg_id_plist);
-static struct otg_id_notifier_block *otg_id_active;
-static bool otg_id_cancelling;
-static bool otg_id_inited;
-static int otg_id_suspended;
-static bool otg_id_pending;
-
-static void otg_id_cancel(void)
-{
-	if (otg_id_active) {
-		otg_id_cancelling = true;
-		mutex_unlock(&otg_id_lock);
-
-		otg_id_active->cancel(otg_id_active);
-
-		mutex_lock(&otg_id_lock);
-		otg_id_cancelling = false;
-	}
-}
-
-static void __otg_id_notify(void)
-{
-	int ret = 0;
-	struct otg_id_notifier_block *otg_id_nb;
-	bool proxy_wait = false;
-	if (plist_head_empty(&otg_id_plist))
-		return;
-
-	plist_for_each_entry(otg_id_nb, &otg_id_plist, p) {
-		if (proxy_wait) {
-			if (otg_id_nb->proxy_wait)
-				ret = otg_id_nb->proxy_wait(otg_id_nb);
-		} else {
-			ret = otg_id_nb->detect(otg_id_nb);
-		}
-		if (ret == OTG_ID_HANDLED) {
-			otg_id_active = otg_id_nb;
-			return;
-		}
-		if (ret == OTG_ID_PROXY_WAIT)
-			proxy_wait = true;
-
-	}
-
-	WARN(1, "otg id event not handled");
-	otg_id_active = NULL;
-}
-
-int otg_id_init(void)
-{
-	mutex_lock(&otg_id_lock);
-
-	otg_id_inited = true;
-	__otg_id_notify();
-
-	mutex_unlock(&otg_id_lock);
-	return 0;
-}
-late_initcall(otg_id_init);
-
-/**
- * otg_id_register_notifier
- * @otg_id_nb: notifier block containing priority and callback function
- *
- * Register a notifier that will be called on any USB cable state change.
- * The priority determines the order the callback will be called in, a higher
- * number will be called first.  A callback function needs to determine the
- * type of USB cable that is connected.  If it can determine the type, it
- * should notify the appropriate drivers (for example, call an otg notifier
- * with USB_EVENT_VBUS), and return OTG_ID_HANDLED.  Once a callback has
- * returned OTG_ID_HANDLED, it is responsible for calling otg_id_notify() when
- * the detected USB cable is disconnected.
- */
-int otg_id_register_notifier(struct otg_id_notifier_block *otg_id_nb)
-{
-	plist_node_init(&otg_id_nb->p, otg_id_nb->priority);
-
-	mutex_lock(&otg_id_lock);
-	plist_add(&otg_id_nb->p, &otg_id_plist);
-
-	if (otg_id_inited) {
-		otg_id_cancel();
-		__otg_id_notify();
-	}
-
-	mutex_unlock(&otg_id_lock);
-
-	return 0;
-}
-
-void otg_id_unregister_notifier(struct otg_id_notifier_block *otg_id_nb)
-{
-	mutex_lock(&otg_id_lock);
-
-	plist_del(&otg_id_nb->p, &otg_id_plist);
-
-	if (otg_id_inited && (otg_id_active == otg_id_nb)) {
-		otg_id_cancel();
-		__otg_id_notify();
-	}
-
-	mutex_unlock(&otg_id_lock);
-}
-
-/**
- * otg_id_notify
- *
- * Notify listeners on any USB cable state change.
- *
- * A driver may only call otg_id_notify if it returned OTG_ID_HANDLED the last
- * time it's notifier was called, and it's cancel function has not been called.
- */
-void otg_id_notify(void)
-{
-	mutex_lock(&otg_id_lock);
-
-	if (otg_id_cancelling)
-		goto out;
-
-	if (otg_id_suspended != 0) {
-		otg_id_pending = true;
-		goto out;
-	}
-
-	__otg_id_notify();
-out:
-	mutex_unlock(&otg_id_lock);
-}
-
-/**
- * otg_id_suspend
- *
- * Mark the otg_id subsystem as going into suspend. From here on out,
- * any notifications will be deferred until the last otg_id client resumes.
- * If there is a pending notification when calling this function, it will
- * return a negative errno and expects that the caller will abort suspend.
- * Returs 0 on success.
- */
-int otg_id_suspend(void)
-{
-	int ret = 0;
-
-	mutex_lock(&otg_id_lock);
-
-	/*
-	 * if there's a pending notification, tell the caller to abort suspend
-	 */
-	if (otg_id_suspended != 0 && otg_id_pending) {
-		pr_info("otg_id: pending notification, should abort suspend\n");
-		ret = -EBUSY;
-		goto out;
-	}
-
-	otg_id_suspended++;
-out:
-	mutex_unlock(&otg_id_lock);
-	return ret;
-}
-
-/**
- * otg_id_resume
- *
- * Inform the otg_id subsystem that a client is resuming. If this is the
- * last client to be resumed and there's a pending notification,
- * otg_id_notify() is called.
- */
-void otg_id_resume(void)
-{
-	mutex_lock(&otg_id_lock);
-	if (WARN(!otg_id_suspended, "unbalanced otg_id_resume\n"))
-		goto out;
-	if (--otg_id_suspended == 0) {
-		if (otg_id_pending) {
-			pr_info("otg_id: had pending notification\n");
-			otg_id_pending = false;
-			__otg_id_notify();
-		}
-	}
-out:
-	mutex_unlock(&otg_id_lock);
-}
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index ed4c25d..1c59a68 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -10,6 +10,8 @@
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select SYNC
+	select SW_SYNC
 	---help---
 	  Support for MSM Framebuffer.
 
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index bfd8238..e50055f 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -3682,6 +3682,8 @@
 
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
+	msm_fb_wait_for_fence(mfd);
+
 	switch (mfd->panel.type) {
 	case MIPI_CMD_PANEL:
 		mdp4_dsi_cmd_pipe_commit(0, 1);
@@ -3703,6 +3705,7 @@
 		ret = -EINVAL;
 		break;
 	}
+	msm_fb_signal_timeline(mfd);
 
 	mdp4_overlay_mdp_perf_upd(mfd, 0);
 
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 99eea82..bfcd7ec 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -28,48 +28,73 @@
 
 static unsigned char *mdss_dsi_base;
 
-static int mdss_dsi_regulator_init(struct platform_device *pdev,
-				   struct dsi_drv_cm_data *dsi_drv)
+static int mdss_dsi_regulator_init(struct platform_device *pdev)
 {
-	int ret;
+	int ret = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct dsi_drv_cm_data *dsi_drv = NULL;
 
-	dsi_drv->vdd_vreg = devm_regulator_get(&pdev->dev, "vdd");
-	if (IS_ERR(dsi_drv->vdd_vreg)) {
-		pr_err("could not get 8941_l22, rc = %ld\n",
-				PTR_ERR(dsi_drv->vdd_vreg));
-		return -ENODEV;
-	}
-
-	ret = regulator_set_voltage(dsi_drv->vdd_vreg, 3000000, 3000000);
-	if (ret) {
-		pr_err("vdd_vreg->set_voltage failed, rc=%d\n", ret);
+	if (!pdev) {
+		pr_err("%s: invalid input\n", __func__);
 		return -EINVAL;
 	}
 
-	dsi_drv->vdd_io_vreg = devm_regulator_get(&pdev->dev, "vdd_io");
-	if (IS_ERR(dsi_drv->vdd_io_vreg)) {
-		pr_err("could not get 8941_l12, rc = %ld\n",
-				PTR_ERR(dsi_drv->vdd_io_vreg));
-		return -ENODEV;
-	}
-
-	ret = regulator_set_voltage(dsi_drv->vdd_io_vreg, 1800000, 1800000);
-	if (ret) {
-		pr_err("vdd_io_vreg->set_voltage failed, rc=%d\n", ret);
+	ctrl_pdata = platform_get_drvdata(pdev);
+	if (!ctrl_pdata) {
+		pr_err("%s: invalid driver data\n", __func__);
 		return -EINVAL;
 	}
 
-	dsi_drv->dsi_vreg = devm_regulator_get(&pdev->dev, "vreg");
-	if (IS_ERR(dsi_drv->dsi_vreg)) {
-		pr_err("could not get 8941_l2, rc = %ld\n",
-				PTR_ERR(dsi_drv->dsi_vreg));
-		return -ENODEV;
-	}
+	dsi_drv = &(ctrl_pdata->shared_pdata);
+	if (ctrl_pdata->power_data.num_vreg > 0) {
+		ret = msm_dss_config_vreg(&pdev->dev,
+				ctrl_pdata->power_data.vreg_config,
+				ctrl_pdata->power_data.num_vreg, 1);
+	} else {
+		dsi_drv->vdd_vreg = devm_regulator_get(&pdev->dev, "vdd");
+		if (IS_ERR(dsi_drv->vdd_vreg)) {
+			pr_err("%s: could not get vdda vreg, rc=%ld\n",
+				__func__, PTR_ERR(dsi_drv->vdd_vreg));
+			return PTR_ERR(dsi_drv->vdd_vreg);
+		}
 
-	ret = regulator_set_voltage(dsi_drv->dsi_vreg, 1200000, 1200000);
-	if (ret) {
-		pr_err("dsi_vreg->set_voltage failed, rc=%d\n", ret);
-		return -EINVAL;
+		ret = regulator_set_voltage(dsi_drv->vdd_vreg, 3000000,
+				3000000);
+		if (ret) {
+			pr_err("%s: set voltage failed on vdda vreg, rc=%d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		dsi_drv->vdd_io_vreg = devm_regulator_get(&pdev->dev, "vddio");
+		if (IS_ERR(dsi_drv->vdd_io_vreg)) {
+			pr_err("%s: could not get vddio reg, rc=%ld\n",
+				__func__, PTR_ERR(dsi_drv->vdd_io_vreg));
+			return PTR_ERR(dsi_drv->vdd_io_vreg);
+		}
+
+		ret = regulator_set_voltage(dsi_drv->vdd_io_vreg, 1800000,
+				1800000);
+		if (ret) {
+			pr_err("%s: set voltage failed on vddio vreg, rc=%d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		dsi_drv->vdda_vreg = devm_regulator_get(&pdev->dev, "vdda");
+		if (IS_ERR(dsi_drv->vdda_vreg)) {
+			pr_err("%s: could not get vdda vreg, rc=%ld\n",
+				__func__, PTR_ERR(dsi_drv->vdda_vreg));
+			return PTR_ERR(dsi_drv->vdda_vreg);
+		}
+
+		ret = regulator_set_voltage(dsi_drv->vdda_vreg, 1200000,
+				1200000);
+		if (ret) {
+			pr_err("%s: set voltage failed on vdda vreg, rc=%d\n",
+				__func__, ret);
+			return ret;
+		}
 	}
 
 	return 0;
@@ -90,51 +115,73 @@
 	pr_debug("%s: enable=%d\n", __func__, enable);
 
 	if (enable) {
-		ret = regulator_set_optimum_mode
-		  ((ctrl_pdata->shared_pdata).vdd_vreg, 100000);
-		if (ret < 0) {
-			pr_err("%s: vdd_vreg set regulator mode failed.\n",
-						       __func__);
-			return ret;
+		if (ctrl_pdata->power_data.num_vreg > 0) {
+			ret = msm_dss_enable_vreg(
+				ctrl_pdata->power_data.vreg_config,
+				ctrl_pdata->power_data.num_vreg, 1);
+			if (ret) {
+				pr_err("%s:Failed to enable regulators.rc=%d\n",
+					__func__, ret);
+				return ret;
+			}
+
+			/*
+			 * A small delay is needed here after enabling
+			 * all regulators and before issuing panel reset
+			 */
+			msleep(20);
+		} else {
+			ret = regulator_set_optimum_mode(
+				(ctrl_pdata->shared_pdata).vdd_vreg, 100000);
+			if (ret < 0) {
+				pr_err("%s: vdd_vreg set opt mode failed.\n",
+					 __func__);
+				return ret;
+			}
+
+			ret = regulator_set_optimum_mode(
+				(ctrl_pdata->shared_pdata).vdd_io_vreg, 100000);
+			if (ret < 0) {
+				pr_err("%s: vdd_io_vreg set opt mode failed.\n",
+					__func__);
+				return ret;
+			}
+
+			ret = regulator_set_optimum_mode
+			  ((ctrl_pdata->shared_pdata).vdda_vreg, 100000);
+			if (ret < 0) {
+				pr_err("%s: vdda_vreg set opt mode failed.\n",
+					__func__);
+				return ret;
+			}
+
+			ret = regulator_enable(
+				(ctrl_pdata->shared_pdata).vdd_io_vreg);
+			if (ret) {
+				pr_err("%s: Failed to enable regulator.\n",
+					__func__);
+				return ret;
+			}
+			msleep(20);
+
+			ret = regulator_enable(
+				(ctrl_pdata->shared_pdata).vdd_vreg);
+			if (ret) {
+				pr_err("%s: Failed to enable regulator.\n",
+					__func__);
+				return ret;
+			}
+			msleep(20);
+
+			ret = regulator_enable(
+				(ctrl_pdata->shared_pdata).vdda_vreg);
+			if (ret) {
+				pr_err("%s: Failed to enable regulator.\n",
+					__func__);
+				return ret;
+			}
 		}
 
-		ret = regulator_set_optimum_mode
-		  ((ctrl_pdata->shared_pdata).vdd_io_vreg, 100000);
-		if (ret < 0) {
-			pr_err("%s: vdd_io_vreg set regulator mode failed.\n",
-						       __func__);
-			return ret;
-		}
-
-		ret = regulator_set_optimum_mode
-		  ((ctrl_pdata->shared_pdata).dsi_vreg, 100000);
-		if (ret < 0) {
-			pr_err("%s: dsi_vreg set regulator mode failed.\n",
-						       __func__);
-			return ret;
-		}
-
-		ret = regulator_enable((ctrl_pdata->shared_pdata).vdd_io_vreg);
-		if (ret) {
-			pr_err("%s: Failed to enable regulator.\n", __func__);
-			return ret;
-		}
-		msleep(20);
-		wmb();
-
-		ret = regulator_enable((ctrl_pdata->shared_pdata).vdd_vreg);
-		if (ret) {
-			pr_err("%s: Failed to enable regulator.\n", __func__);
-			return ret;
-		}
-		msleep(20);
-		wmb();
-
-		ret = regulator_enable((ctrl_pdata->shared_pdata).dsi_vreg);
-		if (ret) {
-			pr_err("%s: Failed to enable regulator.\n", __func__);
-			return ret;
-		}
 		if (pdata->panel_info.panel_power_on == 0)
 			mdss_dsi_panel_reset(pdata, 1);
 
@@ -142,45 +189,62 @@
 
 		mdss_dsi_panel_reset(pdata, 0);
 
-		ret = regulator_disable((ctrl_pdata->shared_pdata).vdd_vreg);
-		if (ret) {
-			pr_err("%s: Failed to disable regulator.\n", __func__);
-			return ret;
-		}
+		if (ctrl_pdata->power_data.num_vreg > 0) {
+			ret = msm_dss_enable_vreg(
+				ctrl_pdata->power_data.vreg_config,
+				ctrl_pdata->power_data.num_vreg, 0);
+			if (ret) {
+				pr_err("%s: Failed to disable regs.rc=%d\n",
+					__func__, ret);
+				return ret;
+			}
+		} else {
+			ret = regulator_disable(
+				(ctrl_pdata->shared_pdata).vdd_vreg);
+			if (ret) {
+				pr_err("%s: Failed to disable regulator.\n",
+					__func__);
+				return ret;
+			}
 
-		ret = regulator_disable((ctrl_pdata->shared_pdata).dsi_vreg);
-		if (ret) {
-			pr_err("%s: Failed to disable regulator.\n", __func__);
-			return ret;
-		}
+			ret = regulator_disable(
+				(ctrl_pdata->shared_pdata).vdda_vreg);
+			if (ret) {
+				pr_err("%s: Failed to disable regulator.\n",
+					__func__);
+				return ret;
+			}
 
-		ret = regulator_disable((ctrl_pdata->shared_pdata).vdd_io_vreg);
-		if (ret) {
-			pr_err("%s: Failed to disable regulator.\n", __func__);
-			return ret;
-		}
+			ret = regulator_disable(
+				(ctrl_pdata->shared_pdata).vdd_io_vreg);
+			if (ret) {
+				pr_err("%s: Failed to disable regulator.\n",
+					__func__);
+				return ret;
+			}
 
-		ret = regulator_set_optimum_mode
-		  ((ctrl_pdata->shared_pdata).vdd_vreg, 100);
-		if (ret < 0) {
-			pr_err("%s: vdd_vreg set regulator mode failed.\n",
-						       __func__);
-			return ret;
-		}
+			ret = regulator_set_optimum_mode(
+				(ctrl_pdata->shared_pdata).vdd_vreg, 100);
+			if (ret < 0) {
+				pr_err("%s: vdd_vreg set opt mode failed.\n",
+					 __func__);
+				return ret;
+			}
 
-		ret = regulator_set_optimum_mode
-		  ((ctrl_pdata->shared_pdata).vdd_io_vreg, 100);
-		if (ret < 0) {
-			pr_err("%s: vdd_io_vreg set regulator mode failed.\n",
-						       __func__);
-			return ret;
-		}
-		ret = regulator_set_optimum_mode
-		  ((ctrl_pdata->shared_pdata).dsi_vreg, 100);
-		if (ret < 0) {
-			pr_err("%s: dsi_vreg set regulator mode failed.\n",
-						       __func__);
-			return ret;
+			ret = regulator_set_optimum_mode(
+				(ctrl_pdata->shared_pdata).vdd_io_vreg, 100);
+			if (ret < 0) {
+				pr_err("%s: vdd_io_vreg set opt mode failed.\n",
+					__func__);
+				return ret;
+			}
+			ret = regulator_set_optimum_mode(
+				(ctrl_pdata->shared_pdata).vdda_vreg, 100);
+			if (ret < 0) {
+				pr_err("%s: vdda_vreg set opt mode failed.\n",
+					__func__);
+				return ret;
+			}
 		}
 	}
 	return 0;
@@ -212,6 +276,154 @@
 	return ret;
 }
 
+static void mdss_dsi_put_dt_vreg_data(struct device *dev,
+	struct dss_module_power *module_power)
+{
+	if (!module_power) {
+		pr_err("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (module_power->vreg_config) {
+		devm_kfree(dev, module_power->vreg_config);
+		module_power->vreg_config = NULL;
+	}
+	module_power->num_vreg = 0;
+}
+
+static int mdss_dsi_get_dt_vreg_data(struct device *dev,
+	struct dss_module_power *mp)
+{
+	int i, rc = 0;
+	int dt_vreg_total = 0;
+	u32 *val_array = NULL;
+	struct device_node *of_node = NULL;
+
+	if (!dev || !mp) {
+		pr_err("%s: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	of_node = dev->of_node;
+
+	mp->num_vreg = 0;
+	dt_vreg_total = of_property_count_strings(of_node, "qcom,supply-names");
+	if (dt_vreg_total < 0) {
+		pr_debug("%s: vreg not found. rc=%d\n", __func__,
+			dt_vreg_total);
+		rc = 0;
+		goto error;
+	} else {
+		pr_debug("%s: vreg found. count=%d\n", __func__, dt_vreg_total);
+	}
+
+	if (dt_vreg_total > 0) {
+		mp->num_vreg = dt_vreg_total;
+		mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+			dt_vreg_total, GFP_KERNEL);
+		if (!mp->vreg_config) {
+			pr_err("%s: can't alloc vreg mem\n", __func__);
+			goto error;
+		}
+	} else {
+		pr_debug("%s: no vreg\n", __func__);
+		return 0;
+	}
+
+	val_array = devm_kzalloc(dev, sizeof(u32) * dt_vreg_total, GFP_KERNEL);
+	if (!val_array) {
+		pr_err("%s: can't allocate vreg scratch mem\n", __func__);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	for (i = 0; i < dt_vreg_total; i++) {
+		const char *st = NULL;
+		/* vreg-name */
+		rc = of_property_read_string_index(of_node, "qcom,supply-names",
+			i, &st);
+		if (rc) {
+			pr_err("%s: error reading name. i=%d, rc=%d\n",
+				__func__, i, rc);
+			goto error;
+		}
+		snprintf(mp->vreg_config[i].vreg_name,
+			ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st);
+
+		/* vreg-type */
+		rc = of_property_read_string_index(of_node, "qcom,supply-type",
+			i, &st);
+		if (rc) {
+			pr_err("%s: error reading vreg type. rc=%d\n",
+				__func__, rc);
+			goto error;
+		}
+		if (!strncmp(st, "regulator", 9))
+			mp->vreg_config[i].type = 0;
+		else if (!strncmp(st, "switch", 6))
+			mp->vreg_config[i].type = 1;
+
+		/* vreg-min-voltage */
+		memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+		rc = of_property_read_u32_array(of_node,
+			"qcom,supply-min-voltage-level", val_array,
+			dt_vreg_total);
+		if (rc) {
+			pr_err("%s: error reading min volt. rc=%d\n",
+				__func__, rc);
+			goto error;
+		}
+		mp->vreg_config[i].min_voltage = val_array[i];
+
+		/* vreg-max-voltage */
+		memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+		rc = of_property_read_u32_array(of_node,
+			"qcom,supply-max-voltage-level", val_array,
+			dt_vreg_total);
+		if (rc) {
+			pr_err("%s: error reading max volt. rc=%d\n",
+				__func__, rc);
+			goto error;
+		}
+		mp->vreg_config[i].max_voltage = val_array[i];
+
+		/* vreg-peak-current*/
+		memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+		rc = of_property_read_u32_array(of_node,
+			"qcom,supply-peak-current", val_array,
+			dt_vreg_total);
+		if (rc) {
+			pr_err("%s: error reading peak current. rc=%d\n",
+				__func__, rc);
+			goto error;
+		}
+		mp->vreg_config[i].optimum_voltage = val_array[i];
+
+		pr_debug("%s: %s type=%d, min=%d, max=%d, op=%d\n",
+			__func__, mp->vreg_config[i].vreg_name,
+			mp->vreg_config[i].type,
+			mp->vreg_config[i].min_voltage,
+			mp->vreg_config[i].max_voltage,
+			mp->vreg_config[i].optimum_voltage);
+	}
+
+	devm_kfree(dev, val_array);
+
+	return rc;
+
+error:
+	if (mp->vreg_config) {
+		devm_kfree(dev, mp->vreg_config);
+		mp->vreg_config = NULL;
+	}
+	mp->num_vreg = 0;
+
+	if (val_array)
+		devm_kfree(dev, val_array);
+	return rc;
+}
+
 static int mdss_dsi_off(struct mdss_panel_data *pdata)
 {
 	int ret = 0;
@@ -460,6 +672,7 @@
 {
 	int rc = 0;
 	u32 index;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
 	pr_debug("%s\n", __func__);
 
@@ -467,6 +680,19 @@
 		struct resource *mdss_dsi_mres;
 		const char *ctrl_name;
 
+		ctrl_pdata = platform_get_drvdata(pdev);
+		if (!ctrl_pdata) {
+			ctrl_pdata = devm_kzalloc(&pdev->dev,
+				sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL);
+			if (!ctrl_pdata) {
+				pr_err("%s: FAILED: cannot alloc dsi ctrl\n",
+					__func__);
+				rc = -ENOMEM;
+				goto error_no_mem;
+			}
+			platform_set_drvdata(pdev, ctrl_pdata);
+		}
+
 		ctrl_name = of_get_property(pdev->dev.of_node, "label", NULL);
 		if (!ctrl_name)
 			pr_info("%s:%d, DSI Ctrl name not specified\n",
@@ -481,7 +707,7 @@
 			dev_err(&pdev->dev,
 				"%s: Cell-index not specified, rc=%d\n",
 							__func__, rc);
-			return rc;
+			goto error_no_mem;
 		}
 
 		if (index == 0)
@@ -493,7 +719,8 @@
 		if (!mdss_dsi_mres) {
 			pr_err("%s:%d unable to get the MDSS resources",
 				       __func__, __LINE__);
-			return -ENOMEM;
+			rc = -ENOMEM;
+			goto error_no_mem;
 		}
 		if (mdss_dsi_mres) {
 			mdss_dsi_base = ioremap(mdss_dsi_mres->start,
@@ -501,7 +728,8 @@
 			if (!mdss_dsi_base) {
 				pr_err("%s:%d unable to remap dsi resources",
 					       __func__, __LINE__);
-				return -ENOMEM;
+				rc = -ENOMEM;
+				goto error_no_mem;
 			}
 		}
 
@@ -511,20 +739,48 @@
 			dev_err(&pdev->dev,
 				"%s: failed to add child nodes, rc=%d\n",
 							__func__, rc);
-			iounmap(mdss_dsi_base);
-			return rc;
+			goto error_ioremap;
+		}
+
+		/* Parse the regulator information */
+		rc = mdss_dsi_get_dt_vreg_data(&pdev->dev,
+			&ctrl_pdata->power_data);
+		if (rc) {
+			pr_err("%s: failed to get vreg data from dt. rc=%d\n",
+				__func__, rc);
+			goto error_vreg;
 		}
 
 		pr_debug("%s: Dsi Ctrl->%d initialized\n", __func__, index);
 	}
 
 	return 0;
+
+error_ioremap:
+	iounmap(mdss_dsi_base);
+error_no_mem:
+	devm_kfree(&pdev->dev, ctrl_pdata);
+error_vreg:
+	mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
+
+	return rc;
 }
 
 static int __devexit mdss_dsi_ctrl_remove(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev);
 
+	if (!ctrl_pdata) {
+		pr_err("%s: no driver data\n", __func__);
+		return -ENODEV;
+	}
+
+	if (msm_dss_config_vreg(&pdev->dev,
+			ctrl_pdata->power_data.vreg_config,
+			ctrl_pdata->power_data.num_vreg, 1) < 0)
+		pr_err("%s: failed to de-init vregs\n", __func__);
+	mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
 	mfd = platform_get_drvdata(pdev);
 	iounmap(mdss_dsi_base);
 	return 0;
@@ -592,7 +848,7 @@
 	int rc;
 	u8 lanes = 0, bpp;
 	u32 h_period, v_period, dsi_pclk_rate;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata;
 	struct device_node *dsi_ctrl_np = NULL;
 	struct platform_device *ctrl_pdev = NULL;
 	unsigned char *ctrl_addr;
@@ -659,31 +915,29 @@
 		return rc;
 	}
 
-	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
+	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
 		dsi_pclk_rate = 35000000;
 	mipi->dsi_pclk_rate = dsi_pclk_rate;
 
-	ctrl_pdata = devm_kzalloc(&pdev->dev,
-		sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL);
-	if (!ctrl_pdata)
-		return -ENOMEM;
-
 	dsi_ctrl_np = of_parse_phandle(pdev->dev.of_node,
 				       "qcom,dsi-ctrl-phandle", 0);
 	if (!dsi_ctrl_np) {
 		pr_err("%s: Dsi controller node not initialized\n", __func__);
-		devm_kfree(&pdev->dev, ctrl_pdata);
 		return -EPROBE_DEFER;
 	}
 
 	ctrl_pdev = of_find_device_by_node(dsi_ctrl_np);
+	ctrl_pdata = platform_get_drvdata(ctrl_pdev);
+	if (!ctrl_pdata) {
+		pr_err("%s: no dsi ctrl driver data\n", __func__);
+		return -EINVAL;
+	}
 
-	rc = mdss_dsi_regulator_init(ctrl_pdev, &(ctrl_pdata->shared_pdata));
+	rc = mdss_dsi_regulator_init(ctrl_pdev);
 	if (rc) {
 		dev_err(&pdev->dev,
 			"%s: failed to init regulator, rc=%d\n",
 						__func__, rc);
-		devm_kfree(&pdev->dev, ctrl_pdata);
 		return rc;
 	}
 
@@ -718,14 +972,14 @@
 			pr_err("request reset gpio failed, rc=%d\n",
 				rc);
 			gpio_free(ctrl_pdata->rst_gpio);
-			gpio_free(ctrl_pdata->disp_en_gpio);
+			if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+				gpio_free(ctrl_pdata->disp_en_gpio);
 			return -ENODEV;
 		}
 	}
 
 	if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
 		pr_err("%s: unable to initialize Dsi ctrl clks\n", __func__);
-		devm_kfree(&pdev->dev, ctrl_pdata);
 		return -EPERM;
 	}
 
@@ -733,7 +987,6 @@
 					     panel_data->panel_info.pdest,
 					     &ctrl_addr)) {
 		pr_err("%s: unable to get Dsi controller res\n", __func__);
-		devm_kfree(&pdev->dev, ctrl_pdata);
 		return -EPERM;
 	}
 
@@ -779,10 +1032,9 @@
 	rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
 	if (rc) {
 		dev_err(&pdev->dev, "unable to register MIPI DSI panel\n");
-		devm_kfree(&pdev->dev, ctrl_pdata);
 		if (ctrl_pdata->rst_gpio)
 			gpio_free(ctrl_pdata->rst_gpio);
-		if (ctrl_pdata->disp_en_gpio)
+		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
 			gpio_free(ctrl_pdata->disp_en_gpio);
 		return rc;
 	}
@@ -790,6 +1042,11 @@
 	ctrl_pdata->on = panel_data->on;
 	ctrl_pdata->off = panel_data->off;
 
+	ctrl_pdata->pclk_rate = dsi_pclk_rate;
+	ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
+			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
+
 	pr_debug("%s: Panal data initialized\n", __func__);
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 06c2952..4a06be5 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -18,6 +18,7 @@
 #include <mach/scm-io.h>
 
 #include "mdss_panel.h"
+#include "mdss_io_util.h"
 
 #define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */
 
@@ -267,7 +268,7 @@
 struct dsi_drv_cm_data {
 	struct regulator *vdd_vreg;
 	struct regulator *vdd_io_vreg;
-	struct regulator *dsi_vreg;
+	struct regulator *vdda_vreg;
 	int broadcast_enable;
 };
 
@@ -286,6 +287,9 @@
 	struct dsi_panel_cmds_list *on_cmds;
 	struct dsi_panel_cmds_list *off_cmds;
 	struct dsi_drv_cm_data shared_pdata;
+	u32 pclk_rate;
+	u32 byte_clk_rate;
+	struct dss_module_power power_data;
 };
 
 int dsi_panel_device_register(struct platform_device *pdev,
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 4c30d18..8d38737 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -45,7 +45,6 @@
 	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
 		pr_debug("%s:%d, reset line not configured\n",
 			   __func__, __LINE__);
-		return;
 	}
 
 	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
@@ -59,18 +58,16 @@
 	if (enable) {
 		gpio_set_value((ctrl_pdata->rst_gpio), 1);
 		msleep(20);
-		wmb();
 		gpio_set_value((ctrl_pdata->rst_gpio), 0);
 		udelay(200);
-		wmb();
 		gpio_set_value((ctrl_pdata->rst_gpio), 1);
 		msleep(20);
-		wmb();
-		gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
-		wmb();
+		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+			gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
 	} else {
 		gpio_set_value((ctrl_pdata->rst_gpio), 0);
-		gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
+		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+			gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
 	}
 }
 
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 1e0de89..3d632c7 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1660,6 +1660,22 @@
 	return ret;
 }
 
+static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd,
+		struct mdss_hw_caps *caps)
+{
+	struct mdss_data_type *mdata = mfd->mdata;
+
+	if (!mdata)
+		return -ENODEV;
+
+	caps->mdp_rev = mdata->mdp_rev;
+	caps->vig_pipes = mdata->nvig_pipes;
+	caps->rgb_pipes = mdata->nrgb_pipes;
+	caps->dma_pipes = mdata->ndma_pipes;
+
+	return 0;
+}
+
 static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
 				struct msmfb_metadata *metadata)
 {
@@ -1669,6 +1685,9 @@
 		metadata->data.panel_frame_rate =
 			mdss_get_panel_framerate(mfd);
 		break;
+	case metadata_op_get_caps:
+		ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
+		break;
 	default:
 		pr_warn("Unsupported request to MDP META IOCTL.\n");
 		ret = -EINVAL;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 4f95aee..e8a3795 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -24,6 +24,7 @@
 
 #define REG_DUMP 0
 
+#include "mdss_debug.h"
 #include "mdss_fb.h"
 #include "mdss_hdmi_tx.h"
 #include "mdss_hdmi_edid.h"
@@ -448,6 +449,18 @@
 		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1;
 } /* hdmi_tx_is_dvi_mode */
 
+static inline void hdmi_tx_send_cable_notification(
+	struct hdmi_tx_ctrl *hdmi_ctrl, int val)
+{
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (!hdmi_ctrl->pdata.primary && (hdmi_ctrl->sdev.state != val))
+		switch_set_state(&hdmi_ctrl->sdev, val);
+} /* hdmi_tx_send_cable_notification */
+
 static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl,
 	int val, bool force)
 {
@@ -694,11 +707,11 @@
 
 	if (hdmi_ctrl->hpd_state) {
 		hdmi_tx_read_sink_info(hdmi_ctrl);
-		switch_set_state(&hdmi_ctrl->sdev, 1);
+		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 {
-		switch_set_state(&hdmi_ctrl->sdev, 0);
+		hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
 		DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
 			__func__, hdmi_ctrl->sdev.state);
 	}
@@ -1774,6 +1787,12 @@
 		return -ENODEV;
 	}
 
+	if (!hdmi_ctrl->audio_sdev.state) {
+		DEV_ERR("%s: failed. HDMI is not connected/ready for audio\n",
+			__func__);
+		return -EPERM;
+	}
+
 	return hdmi_edid_get_audio_blk(
 		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], blk);
 } /* hdmi_tx_get_audio_edid_blk */
@@ -2090,6 +2109,7 @@
 
 static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
 {
+	u32 timeout;
 	int rc = 0;
 	struct dss_io_data *io = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl =
@@ -2114,6 +2134,16 @@
 	/* If a power down is already underway, wait for it to finish */
 	flush_work_sync(&hdmi_ctrl->power_off_work);
 
+	if (hdmi_ctrl->pdata.primary) {
+		timeout = wait_for_completion_interruptible_timeout(
+			&hdmi_ctrl->hpd_done, HZ);
+		if (!timeout) {
+			DEV_ERR("%s: cable connection hasn't happened yet\n",
+				__func__);
+			return -ETIMEDOUT;
+		}
+	}
+
 	rc = hdmi_tx_set_video_fmt(hdmi_ctrl, &panel_data->panel_info);
 	if (rc) {
 		DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
@@ -2182,6 +2212,7 @@
 		DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
 			__func__, rc);
 
+	hdmi_ctrl->hpd_state = false;
 	hdmi_ctrl->hpd_initialized = false;
 } /* hdmi_tx_hpd_off */
 
@@ -2257,7 +2288,7 @@
 		} else {
 			hdmi_ctrl->hpd_off_pending = true;
 
-			switch_set_state(&hdmi_ctrl->sdev, 0);
+			hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
 			DEV_DBG("%s: Hdmi state switch to %d\n", __func__,
 				hdmi_ctrl->sdev.state);
 		}
@@ -2433,6 +2464,20 @@
 			hdmi_tx_sysfs_remove(hdmi_ctrl);
 			return rc;
 		}
+
+		if (hdmi_ctrl->pdata.primary) {
+			INIT_COMPLETION(hdmi_ctrl->hpd_done);
+			rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+			if (rc) {
+				DEV_ERR("%s: hpd_enable failed. rc=%d\n",
+					__func__, rc);
+				hdmi_tx_sysfs_remove(hdmi_ctrl);
+				return rc;
+			} else {
+				hdmi_ctrl->hpd_feature_on = true;
+			}
+		}
+
 		break;
 
 	case MDSS_EVENT_CHECK_PARAMS:
@@ -2479,7 +2524,7 @@
 			if (!timeout & !hdmi_ctrl->hpd_state) {
 				DEV_INFO("%s: cable removed during suspend\n",
 					__func__);
-				switch_set_state(&hdmi_ctrl->sdev, 0);
+				hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
 				rc = -EPERM;
 			} else {
 				DEV_DBG("%s: cable present after resume\n",
@@ -3108,6 +3153,13 @@
 		}
 	}
 
+	if (of_find_property(pdev->dev.of_node, "qcom,primary_panel", NULL)) {
+		u32 tmp;
+		of_property_read_u32(pdev->dev.of_node, "qcom,primary_panel",
+			&tmp);
+		pdata->primary = tmp ? true : false;
+	}
+
 	return rc;
 
 error:
@@ -3167,15 +3219,18 @@
 	if (rc) {
 		DEV_ERR("%s: Failed to add child devices. rc=%d\n",
 			__func__, rc);
-		goto failed_init_features;
+		goto failed_reg_panel;
 	} else {
 		DEV_DBG("%s: Add child devices.\n", __func__);
 	}
 
+	if (mdss_debug_register_base("hdmi",
+			hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+			hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].len))
+		DEV_WARN("%s: hdmi_tx debugfs register failed\n", __func__);
+
 	return rc;
 
-failed_init_features:
-	hdmi_tx_sysfs_remove(hdmi_ctrl);
 failed_reg_panel:
 	hdmi_tx_dev_deinit(hdmi_ctrl);
 failed_dev_init:
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 06ae427..8d9a477 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -30,8 +30,9 @@
 	HDMI_TX_MAX_PM
 };
 
+/* Data filled from device tree */
 struct hdmi_tx_platform_data {
-	/* Data filled from device tree nodes */
+	bool primary;
 	struct dss_io_data io[HDMI_TX_MAX_IO];
 	struct dss_module_power power_data[HDMI_TX_MAX_PM];
 };
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 97428cd..c6b6e3f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -265,12 +265,12 @@
 	if (ctx->rot90) {
 		ctx->opmode |= BIT(5); /* ROT 90 */
 		swap(ctx->width, ctx->height);
+		ctx->format = mdss_mdp_get_rotator_dst_format(rot->format);
+	} else {
+		ctx->format = rot->format;
 	}
 
-	if (mdss_mdp_writeback_format_setup(ctx))
-		return -EINVAL;
-
-	return 0;
+	return mdss_mdp_writeback_format_setup(ctx);
 }
 
 static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index dcefc09..98a8202 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -236,7 +236,7 @@
 	struct mdss_mdp_format_params *fmt;
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_mixer *mixer = NULL;
-	u32 pipe_type, mixer_mux, len;
+	u32 pipe_type, mixer_mux, len, src_format;
 	int ret;
 
 	if (mfd == NULL || mfd->ctl == NULL)
@@ -255,9 +255,13 @@
 		return -ENOTSUPP;
 	}
 
-	fmt = mdss_mdp_get_format_params(req->src.format);
+	src_format = req->src.format;
+	if (req->flags & MDP_SOURCE_ROTATED_90)
+		src_format = mdss_mdp_get_rotator_dst_format(src_format);
+
+	fmt = mdss_mdp_get_format_params(src_format);
 	if (!fmt) {
-		pr_err("invalid pipe format %d\n", req->src.format);
+		pr_err("invalid pipe format %d\n", src_format);
 		return -EINVAL;
 	}
 
@@ -539,9 +543,9 @@
 	virt = ion_map_kernel(iclient, ihdl);
 	ion_phys(iclient, ihdl, &phys, &size);
 
-	pr_debug("%s %d Allocating %u bytes at 0x%lx (%lx phys)\n",
+	pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
 			__func__, __LINE__, size,
-			(unsigned long int)virt, phys);
+			(unsigned long int)virt, &phys);
 
 	bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
 
@@ -1148,7 +1152,7 @@
 	ret = wait_for_completion_interruptible_timeout(&mfd->vsync_comp,
 			timeout);
 	if (ret <= 0) {
-		pr_warn("Sending current time as vsync timestamp for fb%d\n",
+		pr_debug("Sending current time as vsync timestamp for fb%d\n",
 				mfd->index);
 		mfd->vsync_time = ktime_get();
 	}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 70ef6bf..c46f271 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -42,6 +42,18 @@
 	struct list_head head;
 };
 
+static inline u32 mdss_mdp_get_rotator_dst_format(u32 in_format)
+{
+	switch (in_format) {
+	case MDP_Y_CBCR_H2V2_VENUS:
+		return MDP_Y_CBCR_H2V2;
+	case MDP_Y_CR_CB_GH2V2:
+		return MDP_Y_CR_CB_H2V2;
+	default:
+		return in_format;
+	}
+}
+
 struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void);
 struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id);
 
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index 30dd471..ccddf44 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -1712,18 +1712,18 @@
 		struct input_dev *input = mhl_ctrl->input;
 
 		mhl_ctrl->rcp_key_code_tbl = vmalloc(
-			ARRAY_SIZE(support_rcp_key_code_tbl));
+			sizeof(support_rcp_key_code_tbl));
 		if (!mhl_ctrl->rcp_key_code_tbl) {
 			pr_err("%s: no alloc mem for rcp keycode tbl\n",
 			       __func__);
 			return -ENOMEM;
 		}
 
+		mhl_ctrl->rcp_key_code_tbl_len = sizeof(
+			support_rcp_key_code_tbl);
 		memcpy(mhl_ctrl->rcp_key_code_tbl,
 		       &support_rcp_key_code_tbl[0],
-		       ARRAY_SIZE(support_rcp_key_code_tbl));
-		mhl_ctrl->rcp_key_code_tbl_len = ARRAY_SIZE(
-			support_rcp_key_code_tbl);
+		       mhl_ctrl->rcp_key_code_tbl_len);
 
 		input->phys = "cbus/input0";
 		input->id.bustype = BUS_VIRTUAL;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 3b6fc38..2b07e43 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -173,6 +173,7 @@
 void mdss_dsi_clk_enable(struct mdss_panel_data *pdata)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u32 esc_clk_rate = 19200000;
 
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
@@ -186,17 +187,17 @@
 		return;
 	}
 
-	if (clk_set_rate(ctrl_pdata->esc_clk, 19200000) < 0)
-		pr_err("%s: dsi_esc_clk - clk_set_rate failed\n",
-					__func__);
+	pr_debug("%s: Setting clock rates: pclk=%d, byteclk=%d escclk=%d\n",
+			__func__, ctrl_pdata->pclk_rate,
+			ctrl_pdata->byte_clk_rate, esc_clk_rate);
+	if (clk_set_rate(ctrl_pdata->esc_clk, esc_clk_rate) < 0)
+		pr_err("%s: dsi_esc_clk - clk_set_rate failed\n", __func__);
 
-	if (clk_set_rate(ctrl_pdata->byte_clk, 53000000) < 0)
-		pr_err("%s: dsi_byte_clk - clk_set_rate failed\n",
-					__func__);
+	if (clk_set_rate(ctrl_pdata->byte_clk, ctrl_pdata->byte_clk_rate) < 0)
+		pr_err("%s: dsi_byte_clk - clk_set_rate failed\n", __func__);
 
-	if (clk_set_rate(ctrl_pdata->pixel_clk, 70000000) < 0)
-		pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n",
-					__func__);
+	if (clk_set_rate(ctrl_pdata->pixel_clk, ctrl_pdata->pclk_rate) < 0)
+		pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n", __func__);
 
 	clk_enable(ctrl_pdata->esc_clk);
 	clk_enable(ctrl_pdata->byte_clk);
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index b96e093..57bf9f2 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -41,6 +41,9 @@
 #include <linux/android_pmem.h>
 #include <linux/leds.h>
 #include <linux/pm_runtime.h>
+#include <linux/sync.h>
+#include <linux/sw_sync.h>
+#include <linux/file.h>
 
 #define MSM_FB_C
 #include "msm_fb.h"
@@ -115,12 +118,17 @@
 static int mdp_bl_scale_config(struct msm_fb_data_type *mfd,
 						struct mdp_bl_scale_data *data);
 static void msm_fb_scale_bl(__u32 *bl_lvl);
+static void msm_fb_commit_wq_handler(struct work_struct *work);
+static int msm_fb_pan_idle(struct msm_fb_data_type *mfd);
 
 #ifdef MSM_FB_ENABLE_DBGFS
 
 #define MSM_FB_MAX_DBGFS 1024
 #define MAX_BACKLIGHT_BRIGHTNESS 255
 
+/* 200 ms for time out */
+#define WAIT_FENCE_TIMEOUT 200
+
 int msm_fb_debugfs_file_index;
 struct dentry *msm_fb_debugfs_root;
 struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS];
@@ -419,6 +427,16 @@
 
 	pdev_list[pdev_list_cnt++] = pdev;
 	msm_fb_create_sysfs(pdev);
+	if (mfd->timeline == NULL) {
+		mfd->timeline = sw_sync_timeline_create("mdp-timeline");
+		if (mfd->timeline == NULL) {
+			pr_err("%s: cannot create time line", __func__);
+			return -ENOMEM;
+		} else {
+			mfd->timeline_value = 0;
+		}
+	}
+
 	return 0;
 }
 
@@ -863,6 +881,17 @@
 			if (ret)
 				mfd->panel_power_on = curr_pwr_state;
 
+			if (mfd->timeline) {
+				/* Adding 1 is enough when pan_display is still
+				 * a blocking call and with mutex protection.
+				 * But if it is an async call, we will still
+				 * need to add 2. Adding 2 can be safer in
+				 * order to signal all existing fences, and it
+				 * is harmless. */
+				sw_sync_timeline_inc(mfd->timeline, 2);
+				mfd->timeline_value += 2;
+			}
+
 			mfd->op_enable = TRUE;
 		}
 		break;
@@ -905,7 +934,7 @@
 			    const struct fb_fillrect *rect)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-
+	msm_fb_pan_idle(mfd);
 	cfb_fillrect(info, rect);
 	if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
 		!mfd->sw_currently_refreshing) {
@@ -926,6 +955,7 @@
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 
+	msm_fb_pan_idle(mfd);
 	cfb_copyarea(info, area);
 	if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
 		!mfd->sw_currently_refreshing) {
@@ -945,6 +975,7 @@
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 
+	msm_fb_pan_idle(mfd);
 	cfb_imageblit(info, image);
 	if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
 		!mfd->sw_currently_refreshing) {
@@ -963,6 +994,7 @@
 static int msm_fb_blank(int blank_mode, struct fb_info *info)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	msm_fb_pan_idle(mfd);
 	return msm_fb_blank_sub(blank_mode, info, mfd->op_enable);
 }
 
@@ -989,6 +1021,7 @@
 	u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
 	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	msm_fb_pan_idle(mfd);
 	if (off >= len) {
 		/* memory mapped io */
 		off -= len;
@@ -1343,7 +1376,15 @@
 	mfd->msmfb_no_update_notify_timer.data = (unsigned long)mfd;
 	init_completion(&mfd->msmfb_update_notify);
 	init_completion(&mfd->msmfb_no_update_notify);
-
+	init_completion(&mfd->commit_comp);
+	mutex_init(&mfd->sync_mutex);
+	INIT_WORK(&mfd->commit_work, msm_fb_commit_wq_handler);
+	mfd->msm_fb_backup = kzalloc(sizeof(struct msm_fb_backup_type),
+		GFP_KERNEL);
+	if (mfd->msm_fb_backup == 0) {
+		pr_err("error: not enough memory!\n");
+		return -ENOMEM;
+	}
 	fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram;
 	fbram += fbram_offset;
 	fbram_phys += fbram_offset;
@@ -1653,7 +1694,34 @@
 	return ret;
 }
 
-DEFINE_SEMAPHORE(msm_fb_pan_sem);
+int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd)
+{
+	int i, ret = 0;
+	/* buf sync */
+	for (i = 0; i < mfd->acq_fen_cnt; i++) {
+		ret = sync_fence_wait(mfd->acq_fen[i], WAIT_FENCE_TIMEOUT);
+		sync_fence_put(mfd->acq_fen[i]);
+		if (ret < 0) {
+			pr_err("%s: sync_fence_wait failed! ret = %x\n",
+				__func__, ret);
+			break;
+		}
+	}
+	mfd->acq_fen_cnt = 0;
+	return ret;
+}
+int msm_fb_signal_timeline(struct msm_fb_data_type *mfd)
+{
+	mutex_lock(&mfd->sync_mutex);
+	if (mfd->timeline) {
+		sw_sync_timeline_inc(mfd->timeline, 1);
+		mfd->timeline_value++;
+	}
+	mfd->last_rel_fence = mfd->cur_rel_fence;
+	mfd->cur_rel_fence = 0;
+	mutex_unlock(&mfd->sync_mutex);
+	return 0;
+}
 
 static void bl_workqueue_handler(struct work_struct *work)
 {
@@ -1671,9 +1739,81 @@
 	}
 }
 
+DEFINE_SEMAPHORE(msm_fb_pan_sem);
+static int msm_fb_pan_idle(struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	mutex_lock(&mfd->sync_mutex);
+	if (mfd->is_committing) {
+		mutex_unlock(&mfd->sync_mutex);
+		ret = wait_for_completion_timeout(&mfd->commit_comp,
+			msecs_to_jiffies(WAIT_FENCE_TIMEOUT));
+		if (ret <= 0)
+			pr_err("%s wait for commit_comp timeout %d %d",
+				__func__, ret, mfd->is_committing);
+	} else {
+		mutex_unlock(&mfd->sync_mutex);
+	}
+	return ret;
+}
+static int msm_fb_pan_display_ex(struct fb_var_screeninfo *var,
+			      struct fb_info *info, u32 wait_for_finish)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct msm_fb_backup_type *fb_backup;
+	int ret = 0;
+	/*
+	 * If framebuffer is 2, io pen display is not allowed.
+	 */
+	if (bf_supported && info->node == 2) {
+		pr_err("%s: no pan display for fb%d!",
+		       __func__, info->node);
+		return -EPERM;
+	}
+
+	if (info->node != 0 || mfd->cont_splash_done)	/* primary */
+		if ((!mfd->op_enable) || (!mfd->panel_power_on))
+			return -EPERM;
+
+	if (var->xoffset > (info->var.xres_virtual - info->var.xres))
+		return -EINVAL;
+
+	if (var->yoffset > (info->var.yres_virtual - info->var.yres))
+		return -EINVAL;
+	msm_fb_pan_idle(mfd);
+
+	mutex_lock(&mfd->sync_mutex);
+
+	if (info->fix.xpanstep)
+		info->var.xoffset =
+		    (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
+
+	if (info->fix.ypanstep)
+		info->var.yoffset =
+		    (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
+
+	fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
+	memcpy(&fb_backup->info, info, sizeof(struct fb_info));
+	memcpy(&fb_backup->var, var, sizeof(struct fb_var_screeninfo));
+	mfd->is_committing = 1;
+	INIT_COMPLETION(mfd->commit_comp);
+	schedule_work(&mfd->commit_work);
+	mutex_unlock(&mfd->sync_mutex);
+	if (wait_for_finish)
+		msm_fb_pan_idle(mfd);
+	return ret;
+}
+
 static int msm_fb_pan_display(struct fb_var_screeninfo *var,
 			      struct fb_info *info)
 {
+	return msm_fb_pan_display_ex(var, info, TRUE);
+}
+
+static int msm_fb_pan_display_sub(struct fb_var_screeninfo *var,
+			      struct fb_info *info)
+{
 	struct mdp_dirty_region dirty;
 	struct mdp_dirty_region *dirtyPtr = NULL;
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -1748,18 +1888,24 @@
 	mutex_unlock(&msm_fb_notify_update_sem);
 
 	down(&msm_fb_pan_sem);
-
+	msm_fb_wait_for_fence(mfd);
 	if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */
 		mdp_set_dma_pan_info(info, NULL, TRUE);
 		if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
 			pr_err("%s: can't turn on display!\n", __func__);
+			if (mfd->timeline) {
+				sw_sync_timeline_inc(mfd->timeline, 2);
+				mfd->timeline_value += 2;
+			}
 			return -EINVAL;
 		}
 	}
 
 	mdp_set_dma_pan_info(info, dirtyPtr,
 			     (var->activate & FB_ACTIVATE_VBL));
+	/* async call */
 	mdp_dma_pan_update(info);
+	msm_fb_signal_timeline(mfd);
 	up(&msm_fb_pan_sem);
 
 	if (unset_bl_level && !bl_updated)
@@ -1773,8 +1919,30 @@
 	return 0;
 }
 
+static void msm_fb_commit_wq_handler(struct work_struct *work)
+{
+	struct msm_fb_data_type *mfd;
+	struct fb_var_screeninfo *var;
+	struct fb_info *info;
+	struct msm_fb_backup_type *fb_backup;
+
+	mfd = container_of(work, struct msm_fb_data_type, commit_work);
+	fb_backup = (struct msm_fb_backup_type *)mfd->msm_fb_backup;
+	var = &fb_backup->var;
+	info = &fb_backup->info;
+	msm_fb_pan_display_sub(var, info);
+	mutex_lock(&mfd->sync_mutex);
+	mfd->is_committing = 0;
+	complete_all(&mfd->commit_comp);
+	mutex_unlock(&mfd->sync_mutex);
+
+}
+
 static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	msm_fb_pan_idle(mfd);
 	if (var->rotate != FB_ROTATE_UR)
 		return -EINVAL;
 	if (var->grayscale != info->var.grayscale)
@@ -1899,7 +2067,7 @@
 	struct fb_var_screeninfo *var = &info->var;
 	int old_imgType;
 	int blank = 0;
-
+	msm_fb_pan_idle(mfd);
 	old_imgType = mfd->fb_imgType;
 	switch (var->bits_per_pixel) {
 	case 16:
@@ -3331,6 +3499,169 @@
 	return ret;
 }
 
+static int msmfb_handle_buf_sync_ioctl(struct msm_fb_data_type *mfd,
+						struct mdp_buf_sync *buf_sync)
+{
+	int i, fence_cnt = 0, ret;
+	int acq_fen_fd[MDP_MAX_FENCE_FD];
+	struct sync_fence *fence;
+
+	if ((buf_sync->acq_fen_fd_cnt == 0) ||
+		(buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
+		(mfd->timeline == NULL))
+		return -EINVAL;
+
+	ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
+			buf_sync->acq_fen_fd_cnt * sizeof(int));
+	if (ret) {
+		pr_err("%s:copy_from_user failed", __func__);
+		return ret;
+	}
+	mutex_lock(&mfd->sync_mutex);
+	for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
+		fence = sync_fence_fdget(acq_fen_fd[i]);
+		if (fence == NULL) {
+			pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
+				acq_fen_fd[i]);
+			ret = -EINVAL;
+			break;
+		}
+		mfd->acq_fen[i] = fence;
+	}
+	fence_cnt = i;
+	if (ret)
+		goto buf_sync_err_1;
+	mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
+			mfd->timeline_value + 2);
+	if (mfd->cur_rel_sync_pt == NULL) {
+		pr_err("%s: cannot create sync point", __func__);
+		ret = -ENOMEM;
+		goto buf_sync_err_1;
+	}
+	/* create fence */
+	mfd->cur_rel_fence = sync_fence_create("mdp-fence",
+			mfd->cur_rel_sync_pt);
+	if (mfd->cur_rel_fence == NULL) {
+		sync_pt_free(mfd->cur_rel_sync_pt);
+		mfd->cur_rel_sync_pt = NULL;
+		pr_err("%s: cannot create fence", __func__);
+		ret = -ENOMEM;
+		goto buf_sync_err_1;
+	}
+	/* create fd */
+	mfd->cur_rel_fen_fd = get_unused_fd_flags(0);
+	sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd);
+	ret = copy_to_user(buf_sync->rel_fen_fd,
+		&mfd->cur_rel_fen_fd, sizeof(int));
+	if (ret) {
+		pr_err("%s:copy_to_user failed", __func__);
+		goto buf_sync_err_2;
+	}
+	mfd->acq_fen_cnt = buf_sync->acq_fen_fd_cnt;
+	mutex_unlock(&mfd->sync_mutex);
+	return ret;
+buf_sync_err_2:
+	sync_fence_put(mfd->cur_rel_fence);
+	put_unused_fd(mfd->cur_rel_fen_fd);
+	mfd->cur_rel_fence = NULL;
+	mfd->cur_rel_fen_fd = 0;
+buf_sync_err_1:
+	for (i = 0; i < fence_cnt; i++)
+		sync_fence_put(mfd->acq_fen[i]);
+	mfd->acq_fen_cnt = 0;
+	mutex_unlock(&mfd->sync_mutex);
+	return ret;
+}
+
+static int buf_fence_process(struct msm_fb_data_type *mfd,
+						struct mdp_buf_fence *buf_fence)
+{
+	int i, fence_cnt = 0, ret;
+	struct sync_fence *fence;
+
+	if ((buf_fence->acq_fen_fd_cnt == 0) ||
+		(buf_fence->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
+		(mfd->timeline == NULL))
+		return -EINVAL;
+
+	mutex_lock(&mfd->sync_mutex);
+	for (i = 0; i < buf_fence->acq_fen_fd_cnt; i++) {
+		fence = sync_fence_fdget(buf_fence->acq_fen_fd[i]);
+		if (fence == NULL) {
+			pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
+				buf_fence->acq_fen_fd[i]);
+			ret = -EINVAL;
+			break;
+		}
+		mfd->acq_fen[i] = fence;
+	}
+	fence_cnt = i;
+	if (ret)
+		goto buf_fence_err_1;
+	mfd->cur_rel_sync_pt = sw_sync_pt_create(mfd->timeline,
+			mfd->timeline_value + 2);
+	if (mfd->cur_rel_sync_pt == NULL) {
+		pr_err("%s: cannot create sync point", __func__);
+		ret = -ENOMEM;
+		goto buf_fence_err_1;
+	}
+	/* create fence */
+	mfd->cur_rel_fence = sync_fence_create("mdp-fence",
+			mfd->cur_rel_sync_pt);
+	if (mfd->cur_rel_fence == NULL) {
+		sync_pt_free(mfd->cur_rel_sync_pt);
+		mfd->cur_rel_sync_pt = NULL;
+		pr_err("%s: cannot create fence", __func__);
+		ret = -ENOMEM;
+		goto buf_fence_err_1;
+	}
+	/* create fd */
+	mfd->cur_rel_fen_fd = get_unused_fd_flags(0);
+	sync_fence_install(mfd->cur_rel_fence, mfd->cur_rel_fen_fd);
+	buf_fence->rel_fen_fd[0] = mfd->cur_rel_fen_fd;
+	/* Only one released fd for now, -1 indicates an end */
+	buf_fence->rel_fen_fd[1] = -1;
+	mfd->acq_fen_cnt = buf_fence->acq_fen_fd_cnt;
+	mutex_unlock(&mfd->sync_mutex);
+	return ret;
+buf_fence_err_1:
+	for (i = 0; i < fence_cnt; i++)
+		sync_fence_put(mfd->acq_fen[i]);
+	mfd->acq_fen_cnt = 0;
+	mutex_unlock(&mfd->sync_mutex);
+	return ret;
+}
+static int msmfb_display_commit(struct fb_info *info,
+						unsigned long *argp)
+{
+	int ret;
+	u32 copy_back = FALSE;
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct mdp_display_commit disp_commit;
+	struct mdp_buf_fence *buf_fence;
+	ret = copy_from_user(&disp_commit, argp,
+			sizeof(disp_commit));
+	if (ret) {
+		pr_err("%s:copy_from_user failed", __func__);
+		return ret;
+	}
+	buf_fence = &disp_commit.buf_fence;
+	if (buf_fence->acq_fen_fd_cnt > 0)
+		ret = buf_fence_process(mfd, buf_fence);
+	if ((!ret) && (buf_fence->rel_fen_fd[0] > 0))
+		copy_back = TRUE;
+
+	ret = msm_fb_pan_display_ex(&disp_commit.var,
+			      info, disp_commit.wait_for_finish);
+
+	if (copy_back) {
+		ret = copy_to_user(argp,
+			&disp_commit, sizeof(disp_commit));
+		if (ret)
+			pr_err("%s:copy_to_user failed", __func__);
+	}
+	return ret;
+}
 static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
@@ -3349,7 +3680,9 @@
 	struct mdp_page_protection fb_page_protection;
 	struct msmfb_mdp_pp mdp_pp;
 	struct msmfb_metadata mdp_metadata;
+	struct mdp_buf_sync buf_sync;
 	int ret = 0;
+	msm_fb_pan_idle(mfd);
 
 	switch (cmd) {
 #ifdef CONFIG_FB_MSM_OVERLAY
@@ -3636,12 +3969,24 @@
 		if (ret == 1)
 			ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp));
 		break;
+	case MSMFB_BUFFER_SYNC:
+		ret = copy_from_user(&buf_sync, argp, sizeof(buf_sync));
+		if (ret)
+			return ret;
+
+		ret = msmfb_handle_buf_sync_ioctl(mfd, &buf_sync);
+
+		if (!ret)
+			ret = copy_to_user(argp, &buf_sync, sizeof(buf_sync));
+		break;
 
 	case MSMFB_METADATA_SET:
 		ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata));
 		if (ret)
 			return ret;
 		ret = msmfb_handle_metadata_ioctl(mfd, &mdp_metadata);
+	case MSMFB_DISPLAY_COMMIT:
+		ret = msmfb_display_commit(info, argp);
 		break;
 
 	case MSMFB_METADATA_GET:
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 34cb1fc..7519ac7 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -197,6 +197,26 @@
 	void *cpu_pm_hdl;
 	u32 avtimer_phy;
 	int vsync_sysfs_created;
+	u32 acq_fen_cnt;
+	struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
+	int cur_rel_fen_fd;
+	struct sync_pt *cur_rel_sync_pt;
+	struct sync_fence *cur_rel_fence;
+	struct sync_fence *last_rel_fence;
+	struct sw_sync_timeline *timeline;
+	int timeline_value;
+	u32 last_acq_fen_cnt;
+	struct sync_fence *last_acq_fen[MDP_MAX_FENCE_FD];
+	struct mutex sync_mutex;
+	struct completion commit_comp;
+	u32 is_committing;
+	struct work_struct commit_work;
+	void *msm_fb_backup;
+};
+struct msm_fb_backup_type {
+	struct fb_info info;
+	struct fb_var_screeninfo var;
+	struct msm_fb_data_type mfd;
 };
 
 struct dentry *msm_fb_get_debugfs_root(void);
@@ -216,7 +236,8 @@
 int msm_fb_writeback_terminate(struct fb_info *info);
 int msm_fb_detect_client(const char *name);
 int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp);
-
+int msm_fb_wait_for_fence(struct msm_fb_data_type *mfd);
+int msm_fb_signal_timeline(struct msm_fb_data_type *mfd);
 #ifdef CONFIG_FB_BACKLIGHT
 void msm_fb_config_backlight(struct msm_fb_data_type *mfd);
 #endif
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index afc5130..1c69d8f 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -25,7 +25,7 @@
 #include <linux/uaccess.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
 #include <linux/clk.h>
 #include <linux/timer.h>
 #include <mach/msm_subsystem_map.h>
@@ -48,8 +48,6 @@
 static dev_t vid_dec_dev_num;
 static struct class *vid_dec_class;
 
-static unsigned int vidc_mmu_subsystem[] = {
-	MSM_SUBSYSTEM_VIDEO};
 static s32 vid_dec_get_empty_client_index(void)
 {
 	u32 i, found = false;
@@ -875,11 +873,8 @@
 {
 	struct vcd_property_hdr vcd_property_hdr;
 	struct vcd_property_meta_buffer *vcd_meta_buffer = NULL;
-	struct msm_mapped_buffer *mapped_buffer = NULL;
-	struct msm_mapped_buffer *mapped_buffer_iommu = NULL;
 	u32 vcd_status = VCD_ERR_FAIL;
-	u32 len = 0, flags = 0, len_iommu = 0, flags_iommu = 0, buf_size = 0;
-	struct file *file, *file_iommu;
+	u32 len = 0, len_iommu = 0, buf_size = 0;
 	int rc = 0;
 	unsigned long ionflag = 0, ionflag_iommu = 0;
 	unsigned long buffer_size = 0, buffer_size_iommu = 0;
@@ -903,54 +898,8 @@
 	vcd_meta_buffer->pmem_fd_iommu = meta_buffers->pmem_fd_iommu;
 
 	if (!vcd_get_ion_status()) {
-		if (get_pmem_file(vcd_meta_buffer->pmem_fd,
-				(unsigned long *) (&(vcd_meta_buffer->
-				physical_addr)),
-				(unsigned long *) (&vcd_meta_buffer->
-							kernel_virtual_addr),
-				(unsigned long *) (&len), &file)) {
-				ERR("%s(): get_pmem_file failed\n", __func__);
-				return false;
-			}
-		put_pmem_file(file);
-		flags = MSM_SUBSYSTEM_MAP_IOVA;
-		mapped_buffer = msm_subsystem_map_buffer(
-			(unsigned long)vcd_meta_buffer->physical_addr,
-				len, flags, vidc_mmu_subsystem,
-				sizeof(vidc_mmu_subsystem)/
-				sizeof(unsigned int));
-		if (IS_ERR(mapped_buffer)) {
-			pr_err("buffer map failed");
-			return false;
-		}
-		vcd_meta_buffer->client_data = (void *) mapped_buffer;
-		vcd_meta_buffer->dev_addr =
-			(u8 *)mapped_buffer->iova[0];
-
-		if (get_pmem_file(vcd_meta_buffer->pmem_fd_iommu,
-				(unsigned long *) (&(vcd_meta_buffer->
-				physical_addr_iommu)),
-				(unsigned long *) (&vcd_meta_buffer->
-				kernel_virt_addr_iommu),
-				(unsigned long *) (&len_iommu), &file_iommu)) {
-				ERR("%s(): get_pmem_file failed\n", __func__);
-				return false;
-			}
-		put_pmem_file(file_iommu);
-		flags_iommu = MSM_SUBSYSTEM_MAP_IOVA;
-		mapped_buffer_iommu = msm_subsystem_map_buffer(
-			(unsigned long)vcd_meta_buffer->physical_addr_iommu,
-				len_iommu, flags_iommu, vidc_mmu_subsystem,
-				sizeof(vidc_mmu_subsystem)/
-				sizeof(unsigned int));
-		if (IS_ERR(mapped_buffer_iommu)) {
-			pr_err("buffer map failed");
-			return false;
-		}
-		vcd_meta_buffer->client_data_iommu =
-					(void *) mapped_buffer_iommu;
-		vcd_meta_buffer->dev_addr_iommu =
-					(u8 *)mapped_buffer_iommu->iova[0];
+		pr_err("PMEM Not available\n");
+		return false;
 	} else {
 		client_ctx->meta_buffer_ion_handle = ion_import_dma_buf(
 					client_ctx->user_ion_client,
@@ -1132,10 +1081,8 @@
 {
 	struct vcd_property_hdr vcd_property_hdr;
 	struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
-	struct msm_mapped_buffer *mapped_buffer = NULL;
 	u32 vcd_status = VCD_ERR_FAIL;
-	u32 len = 0, flags = 0;
-	struct file *file;
+	u32 len = 0;
 	int rc = 0;
 	unsigned long ionflag = 0;
 	unsigned long buffer_size = 0;
@@ -1156,28 +1103,8 @@
 	vcd_h264_mv_buffer->offset = mv_data->offset;
 
 	if (!vcd_get_ion_status()) {
-		if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
-			(unsigned long *) (&(vcd_h264_mv_buffer->
-			physical_addr)),
-			(unsigned long *) (&vcd_h264_mv_buffer->
-						kernel_virtual_addr),
-			(unsigned long *) (&len), &file)) {
-			ERR("%s(): get_pmem_file failed\n", __func__);
-			return false;
-		}
-		put_pmem_file(file);
-		flags = MSM_SUBSYSTEM_MAP_IOVA;
-		mapped_buffer = msm_subsystem_map_buffer(
-			(unsigned long)vcd_h264_mv_buffer->physical_addr, len,
-				flags, vidc_mmu_subsystem,
-				sizeof(vidc_mmu_subsystem)/
-				sizeof(unsigned int));
-		if (IS_ERR(mapped_buffer)) {
-			pr_err("buffer map failed");
-			return false;
-		}
-		vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
-		vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+		pr_err("PMEM not available\n");
+		return false;
 	} else {
 		client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
 					client_ctx->user_ion_client,
@@ -1818,7 +1745,6 @@
 	u32 vcd_status;
 	unsigned long kernel_vaddr, phy_addr, len;
 	unsigned long ker_vaddr;
-	struct file *pmem_file;
 	u32 result = true;
 	void __user *arg = (void __user *)u_arg;
 	int rc = 0;
@@ -2133,12 +2059,8 @@
 		}
 
 		if (!vcd_get_ion_status()) {
-			if (get_pmem_file(seq_header.pmem_fd,
-				  &phy_addr, &kernel_vaddr, &len, &pmem_file)) {
-				ERR("%s(): get_pmem_file failed\n", __func__);
-				return false;
-			}
-			put_pmem_file(pmem_file);
+			pr_err("PMEM Not available\n");
+			return -EINVAL;
 		} else {
 			client_ctx->seq_hdr_ion_handle = ion_import_dma_buf(
 				client_ctx->user_ion_client,
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index aa17f84..823626a 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -25,7 +25,7 @@
 #include <linux/uaccess.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
 #include <linux/clk.h>
 #include <media/msm/vidc_type.h>
 #include <media/msm/vcd_api.h>
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 14d8bfc..3dae4be1 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -25,7 +25,7 @@
 #include <linux/uaccess.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
 #include <linux/clk.h>
 #include <mach/msm_subsystem_map.h>
 #include <media/msm/vidc_type.h>
@@ -41,9 +41,6 @@
 #endif
 
 #define ERR(x...) printk(KERN_ERR x)
-static unsigned int vidc_mmu_subsystem[] = {
-	MSM_SUBSYSTEM_VIDEO};
-
 
 u32 vid_enc_set_get_base_cfg(struct video_client_ctx *client_ctx,
 		struct venc_basecfg *base_config, u32 set_flag)
@@ -1801,11 +1798,9 @@
 		struct venc_recon_addr *venc_recon)
 {
 	u32 vcd_status = VCD_ERR_FAIL;
-	u32 len, i, flags = 0;
-	struct file *file;
+	u32 len, i;
 	struct vcd_property_hdr vcd_property_hdr;
 	struct vcd_property_enc_recon_buffer *control = NULL;
-	struct msm_mapped_buffer *mapped_buffer = NULL;
 	int rc = -1;
 	unsigned long ionflag = 0;
 	unsigned long iova = 0;
@@ -1837,25 +1832,8 @@
 	control->user_virtual_addr = venc_recon->pbuffer;
 
 	if (!vcd_get_ion_status()) {
-		if (get_pmem_file(control->pmem_fd, (unsigned long *)
-			(&(control->physical_addr)), (unsigned long *)
-			(&control->kernel_virtual_addr),
-			(unsigned long *) (&len), &file)) {
-				ERR("%s(): get_pmem_file failed\n", __func__);
-				return false;
-			}
-			put_pmem_file(file);
-			flags = MSM_SUBSYSTEM_MAP_IOVA;
-			mapped_buffer = msm_subsystem_map_buffer(
-			(unsigned long)control->physical_addr, len,
-			flags, vidc_mmu_subsystem,
-			sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
-			if (IS_ERR(mapped_buffer)) {
-				pr_err("buffer map failed");
-				return false;
-			}
-			control->client_data = (void *) mapped_buffer;
-			control->dev_addr = (u8 *)mapped_buffer->iova[0];
+		pr_err("PMEM not available\n");
+		return false;
 	} else {
 		client_ctx->recon_buffer_ion_handle[i] = ion_import_dma_buf(
 				client_ctx->user_ion_client, control->pmem_fd);
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 9007145..72a1d5f 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,7 +24,7 @@
 #include <linux/uaccess.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
-#include <linux/android_pmem.h>
+
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/debugfs.h>
@@ -49,7 +49,6 @@
 static struct vidc_dev *vidc_device_p;
 static dev_t vidc_dev_num;
 static struct class *vidc_class;
-static unsigned int vidc_mmu_subsystem[] = {MSM_SUBSYSTEM_VIDEO};
 
 static const struct file_operations vidc_fops = {
 	.owner = THIS_MODULE,
@@ -565,9 +564,8 @@
 	unsigned long len, phys_addr;
 	struct file *file = NULL;
 	u32 *num_of_buffers = NULL;
-	u32 i, flags;
+	u32 i;
 	struct buf_addr_table *buf_addr_table;
-	struct msm_mapped_buffer *mapped_buffer = NULL;
 	struct ion_handle *buff_ion_handle = NULL;
 	unsigned long ionflag = 0;
 	unsigned long iova = 0;
@@ -609,26 +607,8 @@
 		goto bail_out_add;
 	} else {
 		if (!vcd_get_ion_status()) {
-			if (get_pmem_file(pmem_fd, &phys_addr,
-					kernel_vaddr, &len, &file)) {
-				ERR("%s(): get_pmem_file failed\n", __func__);
-				goto bail_out_add;
-			}
-			put_pmem_file(file);
-			flags = (buffer == BUFFER_TYPE_INPUT)
-			? MSM_SUBSYSTEM_MAP_IOVA :
-			MSM_SUBSYSTEM_MAP_IOVA|MSM_SUBSYSTEM_ALIGN_IOVA_8K;
-			mapped_buffer = msm_subsystem_map_buffer(phys_addr,
-			length, flags, vidc_mmu_subsystem,
-			sizeof(vidc_mmu_subsystem)/sizeof(unsigned int));
-			if (IS_ERR(mapped_buffer)) {
-				pr_err("buffer map failed");
-				goto bail_out_add;
-			}
-			buf_addr_table[*num_of_buffers].client_data = (void *)
-				mapped_buffer;
-			buf_addr_table[*num_of_buffers].dev_addr =
-				mapped_buffer->iova[0];
+			pr_err("PMEM not available\n");
+			return false;
 		} else {
 			buff_ion_handle = ion_import_dma_buf(
 				client_ctx->user_ion_client, pmem_fd);
diff --git a/fs/fat/Makefile b/fs/fat/Makefile
index 3f3e535..e061903 100644
--- a/fs/fat/Makefile
+++ b/fs/fat/Makefile
@@ -2,7 +2,6 @@
 # Makefile for the Linux fat filesystem support.
 #
 
-
 obj-$(CONFIG_FAT_FS) += fat.o
 obj-$(CONFIG_VFAT_FS) += vfat.o
 obj-$(CONFIG_MSDOS_FS) += msdos.o
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index e52effd..1afb701 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1413,14 +1413,6 @@
 		goto out;
 	}
 
-	if (be32_to_cpu(sb->s_first) == 0 ||
-	    be32_to_cpu(sb->s_first) >= journal->j_maxlen) {
-		printk(KERN_WARNING
-			"JBD2: Invalid start block of journal: %u\n",
-			be32_to_cpu(sb->s_first));
-		goto out;
-	}
-
 	return 0;
 
 out:
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index e35df2d..74c00bc 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1721,18 +1721,6 @@
 								\
 	save = resp->p;
 
-static bool seqid_mutating_err(__be32 err)
-{
-	/* rfc 3530 section 8.1.5: */
-	return	err != nfserr_stale_clientid &&
-		err != nfserr_stale_stateid &&
-		err != nfserr_bad_stateid &&
-		err != nfserr_bad_seqid &&
-		err != nfserr_bad_xdr &&
-		err != nfserr_resource &&
-		err != nfserr_nofilehandle;
-}
-
 /*
  * Routine for encoding the result of a "seqid-mutating" NFSv4 operation.  This
  * is where sequence id's are incremented, and the replay cache is filled.
diff --git a/include/linux/cpuacct.h b/include/linux/cpuacct.h
deleted file mode 100644
index 8f68e73..0000000
--- a/include/linux/cpuacct.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* include/linux/cpuacct.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef _CPUACCT_H_
-#define _CPUACCT_H_
-
-#include <linux/cgroup.h>
-
-#ifdef CONFIG_CGROUP_CPUACCT
-
-/*
- * Platform specific CPU frequency hooks for cpuacct. These functions are
- * called from the scheduler.
- */
-struct cpuacct_charge_calls {
-	/*
-	 * Platforms can take advantage of this data and use
-	 * per-cpu allocations if necessary.
-	 */
-	void (*init) (void **cpuacct_data);
-	void (*charge) (void *cpuacct_data,  u64 cputime, unsigned int cpu);
-	void (*cpufreq_show) (void *cpuacct_data, struct cgroup_map_cb *cb);
-	/* Returns power consumed in milliWatt seconds */
-	u64 (*power_usage) (void *cpuacct_data);
-};
-
-int cpuacct_charge_register(struct cpuacct_charge_calls *fn);
-
-#endif /* CONFIG_CGROUP_CPUACCT */
-
-#endif // _CPUACCT_H_
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 7a5ab0d..d208f1e 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -43,6 +43,10 @@
 #define DIAG_IOCTL_DCI_REG		23
 #define DIAG_IOCTL_DCI_STREAM_INIT	24
 #define DIAG_IOCTL_DCI_HEALTH_STATS	25
+#define DIAG_IOCTL_DCI_LOG_STATUS	26
+#define DIAG_IOCTL_DCI_EVENT_STATUS	27
+#define DIAG_IOCTL_DCI_CLEAR_LOGS	28
+#define DIAG_IOCTL_DCI_CLEAR_EVENTS	29
 #define DIAG_IOCTL_REMOTE_DEV		32
 
 /* PC Tools IDs */
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index 14cb148..4fa41b5 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -39,7 +39,8 @@
 	uint8_t		dev_num;
 	uint8_t		chan_num;
 	uint32_t	timestamp_resp_value;
-	uint32_t	reading_value;
+	int16_t		reading_raw;
+	int32_t		reading_value;
 };
 
 struct epm_psoc_get_buffered_data {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 03fc44b..093f0b8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -17,8 +17,8 @@
  * nr_file rlimit, so it's safe to set up a ridiculously high absolute
  * upper limit on files-per-process.
  *
- * Some programs (notably those using select()) may have to be
- * recompiled to take full advantage of the new limits..
+ * Some programs (notably those using select()) may have to be 
+ * recompiled to take full advantage of the new limits..  
  */
 
 /* Fixed constants first: */
@@ -178,7 +178,7 @@
 #define SEL_EX		4
 
 /* public flags for file_system_type */
-#define FS_REQUIRES_DEV 1
+#define FS_REQUIRES_DEV 1 
 #define FS_BINARY_MOUNTDATA 2
 #define FS_HAS_SUBTYPE 4
 #define FS_REVAL_DOT	16384	/* Check the paths ".", ".." for staleness */
@@ -490,7 +490,7 @@
  */
 #include <linux/quota.h>
 
-/**
+/** 
  * enum positive_aop_returns - aop return codes with specific semantics
  *
  * @AOP_WRITEPAGE_ACTIVATE: Informs the caller that page writeback has
@@ -500,7 +500,7 @@
  * 			    be a candidate for writeback again in the near
  * 			    future.  Other callers must be careful to unlock
  * 			    the page if they get this return.  Returned by
- * 			    writepage();
+ * 			    writepage(); 
  *
  * @AOP_TRUNCATED_PAGE: The AOP method that was handed a locked page has
  *  			unlocked it and the page might have been truncated.
@@ -1078,10 +1078,10 @@
 
 #define	MAX_NON_LFS	((1UL<<31) - 1)
 
-/* Page cache limit. The filesystems should put that into their s_maxbytes
-   limits, otherwise bad things can happen in VM. */
+/* Page cache limit. The filesystems should put that into their s_maxbytes 
+   limits, otherwise bad things can happen in VM. */ 
 #if BITS_PER_LONG==32
-#define MAX_LFS_FILESIZE	(((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
+#define MAX_LFS_FILESIZE	(((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) 
 #elif BITS_PER_LONG==64
 #define MAX_LFS_FILESIZE 	0x7fffffffffffffffUL
 #endif
@@ -2282,7 +2282,7 @@
 
 extern int kernel_read(struct file *, loff_t, char *, unsigned long);
 extern struct file * open_exec(const char *);
-
+ 
 /* fs/dcache.c -- generic fs support functions */
 extern int is_subdir(struct dentry *, struct dentry *);
 extern int path_is_under(struct path *, struct path *);
diff --git a/include/linux/ion.h b/include/linux/ion.h
index f159fe2..fb1c5f6 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -74,7 +74,6 @@
    be converted to phys_addr_t.  For the time being many kernel interfaces
    do not accept phys_addr_t's that would have to */
 #define ion_phys_addr_t unsigned long
-#define ion_virt_addr_t unsigned long
 
 /**
  * struct ion_platform_heap - defines a heap in the given platform
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 37b1fdc..fb0c7af 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -710,7 +710,4 @@
 
 #endif /* __KERNEL__ */
 
-/* To identify board information in panic logs, set this */
-extern char *mach_panic_string;
-
 #endif
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index fc7d1a4..4473d69 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -243,10 +243,6 @@
 extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,
 					  unsigned long pnum);
 
-extern void reserve_hotplug_pages(unsigned long start_pfn,
-				unsigned long nr_pages);
-extern void unreserve_hotplug_pages(unsigned long start_pfn,
-				unsigned long nr_pages);
 #endif /* __LINUX_MEMORY_HOTPLUG_H */
 extern int physical_remove_memory(u64 start, u64 size);
 extern int arch_physical_remove_memory(u64 start, u64 size);
diff --git a/include/linux/mfd/wcd9xxx/wcd9306_registers.h b/include/linux/mfd/wcd9xxx/wcd9306_registers.h
index 1254fac..564e5b3 100644
--- a/include/linux/mfd/wcd9xxx/wcd9306_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9306_registers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,20 +15,20 @@
 
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 
-#define TAPAN_A_CHIP_CTL				WCD9XXX_A_CHIP_CTL
-#define TAPAN_A_CHIP_CTL__POR			WCD9XXX_A_CHIP_CTL__POR
-#define TAPAN_A_CHIP_STATUS				WCD9XXX_A_CHIP_STATUS
-#define TAPAN_A_CHIP_STATUS__POR		WCD9XXX_A_CHIP_STATUS__POR
-#define TAPAN_A_CHIP_ID_BYTE_0			WCD9XXX_A_CHIP_ID_BYTE_0
-#define TAPAN_A_CHIP_ID_BYTE_0__POR		WCD9XXX_A_CHIP_ID_BYTE_0__POR
-#define TAPAN_A_CHIP_ID_BYTE_1			WCD9XXX_A_CHIP_ID_BYTE_1
-#define TAPAN_A_CHIP_ID_BYTE_1__POR		WCD9XXX_A_CHIP_ID_BYTE_1__POR
-#define TAPAN_A_CHIP_ID_BYTE_2			WCD9XXX_A_CHIP_ID_BYTE_2
-#define TAPAN_A_CHIP_ID_BYTE_2__POR		WCD9XXX_A_CHIP_ID_BYTE_2__POR
-#define TAPAN_A_CHIP_ID_BYTE_3			WCD9XXX_A_CHIP_ID_BYTE_3
-#define TAPAN_A_CHIP_ID_BYTE_3__POR		WCD9XXX_A_CHIP_ID_BYTE_3__POR
-#define TAPAN_A_CHIP_VERSION			WCD9XXX_A_CHIP_VERSION
-#define TAPAN_A_CHIP_VERSION__POR		WCD9XXX_A_CHIP_VERSION__POR
+#define TAPAN_A_CHIP_CTL			(0x000)
+#define TAPAN_A_CHIP_CTL__POR				(0x00)
+#define TAPAN_A_CHIP_STATUS			(0x001)
+#define TAPAN_A_CHIP_STATUS__POR				(0x00)
+#define TAPAN_A_CHIP_ID_BYTE_0			(0x004)
+#define TAPAN_A_CHIP_ID_BYTE_0__POR				(0x00)
+#define TAPAN_A_CHIP_ID_BYTE_1			(0x005)
+#define TAPAN_A_CHIP_ID_BYTE_1__POR				(0x00)
+#define TAPAN_A_CHIP_ID_BYTE_2			(0x006)
+#define TAPAN_A_CHIP_ID_BYTE_2__POR				(0x03)
+#define TAPAN_A_CHIP_ID_BYTE_3			(0x007)
+#define TAPAN_A_CHIP_ID_BYTE_3__POR				(0x01)
+#define TAPAN_A_CHIP_VERSION			(0x008)
+#define TAPAN_A_CHIP_VERSION__POR				(0x20)
 #define TAPAN_A_CHIP_DEBUG_CTL			(0x009)
 #define TAPAN_A_CHIP_DEBUG_CTL__POR				(0x00)
 #define TAPAN_A_SLAVE_ID_1			(0x00C)
@@ -566,21 +566,21 @@
 #define TAPAN_A_CDC_TX4_VOL_CTL_CFG			(0x23A)
 #define TAPAN_A_CDC_TX4_VOL_CTL_CFG__POR				(0x00)
 #define TAPAN_A_CDC_TX1_MUX_CTL			(0x223)
-#define TAPAN_A_CDC_TX1_MUX_CTL__POR				(0x00)
+#define TAPAN_A_CDC_TX1_MUX_CTL__POR				(0x08)
 #define TAPAN_A_CDC_TX2_MUX_CTL			(0x22B)
-#define TAPAN_A_CDC_TX2_MUX_CTL__POR				(0x00)
+#define TAPAN_A_CDC_TX2_MUX_CTL__POR				(0x08)
 #define TAPAN_A_CDC_TX3_MUX_CTL			(0x233)
-#define TAPAN_A_CDC_TX3_MUX_CTL__POR				(0x00)
+#define TAPAN_A_CDC_TX3_MUX_CTL__POR				(0x08)
 #define TAPAN_A_CDC_TX4_MUX_CTL			(0x23B)
-#define TAPAN_A_CDC_TX4_MUX_CTL__POR				(0x00)
+#define TAPAN_A_CDC_TX4_MUX_CTL__POR				(0x08)
 #define TAPAN_A_CDC_TX1_CLK_FS_CTL			(0x224)
-#define TAPAN_A_CDC_TX1_CLK_FS_CTL__POR				(0x00)
+#define TAPAN_A_CDC_TX1_CLK_FS_CTL__POR				(0x03)
 #define TAPAN_A_CDC_TX2_CLK_FS_CTL			(0x22C)
-#define TAPAN_A_CDC_TX2_CLK_FS_CTL__POR				(0x00)
+#define TAPAN_A_CDC_TX2_CLK_FS_CTL__POR				(0x03)
 #define TAPAN_A_CDC_TX3_CLK_FS_CTL			(0x234)
-#define TAPAN_A_CDC_TX3_CLK_FS_CTL__POR				(0x00)
+#define TAPAN_A_CDC_TX3_CLK_FS_CTL__POR				(0x03)
 #define TAPAN_A_CDC_TX4_CLK_FS_CTL			(0x23C)
-#define TAPAN_A_CDC_TX4_CLK_FS_CTL__POR				(0x00)
+#define TAPAN_A_CDC_TX4_CLK_FS_CTL__POR				(0x03)
 #define TAPAN_A_CDC_TX1_DMIC_CTL			(0x225)
 #define TAPAN_A_CDC_TX1_DMIC_CTL__POR				(0x00)
 #define TAPAN_A_CDC_TX2_DMIC_CTL			(0x22D)
@@ -608,9 +608,9 @@
 #define TAPAN_A_CDC_SRC2_PDA_CFG			(0x2A8)
 #define TAPAN_A_CDC_SRC2_PDA_CFG__POR				(0x00)
 #define TAPAN_A_CDC_SRC1_FS_CTL			(0x2A1)
-#define TAPAN_A_CDC_SRC1_FS_CTL__POR				(0x00)
+#define TAPAN_A_CDC_SRC1_FS_CTL__POR				(0x1B)
 #define TAPAN_A_CDC_SRC2_FS_CTL			(0x2A9)
-#define TAPAN_A_CDC_SRC2_FS_CTL__POR				(0x00)
+#define TAPAN_A_CDC_SRC2_FS_CTL__POR				(0x1B)
 #define TAPAN_A_CDC_RX1_B1_CTL			(0x2B0)
 #define TAPAN_A_CDC_RX1_B1_CTL__POR				(0x00)
 #define TAPAN_A_CDC_RX2_B1_CTL			(0x2B8)
@@ -644,21 +644,21 @@
 #define TAPAN_A_CDC_RX4_B4_CTL			(0x2CB)
 #define TAPAN_A_CDC_RX4_B4_CTL__POR				(0x00)
 #define TAPAN_A_CDC_RX1_B5_CTL			(0x2B4)
-#define TAPAN_A_CDC_RX1_B5_CTL__POR				(0x00)
+#define TAPAN_A_CDC_RX1_B5_CTL__POR				(0x78)
 #define TAPAN_A_CDC_RX2_B5_CTL			(0x2BC)
-#define TAPAN_A_CDC_RX2_B5_CTL__POR				(0x00)
+#define TAPAN_A_CDC_RX2_B5_CTL__POR				(0x78)
 #define TAPAN_A_CDC_RX3_B5_CTL			(0x2C4)
-#define TAPAN_A_CDC_RX3_B5_CTL__POR				(0x00)
+#define TAPAN_A_CDC_RX3_B5_CTL__POR				(0x78)
 #define TAPAN_A_CDC_RX4_B5_CTL			(0x2CC)
-#define TAPAN_A_CDC_RX4_B5_CTL__POR				(0x00)
+#define TAPAN_A_CDC_RX4_B5_CTL__POR				(0x78)
 #define TAPAN_A_CDC_RX1_B6_CTL			(0x2B5)
-#define TAPAN_A_CDC_RX1_B6_CTL__POR				(0x00)
+#define TAPAN_A_CDC_RX1_B6_CTL__POR				(0x80)
 #define TAPAN_A_CDC_RX2_B6_CTL			(0x2BD)
-#define TAPAN_A_CDC_RX2_B6_CTL__POR				(0x00)
+#define TAPAN_A_CDC_RX2_B6_CTL__POR				(0x80)
 #define TAPAN_A_CDC_RX3_B6_CTL			(0x2C5)
-#define TAPAN_A_CDC_RX3_B6_CTL__POR				(0x00)
+#define TAPAN_A_CDC_RX3_B6_CTL__POR				(0x80)
 #define TAPAN_A_CDC_RX4_B6_CTL			(0x2CD)
-#define TAPAN_A_CDC_RX4_B6_CTL__POR				(0x00)
+#define TAPAN_A_CDC_RX4_B6_CTL__POR				(0x80)
 #define TAPAN_A_CDC_RX1_VOL_CTL_B1_CTL			(0x2B6)
 #define TAPAN_A_CDC_RX1_VOL_CTL_B1_CTL__POR				(0x00)
 #define TAPAN_A_CDC_RX2_VOL_CTL_B1_CTL			(0x2BE)
@@ -784,9 +784,9 @@
 #define TAPAN_A_CDC_IIR2_GAIN_B8_CTL			(0x357)
 #define TAPAN_A_CDC_IIR2_GAIN_B8_CTL__POR				(0x00)
 #define TAPAN_A_CDC_IIR1_CTL			(0x348)
-#define TAPAN_A_CDC_IIR1_CTL__POR				(0x00)
+#define TAPAN_A_CDC_IIR1_CTL__POR				(0x40)
 #define TAPAN_A_CDC_IIR2_CTL			(0x358)
-#define TAPAN_A_CDC_IIR2_CTL__POR				(0x00)
+#define TAPAN_A_CDC_IIR2_CTL__POR				(0x40)
 #define TAPAN_A_CDC_IIR1_GAIN_TIMER_CTL			(0x349)
 #define TAPAN_A_CDC_IIR1_GAIN_TIMER_CTL__POR				(0x00)
 #define TAPAN_A_CDC_IIR2_GAIN_TIMER_CTL			(0x359)
@@ -802,35 +802,35 @@
 #define TAPAN_A_CDC_TOP_GAIN_UPDATE			(0x360)
 #define TAPAN_A_CDC_TOP_GAIN_UPDATE__POR				(0x00)
 #define TAPAN_A_CDC_COMP0_B1_CTL			(0x368)
-#define TAPAN_A_CDC_COMP0_B1_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP0_B1_CTL__POR				(0x30)
 #define TAPAN_A_CDC_COMP1_B1_CTL			(0x370)
-#define TAPAN_A_CDC_COMP1_B1_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP1_B1_CTL__POR				(0x30)
 #define TAPAN_A_CDC_COMP2_B1_CTL			(0x378)
-#define TAPAN_A_CDC_COMP2_B1_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP2_B1_CTL__POR				(0x30)
 #define TAPAN_A_CDC_COMP0_B2_CTL			(0x369)
-#define TAPAN_A_CDC_COMP0_B2_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP0_B2_CTL__POR				(0xB5)
 #define TAPAN_A_CDC_COMP1_B2_CTL			(0x371)
-#define TAPAN_A_CDC_COMP1_B2_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP1_B2_CTL__POR				(0xB5)
 #define TAPAN_A_CDC_COMP2_B2_CTL			(0x379)
-#define TAPAN_A_CDC_COMP2_B2_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP2_B2_CTL__POR				(0xB5)
 #define TAPAN_A_CDC_COMP0_B3_CTL			(0x36A)
-#define TAPAN_A_CDC_COMP0_B3_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP0_B3_CTL__POR				(0x28)
 #define TAPAN_A_CDC_COMP1_B3_CTL			(0x372)
-#define TAPAN_A_CDC_COMP1_B3_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP1_B3_CTL__POR				(0x28)
 #define TAPAN_A_CDC_COMP2_B3_CTL			(0x37A)
-#define TAPAN_A_CDC_COMP2_B3_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP2_B3_CTL__POR				(0x28)
 #define TAPAN_A_CDC_COMP0_B4_CTL			(0x36B)
-#define TAPAN_A_CDC_COMP0_B4_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP0_B4_CTL__POR				(0x37)
 #define TAPAN_A_CDC_COMP1_B4_CTL			(0x373)
-#define TAPAN_A_CDC_COMP1_B4_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP1_B4_CTL__POR				(0x37)
 #define TAPAN_A_CDC_COMP2_B4_CTL			(0x37B)
-#define TAPAN_A_CDC_COMP2_B4_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP2_B4_CTL__POR				(0x37)
 #define TAPAN_A_CDC_COMP0_B5_CTL			(0x36C)
-#define TAPAN_A_CDC_COMP0_B5_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP0_B5_CTL__POR				(0x7F)
 #define TAPAN_A_CDC_COMP1_B5_CTL			(0x374)
-#define TAPAN_A_CDC_COMP1_B5_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP1_B5_CTL__POR				(0x7F)
 #define TAPAN_A_CDC_COMP2_B5_CTL			(0x37C)
-#define TAPAN_A_CDC_COMP2_B5_CTL__POR				(0x00)
+#define TAPAN_A_CDC_COMP2_B5_CTL__POR				(0x7F)
 #define TAPAN_A_CDC_COMP0_B6_CTL			(0x36D)
 #define TAPAN_A_CDC_COMP0_B6_CTL__POR				(0x00)
 #define TAPAN_A_CDC_COMP1_B6_CTL			(0x375)
@@ -838,17 +838,17 @@
 #define TAPAN_A_CDC_COMP2_B6_CTL			(0x37D)
 #define TAPAN_A_CDC_COMP2_B6_CTL__POR				(0x00)
 #define TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS			(0x36E)
-#define TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS__POR				(0x00)
+#define TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS__POR				(0x03)
 #define TAPAN_A_CDC_COMP1_SHUT_DOWN_STATUS			(0x376)
-#define TAPAN_A_CDC_COMP1_SHUT_DOWN_STATUS__POR				(0x00)
+#define TAPAN_A_CDC_COMP1_SHUT_DOWN_STATUS__POR				(0x03)
 #define TAPAN_A_CDC_COMP2_SHUT_DOWN_STATUS			(0x37E)
-#define TAPAN_A_CDC_COMP2_SHUT_DOWN_STATUS__POR				(0x00)
+#define TAPAN_A_CDC_COMP2_SHUT_DOWN_STATUS__POR				(0x03)
 #define TAPAN_A_CDC_COMP0_FS_CFG			(0x36F)
-#define TAPAN_A_CDC_COMP0_FS_CFG__POR				(0x00)
+#define TAPAN_A_CDC_COMP0_FS_CFG__POR				(0x03)
 #define TAPAN_A_CDC_COMP1_FS_CFG			(0x377)
-#define TAPAN_A_CDC_COMP1_FS_CFG__POR				(0x00)
+#define TAPAN_A_CDC_COMP1_FS_CFG__POR				(0x03)
 #define TAPAN_A_CDC_COMP2_FS_CFG			(0x37F)
-#define TAPAN_A_CDC_COMP2_FS_CFG__POR				(0x00)
+#define TAPAN_A_CDC_COMP2_FS_CFG__POR				(0x03)
 #define TAPAN_A_CDC_CONN_RX1_B1_CTL			(0x380)
 #define TAPAN_A_CDC_CONN_RX1_B1_CTL__POR				(0x00)
 #define TAPAN_A_CDC_CONN_RX1_B2_CTL			(0x381)
@@ -992,12 +992,18 @@
 #define TAPAN_A_CDC_MBHC_SPARE			(0x3DF)
 #define TAPAN_A_CDC_MBHC_SPARE__POR				(0x00)
 
-
 /* SLIMBUS Slave Registers */
-#define TAPAN_SLIM_PGD_PORT_INT_EN0 (0x30)
-#define TAPAN_SLIM_PGD_PORT_INT_STATUS0 (0x34)
-#define TAPAN_SLIM_PGD_PORT_INT_CLR0 (0x38)
-#define TAPAN_SLIM_PGD_PORT_INT_SOURCE0 (0x60)
+#define TAPAN_SLIM_PGD_PORT_INT_EN0                     (0x30)
+#define TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_0             (0x34)
+#define TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_1             (0x35)
+#define TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_0             (0x36)
+#define TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_1             (0x37)
+#define TAPAN_SLIM_PGD_PORT_INT_CLR_RX_0                (0x38)
+#define TAPAN_SLIM_PGD_PORT_INT_CLR_RX_1                (0x39)
+#define TAPAN_SLIM_PGD_PORT_INT_CLR_TX_0                (0x3A)
+#define TAPAN_SLIM_PGD_PORT_INT_CLR_TX_1                (0x3B)
+#define TAPAN_SLIM_PGD_PORT_INT_RX_SOURCE0		(0x60)
+#define TAPAN_SLIM_PGD_PORT_INT_TX_SOURCE0		(0x70)
 
 /* Macros for Packing Register Writes into a U32 */
 #define TAPAN_PACKED_REG_SIZE sizeof(u32)
diff --git a/include/linux/mhl_defs.h b/include/linux/mhl_defs.h
index f9d1ce4..aa63e03 100644
--- a/include/linux/mhl_defs.h
+++ b/include/linux/mhl_defs.h
@@ -57,7 +57,7 @@
 /* bits 4..7 */
 #define	MHL_VER_MAJOR           (0x01 << 4)
 /* bits 0..3 */
-#define	MHL_VER_MINOR		0x01
+#define	MHL_VER_MINOR		0x02
 #define MHL_VERSION		(MHL_VER_MAJOR | MHL_VER_MINOR)
 
 /*Device Category*/
diff --git a/include/linux/mhl_devcap.h b/include/linux/mhl_devcap.h
index 40a87fe..37a0dc5 100644
--- a/include/linux/mhl_devcap.h
+++ b/include/linux/mhl_devcap.h
@@ -16,26 +16,23 @@
 #define SILICON_IMAGE_ADOPTER_ID 322
 #define TRANSCODER_DEVICE_ID 0x8334
 
-#define MHL_DEV_LD_AUDIO (0x01 << 2)
-#define MHL_DEV_LD_VIDEO (0x01 << 1)
-#define MHL_DEV_LD_MEDIA (0x01 << 3)
 #define MHL_DEV_LD_GUI (0x01 << 7)
-#define	MHL_LOGICAL_DEVICE_MAP		(MHL_DEV_LD_AUDIO |\
-	MHL_DEV_LD_VIDEO | MHL_DEV_LD_MEDIA | MHL_DEV_LD_GUI)
+#define	MHL_LOGICAL_DEVICE_MAP		MHL_DEV_LD_GUI
 
 #define DEVCAP_VAL_DEV_STATE       0
 #define DEVCAP_VAL_MHL_VERSION     MHL_VERSION
-#define DEVCAP_VAL_DEV_CAT         (MHL_DEV_CAT_SOURCE |\
-	MHL_DEV_CATEGORY_POW_BIT)
+#define DEVCAP_VAL_DEV_CAT         MHL_DEV_CAT_SOURCE
+
 #define DEVCAP_VAL_ADOPTER_ID_H    (uint8_t)(SILICON_IMAGE_ADOPTER_ID >>   8)
 #define DEVCAP_VAL_ADOPTER_ID_L    (uint8_t)(SILICON_IMAGE_ADOPTER_ID & 0xFF)
-#define DEVCAP_VAL_VID_LINK_MODE   MHL_DEV_VID_LINK_SUPPRGB444
+#define DEVCAP_VAL_VID_LINK_MODE   (MHL_DEV_VID_LINK_SUPPRGB444 |\
+						MHL_DEV_VID_LINK_SUPP_ISLANDS)
 #define DEVCAP_VAL_AUD_LINK_MODE   MHL_DEV_AUD_LINK_2CH
 #define DEVCAP_VAL_VIDEO_TYPE      0
 #define DEVCAP_VAL_LOG_DEV_MAP     MHL_LOGICAL_DEVICE_MAP
 #define DEVCAP_VAL_BANDWIDTH       0
 #define DEVCAP_VAL_FEATURE_FLAG    (MHL_FEATURE_RCP_SUPPORT |\
-	MHL_FEATURE_RAP_SUPPORT | MHL_FEATURE_SP_SUPPORT)
+			MHL_FEATURE_RAP_SUPPORT | MHL_FEATURE_SP_SUPPORT)
 #define DEVCAP_VAL_DEVICE_ID_H     (uint8_t)(TRANSCODER_DEVICE_ID >>   8)
 #define DEVCAP_VAL_DEVICE_ID_L     (uint8_t)(TRANSCODER_DEVICE_ID & 0xFF)
 #define DEVCAP_VAL_SCRATCHPAD_SIZE MHL_SCRATCHPAD_SIZE
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index e4aab43..9a4e61d 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -385,6 +385,9 @@
 	struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
 
 	struct mmc_bkops_info	bkops_info;
+
+	struct device_attribute rpm_attrib;
+	unsigned int		idle_timeout;
 };
 
 /*
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 5f1e2d9..995f8a2 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -198,14 +198,13 @@
 extern void mmc_release_host(struct mmc_host *host);
 extern int mmc_try_claim_host(struct mmc_host *host);
 extern void mmc_set_ios(struct mmc_host *host);
-extern int mmc_detect_card_removed(struct mmc_host *host);
-extern int mmc_flush_cache(struct mmc_card *);
-
 extern int mmc_flush_cache(struct mmc_card *);
 
 extern int mmc_detect_card_removed(struct mmc_host *host);
 
 extern void mmc_blk_init_bkops_statistics(struct mmc_card *card);
+extern void mmc_rpm_hold(struct mmc_host *host, struct device *dev);
+extern void mmc_rpm_release(struct mmc_host *host, struct device *dev);
 
 /**
  *	mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2bfd9a2..05271ba 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -60,8 +60,6 @@
 #define MMC_TIMING_UHS_DDR50	5
 #define MMC_TIMING_MMC_HS200	6
 
-	unsigned char	ddr;			/* dual data rate used */
-
 #define MMC_SDR_MODE		0
 #define MMC_1_2V_DDR_MODE	1
 #define MMC_1_8V_DDR_MODE	2
@@ -283,6 +281,8 @@
 #define MMC_CAP2_INIT_BKOPS	    (1 << 16)	/* Need to set BKOPS_EN */
 #define MMC_CAP2_CLK_SCALE	(1 << 17)	/* Allow dynamic clk scaling */
 #define MMC_CAP2_STOP_REQUEST	(1 << 18)	/* Allow stop ongoing request */
+/* Use runtime PM framework provided by MMC core */
+#define MMC_CAP2_CORE_RUNTIME_PM (1 << 19)
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
 	int			clk_requests;	/* internal reference counter */
@@ -386,7 +386,6 @@
 	} perf;
 	bool perf_enable;
 #endif
-
 	struct mmc_ios saved_ios;
 	struct {
 		unsigned long	busy_time_us;
@@ -483,9 +482,6 @@
 int mmc_card_sleep(struct mmc_host *host);
 int mmc_card_can_sleep(struct mmc_host *host);
 
-int mmc_host_enable(struct mmc_host *host);
-int mmc_host_disable(struct mmc_host *host);
-int mmc_host_lazy_disable(struct mmc_host *host);
 int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
 
 /* Module parameter */
@@ -543,4 +539,10 @@
 	return host->ios.clock;
 }
 #endif
+
+static inline int mmc_use_core_runtime_pm(struct mmc_host *host)
+{
+	return host->caps2 & MMC_CAP2_CORE_RUNTIME_PM;
+}
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 7f316a9..de145d6 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -348,7 +348,6 @@
 
 #define EXT_CSD_PART_CONFIG_ACC_MASK	(0x7)
 #define EXT_CSD_PART_CONFIG_ACC_BOOT0	(0x1)
-#define EXT_CSD_PART_CONFIG_ACC_BOOT1	(0x2)
 #define EXT_CSD_PART_CONFIG_ACC_RPMB	(0x3)
 #define EXT_CSD_PART_CONFIG_ACC_GP0	(0x4)
 
@@ -390,14 +389,6 @@
 #define EXT_CSD_POWER_OFF_SHORT		2
 #define EXT_CSD_POWER_OFF_LONG		3
 
-#define EXT_CSD_RST_N_EN_MASK	0x3
-#define EXT_CSD_RST_N_ENABLED	1	/* RST_n is enabled on card */
-
-#define EXT_CSD_NO_POWER_NOTIFICATION	0
-#define EXT_CSD_POWER_ON		1
-#define EXT_CSD_POWER_OFF_SHORT		2
-#define EXT_CSD_POWER_OFF_LONG		3
-
 #define EXT_CSD_PWR_CL_8BIT_MASK	0xF0	/* 8 bit PWR CLS */
 #define EXT_CSD_PWR_CL_4BIT_MASK	0x0F	/* 8 bit PWR CLS */
 #define EXT_CSD_PWR_CL_8BIT_SHIFT	4
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index bd24575..f26b903 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -18,6 +18,11 @@
 #include <linux/mmc/host.h>
 #include <linux/pm_qos.h>
 
+struct sdhci_next {
+	unsigned int sg_count;
+	s32 cookie;
+};
+
 struct sdhci_host {
 	/* Data set by hardware interface driver */
 	const char *hw_name;	/* Hardware bus name */
@@ -191,6 +196,8 @@
 	unsigned int cpu_dma_latency_us;
 	struct pm_qos_request pm_qos_req_dma;
 
+	struct sdhci_next next_data;
+
 	unsigned long private[0] ____cacheline_aligned;
 };
 #endif /* LINUX_MMC_SDHCI_H */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 6e12694..ca7a586 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -529,12 +529,6 @@
 	return test_bit(ZONE_OOM_LOCKED, &zone->flags);
 }
 
-#ifdef CONFIG_SMP
-unsigned long zone_nr_free_pages(struct zone *zone);
-#else
-#define zone_nr_free_pages(zone) zone_page_state(zone, NR_FREE_PAGES)
-#endif /* CONFIG_SMP */
-
 /*
  * The "priority" of VM scanning is how much of the queues we will scan in one
  * go. A value of 12 for DEF_PRIORITY implies that we will scan 1/4096th of the
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index f0c4915..646c22e 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -53,6 +53,10 @@
 			(AUDIO_MAX_COMMON_IOCTL_NUM+23), unsigned)
 #define AUDIO_SET_ASM_CUSTOM_TOPOLOGY	_IOW(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_COMMON_IOCTL_NUM+24), unsigned)
+#define AUDIO_SET_SPEAKER_PROT _IOW(AUDIO_IOCTL_MAGIC, 25, \
+		struct msm_spk_prot_cfg)
+#define AUDIO_GET_SPEAKER_PROT _IOR(AUDIO_IOCTL_MAGIC, 26, \
+		struct msm_spk_prot_status)
 
 #define	AUDIO_MAX_ACDB_IOCTL	(AUDIO_MAX_COMMON_IOCTL_NUM+30)
 
@@ -67,6 +71,19 @@
 	uint16_t	gain;
 };
 
+struct msm_spk_prot_cfg {
+	int r0;
+	int t0;
+	uint32_t mode; /*0 - Start spk prot
+	1 - Start calib
+	2 - Disable spk prot*/
+};
+
+struct msm_spk_prot_status {
+	int r0;
+	int status;
+};
+
 /* For Real-Time Audio Calibration */
 #define AUDIO_GET_RTAC_ADM_INFO		_IOR(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_ACDB_IOCTL+1), unsigned)
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index ff22e12..a683ed4 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -163,7 +163,7 @@
 	enum ion_fixed_position fixed_position;
 	int iommu_map_all;
 	int iommu_2x_map_domain;
-	ion_virt_addr_t *virt_addr;
+	void *virt_addr;
 	int (*request_region)(void *);
 	int (*release_region)(void *);
 	void *(*setup_region)(void);
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 45bc0ea..6a2c95d 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -70,11 +70,11 @@
 #define MSMFB_MDP_PP _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp)
 #define MSMFB_OVERLAY_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int)
 #define MSMFB_VSYNC_CTRL  _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int)
-#define MSMFB_METADATA_SET  _IOW(MSMFB_IOCTL_MAGIC, 162, struct msmfb_metadata)
+#define MSMFB_BUFFER_SYNC  _IOW(MSMFB_IOCTL_MAGIC, 162, struct mdp_buf_sync)
 #define MSMFB_OVERLAY_COMMIT      _IO(MSMFB_IOCTL_MAGIC, 163)
-#define MSMFB_BUFFER_SYNC  _IOW(MSMFB_IOCTL_MAGIC, 164, struct mdp_buf_sync)
-#define MSMFB_DISPLAY_COMMIT      _IOW(MSMFB_IOCTL_MAGIC, 165, \
+#define MSMFB_DISPLAY_COMMIT      _IOW(MSMFB_IOCTL_MAGIC, 164, \
 						struct mdp_display_commit)
+#define MSMFB_METADATA_SET  _IOW(MSMFB_IOCTL_MAGIC, 165, struct msmfb_metadata)
 #define MSMFB_METADATA_GET  _IOW(MSMFB_IOCTL_MAGIC, 166, struct msmfb_metadata)
 
 #define FB_TYPE_3D_PANEL 0x10101010
@@ -595,6 +595,7 @@
 	metadata_op_frame_rate,
 	metadata_op_vic,
 	metadata_op_wb_format,
+	metadata_op_get_caps,
 	metadata_op_max
 };
 
@@ -607,6 +608,13 @@
 	uint32_t alpha;
 };
 
+struct mdss_hw_caps {
+	uint32_t mdp_rev;
+	uint8_t rgb_pipes;
+	uint8_t vig_pipes;
+	uint8_t dma_pipes;
+};
+
 struct msmfb_metadata {
 	uint32_t op;
 	uint32_t flags;
@@ -615,6 +623,7 @@
 		struct mdp_mixer_cfg mixer_cfg;
 		uint32_t panel_frame_rate;
 		uint32_t video_info_code;
+		struct mdss_hw_caps caps;
 	} data;
 };
 
@@ -629,11 +638,19 @@
 };
 
 #define MDP_DISPLAY_COMMIT_OVERLAY	1
+struct mdp_buf_fence {
+	uint32_t flags;
+	uint32_t acq_fen_fd_cnt;
+	int acq_fen_fd[MDP_MAX_FENCE_FD];
+	int rel_fen_fd[MDP_MAX_FENCE_FD];
+};
+
 
 struct mdp_display_commit {
 	uint32_t flags;
 	uint32_t wait_for_finish;
 	struct fb_var_screeninfo var;
+	struct mdp_buf_fence buf_fence;
 };
 
 struct mdp_page_protection {
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 6e4b7a6..ce5ddf3 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1135,55 +1135,6 @@
  *	%NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
  *	(Re)Association Response frames when the driver (or firmware) replies to
  *	(Re)Association Request frames.
- * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
- *      of the station, see &enum nl80211_sta_wme_attr.
- * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
- *      as AP.
- *
- * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
- *      roaming to another AP in the same ESS if the signal lever is low.
- *
- * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
- *      candidate information, see &enum nl80211_pmksa_candidate_attr.
- *
- * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
- *      for management frames transmission. In order to avoid p2p probe/action
- *      frames are being transmitted at CCK rate in 2GHz band, the user space
- *      applications use this attribute.
- *      This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
- *      %NL80211_CMD_FRAME commands.
- *
- * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
- *      request, link setup confirm, link teardown, etc.). Values are
- *      described in the TDLS (802.11z) specification.
- * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
- *      TDLS conversation between two devices.
- * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
- *      &enum nl80211_tdls_operation, represented as a u8.
- * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
- *      as a TDLS peer sta.
- * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
- *      procedures should be performed by sending TDLS packets via
- *      %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
- *      used for asking the driver to perform a TDLS operation.
- *
- * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
- *      that have AP support to indicate that they have the AP SME integrated
- *      with support for the features listed in this attribute, see
- *      &enum nl80211_ap_sme_features.
- *
- * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
- *      the driver to not wait for an acknowledgement. Note that due to this,
- *      it will also not give a status callback nor return a cookie. This is
- *      mostly useful for probe responses to save airtime.
- *
- * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
- *      &enum nl80211_feature_flags and is advertised in wiphy information.
- * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
- *
- *      requests while operating in AP-mode.
- *      This attribute holds a bitmap of the supported protocols for
- *      offloading (see &enum nl80211_probe_resp_offload_support_attr).
  *
  * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
  *	of the station, see &enum nl80211_sta_wme_attr.
diff --git a/include/linux/platform_data/ram_console.h b/include/linux/platform_data/ram_console.h
deleted file mode 100644
index 9f1125c..0000000
--- a/include/linux/platform_data/ram_console.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
-#define _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
-
-struct ram_console_platform_data {
-	const char *bootinfo;
-};
-
-#endif /* _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ */
diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
index 5285317..569781f 100644
--- a/include/linux/pm_wakeup.h
+++ b/include/linux/pm_wakeup.h
@@ -34,6 +34,7 @@
  * @total_time: Total time this wakeup source has been active.
  * @max_time: Maximum time this wakeup source has been continuously active.
  * @last_time: Monotonic clock when the wakeup source's was touched last time.
+ * @prevent_sleep_time: Total time this source has been preventing autosleep.
  * @event_count: Number of signaled wakeup events.
  * @active_count: Number of times the wakeup sorce was activated.
  * @relax_count: Number of times the wakeup sorce was deactivated.
@@ -51,12 +52,15 @@
 	ktime_t total_time;
 	ktime_t max_time;
 	ktime_t last_time;
+	ktime_t start_prevent_time;
+	ktime_t prevent_sleep_time;
 	unsigned long		event_count;
 	unsigned long		active_count;
 	unsigned long		relax_count;
 	unsigned long		expire_count;
 	unsigned long		wakeup_count;
 	bool			active:1;
+	bool			autosleep_enabled:1;
 };
 
 #ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index b784531..2683fd7 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -27,22 +27,6 @@
 #ifdef CONFIG_ARCH_MSM8974
 int __init krait_power_init(void);
 void secondary_cpu_hs_init(void *base_ptr);
-
-/**
- * krait_power_mdd_enable - function to turn on/off MDD. Turning off MDD
- *				turns off badngap reference for LDO. If
- *				a core is running on a LDO, requests to
- *				turn off MDD will not be honoured
- * @on:	boolean to indicate whether to turn MDD on/off
- *
- * CONTEXT: Can be called in interrupt context, only when the core
- *		is about to go to idle, this guarantees that there are no
- *		frequency changes on that cpu happening. Note if going from off
- *		to on mode there will be settling delays
- *
- * RETURNS: -EINVAL if MDD cannot be turned off
- */
-int krait_power_mdd_enable(int cpu_num, bool on);
 #else
 static inline int __init krait_power_init(void)
 {
@@ -50,10 +34,6 @@
 }
 
 static inline void secondary_cpu_hs_init(void *base_ptr) {}
-static inline int krait_power_mdd_enable(int cpu_num, bool on)
-{
-	return -EINVAL;
-}
 #endif
 
 #endif
diff --git a/include/linux/rq_stats.h b/include/linux/rq_stats.h
index 65d8e8f..0accf38 100644
--- a/include/linux/rq_stats.h
+++ b/include/linux/rq_stats.h
@@ -19,6 +19,7 @@
 	unsigned long rq_poll_total_jiffies;
 	unsigned long def_timer_last_jiffy;
 	unsigned int def_interval;
+	unsigned int hotplug_disabled;
 	int64_t def_start_time;
 	struct attribute_group *attr_group;
 	struct kobject *kobj;
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
index f9547f4..3b5e910 100644
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -27,8 +27,6 @@
 	struct cpu_stop_done	*done;
 };
 
-extern struct mutex stop_cpus_mutex;
-
 int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
 void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
 			 struct cpu_stop_work *work_buf);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index ac1c114..cd83059 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -356,8 +356,9 @@
 extern bool events_check_enabled;
 
 extern bool pm_wakeup_pending(void);
-extern bool pm_get_wakeup_count(unsigned int *count);
+extern bool pm_get_wakeup_count(unsigned int *count, bool block);
 extern bool pm_save_wakeup_count(unsigned int count);
+extern void pm_wakep_autosleep_enabled(bool set);
 
 static inline void lock_system_sleep(void)
 {
@@ -407,6 +408,17 @@
 
 #endif /* !CONFIG_PM_SLEEP */
 
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+void queue_up_suspend_work(void);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline void queue_up_suspend_work(void) {}
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
 #ifdef CONFIG_ARCH_SAVE_PAGE_KEYS
 /*
  * The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture
diff --git a/include/linux/usb/android_composite.h b/include/linux/usb/android_composite.h
deleted file mode 100644
index 438dfa4..0000000
--- a/include/linux/usb/android_composite.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Platform data for Android USB
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-#ifndef	__LINUX_USB_ANDROID_H
-#define	__LINUX_USB_ANDROID_H
-
-#include <linux/usb/composite.h>
-#include <linux/if_ether.h>
-
-struct android_usb_function {
-	struct list_head	list;
-	char			*name;
-	int 			(*bind_config)(struct usb_configuration *c);
-};
-
-struct android_usb_product {
-	/* Default product ID. */
-	__u16 product_id;
-
-	/* List of function names associated with this product.
-	 * This is used to compute the USB product ID dynamically
-	 * based on which functions are enabled.
-	 */
-	int num_functions;
-	char **functions;
-};
-
-struct android_usb_platform_data {
-	/* USB device descriptor fields */
-	__u16 vendor_id;
-
-	/* Default product ID. */
-	__u16 product_id;
-
-	__u16 version;
-
-	char *product_name;
-	char *manufacturer_name;
-	char *serial_number;
-
-	/* List of available USB products.
-	 * This is used to compute the USB product ID dynamically
-	 * based on which functions are enabled.
-	 * if num_products is zero or no match can be found,
-	 * we use the default product ID
-	 */
-	int num_products;
-	struct android_usb_product *products;
-
-	/* List of all supported USB functions.
-	 * This list is used to define the order in which
-	 * the functions appear in the configuration's list of USB interfaces.
-	 * This is necessary to avoid depending upon the order in which
-	 * the individual function drivers are initialized.
-	 */
-	int num_functions;
-	char **functions;
-};
-
-/* Platform data for "usb_mass_storage" driver. */
-struct usb_mass_storage_platform_data {
-	/* Contains values for the SC_INQUIRY SCSI command. */
-	char *vendor;
-	char *product;
-	int release;
-
-	char can_stall;
-	/* number of LUNS */
-	int nluns;
-};
-
-/* Platform data for USB ethernet driver. */
-struct usb_ether_platform_data {
-	u8	ethaddr[ETH_ALEN];
-	u32	vendorID;
-	const char *vendorDescr;
-};
-
-extern void android_register_function(struct android_usb_function *f);
-
-extern int android_enable_function(struct usb_function *f, int enable);
-
-
-#endif	/* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index c7c6b05..79fe16b 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/arch-msm/hsusb.h
+/* include/linux/usb/msm_hsusb.h
  *
  * Copyright (C) 2008 Google, Inc.
  * Author: Brian Swetland <swetland@google.com>
@@ -406,12 +406,16 @@
 	struct msm_bus_scale_pdata *bus_scale_table;
 	unsigned log2_irq_thresh;
 
+	/* gpio used to resume peripheral */
+	unsigned resume_gpio;
+
 	/*swfi latency is required while driving resume on to the bus */
 	u32 swfi_latency;
 
 	/*standalone latency is required when HSCI is active*/
 	u32 standalone_latency;
 	bool pool_64_bit_align;
+	bool enable_hbm;
 };
 
 struct msm_usb_host_platform_data {
@@ -431,68 +435,6 @@
 	bool core_clk_always_on_workaround;
 };
 
-enum usb_pipe_mem_type {
-	SPS_PIPE_MEM = 0,	/* Default, SPS dedicated pipe memory */
-	USB_PRIVATE_MEM,	/* USB's private memory */
-	SYSTEM_MEM,		/* System RAM, requires allocation */
-};
-
-/**
- * struct usb_bam_pipe_connect: pipe connection information
- * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
- * either src BAM or dst BAM
- * @src_phy_addr: src bam physical address.
- * @src_pipe_index: src bam pipe index.
- * @dst_phy_addr: dst bam physical address.
- * @dst_pipe_index: dst bam pipe index.
- * @mem_type: type of memory used for BAM FIFOs
- * @data_fifo_base_offset: data fifo offset.
- * @data_fifo_size: data fifo size.
- * @desc_fifo_base_offset: descriptor fifo offset.
- * @desc_fifo_size: descriptor fifo size.
- */
-struct usb_bam_pipe_connect {
-	u32 src_phy_addr;
-	u32 src_pipe_index;
-	u32 dst_phy_addr;
-	u32 dst_pipe_index;
-	enum usb_pipe_mem_type mem_type;
-	u32 data_fifo_base_offset;
-	u32 data_fifo_size;
-	u32 desc_fifo_base_offset;
-	u32 desc_fifo_size;
-};
-
-enum usb_bam {
-	SSUSB_BAM = 0,
-	HSUSB_BAM,
-	HSIC_BAM,
-	MAX_BAMS,
-};
-
-/**
- * struct msm_usb_bam_platform_data: pipe connection information
- * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
- * either src BAM or dst BAM
- * @connections: holds all pipe connections data.
- * @usb_active_bam: set USB or HSIC as the active BAM.
- * @usb_bam_num_pipes: max number of pipes to use.
- * @active_conn_num: number of active pipe connections.
- * @usb_base_address: BAM physical address.
- * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
- * @disable_clk_gating: Disable clock gating
- */
-struct msm_usb_bam_platform_data {
-	struct usb_bam_pipe_connect *connections;
-	int usb_active_bam;
-	int usb_bam_num_pipes;
-	u32 total_bam_num;
-	u32 usb_base_address;
-	bool ignore_core_reset_ack;
-	bool reset_on_connect[MAX_BAMS];
-	bool disable_clk_gating;
-};
-
 /**
  * struct usb_ext_notification: event notification structure
  * @notify: pointer to client function to call when ID event is detected.
diff --git a/include/linux/usb/otg_id.h b/include/linux/usb/otg_id.h
deleted file mode 100644
index f9f5189..0000000
--- a/include/linux/usb/otg_id.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2011 Google, Inc.
- *
- * Author:
- *	Colin Cross <ccross@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __LINUX_USB_OTG_ID_H
-#define __LINUX_USB_OTG_ID_H
-
-#include <linux/notifier.h>
-#include <linux/plist.h>
-
-/**
- * otg_id_notifier_block
- *
- * @priority: Order the notifications will be called in.  Higher numbers
- *    get called first.
- * @detect: Called during otg_id_notify.  Return OTG_ID_HANDLED if the USB cable
- *    has been identified
- * @proxy_wait: Called during otg_id_notify if a previous handler returns
- *    OTG_ID_PROXY_WAIT.  This should wait on ID change then call otg_id_notify.
- *    This is used when a handler knows what's connected but can't detect
- *    the change itself.
- * @cancel: Called after detect has returned OTG_ID_HANDLED to ask it to
- *    release detection resources to allow a new identification to occur.
- */
-
-struct otg_id_notifier_block {
-	int priority;
-	int (*detect)(struct otg_id_notifier_block *otg_id_nb);
-	int (*proxy_wait)(struct otg_id_notifier_block *otg_id_nb);
-	void (*cancel)(struct otg_id_notifier_block *otg_id_nb);
-	struct plist_node p;
-};
-
-#define OTG_ID_PROXY_WAIT 2
-#define OTG_ID_HANDLED 1
-#define OTG_ID_UNHANDLED 0
-
-int otg_id_register_notifier(struct otg_id_notifier_block *otg_id_nb);
-void otg_id_unregister_notifier(struct otg_id_notifier_block *otg_id_nb);
-
-void otg_id_notify(void);
-int otg_id_suspend(void);
-void otg_id_resume(void);
-
-#endif /* __LINUX_USB_OTG_ID_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 2972dc0..a1d0445 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1491,6 +1491,7 @@
 	V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE			= 0,
 	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME	= 1,
 	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME		= 2,
+
 };
 #define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC			(V4L2_CID_MPEG_BASE+217)
 #define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE		(V4L2_CID_MPEG_BASE+218)
@@ -1602,7 +1603,6 @@
 #define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP	(V4L2_CID_MPEG_BASE+403)
 #define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP	(V4L2_CID_MPEG_BASE+404)
 #define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL		(V4L2_CID_MPEG_BASE+405)
-
 enum v4l2_mpeg_video_mpeg4_level {
 	V4L2_MPEG_VIDEO_MPEG4_LEVEL_0	= 0,
 	V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B	= 1,
diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h
index 5b2d0f3..f4a698a 100644
--- a/include/linux/wakelock.h
+++ b/include/linux/wakelock.h
@@ -1,6 +1,6 @@
 /* include/linux/wakelock.h
  *
- * Copyright (C) 2007-2008 Google, Inc.
+ * Copyright (C) 2007-2012 Google, Inc.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -16,14 +16,12 @@
 #ifndef _LINUX_WAKELOCK_H
 #define _LINUX_WAKELOCK_H
 
-#include <linux/list.h>
 #include <linux/ktime.h>
+#include <linux/device.h>
 
 /* A wake_lock prevents the system from entering suspend or other low power
  * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock
- * prevents a full system suspend. If the type is WAKE_LOCK_IDLE, low power
- * states that cause large interrupt latencies or that disable a set of
- * interrupts will not entered from idle until the wake_locks are released.
+ * prevents a full system suspend.
  */
 
 enum {
@@ -32,59 +30,38 @@
 };
 
 struct wake_lock {
-#ifdef CONFIG_HAS_WAKELOCK
-	struct list_head    link;
-	int                 flags;
-	const char         *name;
-	unsigned long       expires;
-#ifdef CONFIG_WAKELOCK_STAT
-	struct {
-		int             count;
-		int             expire_count;
-		int             wakeup_count;
-		ktime_t         total_time;
-		ktime_t         prevent_suspend_time;
-		ktime_t         max_time;
-		ktime_t         last_time;
-	} stat;
-#endif
-#endif
+	struct wakeup_source ws;
 };
 
-#ifdef CONFIG_HAS_WAKELOCK
-
-void wake_lock_init(struct wake_lock *lock, int type, const char *name);
-void wake_lock_destroy(struct wake_lock *lock);
-void wake_lock(struct wake_lock *lock);
-void wake_lock_timeout(struct wake_lock *lock, long timeout);
-void wake_unlock(struct wake_lock *lock);
-
-/* wake_lock_active returns a non-zero value if the wake_lock is currently
- * locked. If the wake_lock has a timeout, it does not check the timeout
- * but if the timeout had aready been checked it will return 0.
- */
-int wake_lock_active(struct wake_lock *lock);
-
-/* has_wake_lock returns 0 if no wake locks of the specified type are active,
- * and non-zero if one or more wake locks are held. Specifically it returns
- * -1 if one or more wake locks with no timeout are active or the
- * number of jiffies until all active wake locks time out.
- */
-long has_wake_lock(int type);
-
-#else
-
 static inline void wake_lock_init(struct wake_lock *lock, int type,
-					const char *name) {}
-static inline void wake_lock_destroy(struct wake_lock *lock) {}
-static inline void wake_lock(struct wake_lock *lock) {}
-static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) {}
-static inline void wake_unlock(struct wake_lock *lock) {}
+				  const char *name)
+{
+	wakeup_source_init(&lock->ws, name);
+}
 
-static inline int wake_lock_active(struct wake_lock *lock) { return 0; }
-static inline long has_wake_lock(int type) { return 0; }
+static inline void wake_lock_destroy(struct wake_lock *lock)
+{
+	wakeup_source_trash(&lock->ws);
+}
+
+static inline void wake_lock(struct wake_lock *lock)
+{
+	__pm_stay_awake(&lock->ws);
+}
+
+static inline void wake_lock_timeout(struct wake_lock *lock, long timeout)
+{
+	__pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout));
+}
+
+static inline void wake_unlock(struct wake_lock *lock)
+{
+	__pm_relax(&lock->ws);
+}
+
+static inline int wake_lock_active(struct wake_lock *lock)
+{
+	return lock->ws.active;
+}
 
 #endif
-
-#endif
-
diff --git a/include/media/gpio-ir-recv.h b/include/media/gpio-ir-recv.h
index 63f40f7..a81f0bb 100644
--- a/include/media/gpio-ir-recv.h
+++ b/include/media/gpio-ir-recv.h
@@ -14,7 +14,7 @@
 #define __GPIO_IR_RECV_H__
 
 struct gpio_ir_recv_platform_data {
-	unsigned int gpio_nr;
+	int gpio_nr;
 	bool active_low;
 	bool can_wakeup;
 	u32 swfi_latency;
diff --git a/include/media/msm/vidc_type.h b/include/media/msm/vidc_type.h
index 77bae5a..5463fc6 100644
--- a/include/media/msm/vidc_type.h
+++ b/include/media/msm/vidc_type.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,7 @@
 #include <linux/list.h>
 #include <linux/time.h>
 #include <linux/dma-mapping.h>
-#include <linux/android_pmem.h>
+
 
 #define DDL_MSG_LOG 0
 #define DEBUG 0
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 56c257d..6f8e865 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -109,6 +109,9 @@
 #define VIDIOC_MSM_CPP_GET_HW_INFO \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t)
 
+#define VIDIOC_MSM_CPP_FLUSH_QUEUE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t)
+
 #define V4L2_EVENT_CPP_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 0)
 
 struct msm_camera_v4l2_ioctl_t {
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index e3c4567..84789f1 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -52,6 +52,27 @@
 #define FM_TX_PHY_CFG_MODE   0x3c
 #define FM_TX_PHY_CFG_LEN    0x10
 #define FM_TX_PWR_GAIN_OFFSET 14
+/**RDS CONFIG MODE**/
+#define FM_RDS_CNFG_MODE	0x0f
+#define FM_RDS_CNFG_LEN		0x10
+#define AF_RMSSI_TH_LSB_OFFSET	10
+#define AF_RMSSI_TH_MSB_OFFSET	11
+#define AF_RMSSI_SAMPLES_OFFSET	15
+/**RX CONFIG MODE**/
+#define FM_RX_CONFG_MODE	0x15
+#define FM_RX_CNFG_LEN		0x20
+#define GD_CH_RMSSI_TH_OFFSET	12
+#define MAX_GD_CH_RMSSI_TH	127
+#define SRCH_ALGO_TYPE_OFFSET  25
+#define SINRFIRSTSTAGE_OFFSET  26
+#define RMSSIFIRSTSTAGE_OFFSET 27
+#define CF0TH12_BYTE1_OFFSET   8
+#define CF0TH12_BYTE2_OFFSET   9
+#define CF0TH12_BYTE3_OFFSET   10
+#define CF0TH12_BYTE4_OFFSET   11
+#define MAX_SINR_FIRSTSTAGE	127
+#define MAX_RMSSI_FIRSTSTAGE	127
+
 /* HCI timeouts */
 #define RADIO_HCI_TIMEOUT	(10000)	/* 10 seconds */
 
@@ -658,6 +679,14 @@
 	V4L2_CID_PRIVATE_SPUR_SELECTION,
 	V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE,
 	V4L2_CID_PRIVATE_VALID_CHANNEL,
+	V4L2_CID_PRIVATE_AF_RMSSI_TH,
+	V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES,
+	V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH,
+	V4L2_CID_PRIVATE_SRCHALGOTYPE,
+	V4L2_CID_PRIVATE_CF0TH12,
+	V4L2_CID_PRIVATE_SINRFIRSTSTAGE,
+	V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE,
+
 
 	/*using private CIDs under userclass*/
 	V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928,
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index a51f84c..5b4ad6d 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -152,8 +152,8 @@
 #define RC_MAP_TREKSTOR                  "rc-trekstor"
 #define RC_MAP_TT_1500                   "rc-tt-1500"
 #define RC_MAP_TWINHAN_VP1027_DVBS       "rc-twinhan1027"
-#define RC_MAP_VIDEOMATE_K100            "rc-videomate-k100"
 #define RC_MAP_UE_RF4CE			 "rc-ue-rf4ce"
+#define RC_MAP_VIDEOMATE_K100            "rc-videomate-k100"
 #define RC_MAP_VIDEOMATE_S350            "rc-videomate-s350"
 #define RC_MAP_VIDEOMATE_TV_PVR          "rc-videomate-tv-pvr"
 #define RC_MAP_WINFAST                   "rc-winfast"
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index efc11bb..c68d427 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -26,7 +26,6 @@
 #define __HCI_CORE_H
 
 #include <net/bluetooth/hci.h>
-#include <linux/wakelock.h>
 /* HCI upper protocols */
 #define HCI_PROTO_L2CAP	0
 #define HCI_PROTO_SCO	1
@@ -327,7 +326,6 @@
 
 	struct work_struct work_add;
 	struct work_struct work_del;
-	struct wake_lock idle_lock;
 	struct device	dev;
 	atomic_t	devref;
 
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3a7edf3..1645608 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -669,7 +669,9 @@
 
 	const u8 *assoc_req_ies;
 	size_t assoc_req_ies_len;
+
 	u32 beacon_loss_count;
+
 	/*
 	 * Note: Add a new enum station_info_flags value for each new field and
 	 * use it to check which fields are initialized.
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 6f1470f..498433d 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -14,8 +14,6 @@
 
 struct flowi6;
 
-extern void initialize_hashidentrnd(void);
-
 /* extension headers */
 extern int				ipv6_exthdrs_init(void);
 extern void				ipv6_exthdrs_exit(void);
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index ba75dca..edadaa9 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -11,3 +11,4 @@
 header-y += tlv.h
 header-y += compress_params.h
 header-y += compress_offload.h
+header-y += lsm_params.h
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 93f0aa90..f88c817 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -658,6 +658,11 @@
 #define SLIMBUS_3_TX		0x4007
 #define SLIMBUS_4_RX		0x4008
 #define SLIMBUS_4_TX		0x4009		/* index = 24 */
+#define SLIMBUS_5_RX		0x400a
+#define SLIMBUS_5_TX		0x400b
+#define SLIMBUS_6_RX		0x400c
+#define SLIMBUS_6_TX		0x400d
+#define SLIMBUS_PORT_LAST	SLIMBUS_6_TX
 #define INT_BT_SCO_RX 0x3000		/* index = 25 */
 #define INT_BT_SCO_TX 0x3001		/* index = 26 */
 #define INT_BT_A2DP_RX 0x3002		/* index = 27 */
@@ -798,6 +803,15 @@
 #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX      0x4008
 /* SLIMbus Tx port on channel 4. */
 #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX      0x4009
+/* SLIMbus Rx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX      0x400a
+/* SLIMbus Tx port on channel 5. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX      0x400b
+/* SLIMbus Rx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX      0x400c
+/* SLIMbus Tx port on channel 6. */
+#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX      0x400d
+
 /* Generic pseudoport 1. */
 #define AFE_PORT_ID_PSEUDOPORT_01      0x8001
 /* Generic pseudoport 2. */
@@ -1972,7 +1986,6 @@
 	 */
 } __packed;
 
-
 union afe_port_config {
 	struct afe_param_id_pcm_cfg               pcm;
 	struct afe_param_id_i2s_cfg               i2s;
@@ -6252,6 +6265,93 @@
 	/* Size in bytes of the variable payload in shared memory */
 } __packed;
 
+/* This module represents the Rx processing of Feedback speaker protection.
+ * It contains the excursion control, thermal protection,
+ * analog clip manager features in it.
+ * This module id will support following param ids.
+ * - AFE_PARAM_ID_FBSP_MODE_RX_CFG
+ */
+
+#define AFE_MODULE_FB_SPKR_PROT_RX 0x0001021C
+
+#define AFE_PARAM_ID_FBSP_MODE_RX_CFG 0x0001021D
+
+struct asm_fbsp_mode_rx_cfg {
+	uint32_t minor_version;
+	uint32_t mode;
+} __packed;
+
+/* This module represents the VI processing of feedback speaker protection.
+ * It will receive Vsens and Isens from codec and generates necessary
+ * parameters needed by Rx processing.
+ * This module id will support following param ids.
+ * - AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG
+ * - AFE_PARAM_ID_CALIB_RES_CFG
+ * - AFE_PARAM_ID_FEEDBACK_PATH_CFG
+ */
+
+#define AFE_MODULE_FB_SPKR_PROT_VI_PROC 0x00010226
+
+#define AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG 0x0001022A
+
+struct asm_spkr_calib_vi_proc_cfg {
+	uint32_t minor_version;
+	int32_t	r0_cali_q24;
+	int16_t	t0_cali_q6;
+	int16_t	reserved;
+} __packed;
+
+#define AFE_PARAM_ID_CALIB_RES_CFG 0x0001022B
+
+struct asm_calib_res_cfg {
+	uint32_t minor_version;
+	int32_t	r0_cali_q24;
+	uint32_t th_vi_ca_state;
+} __packed;
+
+#define AFE_PARAM_ID_FEEDBACK_PATH_CFG 0x0001022C
+
+struct asm_feedback_path_cfg {
+	uint32_t minor_version;
+	int32_t	dst_portid;
+	int32_t	num_channels;
+	int32_t	chan_info[4];
+} __packed;
+
+#define AFE_PARAM_ID_MODE_VI_PROC_CFG 0x00010227
+
+struct asm_mode_vi_proc_cfg {
+	uint32_t minor_version;
+	uint32_t cal_mode;
+} __packed;
+
+union afe_spkr_prot_config {
+	struct asm_fbsp_mode_rx_cfg mode_rx_cfg;
+	struct asm_spkr_calib_vi_proc_cfg vi_proc_cfg;
+	struct asm_feedback_path_cfg feedback_path_cfg;
+	struct asm_mode_vi_proc_cfg mode_vi_proc_cfg;
+} __packed;
+
+struct afe_spkr_prot_config_command {
+	struct apr_hdr hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2 pdata;
+	union afe_spkr_prot_config prot_config;
+} __packed;
+
+struct afe_spkr_prot_get_vi_calib {
+	struct afe_port_cmd_get_param_v2 get_param;
+	struct afe_port_param_data_v2 pdata;
+	struct asm_calib_res_cfg res_cfg;
+} __packed;
+
+struct afe_spkr_prot_calib_get_resp {
+	uint32_t status;
+	struct afe_port_param_data_v2 pdata;
+	struct asm_calib_res_cfg res_cfg;
+} __packed;
+
+
 /* SRS TRUMEDIA start */
 /* topology */
 #define SRS_TRUMEDIA_TOPOLOGY_ID			0x00010D90
@@ -6355,7 +6455,55 @@
 } __packed;
 /* SRS TruMedia end */
 
+/* LSM Specific */
+#define VW_FEAT_DIM					(39)
 
+#define APRV2_IDS_SERVICE_ID_ADSP_LSM_V			(0xD)
+#define APRV2_IDS_DOMAIN_ID_ADSP_V			(0x4)
+#define APRV2_IDS_DOMAIN_ID_APPS_V			(0x5)
+
+#define LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS		(0x00012A7F)
+#define LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS	(0x00012A80)
+#define LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS	(0x00012A81)
+#define LSM_SESSION_CMD_OPEN_TX				(0x00012A82)
+#define LSM_SESSION_CMD_CLOSE_TX			(0x00012A88)
+#define LSM_SESSION_CMD_SET_PARAMS			(0x00012A83)
+#define LSM_SESSION_CMD_REGISTER_SOUND_MODEL		(0x00012A84)
+#define LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL		(0x00012A85)
+#define LSM_SESSION_CMD_START				(0x00012A86)
+#define LSM_SESSION_CMD_STOP				(0x00012A87)
+
+#define LSM_SESSION_EVENT_DETECTION_STATUS		(0x00012B00)
+
+#define LSM_MODULE_ID_VOICE_WAKEUP			(0x00012C00)
+#define LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD		(0x00012C01)
+#define LSM_PARAM_ID_OPERATION_MODE			(0x00012C02)
+#define LSM_PARAM_ID_GAIN				(0x00012C03)
+#define LSM_PARAM_ID_CONNECT_TO_PORT			(0x00012C04)
+#define LSM_PARAM_ID_KEYWORD_DETECT_SENSITIVITY		(0x00012C05)
+#define LSM_PARAM_ID_USER_DETECT_SENSITIVITY		(0x00012C06)
+#define LSM_PARAM_ID_FEATURE_COMPENSATION_DATA		(0x00012C07)
+
+
+/* HW MAD specific */
+#define AFE_MODULE_HW_MAD				(0x00010230)
+#define AFE_PARAM_ID_HW_MAD_CFG				(0x00010231)
+#define AFE_PARAM_ID_HW_MAD_CTRL			(0x00010232)
+#define AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG		(0x00010233)
+
+/* SW MAD specific */
+#define AFE_MODULE_SW_MAD				(0x0001022D)
+#define AFE_PARAM_ID_SW_MAD_CFG				(0x0001022E)
+#define AFE_PARAM_ID_SVM_MODEL				(0x0001022F)
+
+/* Commands/Params to pass the codec/slimbus data to DSP */
+#define AFE_SVC_CMD_SET_PARAM				(0x000100f3)
+#define AFE_MODULE_CDC_DEV_CFG				(0x00010234)
+#define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG		(0x00010235)
+#define AFE_PARAM_ID_CDC_REG_CFG			(0x00010236)
+#define AFE_PARAM_ID_CDC_REG_CFG_INIT			(0x00010237)
+
+#define AFE_MAX_CDC_REGISTERS_TO_CONFIG			(20)
 
 /* ERROR CODES */
 /* Success. The operation completed with no errors. */
@@ -6584,4 +6732,104 @@
 	uint16_t                  reserved;
 } __packed;
 
+enum afe_config_type {
+	AFE_SLIMBUS_SLAVE_PORT_CONFIG,
+	AFE_SLIMBUS_SLAVE_CONFIG,
+	AFE_CDC_REGISTERS_CONFIG,
+	AFE_MAX_CONFIG_TYPES,
+};
+
+struct afe_param_slimbus_slave_port_cfg {
+	uint32_t minor_version;
+	uint16_t slimbus_dev_id;
+	uint16_t slave_dev_pgd_la;
+	uint16_t slave_dev_intfdev_la;
+	uint16_t bit_width;
+	uint16_t data_format;
+	uint16_t num_channels;
+	uint16_t slave_port_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+} __packed;
+
+struct afe_param_cdc_slimbus_slave_cfg {
+	uint32_t minor_version;
+	uint32_t device_enum_addr_lsw;
+	uint32_t device_enum_addr_msw;
+	uint16_t tx_slave_port_offset;
+	uint16_t rx_slave_port_offset;
+} __packed;
+
+struct afe_param_cdc_reg_cfg {
+	uint32_t minor_version;
+	uint32_t reg_logical_addr;
+	uint32_t reg_field_type;
+	uint32_t reg_field_bit_mask;
+	uint16_t reg_bit_width;
+	uint16_t reg_offset_scale;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_data {
+	uint32_t num_registers;
+	struct afe_param_cdc_reg_cfg *reg_data;
+} __packed;
+
+struct afe_svc_cmd_set_param {
+	uint32_t payload_size;
+	uint32_t payload_address_lsw;
+	uint32_t payload_address_msw;
+	uint32_t mem_map_handle;
+} __packed;
+
+struct afe_param_hw_mad_ctrl {
+	uint32_t minor_version;
+	uint16_t mad_type;
+	uint16_t mad_enable;
+} __packed;
+
+struct afe_cmd_hw_mad_ctrl {
+	struct apr_hdr hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2 pdata;
+	struct afe_param_hw_mad_ctrl payload;
+} __packed;
+
+struct afe_cmd_hw_mad_slimbus_slave_port_cfg {
+	struct apr_hdr hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2 pdata;
+	struct afe_param_slimbus_slave_port_cfg sb_port_cfg;
+} __packed;
+
+struct afe_cmd_sw_mad_enable {
+	struct apr_hdr hdr;
+	struct afe_port_cmd_set_param_v2 param;
+	struct afe_port_param_data_v2 pdata;
+} __packed;
+
+struct afe_param_cdc_reg_cfg_payload {
+	struct afe_port_param_data_v2 common;
+	struct afe_param_cdc_reg_cfg  reg_cfg;
+} __packed;
+
+/*
+ * reg_data's size can be up to AFE_MAX_CDC_REGISTERS_TO_CONFIG
+ */
+struct afe_svc_cmd_cdc_reg_cfg {
+	struct apr_hdr hdr;
+	struct afe_svc_cmd_set_param param;
+	struct afe_param_cdc_reg_cfg_payload reg_data[0];
+} __packed;
+
+struct afe_svc_cmd_init_cdc_reg_cfg {
+	struct apr_hdr hdr;
+	struct afe_svc_cmd_set_param param;
+	struct afe_port_param_data_v2 init;
+} __packed;
+
+struct afe_svc_cmd_sb_slave_cfg {
+	struct apr_hdr hdr;
+	struct afe_svc_cmd_set_param param;
+	struct afe_port_param_data_v2 pdata;
+	struct afe_param_cdc_slimbus_slave_cfg sb_slave_cfg;
+} __packed;
+
 #endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/lsm_params.h b/include/sound/lsm_params.h
new file mode 100644
index 0000000..0edd8b5
--- /dev/null
+++ b/include/sound/lsm_params.h
@@ -0,0 +1,36 @@
+#ifndef __LSM_PARAMS_H__
+#define __LSM_PARAMS_H__
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
+
+enum lsm_detection_mode {
+	LSM_MODE_KEYWORD_ONLY_DETECTION = 1,
+	LSM_MODE_USER_KEYWORD_DETECTION
+};
+
+struct snd_lsm_sound_model {
+	__u8 *data;
+	__u32 data_size;
+	enum lsm_detection_mode detection_mode;
+	__u16 min_keyw_confidence;
+	__u16 min_user_confidence;
+	bool detect_failure;
+};
+
+struct snd_lsm_event_status {
+	__u16 status;
+	__u16 payload_size;
+	__u8 payload[0];
+};
+
+#define SNDRV_LSM_REG_SND_MODEL	 _IOW('U', 0x00, struct snd_lsm_sound_model)
+#define SNDRV_LSM_DEREG_SND_MODEL _IOW('U', 0x01, int)
+#define SNDRV_LSM_EVENT_STATUS	_IOW('U', 0x02, struct snd_lsm_event_status)
+#define SNDRV_LSM_ABORT_EVENT	_IOW('U', 0x03, int)
+#define SNDRV_LSM_START		_IOW('U', 0x04, int)
+#define SNDRV_LSM_STOP		_IOW('U', 0x05, int)
+
+#endif
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 506e877..22ddbbc 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -64,24 +64,34 @@
 	IDX_SLIMBUS_3_TX = 22,
 	IDX_SLIMBUS_4_RX = 23,
 	IDX_SLIMBUS_4_TX = 24,
-	IDX_INT_BT_SCO_RX = 25,
-	IDX_INT_BT_SCO_TX = 26,
-	IDX_INT_BT_A2DP_RX = 27,
-	IDX_INT_FM_RX = 28,
-	IDX_INT_FM_TX = 29,
-	IDX_RT_PROXY_PORT_001_RX = 30,
-	IDX_RT_PROXY_PORT_001_TX = 31,
-	IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 32,
-	IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 33,
-	IDX_AFE_PORT_ID_SECONDARY_MI2S_RX = 34,
-	IDX_AFE_PORT_ID_SECONDARY_MI2S_TX = 35,
-	IDX_AFE_PORT_ID_TERTIARY_MI2S_RX = 36,
-	IDX_AFE_PORT_ID_TERTIARY_MI2S_TX = 37,
-	IDX_AFE_PORT_ID_PRIMARY_MI2S_RX = 38,
-	IDX_AFE_PORT_ID_PRIMARY_MI2S_TX = 39,
+	IDX_SLIMBUS_5_RX = 25,
+	IDX_SLIMBUS_5_TX = 26,
+	IDX_INT_BT_SCO_RX = 27,
+	IDX_INT_BT_SCO_TX = 28,
+	IDX_INT_BT_A2DP_RX = 29,
+	IDX_INT_FM_RX = 30,
+	IDX_INT_FM_TX = 31,
+	IDX_RT_PROXY_PORT_001_RX = 32,
+	IDX_RT_PROXY_PORT_001_TX = 33,
+	IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 34,
+	IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 35,
+	IDX_AFE_PORT_ID_SECONDARY_MI2S_RX = 36,
+	IDX_AFE_PORT_ID_SECONDARY_MI2S_TX = 37,
+	IDX_AFE_PORT_ID_TERTIARY_MI2S_RX = 38,
+	IDX_AFE_PORT_ID_TERTIARY_MI2S_TX = 39,
+	IDX_AFE_PORT_ID_PRIMARY_MI2S_RX = 40,
+	IDX_AFE_PORT_ID_PRIMARY_MI2S_TX = 41,
+	IDX_GLOBAL_CFG,
 	AFE_MAX_PORTS
 };
 
+enum afe_mad_type {
+	MAD_HW_NONE = 0x00,
+	MAD_HW_AUDIO = 0x01,
+	MAD_HW_BEACON = 0x02,
+	MAD_HW_ULTRASOUND = 0x04
+};
+
 struct afe_audio_buffer {
 	dma_addr_t phys;
 	void       *data;
@@ -145,6 +155,9 @@
 int afe_rt_proxy_port_read(u32 buf_addr_p, u32 mem_map_handle, int bytes);
 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 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);
 int afe_q6_interface_prepare(void);
@@ -169,4 +182,10 @@
 				struct afe_digital_clk_cfg *cfg);
 int q6afe_check_osr_clk_freq(u32 freq);
 
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 mad_enable);
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type);
+enum afe_mad_type afe_port_get_mad_type(u16 port_id);
+int afe_set_config(enum afe_config_type config_type, void *config_data,
+		   int arg);
+
 #endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
new file mode 100644
index 0000000..5c9d4b9
--- /dev/null
+++ b/include/sound/q6lsm.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __Q6LSM_H__
+#define __Q6LSM_H__
+
+#include <linux/list.h>
+#include <linux/msm_ion.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/msm_subsystem_map.h>
+
+typedef void (*app_cb)(uint32_t opcode, uint32_t token,
+		       uint32_t *payload, void *priv);
+
+struct lsm_sound_model {
+	dma_addr_t      phys;
+	void		*data;
+	uint32_t	size; /* size of buffer */
+	uint32_t	actual_size; /* actual number of bytes read by DSP */
+	struct ion_handle *handle;
+	struct ion_client *client;
+	uint32_t	mem_map_handle;
+};
+
+struct lsm_client {
+	int		session;
+	app_cb		cb;
+	atomic_t	cmd_state;
+	void		*priv;
+	struct apr_svc  *apr;
+	struct apr_svc  *mmap_apr;
+	struct mutex    cmd_lock;
+	struct lsm_sound_model sound_model;
+	wait_queue_head_t cmd_wait;
+	uint16_t	mode;
+	uint16_t	connect_to_port;
+	uint16_t	user_sensitivity;
+	uint16_t	kw_sensitivity;
+	bool		started;
+};
+
+struct lsm_stream_cmd_open_tx {
+	struct apr_hdr  hdr;
+	uint16_t	app_id;
+	uint16_t	reserved;
+	uint32_t	sampling_rate;
+} __packed;
+
+struct lsm_param_payload_common {
+	uint32_t	module_id;
+	uint32_t	param_id;
+	uint16_t	param_size;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_param_op_mode {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	uint16_t	mode;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_param_connect_to_port {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	/* AFE port id that receives voice wake up data */
+	uint16_t	port_id;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_param_kw_detect_sensitivity {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	/* scale factor to change the keyword confidence thresholds */
+	uint16_t	keyword_sensitivity;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_param_user_detect_sensitivity {
+	struct lsm_param_payload_common common;
+	uint32_t	minor_version;
+	/* scale factor to change the user confidence thresholds */
+	uint16_t	user_sensitivity;
+	uint16_t	reserved;
+} __packed;
+
+struct lsm_params_payload {
+	struct lsm_param_connect_to_port connect_to_port;
+	struct lsm_param_op_mode	op_mode;
+	struct lsm_param_kw_detect_sensitivity kwds;
+	struct lsm_param_user_detect_sensitivity uds;
+} __packed;
+
+struct lsm_cmd_set_params {
+	struct apr_hdr  hdr;
+	uint32_t	data_payload_size;
+	uint32_t	data_payload_addr_lsw;
+	uint32_t	data_payload_addr_msw;
+	uint32_t	mem_map_handle;
+	struct lsm_params_payload payload;
+} __packed;
+
+struct lsm_cmd_reg_snd_model {
+	struct apr_hdr	hdr;
+	uint32_t	model_size;
+	uint32_t	model_addr_lsw;
+	uint32_t	model_addr_msw;
+	uint32_t	mem_map_handle;
+} __packed;
+
+struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv);
+void q6lsm_client_free(struct lsm_client *client);
+int q6lsm_open(struct lsm_client *client);
+int q6lsm_start(struct lsm_client *client, bool wait);
+int q6lsm_stop(struct lsm_client *client, bool wait);
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
+int q6lsm_close(struct lsm_client *client);
+int q6lsm_register_sound_model(struct lsm_client *client,
+			       enum lsm_detection_mode mode, u16 minkeyword,
+			       u16 minuser, bool detectfailure);
+int q6lsm_deregister_sound_model(struct lsm_client *client);
+
+#endif /* __Q6LSM_H__ */
diff --git a/init/Kconfig b/init/Kconfig
index b2126bc..e4b67a1 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1132,15 +1132,6 @@
 	  option replaces shmem and tmpfs with the much simpler ramfs code,
 	  which may be appropriate on small systems without swap.
 
-config ASHMEM
-	bool "Enable the Anonymous Shared Memory Subsystem"
-	default n
-	depends on SHMEM || TINY_SHMEM
-	help
-	  The ashmem subsystem is a new shared memory allocator, similar to
-	  POSIX SHM but with different behavior and sporting a simpler
-	  file-based API.
-
 config AIO
 	bool "Enable AIO support" if EXPERT
 	default y
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 1878b6e..371ddf6 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -103,6 +103,33 @@
 	select HOTPLUG
 	select HOTPLUG_CPU
 
+config PM_AUTOSLEEP
+	bool "Opportunistic sleep"
+	depends on PM_SLEEP
+	default n
+	---help---
+	Allow the kernel to trigger a system transition into a global sleep
+	state automatically whenever there are no active wakeup sources.
+
+config PM_WAKELOCKS
+	bool "User space wakeup sources interface"
+	depends on PM_SLEEP
+	default n
+	---help---
+	Allow user space to create, activate and deactivate wakeup source
+	objects with the help of a sysfs-based interface.
+
+config PM_WAKELOCKS_LIMIT
+	int "Maximum number of user space wakeup sources (0 = no limit)"
+	range 0 100000
+	default 100
+	depends on PM_WAKELOCKS
+
+config PM_WAKELOCKS_GC
+	bool "Garbage collector for user space wakeup sources"
+	depends on PM_WAKELOCKS
+	default y
+
 config PM_RUNTIME
 	bool "Run-time PM core functionality"
 	depends on !IA64_HP_SIM
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 5ad8c75..29472bf 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -9,11 +9,7 @@
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o \
 				   block_io.o
-obj-$(CONFIG_WAKELOCK)		+= wakelock.o
-obj-$(CONFIG_USER_WAKELOCK)	+= userwakelock.o
-obj-$(CONFIG_EARLYSUSPEND)	+= earlysuspend.o
-obj-$(CONFIG_CONSOLE_EARLYSUSPEND)	+= consoleearlysuspend.o
-obj-$(CONFIG_FB_EARLYSUSPEND)	+= fbearlysuspend.o
-obj-$(CONFIG_SUSPEND_TIME)	+= suspend_time.o
+obj-$(CONFIG_PM_AUTOSLEEP)	+= autosleep.o
+obj-$(CONFIG_PM_WAKELOCKS)	+= wakelock.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
diff --git a/kernel/power/autosleep.c b/kernel/power/autosleep.c
new file mode 100644
index 0000000..ca304046
--- /dev/null
+++ b/kernel/power/autosleep.c
@@ -0,0 +1,127 @@
+/*
+ * kernel/power/autosleep.c
+ *
+ * Opportunistic sleep support.
+ *
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
+ */
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/pm_wakeup.h>
+
+#include "power.h"
+
+static suspend_state_t autosleep_state;
+static struct workqueue_struct *autosleep_wq;
+/*
+ * Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source
+ * is active, otherwise a deadlock with try_to_suspend() is possible.
+ * Alternatively mutex_lock_interruptible() can be used.  This will then fail
+ * if an auto_sleep cycle tries to freeze processes.
+ */
+static DEFINE_MUTEX(autosleep_lock);
+static struct wakeup_source *autosleep_ws;
+
+static void try_to_suspend(struct work_struct *work)
+{
+	unsigned int initial_count, final_count;
+
+	if (!pm_get_wakeup_count(&initial_count, true))
+		goto out;
+
+	mutex_lock(&autosleep_lock);
+
+	if (!pm_save_wakeup_count(initial_count)) {
+		mutex_unlock(&autosleep_lock);
+		goto out;
+	}
+
+	if (autosleep_state == PM_SUSPEND_ON) {
+		mutex_unlock(&autosleep_lock);
+		return;
+	}
+	if (autosleep_state >= PM_SUSPEND_MAX)
+		hibernate();
+	else
+		pm_suspend(autosleep_state);
+
+	mutex_unlock(&autosleep_lock);
+
+	if (!pm_get_wakeup_count(&final_count, false))
+		goto out;
+
+	/*
+	 * If the wakeup occured for an unknown reason, wait to prevent the
+	 * system from trying to suspend and waking up in a tight loop.
+	 */
+	if (final_count == initial_count)
+		schedule_timeout_uninterruptible(HZ / 2);
+
+ out:
+	queue_up_suspend_work();
+}
+
+static DECLARE_WORK(suspend_work, try_to_suspend);
+
+void queue_up_suspend_work(void)
+{
+	if (!work_pending(&suspend_work) && autosleep_state > PM_SUSPEND_ON)
+		queue_work(autosleep_wq, &suspend_work);
+}
+
+suspend_state_t pm_autosleep_state(void)
+{
+	return autosleep_state;
+}
+
+int pm_autosleep_lock(void)
+{
+	return mutex_lock_interruptible(&autosleep_lock);
+}
+
+void pm_autosleep_unlock(void)
+{
+	mutex_unlock(&autosleep_lock);
+}
+
+int pm_autosleep_set_state(suspend_state_t state)
+{
+
+#ifndef CONFIG_HIBERNATION
+	if (state >= PM_SUSPEND_MAX)
+		return -EINVAL;
+#endif
+
+	__pm_stay_awake(autosleep_ws);
+
+	mutex_lock(&autosleep_lock);
+
+	autosleep_state = state;
+
+	__pm_relax(autosleep_ws);
+
+	if (state > PM_SUSPEND_ON) {
+		pm_wakep_autosleep_enabled(true);
+		queue_up_suspend_work();
+	} else {
+		pm_wakep_autosleep_enabled(false);
+	}
+
+	mutex_unlock(&autosleep_lock);
+	return 0;
+}
+
+int __init pm_autosleep_init(void)
+{
+	autosleep_ws = wakeup_source_register("autosleep");
+	if (!autosleep_ws)
+		return -ENOMEM;
+
+	autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
+	if (autosleep_wq)
+		return 0;
+
+	wakeup_source_unregister(autosleep_ws);
+	return -ENOMEM;
+}
diff --git a/kernel/power/main.c b/kernel/power/main.c
index a1d13f5..7aac5f6 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -354,8 +354,7 @@
 	return (s - buf);
 }
 
-static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
-			   const char *buf, size_t n)
+static suspend_state_t decode_state(const char *buf, size_t n)
 {
 #ifdef CONFIG_SUSPEND
 #ifdef CONFIG_EARLYSUSPEND
@@ -367,34 +366,48 @@
 #endif
 	char *p;
 	int len;
-	int error = -EINVAL;
 
 	p = memchr(buf, '\n', n);
 	len = p ? p - buf : n;
 
-	/* First, check if we are requested to hibernate */
-	if (len == 4 && !strncmp(buf, "disk", len)) {
-		error = hibernate();
-		goto Exit;
-	}
+	/* Check hibernation first. */
+	if (len == 4 && !strncmp(buf, "disk", len))
+		return PM_SUSPEND_MAX;
 
 #ifdef CONFIG_SUSPEND
-	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
-		if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
-#ifdef CONFIG_EARLYSUSPEND
-			if (state == PM_SUSPEND_ON || valid_state(state)) {
-				error = 0;
-				request_suspend_state(state);
-				break;
-			}
-#else
-			error = pm_suspend(state);
-#endif
-		}
-	}
+	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++)
+		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
+			return state;
 #endif
 
- Exit:
+	return PM_SUSPEND_ON;
+}
+
+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
+			   const char *buf, size_t n)
+{
+	suspend_state_t state;
+	int error;
+
+	error = pm_autosleep_lock();
+	if (error)
+		return error;
+
+	if (pm_autosleep_state() > PM_SUSPEND_ON) {
+		error = -EBUSY;
+		goto out;
+	}
+
+	state = decode_state(buf, n);
+	if (state < PM_SUSPEND_MAX)
+		error = pm_suspend(state);
+	else if (state == PM_SUSPEND_MAX)
+		error = hibernate();
+	else
+		error = -EINVAL;
+
+ out:
+	pm_autosleep_unlock();
 	return error ? error : n;
 }
 
@@ -435,7 +448,8 @@
 {
 	unsigned int val;
 
-	return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR;
+	return pm_get_wakeup_count(&val, true) ?
+		sprintf(buf, "%u\n", val) : -EINTR;
 }
 
 static ssize_t wakeup_count_store(struct kobject *kobj,
@@ -443,15 +457,106 @@
 				const char *buf, size_t n)
 {
 	unsigned int val;
+	int error;
 
+	error = pm_autosleep_lock();
+	if (error)
+		return error;
+
+	if (pm_autosleep_state() > PM_SUSPEND_ON) {
+		error = -EBUSY;
+		goto out;
+	}
+
+	error = -EINVAL;
 	if (sscanf(buf, "%u", &val) == 1) {
 		if (pm_save_wakeup_count(val))
-			return n;
+			error = n;
 	}
-	return -EINVAL;
+
+ out:
+	pm_autosleep_unlock();
+	return error;
 }
 
 power_attr(wakeup_count);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t autosleep_show(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      char *buf)
+{
+	suspend_state_t state = pm_autosleep_state();
+
+	if (state == PM_SUSPEND_ON)
+		return sprintf(buf, "off\n");
+
+#ifdef CONFIG_SUSPEND
+	if (state < PM_SUSPEND_MAX)
+		return sprintf(buf, "%s\n", valid_state(state) ?
+						pm_states[state] : "error");
+#endif
+#ifdef CONFIG_HIBERNATION
+	return sprintf(buf, "disk\n");
+#else
+	return sprintf(buf, "error");
+#endif
+}
+
+static ssize_t autosleep_store(struct kobject *kobj,
+			       struct kobj_attribute *attr,
+			       const char *buf, size_t n)
+{
+	suspend_state_t state = decode_state(buf, n);
+	int error;
+
+	if (state == PM_SUSPEND_ON
+	    && !(strncmp(buf, "off", 3) && strncmp(buf, "off\n", 4)))
+		return -EINVAL;
+
+	error = pm_autosleep_set_state(state);
+	return error ? error : n;
+}
+
+power_attr(autosleep);
+#endif /* CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+static ssize_t wake_lock_show(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      char *buf)
+{
+	return pm_show_wakelocks(buf, true);
+}
+
+static ssize_t wake_lock_store(struct kobject *kobj,
+			       struct kobj_attribute *attr,
+			       const char *buf, size_t n)
+{
+	int error = pm_wake_lock(buf);
+	return error ? error : n;
+}
+
+power_attr(wake_lock);
+
+static ssize_t wake_unlock_show(struct kobject *kobj,
+				struct kobj_attribute *attr,
+				char *buf)
+{
+	return pm_show_wakelocks(buf, false);
+}
+
+static ssize_t wake_unlock_store(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf, size_t n)
+{
+	int error = pm_wake_unlock(buf);
+	return error ? error : n;
+}
+
+power_attr(wake_unlock);
+
+#endif /* CONFIG_PM_WAKELOCKS */
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_TRACE
@@ -502,8 +607,6 @@
 #endif
 
 static struct attribute *g[] = {
-	&touch_event_attr.attr,
-	&touch_event_timer_attr.attr,
 	&state_attr.attr,
 #ifdef CONFIG_PM_TRACE
 	&pm_trace_attr.attr,
@@ -512,6 +615,15 @@
 #ifdef CONFIG_PM_SLEEP
 	&pm_async_attr.attr,
 	&wakeup_count_attr.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+	&autosleep_attr.attr,
+#endif
+#ifdef CONFIG_PM_WAKELOCKS
+	&wake_lock_attr.attr,
+	&wake_unlock_attr.attr,
+#endif
+	&touch_event_attr.attr,
+	&touch_event_timer_attr.attr,
 #ifdef CONFIG_PM_DEBUG
 	&pm_test_attr.attr,
 #endif
@@ -554,11 +666,13 @@
 	tc_ev_timer.function = &tc_ev_stop;
 	tc_ev_processed = 1;
 
-
 	power_kobj = kobject_create_and_add("power", NULL);
 	if (!power_kobj)
 		return -ENOMEM;
-	return sysfs_create_group(power_kobj, &attr_group);
+	error = sysfs_create_group(power_kobj, &attr_group);
+	if (error)
+		return error;
+	return pm_autosleep_init();
 }
 
 core_initcall(pm_init);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 32e08a1..b0bd4be 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -265,31 +265,29 @@
 }
 #endif
 
-#ifdef CONFIG_WAKELOCK
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+extern int pm_autosleep_init(void);
+extern int pm_autosleep_lock(void);
+extern void pm_autosleep_unlock(void);
+extern suspend_state_t pm_autosleep_state(void);
+extern int pm_autosleep_set_state(suspend_state_t state);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline int pm_autosleep_init(void) { return 0; }
+static inline int pm_autosleep_lock(void) { return 0; }
+static inline void pm_autosleep_unlock(void) {}
+static inline suspend_state_t pm_autosleep_state(void) { return PM_SUSPEND_ON; }
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+
 /* kernel/power/wakelock.c */
-extern struct workqueue_struct *suspend_work_queue;
-extern struct wake_lock main_wake_lock;
-extern suspend_state_t requested_suspend_state;
-extern void suspend_sys_sync_queue(void);
-extern int suspend_sys_sync_wait(void);
-#else
-static inline void suspend_sys_sync_queue(void) {}
-static inline int suspend_sys_sync_wait(void) { return 0; }
-#endif
+extern ssize_t pm_show_wakelocks(char *buf, bool show_active);
+extern int pm_wake_lock(const char *buf);
+extern int pm_wake_unlock(const char *buf);
 
-#ifdef CONFIG_USER_WAKELOCK
-ssize_t wake_lock_show(struct kobject *kobj, struct kobj_attribute *attr,
-			char *buf);
-ssize_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr,
-			const char *buf, size_t n);
-ssize_t wake_unlock_show(struct kobject *kobj, struct kobj_attribute *attr,
-			char *buf);
-ssize_t  wake_unlock_store(struct kobject *kobj, struct kobj_attribute *attr,
-			const char *buf, size_t n);
-#endif
-
-#ifdef CONFIG_EARLYSUSPEND
-/* kernel/power/earlysuspend.c */
-void request_suspend_state(suspend_state_t state);
-suspend_state_t get_suspend_state(void);
-#endif
+#endif /* !CONFIG_PM_WAKELOCKS */
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index 2583856..c8fba33 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -1,712 +1,259 @@
-/* kernel/power/wakelock.c
+/*
+ * kernel/power/wakelock.c
  *
- * Copyright (C) 2005-2008 Google, Inc.
+ * User space wakeup sources support.
  *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
  *
- * 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.
- *
+ * This code is based on the analogous interface allowing user space to
+ * manipulate wakelocks on Android.
  */
 
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/rtc.h>
-#include <linux/suspend.h>
-#include <linux/syscalls.h> /* sys_sync */
-#include <linux/wakelock.h>
-#ifdef CONFIG_WAKELOCK_STAT
-#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(wakelocks_lock);
+
+struct wakelock {
+	char			*name;
+	struct rb_node		node;
+	struct wakeup_source	ws;
+#ifdef CONFIG_PM_WAKELOCKS_GC
+	struct list_head	lru;
 #endif
-#include "power.h"
-
-enum {
-	DEBUG_EXIT_SUSPEND = 1U << 0,
-	DEBUG_WAKEUP = 1U << 1,
-	DEBUG_SUSPEND = 1U << 2,
-	DEBUG_EXPIRE = 1U << 3,
-	DEBUG_WAKE_LOCK = 1U << 4,
 };
-static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP;
-module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
-#define WAKE_LOCK_TYPE_MASK              (0x0f)
-#define WAKE_LOCK_INITIALIZED            (1U << 8)
-#define WAKE_LOCK_ACTIVE                 (1U << 9)
-#define WAKE_LOCK_AUTO_EXPIRE            (1U << 10)
-#define WAKE_LOCK_PREVENTING_SUSPEND     (1U << 11)
+static struct rb_root wakelocks_tree = RB_ROOT;
 
-static DEFINE_SPINLOCK(list_lock);
-static LIST_HEAD(inactive_locks);
-static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];
-static int current_event_num;
-static int suspend_sys_sync_count;
-static DEFINE_SPINLOCK(suspend_sys_sync_lock);
-static struct workqueue_struct *suspend_sys_sync_work_queue;
-static DECLARE_COMPLETION(suspend_sys_sync_comp);
-struct workqueue_struct *suspend_work_queue;
-struct wake_lock main_wake_lock;
-suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
-static struct wake_lock unknown_wakeup;
-static struct wake_lock suspend_backoff_lock;
-
-#define SUSPEND_BACKOFF_THRESHOLD	10
-#define SUSPEND_BACKOFF_INTERVAL	10000
-
-static unsigned suspend_short_count;
-
-#ifdef CONFIG_WAKELOCK_STAT
-static struct wake_lock deleted_wake_locks;
-static ktime_t last_sleep_time_update;
-static int wait_for_wakeup;
-
-int get_expired_time(struct wake_lock *lock, ktime_t *expire_time)
+ssize_t pm_show_wakelocks(char *buf, bool show_active)
 {
-	struct timespec ts;
-	struct timespec kt;
-	struct timespec tomono;
-	struct timespec delta;
-	struct timespec sleep;
-	long timeout;
+	struct rb_node *node;
+	struct wakelock *wl;
+	char *str = buf;
+	char *end = buf + PAGE_SIZE;
 
-	if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))
-		return 0;
-	get_xtime_and_monotonic_and_sleep_offset(&kt, &tomono, &sleep);
-	timeout = lock->expires - jiffies;
-	if (timeout > 0)
-		return 0;
-	jiffies_to_timespec(-timeout, &delta);
-	set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
-				kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
-	*expire_time = timespec_to_ktime(ts);
-	return 1;
-}
+	mutex_lock(&wakelocks_lock);
 
-
-static int print_lock_stat(struct seq_file *m, struct wake_lock *lock)
-{
-	int lock_count = lock->stat.count;
-	int expire_count = lock->stat.expire_count;
-	ktime_t active_time = ktime_set(0, 0);
-	ktime_t total_time = lock->stat.total_time;
-	ktime_t max_time = lock->stat.max_time;
-
-	ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;
-	if (lock->flags & WAKE_LOCK_ACTIVE) {
-		ktime_t now, add_time;
-		int expired = get_expired_time(lock, &now);
-		if (!expired)
-			now = ktime_get();
-		add_time = ktime_sub(now, lock->stat.last_time);
-		lock_count++;
-		if (!expired)
-			active_time = add_time;
-		else
-			expire_count++;
-		total_time = ktime_add(total_time, add_time);
-		if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)
-			prevent_suspend_time = ktime_add(prevent_suspend_time,
-					ktime_sub(now, last_sleep_time_update));
-		if (add_time.tv64 > max_time.tv64)
-			max_time = add_time;
+	for (node = rb_first(&wakelocks_tree); node; node = rb_next(node)) {
+		wl = rb_entry(node, struct wakelock, node);
+		if (wl->ws.active == show_active)
+			str += scnprintf(str, end - str, "%s ", wl->name);
 	}
+	if (str > buf)
+		str--;
 
-	return seq_printf(m,
-		     "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
-		     lock->name, lock_count, expire_count,
-		     lock->stat.wakeup_count, ktime_to_ns(active_time),
-		     ktime_to_ns(total_time),
-		     ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
-		     ktime_to_ns(lock->stat.last_time));
+	str += scnprintf(str, end - str, "\n");
+
+	mutex_unlock(&wakelocks_lock);
+	return (str - buf);
 }
 
-static int wakelock_stats_show(struct seq_file *m, void *unused)
+#if CONFIG_PM_WAKELOCKS_LIMIT > 0
+static unsigned int number_of_wakelocks;
+
+static inline bool wakelocks_limit_exceeded(void)
 {
-	unsigned long irqflags;
-	struct wake_lock *lock;
-	int ret;
-	int type;
-
-	spin_lock_irqsave(&list_lock, irqflags);
-
-	ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since"
-			"\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
-	list_for_each_entry(lock, &inactive_locks, link)
-		ret = print_lock_stat(m, lock);
-	for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
-		list_for_each_entry(lock, &active_wake_locks[type], link)
-			ret = print_lock_stat(m, lock);
-	}
-	spin_unlock_irqrestore(&list_lock, irqflags);
-	return 0;
+	return number_of_wakelocks > CONFIG_PM_WAKELOCKS_LIMIT;
 }
 
-static void wake_unlock_stat_locked(struct wake_lock *lock, int expired)
+static inline void increment_wakelocks_number(void)
 {
-	ktime_t duration;
+	number_of_wakelocks++;
+}
+
+static inline void decrement_wakelocks_number(void)
+{
+	number_of_wakelocks--;
+}
+#else /* CONFIG_PM_WAKELOCKS_LIMIT = 0 */
+static inline bool wakelocks_limit_exceeded(void) { return false; }
+static inline void increment_wakelocks_number(void) {}
+static inline void decrement_wakelocks_number(void) {}
+#endif /* CONFIG_PM_WAKELOCKS_LIMIT */
+
+#ifdef CONFIG_PM_WAKELOCKS_GC
+#define WL_GC_COUNT_MAX	100
+#define WL_GC_TIME_SEC	300
+
+static LIST_HEAD(wakelocks_lru_list);
+static unsigned int wakelocks_gc_count;
+
+static inline void wakelocks_lru_add(struct wakelock *wl)
+{
+	list_add(&wl->lru, &wakelocks_lru_list);
+}
+
+static inline void wakelocks_lru_most_recent(struct wakelock *wl)
+{
+	list_move(&wl->lru, &wakelocks_lru_list);
+}
+
+static void wakelocks_gc(void)
+{
+	struct wakelock *wl, *aux;
 	ktime_t now;
-	if (!(lock->flags & WAKE_LOCK_ACTIVE))
-		return;
-	if (get_expired_time(lock, &now))
-		expired = 1;
-	else
-		now = ktime_get();
-	lock->stat.count++;
-	if (expired)
-		lock->stat.expire_count++;
-	duration = ktime_sub(now, lock->stat.last_time);
-	lock->stat.total_time = ktime_add(lock->stat.total_time, duration);
-	if (ktime_to_ns(duration) > ktime_to_ns(lock->stat.max_time))
-		lock->stat.max_time = duration;
-	lock->stat.last_time = ktime_get();
-	if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) {
-		duration = ktime_sub(now, last_sleep_time_update);
-		lock->stat.prevent_suspend_time = ktime_add(
-			lock->stat.prevent_suspend_time, duration);
-		lock->flags &= ~WAKE_LOCK_PREVENTING_SUSPEND;
-	}
-}
 
-static void update_sleep_wait_stats_locked(int done)
-{
-	struct wake_lock *lock;
-	ktime_t now, etime, elapsed, add;
-	int expired;
+	if (++wakelocks_gc_count <= WL_GC_COUNT_MAX)
+		return;
 
 	now = ktime_get();
-	elapsed = ktime_sub(now, last_sleep_time_update);
-	list_for_each_entry(lock, &active_wake_locks[WAKE_LOCK_SUSPEND], link) {
-		expired = get_expired_time(lock, &etime);
-		if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) {
-			if (expired)
-				add = ktime_sub(etime, last_sleep_time_update);
+	list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
+		u64 idle_time_ns;
+		bool active;
+
+		spin_lock_irq(&wl->ws.lock);
+		idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
+		active = wl->ws.active;
+		spin_unlock_irq(&wl->ws.lock);
+
+		if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
+			break;
+
+		if (!active) {
+			wakeup_source_remove(&wl->ws);
+			rb_erase(&wl->node, &wakelocks_tree);
+			list_del(&wl->lru);
+			kfree(wl->name);
+			kfree(wl);
+			decrement_wakelocks_number();
+		}
+	}
+	wakelocks_gc_count = 0;
+}
+#else /* !CONFIG_PM_WAKELOCKS_GC */
+static inline void wakelocks_lru_add(struct wakelock *wl) {}
+static inline void wakelocks_lru_most_recent(struct wakelock *wl) {}
+static inline void wakelocks_gc(void) {}
+#endif /* !CONFIG_PM_WAKELOCKS_GC */
+
+static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
+					    bool add_if_not_found)
+{
+	struct rb_node **node = &wakelocks_tree.rb_node;
+	struct rb_node *parent = *node;
+	struct wakelock *wl;
+
+	while (*node) {
+		int diff;
+
+		parent = *node;
+		wl = rb_entry(*node, struct wakelock, node);
+		diff = strncmp(name, wl->name, len);
+		if (diff == 0) {
+			if (wl->name[len])
+				diff = -1;
 			else
-				add = elapsed;
-			lock->stat.prevent_suspend_time = ktime_add(
-				lock->stat.prevent_suspend_time, add);
+				return wl;
 		}
-		if (done || expired)
-			lock->flags &= ~WAKE_LOCK_PREVENTING_SUSPEND;
+		if (diff < 0)
+			node = &(*node)->rb_left;
 		else
-			lock->flags |= WAKE_LOCK_PREVENTING_SUSPEND;
+			node = &(*node)->rb_right;
 	}
-	last_sleep_time_update = now;
-}
-#endif
+	if (!add_if_not_found)
+		return ERR_PTR(-EINVAL);
 
+	if (wakelocks_limit_exceeded())
+		return ERR_PTR(-ENOSPC);
 
-static void expire_wake_lock(struct wake_lock *lock)
-{
-#ifdef CONFIG_WAKELOCK_STAT
-	wake_unlock_stat_locked(lock, 1);
-#endif
-	lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
-	list_del(&lock->link);
-	list_add(&lock->link, &inactive_locks);
-	if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE))
-		pr_info("expired wake lock %s\n", lock->name);
-}
+	/* Not found, we have to add a new one. */
+	wl = kzalloc(sizeof(*wl), GFP_KERNEL);
+	if (!wl)
+		return ERR_PTR(-ENOMEM);
 
-/* Caller must acquire the list_lock spinlock */
-static void print_active_locks(int type)
-{
-	struct wake_lock *lock;
-	bool print_expired = true;
-
-	BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
-	list_for_each_entry(lock, &active_wake_locks[type], link) {
-		if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
-			long timeout = lock->expires - jiffies;
-			if (timeout > 0)
-				pr_info("active wake lock %s, time left %ld\n",
-					lock->name, timeout);
-			else if (print_expired)
-				pr_info("wake lock %s, expired\n", lock->name);
-		} else {
-			pr_info("active wake lock %s\n", lock->name);
-			if (!(debug_mask & DEBUG_EXPIRE))
-				print_expired = false;
-		}
+	wl->name = kstrndup(name, len, GFP_KERNEL);
+	if (!wl->name) {
+		kfree(wl);
+		return ERR_PTR(-ENOMEM);
 	}
+	wl->ws.name = wl->name;
+	wakeup_source_add(&wl->ws);
+	rb_link_node(&wl->node, parent, node);
+	rb_insert_color(&wl->node, &wakelocks_tree);
+	wakelocks_lru_add(wl);
+	increment_wakelocks_number();
+	return wl;
 }
 
-static long has_wake_lock_locked(int type)
+int pm_wake_lock(const char *buf)
 {
-	struct wake_lock *lock, *n;
-	long max_timeout = 0;
+	const char *str = buf;
+	struct wakelock *wl;
+	u64 timeout_ns = 0;
+	size_t len;
+	int ret = 0;
 
-	BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
-	list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {
-		if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
-			long timeout = lock->expires - jiffies;
-			if (timeout <= 0)
-				expire_wake_lock(lock);
-			else if (timeout > max_timeout)
-				max_timeout = timeout;
-		} else
-			return -1;
+	while (*str && !isspace(*str))
+		str++;
+
+	len = str - buf;
+	if (!len)
+		return -EINVAL;
+
+	if (*str && *str != '\n') {
+		/* Find out if there's a valid timeout string appended. */
+		ret = kstrtou64(skip_spaces(str), 10, &timeout_ns);
+		if (ret)
+			return -EINVAL;
 	}
-	return max_timeout;
-}
 
-long has_wake_lock(int type)
-{
-	long ret;
-	unsigned long irqflags;
-	spin_lock_irqsave(&list_lock, irqflags);
-	ret = has_wake_lock_locked(type);
-	if (ret && (debug_mask & DEBUG_WAKEUP) && type == WAKE_LOCK_SUSPEND)
-		print_active_locks(type);
-	spin_unlock_irqrestore(&list_lock, irqflags);
+	mutex_lock(&wakelocks_lock);
+
+	wl = wakelock_lookup_add(buf, len, true);
+	if (IS_ERR(wl)) {
+		ret = PTR_ERR(wl);
+		goto out;
+	}
+	if (timeout_ns) {
+		u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;
+
+		do_div(timeout_ms, NSEC_PER_MSEC);
+		__pm_wakeup_event(&wl->ws, timeout_ms);
+	} else {
+		__pm_stay_awake(&wl->ws);
+	}
+
+	wakelocks_lru_most_recent(wl);
+
+ out:
+	mutex_unlock(&wakelocks_lock);
 	return ret;
 }
 
-static void suspend_sys_sync(struct work_struct *work)
+int pm_wake_unlock(const char *buf)
 {
-	if (debug_mask & DEBUG_SUSPEND)
-		pr_info("PM: Syncing filesystems...\n");
+	struct wakelock *wl;
+	size_t len;
+	int ret = 0;
 
-	sys_sync();
+	len = strlen(buf);
+	if (!len)
+		return -EINVAL;
 
-	if (debug_mask & DEBUG_SUSPEND)
-		pr_info("sync done.\n");
+	if (buf[len-1] == '\n')
+		len--;
 
-	spin_lock(&suspend_sys_sync_lock);
-	suspend_sys_sync_count--;
-	spin_unlock(&suspend_sys_sync_lock);
-}
-static DECLARE_WORK(suspend_sys_sync_work, suspend_sys_sync);
+	if (!len)
+		return -EINVAL;
 
-void suspend_sys_sync_queue(void)
-{
-	int ret;
+	mutex_lock(&wakelocks_lock);
 
-	spin_lock(&suspend_sys_sync_lock);
-	ret = queue_work(suspend_sys_sync_work_queue, &suspend_sys_sync_work);
-	if (ret)
-		suspend_sys_sync_count++;
-	spin_unlock(&suspend_sys_sync_lock);
-}
-
-static bool suspend_sys_sync_abort;
-static void suspend_sys_sync_handler(unsigned long);
-static DEFINE_TIMER(suspend_sys_sync_timer, suspend_sys_sync_handler, 0, 0);
-/* value should be less then half of input event wake lock timeout value
- * which is currently set to 5*HZ (see drivers/input/evdev.c)
- */
-#define SUSPEND_SYS_SYNC_TIMEOUT (HZ/4)
-static void suspend_sys_sync_handler(unsigned long arg)
-{
-	if (suspend_sys_sync_count == 0) {
-		complete(&suspend_sys_sync_comp);
-	} else if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
-		suspend_sys_sync_abort = true;
-		complete(&suspend_sys_sync_comp);
-	} else {
-		mod_timer(&suspend_sys_sync_timer, jiffies +
-				SUSPEND_SYS_SYNC_TIMEOUT);
+	wl = wakelock_lookup_add(buf, len, false);
+	if (IS_ERR(wl)) {
+		ret = PTR_ERR(wl);
+		goto out;
 	}
-}
+	__pm_relax(&wl->ws);
 
-int suspend_sys_sync_wait(void)
-{
-	suspend_sys_sync_abort = false;
+	wakelocks_lru_most_recent(wl);
+	wakelocks_gc();
 
-	if (suspend_sys_sync_count != 0) {
-		mod_timer(&suspend_sys_sync_timer, jiffies +
-				SUSPEND_SYS_SYNC_TIMEOUT);
-		wait_for_completion(&suspend_sys_sync_comp);
-	}
-	if (suspend_sys_sync_abort) {
-		pr_info("suspend aborted....while waiting for sys_sync\n");
-		return -EAGAIN;
-	}
-
-	return 0;
-}
-
-static void suspend_backoff(void)
-{
-	pr_info("suspend: too many immediate wakeups, back off\n");
-	wake_lock_timeout(&suspend_backoff_lock,
-			  msecs_to_jiffies(SUSPEND_BACKOFF_INTERVAL));
-}
-
-static void suspend(struct work_struct *work)
-{
-	int ret;
-	int entry_event_num;
-	struct timespec ts_entry, ts_exit;
-
-	if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
-		if (debug_mask & DEBUG_SUSPEND)
-			pr_info("suspend: abort suspend\n");
-		return;
-	}
-
-	entry_event_num = current_event_num;
-	suspend_sys_sync_queue();
-	if (debug_mask & DEBUG_SUSPEND)
-		pr_info("suspend: enter suspend\n");
-	getnstimeofday(&ts_entry);
-	ret = pm_suspend(requested_suspend_state);
-	getnstimeofday(&ts_exit);
-
-	if (debug_mask & DEBUG_EXIT_SUSPEND) {
-		struct rtc_time tm;
-		rtc_time_to_tm(ts_exit.tv_sec, &tm);
-		pr_info("suspend: exit suspend, ret = %d "
-			"(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
-			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-			tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);
-	}
-
-	if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {
-		++suspend_short_count;
-
-		if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {
-			suspend_backoff();
-			suspend_short_count = 0;
-		}
-	} else {
-		suspend_short_count = 0;
-	}
-
-	if (current_event_num == entry_event_num) {
-		if (debug_mask & DEBUG_SUSPEND)
-			pr_info("suspend: pm_suspend returned with no event\n");
-		wake_lock_timeout(&unknown_wakeup, HZ / 2);
-	}
-}
-static DECLARE_WORK(suspend_work, suspend);
-
-static void expire_wake_locks(unsigned long data)
-{
-	long has_lock;
-	unsigned long irqflags;
-	if (debug_mask & DEBUG_EXPIRE)
-		pr_info("expire_wake_locks: start\n");
-	spin_lock_irqsave(&list_lock, irqflags);
-	if (debug_mask & DEBUG_SUSPEND)
-		print_active_locks(WAKE_LOCK_SUSPEND);
-	has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
-	if (debug_mask & DEBUG_EXPIRE)
-		pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);
-	if (has_lock == 0)
-		queue_work(suspend_work_queue, &suspend_work);
-	spin_unlock_irqrestore(&list_lock, irqflags);
-}
-static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
-
-static int power_suspend_late(struct device *dev)
-{
-	int ret = has_wake_lock(WAKE_LOCK_SUSPEND) ? -EAGAIN : 0;
-#ifdef CONFIG_WAKELOCK_STAT
-	wait_for_wakeup = !ret;
-#endif
-	if (debug_mask & DEBUG_SUSPEND)
-		pr_info("power_suspend_late return %d\n", ret);
+ out:
+	mutex_unlock(&wakelocks_lock);
 	return ret;
 }
-
-static struct dev_pm_ops power_driver_pm_ops = {
-	.suspend_noirq = power_suspend_late,
-};
-
-static struct platform_driver power_driver = {
-	.driver.name = "power",
-	.driver.pm = &power_driver_pm_ops,
-};
-static struct platform_device power_device = {
-	.name = "power",
-};
-
-void wake_lock_init(struct wake_lock *lock, int type, const char *name)
-{
-	unsigned long irqflags = 0;
-
-	if (name)
-		lock->name = name;
-	BUG_ON(!lock->name);
-
-	if (debug_mask & DEBUG_WAKE_LOCK)
-		pr_info("wake_lock_init name=%s\n", lock->name);
-#ifdef CONFIG_WAKELOCK_STAT
-	lock->stat.count = 0;
-	lock->stat.expire_count = 0;
-	lock->stat.wakeup_count = 0;
-	lock->stat.total_time = ktime_set(0, 0);
-	lock->stat.prevent_suspend_time = ktime_set(0, 0);
-	lock->stat.max_time = ktime_set(0, 0);
-	lock->stat.last_time = ktime_set(0, 0);
-#endif
-	lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
-
-	INIT_LIST_HEAD(&lock->link);
-	spin_lock_irqsave(&list_lock, irqflags);
-	list_add(&lock->link, &inactive_locks);
-	spin_unlock_irqrestore(&list_lock, irqflags);
-}
-EXPORT_SYMBOL(wake_lock_init);
-
-void wake_lock_destroy(struct wake_lock *lock)
-{
-	unsigned long irqflags;
-	if (debug_mask & DEBUG_WAKE_LOCK)
-		pr_info("wake_lock_destroy name=%s\n", lock->name);
-	spin_lock_irqsave(&list_lock, irqflags);
-	lock->flags &= ~WAKE_LOCK_INITIALIZED;
-#ifdef CONFIG_WAKELOCK_STAT
-	if (lock->stat.count) {
-		deleted_wake_locks.stat.count += lock->stat.count;
-		deleted_wake_locks.stat.expire_count += lock->stat.expire_count;
-		deleted_wake_locks.stat.total_time =
-			ktime_add(deleted_wake_locks.stat.total_time,
-				  lock->stat.total_time);
-		deleted_wake_locks.stat.prevent_suspend_time =
-			ktime_add(deleted_wake_locks.stat.prevent_suspend_time,
-				  lock->stat.prevent_suspend_time);
-		deleted_wake_locks.stat.max_time =
-			ktime_add(deleted_wake_locks.stat.max_time,
-				  lock->stat.max_time);
-	}
-#endif
-	list_del(&lock->link);
-	spin_unlock_irqrestore(&list_lock, irqflags);
-}
-EXPORT_SYMBOL(wake_lock_destroy);
-
-static void wake_lock_internal(
-	struct wake_lock *lock, long timeout, int has_timeout)
-{
-	int type;
-	unsigned long irqflags;
-	long expire_in;
-
-	spin_lock_irqsave(&list_lock, irqflags);
-	type = lock->flags & WAKE_LOCK_TYPE_MASK;
-	BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
-	BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
-#ifdef CONFIG_WAKELOCK_STAT
-	if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
-		if (debug_mask & DEBUG_WAKEUP)
-			pr_info("wakeup wake lock: %s\n", lock->name);
-		wait_for_wakeup = 0;
-		lock->stat.wakeup_count++;
-	}
-	if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
-	    (long)(lock->expires - jiffies) <= 0) {
-		wake_unlock_stat_locked(lock, 0);
-		lock->stat.last_time = ktime_get();
-	}
-#endif
-	if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
-		lock->flags |= WAKE_LOCK_ACTIVE;
-#ifdef CONFIG_WAKELOCK_STAT
-		lock->stat.last_time = ktime_get();
-#endif
-	}
-	list_del(&lock->link);
-	if (has_timeout) {
-		if (debug_mask & DEBUG_WAKE_LOCK)
-			pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
-				lock->name, type, timeout / HZ,
-				(timeout % HZ) * MSEC_PER_SEC / HZ);
-		lock->expires = jiffies + timeout;
-		lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
-		list_add_tail(&lock->link, &active_wake_locks[type]);
-	} else {
-		if (debug_mask & DEBUG_WAKE_LOCK)
-			pr_info("wake_lock: %s, type %d\n", lock->name, type);
-		lock->expires = LONG_MAX;
-		lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
-		list_add(&lock->link, &active_wake_locks[type]);
-	}
-	if (type == WAKE_LOCK_SUSPEND) {
-		current_event_num++;
-#ifdef CONFIG_WAKELOCK_STAT
-		if (lock == &main_wake_lock)
-			update_sleep_wait_stats_locked(1);
-		else if (!wake_lock_active(&main_wake_lock))
-			update_sleep_wait_stats_locked(0);
-#endif
-		if (has_timeout)
-			expire_in = has_wake_lock_locked(type);
-		else
-			expire_in = -1;
-		if (expire_in > 0) {
-			if (debug_mask & DEBUG_EXPIRE)
-				pr_info("wake_lock: %s, start expire timer, "
-					"%ld\n", lock->name, expire_in);
-			mod_timer(&expire_timer, jiffies + expire_in);
-		} else {
-			if (del_timer(&expire_timer))
-				if (debug_mask & DEBUG_EXPIRE)
-					pr_info("wake_lock: %s, stop expire timer\n",
-						lock->name);
-			if (expire_in == 0)
-				queue_work(suspend_work_queue, &suspend_work);
-		}
-	}
-	spin_unlock_irqrestore(&list_lock, irqflags);
-}
-
-void wake_lock(struct wake_lock *lock)
-{
-	wake_lock_internal(lock, 0, 0);
-}
-EXPORT_SYMBOL(wake_lock);
-
-void wake_lock_timeout(struct wake_lock *lock, long timeout)
-{
-	wake_lock_internal(lock, timeout, 1);
-}
-EXPORT_SYMBOL(wake_lock_timeout);
-
-void wake_unlock(struct wake_lock *lock)
-{
-	int type;
-	unsigned long irqflags;
-	spin_lock_irqsave(&list_lock, irqflags);
-	type = lock->flags & WAKE_LOCK_TYPE_MASK;
-#ifdef CONFIG_WAKELOCK_STAT
-	wake_unlock_stat_locked(lock, 0);
-#endif
-	if (debug_mask & DEBUG_WAKE_LOCK)
-		pr_info("wake_unlock: %s\n", lock->name);
-	lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
-	list_del(&lock->link);
-	list_add(&lock->link, &inactive_locks);
-	if (type == WAKE_LOCK_SUSPEND) {
-		long has_lock = has_wake_lock_locked(type);
-		if (has_lock > 0) {
-			if (debug_mask & DEBUG_EXPIRE)
-				pr_info("wake_unlock: %s, start expire timer, "
-					"%ld\n", lock->name, has_lock);
-			mod_timer(&expire_timer, jiffies + has_lock);
-		} else {
-			if (del_timer(&expire_timer))
-				if (debug_mask & DEBUG_EXPIRE)
-					pr_info("wake_unlock: %s, stop expire "
-						"timer\n", lock->name);
-			if (has_lock == 0)
-				queue_work(suspend_work_queue, &suspend_work);
-		}
-		if (lock == &main_wake_lock) {
-			if (debug_mask & DEBUG_SUSPEND)
-				print_active_locks(WAKE_LOCK_SUSPEND);
-#ifdef CONFIG_WAKELOCK_STAT
-			update_sleep_wait_stats_locked(0);
-#endif
-		}
-	}
-	spin_unlock_irqrestore(&list_lock, irqflags);
-}
-EXPORT_SYMBOL(wake_unlock);
-
-int wake_lock_active(struct wake_lock *lock)
-{
-	return !!(lock->flags & WAKE_LOCK_ACTIVE);
-}
-EXPORT_SYMBOL(wake_lock_active);
-
-static int wakelock_stats_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, wakelock_stats_show, NULL);
-}
-
-static const struct file_operations wakelock_stats_fops = {
-	.owner = THIS_MODULE,
-	.open = wakelock_stats_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int __init wakelocks_init(void)
-{
-	int ret;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
-		INIT_LIST_HEAD(&active_wake_locks[i]);
-
-#ifdef CONFIG_WAKELOCK_STAT
-	wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
-			"deleted_wake_locks");
-#endif
-	wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
-	wake_lock(&main_wake_lock);
-	wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
-	wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND,
-		       "suspend_backoff");
-
-	ret = platform_device_register(&power_device);
-	if (ret) {
-		pr_err("wakelocks_init: platform_device_register failed\n");
-		goto err_platform_device_register;
-	}
-	ret = platform_driver_register(&power_driver);
-	if (ret) {
-		pr_err("wakelocks_init: platform_driver_register failed\n");
-		goto err_platform_driver_register;
-	}
-
-	INIT_COMPLETION(suspend_sys_sync_comp);
-	suspend_sys_sync_work_queue =
-		create_singlethread_workqueue("suspend_sys_sync");
-	if (suspend_sys_sync_work_queue == NULL) {
-		ret = -ENOMEM;
-		goto err_suspend_sys_sync_work_queue;
-	}
-
-	suspend_work_queue = create_singlethread_workqueue("suspend");
-	if (suspend_work_queue == NULL) {
-		ret = -ENOMEM;
-		goto err_suspend_work_queue;
-	}
-
-#ifdef CONFIG_WAKELOCK_STAT
-	proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
-#endif
-
-	return 0;
-
-err_suspend_work_queue:
-err_suspend_sys_sync_work_queue:
-	platform_driver_unregister(&power_driver);
-err_platform_driver_register:
-	platform_device_unregister(&power_device);
-err_platform_device_register:
-	wake_lock_destroy(&suspend_backoff_lock);
-	wake_lock_destroy(&unknown_wakeup);
-	wake_lock_destroy(&main_wake_lock);
-#ifdef CONFIG_WAKELOCK_STAT
-	wake_lock_destroy(&deleted_wake_locks);
-#endif
-	return ret;
-}
-
-static void  __exit wakelocks_exit(void)
-{
-#ifdef CONFIG_WAKELOCK_STAT
-	remove_proc_entry("wakelocks", NULL);
-#endif
-	destroy_workqueue(suspend_work_queue);
-	destroy_workqueue(suspend_sys_sync_work_queue);
-	platform_driver_unregister(&power_driver);
-	platform_device_unregister(&power_device);
-	wake_lock_destroy(&suspend_backoff_lock);
-	wake_lock_destroy(&unknown_wakeup);
-	wake_lock_destroy(&main_wake_lock);
-#ifdef CONFIG_WAKELOCK_STAT
-	wake_lock_destroy(&deleted_wake_locks);
-#endif
-}
-
-core_initcall(wakelocks_init);
-module_exit(wakelocks_exit);
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index b0f118e..2f194e9 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -133,8 +133,8 @@
 	cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), work_buf);
 }
 
-DEFINE_MUTEX(stop_cpus_mutex);
 /* static data for stop_cpus */
+static DEFINE_MUTEX(stop_cpus_mutex);
 static DEFINE_PER_CPU(struct cpu_stop_work, stop_cpus_work);
 
 static void queue_stop_cpus_work(const struct cpumask *cpumask,
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 50f73be..7ffcc1b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -543,7 +543,6 @@
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 	conn->conn_valid = true;
 	spin_lock_init(&conn->lock);
-	wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle");
 
 	switch (type) {
 	case ACL_LINK:
@@ -621,7 +620,6 @@
 
 	/* Make sure no timers are running */
 	del_timer(&conn->idle_timer);
-	wake_lock_destroy(&conn->idle_lock);
 	del_timer(&conn->disc_timer);
 	del_timer(&conn->smp_timer);
 	__cancel_delayed_work(&conn->rssi_update_work);
@@ -1082,7 +1080,6 @@
 		if (conn->conn_valid) {
 			mod_timer(&conn->idle_timer,
 				jiffies + msecs_to_jiffies(hdev->idle_timeout));
-			wake_lock(&conn->idle_lock);
 		}
 		spin_unlock_bh(&conn->lock);
 	}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 198773c..d243646 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2596,9 +2596,6 @@
 			else
 				conn->power_save = 0;
 		}
-		if (conn->mode == HCI_CM_SNIFF)
-			if (wake_lock_active(&conn->idle_lock))
-				wake_unlock(&conn->idle_lock);
 
 		if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
 			hci_sco_setup(conn, ev->status);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index d778ae3..83087d1 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -201,7 +201,7 @@
 		l2cap_pi(sk)->mode, sk->sk_state);
 
 	if (!addr || alen < sizeof(addr->sa_family) ||
-	    addr->sa_family != AF_BLUETOOTH)
+		addr->sa_family != AF_BLUETOOTH)
 		return -EINVAL;
 
 	memset(&la, 0, sizeof(la));
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 5190c0b..b57532d 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -736,7 +736,6 @@
 		}
 #if IS_ENABLED(CONFIG_IPV6)
 		else if (skb->protocol == htons(ETH_P_IPV6)) {
-			struct neighbour *neigh = dst_get_neighbour(skb_dst(skb));
 			const struct in6_addr *addr6;
 			struct neighbour *neigh;
 			bool do_tx_error_icmp;
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 291934b..a00a904 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -69,3 +69,4 @@
 obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
 
 obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
+
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index ab7bd2c..0cb86ce 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1991,49 +1991,6 @@
 }
 EXPORT_SYMBOL(tcp_v4_destroy_sock);
 
-/*
- * tcp_v4_nuke_addr - destroy all sockets on the given local address
- */
-void tcp_v4_nuke_addr(__u32 saddr)
-{
-	unsigned int bucket;
-
-	for (bucket = 0; bucket < tcp_hashinfo.ehash_mask; bucket++) {
-		struct hlist_nulls_node *node;
-		struct sock *sk;
-		spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
-
-restart:
-		spin_lock_bh(lock);
-		sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
-			struct inet_sock *inet = inet_sk(sk);
-
-			if (inet->inet_rcv_saddr != saddr)
-				continue;
-			if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
-				continue;
-			if (sock_flag(sk, SOCK_DEAD))
-				continue;
-
-			sock_hold(sk);
-			spin_unlock_bh(lock);
-
-			local_bh_disable();
-			bh_lock_sock(sk);
-			sk->sk_err = ETIMEDOUT;
-			sk->sk_error_report(sk);
-
-			tcp_done(sk);
-			bh_unlock_sock(sk);
-			local_bh_enable();
-			sock_put(sk);
-
-			goto restart;
-		}
-		spin_unlock_bh(lock);
-	}
-}
-
 #ifdef CONFIG_PROC_FS
 /* Proc filesystem TCP sock list dumping. */
 
diff --git a/net/wireless/util.c b/net/wireless/util.c
index a448b80..017d4fc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1038,6 +1038,7 @@
 		if (!found)
 			return -EINVAL;
 	}
+
 	/*
 	 * mask must have at least one bit set here since we
 	 * didn't accept a 0-length rates array nor allowed
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 4636247..7403b40 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1534,6 +1534,20 @@
 	err = substream->ops->ioctl(substream, cmd, arg);
 	return err;
 }
+
+static int snd_user_ioctl(struct snd_pcm_substream *substream,
+			  unsigned int cmd, void __user *arg)
+{
+	struct snd_pcm_runtime *runtime;
+	int err = 0;
+
+	if (PCM_RUNTIME_CHECK(substream))
+		return -ENXIO;
+	runtime = substream->runtime;
+	err = substream->ops->ioctl(substream, cmd, arg);
+	return err;
+}
+
 /*
  * drop ioctl
  *
@@ -2605,6 +2619,9 @@
 	case SNDRV_COMPRESS_TSTAMP:
 	case SNDRV_COMPRESS_DRAIN:
 		return snd_compressed_ioctl(substream, cmd, arg);
+	default:
+		if (((cmd >> 8) & 0xff) == 'U')
+			return snd_user_ioctl(substream, cmd, arg);
 	}
 	snd_printd("unknown ioctl = 0x%x\n", cmd);
 	return -ENOTTY;
@@ -2788,10 +2805,12 @@
 				  unsigned long arg)
 {
 	struct snd_pcm_file *pcm_file;
+	unsigned char ioctl_magic;
 
 	pcm_file = file->private_data;
+	ioctl_magic = ((cmd >> 8) & 0xff);
 
-	if ((((cmd >> 8) & 0xff) != 'A') && (((cmd >> 8) & 0xff) != 'C'))
+	if (ioctl_magic != 'A' && ioctl_magic != 'C' && ioctl_magic != 'U')
 		return -ENOTTY;
 
 	return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index a09dab3..f0cd026 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -52,7 +52,7 @@
 snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
 snd-soc-cs8427-objs := cs8427.o
 snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o wcd9xxx-common.o
-snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o
+snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o wcd9xxx-common.o
 snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 25d3f56..634493b 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -18,6 +18,8 @@
 #include <linux/printk.h>
 #include <linux/ratelimit.h>
 #include <linux/debugfs.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
 #include <linux/mfd/wcd9xxx/core.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9xxx/wcd9306_registers.h>
@@ -34,6 +36,20 @@
 #include <linux/gpio.h>
 #include "wcd9306.h"
 #include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
+
+static atomic_t kp_tapan_priv;
+static int spkr_drv_wrnd_param_set(const char *val,
+				   const struct kernel_param *kp);
+static int spkr_drv_wrnd = 1;
+
+static struct kernel_param_ops spkr_drv_wrnd_param_ops = {
+	.set = spkr_drv_wrnd_param_set,
+	.get = param_get_int,
+};
+module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
+MODULE_PARM_DESC(spkr_drv_wrnd,
+	       "Run software workaround to avoid leakage on the speaker drive");
 
 #define WCD9306_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
 			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
@@ -42,10 +58,22 @@
 #define NUM_DECIMATORS 4
 #define NUM_INTERPOLATORS 4
 #define BITS_PER_REG 8
+/* This actual number of TX ports supported in slimbus slave */
 #define TAPAN_TX_PORT_NUMBER	16
 
-#define TAPAN_I2S_MASTER_MODE_MASK 0x08
+/* Nummer of TX ports actually connected from Slimbus slave to codec Digital */
+#define TAPAN_SLIM_CODEC_TX_PORTS 5
 
+#define TAPAN_I2S_MASTER_MODE_MASK 0x08
+#define TAPAN_MCLK_CLK_12P288MHZ 12288000
+#define TAPAN_MCLK_CLK_9P6HZ 9600000
+
+#define TAPAN_SLIM_CLOSE_TIMEOUT 1000
+#define TAPAN_SLIM_IRQ_OVERFLOW (1 << 0)
+#define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
+#define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
+#define TAPAN_MCLK_CLK_12P288MHZ 12288000
+#define TAPAN_MCLK_CLK_9P6HZ 9600000
 enum {
 	AIF1_PB = 0,
 	AIF1_CAP,
@@ -67,8 +95,6 @@
 	RX_MIX1_INP_SEL_RX3,
 	RX_MIX1_INP_SEL_RX4,
 	RX_MIX1_INP_SEL_RX5,
-	RX_MIX1_INP_SEL_RX6,
-	RX_MIX1_INP_SEL_RX7,
 	RX_MIX1_INP_SEL_AUXRX,
 };
 
@@ -97,7 +123,8 @@
 };
 
 enum {
-	COMPANDER_1 = 0,
+	COMPANDER_0,
+	COMPANDER_1,
 	COMPANDER_2,
 	COMPANDER_MAX,
 };
@@ -152,6 +179,11 @@
 	(1 << AIF1_CAP) | (1 << AIF2_CAP),	/* AIF2_CAP */
 };
 
+static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
+	0,	/* AIF1_PB */
+	0,	/* AIF1_CAP */
+};
+
 struct tapan_priv {
 	struct snd_soc_codec *codec;
 	u32 adc_count;
@@ -168,22 +200,82 @@
 	/* num of slim ports required */
 	struct wcd9xxx_codec_dai_data  dai[NUM_CODEC_DAIS];
 
+	/*compander*/
+	int comp_enabled[COMPANDER_MAX];
+	u32 comp_fs[COMPANDER_MAX];
+
 	/* Maintain the status of AUX PGA */
 	int aux_pga_cnt;
 	u8 aux_l_gain;
 	u8 aux_r_gain;
 
+	bool spkr_pa_widget_on;
+
 	/* resmgr module */
 	struct wcd9xxx_resmgr resmgr;
 	/* mbhc module */
 	struct wcd9xxx_mbhc mbhc;
+
+	/* class h specific data */
+	struct wcd9xxx_clsh_cdc_data clsh_d;
 };
 
 static const u32 comp_shift[] = {
+	4, /* Compander 0's clock source is on interpolator 7 */
 	0,
 	2,
 };
 
+static const int comp_rx_path[] = {
+	COMPANDER_1,
+	COMPANDER_1,
+	COMPANDER_2,
+	COMPANDER_2,
+	COMPANDER_2,
+	COMPANDER_2,
+	COMPANDER_0,
+	COMPANDER_MAX,
+};
+
+static const struct comp_sample_dependent_params comp_samp_params[] = {
+	{
+		/* 8 Khz */
+		.peak_det_timeout = 0x02,
+		.rms_meter_div_fact = 0x09,
+		.rms_meter_resamp_fact = 0x06,
+	},
+	{
+		/* 16 Khz */
+		.peak_det_timeout = 0x03,
+		.rms_meter_div_fact = 0x0A,
+		.rms_meter_resamp_fact = 0x0C,
+	},
+	{
+		/* 32 Khz */
+		.peak_det_timeout = 0x05,
+		.rms_meter_div_fact = 0x0B,
+		.rms_meter_resamp_fact = 0x1E,
+	},
+	{
+		/* 48 Khz */
+		.peak_det_timeout = 0x05,
+		.rms_meter_div_fact = 0x0B,
+		.rms_meter_resamp_fact = 0x28,
+	},
+	{
+		/* 96 Khz */
+		.peak_det_timeout = 0x06,
+		.rms_meter_div_fact = 0x0C,
+		.rms_meter_resamp_fact = 0x50,
+	},
+	{
+		/* 192 Khz */
+		.peak_det_timeout = 0x07,
+		.rms_meter_div_fact = 0xD,
+		.rms_meter_resamp_fact = 0xA0,
+	},
+};
+
 static unsigned short rx_digital_gain_reg[] = {
 	TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
 	TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
@@ -198,71 +290,61 @@
 	TAPAN_A_CDC_TX4_VOL_CTL_GAIN,
 };
 
-static int tapan_codec_enable_class_h_clk(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
+static int spkr_drv_wrnd_param_set(const char *val,
+				   const struct kernel_param *kp)
 {
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec;
+	int ret, old;
+	struct tapan_priv *priv;
 
-	dev_dbg(codec->dev, "%s %s  %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, TAPAN_A_CDC_CLSH_B1_CTL, 0x01, 0x01);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_1, 0x80, 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_CDC_CLSH_B1_CTL, 0x01, 0x00);
-		break;
+	priv = (struct tapan_priv *)atomic_read(&kp_tapan_priv);
+	if (!priv) {
+		pr_debug("%s: codec isn't yet registered\n", __func__);
+		return 0;
 	}
+
+	WCD9XXX_BCL_LOCK(&priv->resmgr);
+	old = spkr_drv_wrnd;
+	ret = param_set_int(val, kp);
+	if (ret) {
+		WCD9XXX_BCL_UNLOCK(&priv->resmgr);
+		return ret;
+	}
+
+	codec = priv->codec;
+	dev_dbg(codec->dev, "%s: spkr_drv_wrnd %d -> %d\n",
+			__func__, old, spkr_drv_wrnd);
+	if (old == 0 && spkr_drv_wrnd == 1) {
+		wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
+					   WCD9XXX_BANDGAP_AUDIO_MODE);
+		snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
+	} else if (old == 1 && spkr_drv_wrnd == 0) {
+		wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
+					   WCD9XXX_BANDGAP_AUDIO_MODE);
+		if (!priv->spkr_pa_widget_on)
+			snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
+					    0x00);
+	}
+
+	WCD9XXX_BCL_UNLOCK(&priv->resmgr);
 	return 0;
 }
 
-static int tapan_codec_enable_class_h(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
+static int tapan_get_anc_slot(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = w->codec;
-
-	dev_dbg(codec->dev, "%s %s  %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_5, 0x02, 0x02);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_4, 0xFF, 0xFF);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_1, 0x04, 0x04);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_1, 0x04, 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x04, 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x08, 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_1, 0x80, 0x80);
-		usleep_range(1000, 1000);
-		break;
-	}
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	ucontrol->value.integer.value[0] = tapan->anc_slot;
 	return 0;
 }
 
-static int tapan_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
+static int tapan_put_anc_slot(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_codec *codec = w->codec;
-
-	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, w->reg, 0x01, 0x01);
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_NCP_STATIC, 0x0f, 0x01);
-		break;
-
-	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(1000, 1000);
-		break;
-
-	case SND_SOC_DAPM_PRE_PMD:
-	    snd_soc_update_bits(codec, w->reg, 0x01, 0x00);
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
-		snd_soc_update_bits(codec, TAPAN_A_NCP_STATIC, 0x0f, 0x08);
-		break;
-	}
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	tapan->anc_slot = ucontrol->value.integer.value[0];
 	return 0;
 }
 
@@ -464,6 +546,168 @@
 	return 0;
 }
 
+static int tapan_get_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tapan->comp_enabled[comp];
+	return 0;
+}
+
+static int tapan_set_compander(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	int comp = ((struct soc_multi_mixer_control *)
+		    kcontrol->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+
+	dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n",
+		 __func__, comp, tapan->comp_enabled[comp], value);
+	tapan->comp_enabled[comp] = value;
+	return 0;
+}
+
+static int tapan_config_gain_compander(struct snd_soc_codec *codec,
+				       int comp, bool enable)
+{
+	int ret = 0;
+
+	switch (comp) {
+	case COMPANDER_0:
+		snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_GAIN,
+				    1 << 2, !enable << 2);
+		break;
+	case COMPANDER_1:
+		snd_soc_update_bits(codec, TAPAN_A_RX_HPH_L_GAIN,
+				    1 << 5, !enable << 5);
+		snd_soc_update_bits(codec, TAPAN_A_RX_HPH_R_GAIN,
+				    1 << 5, !enable << 5);
+		break;
+	case COMPANDER_2:
+		snd_soc_update_bits(codec, TAPAN_A_RX_LINE_1_GAIN,
+				    1 << 5, !enable << 5);
+		snd_soc_update_bits(codec, TAPAN_A_RX_LINE_2_GAIN,
+				    1 << 5, !enable << 5);
+		break;
+	default:
+		WARN_ON(1);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void tapan_discharge_comp(struct snd_soc_codec *codec, int comp)
+{
+	/* Update RSM to 1, DIVF to 5 */
+	snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8), 1);
+	snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8), 0xF0,
+			    1 << 5);
+	/* Wait for 1ms */
+	usleep_range(1000, 1000);
+}
+
+static int tapan_config_compander(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	int mask, emask;
+	bool timedout;
+	unsigned long timeout;
+	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	const int comp = w->shift;
+	const u32 rate = tapan->comp_fs[comp];
+	const struct comp_sample_dependent_params *comp_params =
+	    &comp_samp_params[rate];
+
+	dev_dbg(codec->dev, "%s: %s event %d compander %d, enabled %d",
+		__func__, w->name, event, comp, tapan->comp_enabled[comp]);
+
+	if (!tapan->comp_enabled[comp])
+		return 0;
+
+	/* Compander 0 has single channel */
+	mask = (comp == COMPANDER_0 ? 0x01 : 0x03);
+	emask = (comp == COMPANDER_0 ? 0x02 : 0x03);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Set gain source to compander */
+		tapan_config_gain_compander(codec, comp, true);
+		/* Enable RX interpolation path clocks */
+		snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
+				    mask << comp_shift[comp],
+				    mask << comp_shift[comp]);
+
+		tapan_discharge_comp(codec, comp);
+
+		/* Clear compander halt */
+		snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
+					   (comp * 8),
+				    1 << 2, 0);
+		/* Toggle compander reset bits */
+		snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
+				    mask << comp_shift[comp],
+				    mask << comp_shift[comp]);
+		snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
+				    mask << comp_shift[comp], 0);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Set sample rate dependent paramater */
+		snd_soc_update_bits(codec,
+				    TAPAN_A_CDC_COMP0_FS_CFG + (comp * 8),
+				    0x07, rate);
+		snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8),
+			      comp_params->rms_meter_resamp_fact);
+		snd_soc_update_bits(codec,
+				    TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
+				    0x0F, comp_params->peak_det_timeout);
+		snd_soc_update_bits(codec,
+				    TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
+				    0xF0, comp_params->rms_meter_div_fact << 4);
+		/* Compander enable */
+		snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
+				    (comp * 8), emask, emask);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Halt compander */
+		snd_soc_update_bits(codec,
+				    TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
+				    1 << 2, 1 << 2);
+		/* Wait up to a second for shutdown complete */
+		timeout = jiffies + HZ;
+		do {
+			if ((snd_soc_read(codec,
+					  TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS +
+					  (comp * 8)) & mask) == mask)
+				break;
+		} while (!(timedout = time_after(jiffies, timeout)));
+		dev_dbg(codec->dev, "%s: Compander %d shutdown %s in %dms\n",
+			 __func__, comp, timedout ? "timedout" : "completed",
+			 jiffies_to_msecs(timeout - HZ - jiffies));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable compander */
+		snd_soc_update_bits(codec,
+				    TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
+				    emask, 0x00);
+		/* Turn off the clock for compander in pair */
+		snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
+				    mask << comp_shift[comp], 0);
+		/* Set gain source to register */
+		tapan_config_gain_compander(codec, comp, false);
+		break;
+	}
+	return 0;
+}
+
 static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
 static const struct soc_enum tapan_ear_pa_gain_enum[] = {
 		SOC_ENUM_SINGLE_EXT(2, tapan_ear_pa_gain_text),
@@ -498,21 +742,40 @@
 static const struct soc_enum cf_rxmix4_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
 
+static const char * const class_h_dsm_text[] = {
+	"ZERO", "RX_HPHL", "RX_SPKR"
+};
+
+static const struct soc_enum class_h_dsm_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_CLSH_CTL, 2, 3, class_h_dsm_text);
+
+static const struct snd_kcontrol_new class_h_dsm_mux =
+	SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
+
 static const struct snd_kcontrol_new tapan_snd_controls[] = {
 
 	SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
 		tapan_pa_gain_get, tapan_pa_gain_put),
 
-	SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 12, 1,
+	SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 14, 1,
 		line_gain),
-	SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 12, 1,
+	SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 14, 1,
 		line_gain),
 
-	SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 12, 1,
+	SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 14, 1,
 		line_gain),
-	SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 12, 1,
+	SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 14, 1,
 		line_gain),
 
+	SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 7, 1,
+		line_gain),
+
+	SOC_SINGLE_TLV("ADC1 Volume", TAPAN_A_TX_1_EN, 2, 13, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 13, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 13, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 13, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 13, 0, analog_gain),
+
 	SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
 		-84, 40, digital_gain),
 	SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
@@ -540,9 +803,8 @@
 	SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAPAN_A_CDC_IIR1_GAIN_B4_CTL, -84,
 		40, digital_gain),
 
-	SOC_SINGLE("MICBIAS1 CAPLESS Switch", TAPAN_A_MICB_1_CTL, 4, 1, 1),
-	SOC_SINGLE("MICBIAS2 CAPLESS Switch", TAPAN_A_MICB_2_CTL, 4, 1, 1),
-	SOC_SINGLE("MICBIAS3 CAPLESS Switch", TAPAN_A_MICB_3_CTL, 4, 1, 1),
+	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tapan_get_anc_slot,
+		tapan_put_anc_slot),
 
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
@@ -606,11 +868,23 @@
 	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
 	tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
 
+	SOC_SINGLE_EXT("COMP0 Switch", SND_SOC_NOPM, COMPANDER_0, 1, 0,
+		       tapan_get_compander, tapan_set_compander),
+	SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
+		       tapan_get_compander, tapan_set_compander),
+	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
+		       tapan_get_compander, tapan_set_compander),
+
 };
 
-static const char * const rx_mix1_text[] = {
+static const char * const rx_1_2_mix1_text[] = {
 	"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
-		"RX5", "RX6", "RX7"
+		"RX5", "AUXRX", "AUXTX1"
+};
+
+static const char * const rx_3_4_mix1_text[] = {
+	"ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
+		"RX5", "AUXRX", "AUXTX1", "AUXTX2"
 };
 
 static const char * const rx_mix2_text[] = {
@@ -621,86 +895,85 @@
 	"DEM4", "DEM3_INV"
 };
 
-static const char * const rx_rdac7_text[] = {
-	"DEM6", "DEM5_INV"
-};
-
-static const char * const sb_tx1_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC1"
-};
-
-static const char * const sb_tx2_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC2"
+static const char * const sb_tx_1_2_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
+	"RSVD", "RSVD", "RSVD",
+	"DEC1", "DEC2", "DEC3", "DEC4"
 };
 
 static const char * const sb_tx3_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC3"
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
+	"RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
+	"DEC3"
 };
 
 static const char * const sb_tx4_mux_text[] = {
-	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
-		"DEC4"
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
+	"RSVD", "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
+	"DEC4"
 };
 
-static const char * const dec1_mux_text[] = {
-	"ZERO", "DMIC1", "ADC6",
+static const char * const sb_tx5_mux_text[] = {
+	"ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
+	"RSVD", "RSVD", "RSVD",
+	"DEC1"
 };
 
-static const char * const dec2_mux_text[] = {
-	"ZERO", "DMIC2", "ADC5",
+static const char * const dec_1_2_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4",  "ADCMB",
+	"DMIC1", "DMIC2", "DMIC3", "DMIC4"
 };
 
 static const char * const dec3_mux_text[] = {
-	"ZERO", "DMIC3", "ADC4",
+	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
+	"DMIC1", "DMIC2", "DMIC3", "DMIC4",
+	"ANCFBTUNE1"
 };
 
 static const char * const dec4_mux_text[] = {
-	"ZERO", "DMIC4", "ADC3",
+	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
+	"DMIC1", "DMIC2", "DMIC3", "DMIC4",
+	"ANCFBTUNE2"
 };
 
 static const char * const anc_mux_text[] = {
-	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
-		"RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
-};
-
-static const char * const anc1_fb_mux_text[] = {
-	"ZERO", "EAR_HPH_L", "EAR_LINE_1",
+	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5",
+	"RSVD", "RSVD", "RSVD",
+	"DMIC1", "DMIC2", "DMIC3", "DMIC4",
+	"RSVD", "RSVD"
 };
 
 static const char * const iir1_inp1_text[] = {
-	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
-	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4",
+	"RX1", "RX2", "RX3", "RX4", "RX5"
 };
 
 static const struct soc_enum rx_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_1_2_mix1_text);
 
 static const struct soc_enum rx_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_1_2_mix1_text);
 
 static const struct soc_enum rx_mix1_inp3_chain_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_mix1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_1_2_mix1_text);
 
 static const struct soc_enum rx2_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_1_2_mix1_text);
 
 static const struct soc_enum rx2_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_1_2_mix1_text);
 
 static const struct soc_enum rx3_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 0, 13, rx_3_4_mix1_text);
 
 static const struct soc_enum rx3_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 4, 13, rx_3_4_mix1_text);
 
 static const struct soc_enum rx4_mix1_inp1_chain_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 0, 13, rx_3_4_mix1_text);
 
 static const struct soc_enum rx4_mix1_inp2_chain_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 13, rx_3_4_mix1_text);
 
 static const struct soc_enum rx1_mix2_inp1_chain_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
@@ -714,38 +987,52 @@
 static const struct soc_enum rx2_mix2_inp2_chain_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
 
+static const struct soc_enum rx4_mix2_inp1_chain_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 0, 5, rx_mix2_text);
+
+static const struct soc_enum rx4_mix2_inp2_chain_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 3, 5, rx_mix2_text);
+
 static const struct soc_enum rx_rdac5_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
 
-static const struct soc_enum rx_rdac7_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 1, 2, rx_rdac7_text);
-
 static const struct soc_enum sb_tx1_mux_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0, 12,
+					sb_tx_1_2_mux_text);
 
 static const struct soc_enum sb_tx2_mux_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0, 12,
+					sb_tx_1_2_mux_text);
 
 static const struct soc_enum sb_tx3_mux_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0, 11, sb_tx3_mux_text);
 
 static const struct soc_enum sb_tx4_mux_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0, 12, sb_tx4_mux_text);
+
+static const struct soc_enum sb_tx5_mux_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
 
 static const struct soc_enum dec1_mux_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 0, 10, dec_1_2_mux_text);
 
 static const struct soc_enum dec2_mux_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 4, 10, dec_1_2_mux_text);
 
 static const struct soc_enum dec3_mux_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 0, 12, dec3_mux_text);
 
 static const struct soc_enum dec4_mux_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 4, 12, dec4_mux_text);
+
+static const struct soc_enum anc1_mux_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 0, 15, anc_mux_text);
+
+static const struct soc_enum anc2_mux_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 4, 15, anc_mux_text);
 
 static const struct soc_enum iir1_inp1_mux_enum =
-	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_EQ1_B1_CTL, 0, 10, iir1_inp1_text);
 
 static const struct snd_kcontrol_new rx_mix1_inp1_mux =
 	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
@@ -786,6 +1073,12 @@
 static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
 	SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
 
+static const struct snd_kcontrol_new rx4_mix2_inp1_mux =
+	SOC_DAPM_ENUM("RX4 MIX2 INP1 Mux", rx4_mix2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx4_mix2_inp2_mux =
+	SOC_DAPM_ENUM("RX4 MIX2 INP2 Mux", rx4_mix2_inp2_chain_enum);
+
 static const struct snd_kcontrol_new rx_dac5_mux =
 	SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
 
@@ -801,9 +1094,8 @@
 static const struct snd_kcontrol_new sb_tx4_mux =
 	SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
 
-/*static const struct snd_kcontrol_new sb_tx5_mux =
+static const struct snd_kcontrol_new sb_tx5_mux =
 	SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
-*/
 
 static int wcd9306_put_dec_enum(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
@@ -851,23 +1143,17 @@
 	switch (decimator) {
 	case 1:
 	case 2:
+		if ((dec_mux >= 1) && (dec_mux <= 5))
+			adc_dmic_sel = 0x0;
+		else if ((dec_mux >= 6) && (dec_mux <= 9))
+			adc_dmic_sel = 0x1;
+		break;
 	case 3:
 	case 4:
-	case 5:
-	case 6:
-		if (dec_mux == 1)
-			adc_dmic_sel = 0x1;
-		else
+		if ((dec_mux >= 1) && (dec_mux <= 6))
 			adc_dmic_sel = 0x0;
-		break;
-	case 7:
-	case 8:
-	case 9:
-	case 10:
-		if ((dec_mux == 1) || (dec_mux == 2))
+		else if ((dec_mux >= 7) && (dec_mux <= 10))
 			adc_dmic_sel = 0x1;
-		else
-			adc_dmic_sel = 0x0;
 		break;
 	default:
 		pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
@@ -908,6 +1194,12 @@
 static const struct snd_kcontrol_new iir1_inp1_mux =
 	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
 
+static const struct snd_kcontrol_new anc1_mux =
+	SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
+
+static const struct snd_kcontrol_new anc2_mux =
+	SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
+
 static const struct snd_kcontrol_new dac1_switch[] = {
 	SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_EAR_EN, 5, 1, 0)
 };
@@ -915,6 +1207,10 @@
 	SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
 };
 
+static const struct snd_kcontrol_new spk_dac_switch[] = {
+	SOC_DAPM_SINGLE("Switch", TAPAN_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
+};
+
 static const struct snd_kcontrol_new hphl_pa_mix[] = {
 	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
 					7, 1, 0),
@@ -939,15 +1235,6 @@
 					3, 1, 0),
 };
 
-static const struct snd_kcontrol_new lineout3_pa_mix[] = {
-	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
-					2, 1, 0),
-};
-
-static const struct snd_kcontrol_new lineout4_pa_mix[] = {
-	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
-					1, 1, 0),
-};
 
 /* virtual port entries */
 static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
@@ -973,6 +1260,7 @@
 	u32 dai_id = widget->shift;
 	u32 port_id = mixer->shift;
 	u32 enable = ucontrol->value.integer.value[0];
+	u32 vtable = vport_check_table[dai_id];
 
 	dev_dbg(codec->dev, "%s: wname %s cname %s\n",
 		__func__, widget->name,	ucontrol->id.name);
@@ -997,8 +1285,15 @@
 		/* only add to the list if value not set
 		 */
 		if (enable && !(widget->value & 1 << port_id)) {
+			if (tapan_p->intf_type ==
+					WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+				vtable = vport_check_table[dai_id];
+			if (tapan_p->intf_type ==
+					WCD9XXX_INTERFACE_TYPE_I2C)
+				vtable = vport_i2s_check_table[dai_id];
+
 			if (wcd9xxx_tx_vport_validation(
-						vport_check_table[dai_id],
+						vtable,
 						port_id,
 						tapan_p->dai)) {
 				dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
@@ -1009,27 +1304,29 @@
 			widget->value |= 1 << port_id;
 			list_add_tail(&core->tx_chs[port_id].list,
 				      &tapan_p->dai[dai_id].wcd9xxx_ch_list
-				      );
+					      );
 		} else if (!enable && (widget->value & 1 << port_id)) {
 			widget->value &= ~(1 << port_id);
 			list_del_init(&core->tx_chs[port_id].list);
 		} else {
 			if (enable)
-				dev_dbg(codec->dev, "%s: TX%u port is used by this virtual port\n",
+				dev_dbg(codec->dev, "%s: TX%u port is used by\n"
+					"this virtual port\n",
 					__func__, port_id + 1);
 			else
-				dev_dbg(codec->dev, "%s: TX%u port is not used by this virtual port\n",
+				dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
+					"this virtual port\n",
 					__func__, port_id + 1);
 			/* avoid update power function */
 			mutex_unlock(&codec->mutex);
 			return 0;
 		}
 		break;
-	default:
-		pr_err("Unknown AIF %d\n", dai_id);
-		mutex_unlock(&codec->mutex);
-		return -EINVAL;
-	}
+		default:
+			dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
+			mutex_unlock(&codec->mutex);
+			return -EINVAL;
+		}
 	dev_dbg(codec->dev, "%s: name %s sname %s updated value %u shift %d\n",
 		 __func__, widget->name, widget->sname,
 		 widget->value, widget->shift);
@@ -1153,6 +1450,49 @@
 			slim_tx_mixer_get, slim_tx_mixer_put),
 };
 
+static int tapan_codec_enable_adc(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u16 adc_reg;
+	u8 init_bit_shift;
+
+	dev_dbg(codec->dev, "%s(): %s %d\n", __func__, w->name, event);
+
+	if (w->reg == TAPAN_A_TX_1_EN) {
+		init_bit_shift = 7;
+		adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
+	} else if (w->reg == TAPAN_A_TX_2_EN) {
+		init_bit_shift = 6;
+		adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
+	} else if (w->reg == TAPAN_A_TX_3_EN) {
+		init_bit_shift = 6;
+		adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
+	} else if (w->reg == TAPAN_A_TX_4_EN) {
+		init_bit_shift = 7;
+		adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
+	} else if (w->reg == TAPAN_A_TX_5_EN) {
+		init_bit_shift = 6;
+		adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
+	} else {
+		pr_err("%s: Error, invalid adc register\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+				1 << init_bit_shift);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+
+		break;
+	}
+	return 0;
+}
+
 static int tapan_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -1188,6 +1528,7 @@
 		struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 	u16 lineout_gain_reg;
 
 	dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
@@ -1207,15 +1548,21 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
+		wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+						 WCD9XXX_CLSH_STATE_LO,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
+		dev_dbg(codec->dev, "%s: sleeping 3 ms after %s PA turn on\n",
 				__func__, w->name);
-		usleep_range(16000, 16000);
+		usleep_range(3000, 3010);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+		wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+						 WCD9XXX_CLSH_STATE_LO,
+						 WCD9XXX_CLSH_REQ_DISABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
 		break;
 	}
 	return 0;
@@ -1224,7 +1571,22 @@
 static int tapan_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
 				     struct snd_kcontrol *kcontrol, int event)
 {
-	dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
+	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
+	WCD9XXX_BCL_LOCK(&tapan->resmgr);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tapan->spkr_pa_widget_on = true;
+		snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		tapan->spkr_pa_widget_on = false;
+		snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x00);
+		break;
+	}
+	WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
 	return 0;
 }
 
@@ -1239,7 +1601,7 @@
 	unsigned int dmic;
 	int ret;
 
-	ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
+	ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
 	if (ret < 0) {
 		pr_err("%s: Invalid DMIC line on the codec\n", __func__);
 		return -EINVAL;
@@ -1266,17 +1628,6 @@
 			__func__, event,  dmic, *dmic_clk_cnt);
 		break;
 
-	case 5:
-	case 6:
-		dmic_clk_en = 0x01;
-		dmic_clk_cnt = &(tapan->dmic_5_6_clk_cnt);
-		dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B2_CTL;
-
-		dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_5_6_clk_cnt %d\n",
-			__func__, event,  dmic, *dmic_clk_cnt);
-
-		break;
-
 	default:
 		pr_err("%s: Invalid DMIC Selection\n", __func__);
 		return -EINVAL;
@@ -1600,7 +1951,7 @@
 					msecs_to_jiffies(300));
 		}
 		/* apply the digital gain after the decimator is enabled*/
-		if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
+		if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
 			snd_soc_write(codec,
 				  tx_digital_gain_reg[w->shift + offset],
 				  snd_soc_read(codec,
@@ -1628,6 +1979,42 @@
 	return ret;
 }
 
+static int tapan_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+
+	dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+
+		if (spkr_drv_wrnd > 0) {
+			WARN_ON(!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
+				  0x80));
+			snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
+					    0x00);
+		}
+		if (TAPAN_IS_1_0(core->version))
+			snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
+					    0x24, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (TAPAN_IS_1_0(core->version))
+			snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
+					    0x24, 0x24);
+		if (spkr_drv_wrnd > 0) {
+			WARN_ON(!!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
+				   0x80));
+			snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
+					    0x80);
+		}
+		break;
+	}
+	return 0;
+}
+
 static int tapan_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -1685,18 +2072,53 @@
 	}
 	return 0;
 }
-static int tapan_hphr_dac_event(struct snd_soc_dapm_widget *w,
+
+
+static int tapan_hphl_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
 
 	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x02, 0x02);
+		wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_HPHL,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x02, 0x00);
+	}
+	return 0;
+}
+
+static int tapan_hphr_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x04, 0x04);
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_HPHR,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x04, 0x00);
 		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
 		break;
 	}
@@ -1709,14 +2131,17 @@
 	struct snd_soc_codec *codec = w->codec;
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 	enum wcd9xxx_notify_event e_pre_on, e_post_off;
+	u8 req_clsh_state;
 
 	dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
 	if (w->shift == 5) {
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
+		req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
 	} else if (w->shift == 4) {
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+		req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
 	} else {
 		pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
 		return -EINVAL;
@@ -1729,43 +2154,51 @@
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(10000, 10000);
+		wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+						 req_clsh_state,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
 
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_5, 0x02, 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_NCP_STATIC, 0x20, 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x04, 0x04);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x08, 0x00);
 
-		usleep_range(10, 10);
+		usleep_range(5000, 5010);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
 		/* Let MBHC module know PA turned off */
 		wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
 
-		/*
-		 * schedule work is required because at the time HPH PA DAPM
-		 * event callback is called by DAPM framework, CODEC dapm mutex
-		 * would have been locked while snd_soc_jack_report also
-		 * attempts to acquire same lock.
-		 */
+		wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+						 req_clsh_state,
+						 WCD9XXX_CLSH_REQ_DISABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
+
 		dev_dbg(codec->dev, "%s: sleep 10 ms after %s PA disable.\n",
 			 __func__, w->name);
-		usleep_range(5000, 5000);
+		usleep_range(5000, 5010);
 		break;
 	}
 	return 0;
 }
 
+static const struct snd_soc_dapm_widget tapan_dapm_i2s_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("I2S_CLK", TAPAN_A_CDC_CLK_I2S_CTL,
+	4, 0, NULL, 0),
+};
+
 static int tapan_lineout_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 
 	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
+						 WCD9XXX_CLSH_STATE_LO,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
 		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
 		break;
 
@@ -1786,12 +2219,12 @@
 }
 
 static const struct snd_soc_dapm_route audio_i2s_map[] = {
-	{"RX_I2S_CLK", NULL, "CDC_CONN"},
-	{"SLIM RX1", NULL, "RX_I2S_CLK"},
-	{"SLIM RX2", NULL, "RX_I2S_CLK"},
+	{"I2S_CLK", NULL, "CDC_CONN"},
+	{"SLIM RX1", NULL, "I2S_CLK"},
+	{"SLIM RX2", NULL, "I2S_CLK"},
 
-	{"SLIM TX1 MUX", NULL, "TX_I2S_CLK"},
-	{"SLIM TX2 MUX", NULL, "TX_I2S_CLK"},
+	{"SLIM TX1 MUX", NULL, "I2S_CLK"},
+	{"SLIM TX2 MUX", NULL, "I2S_CLK"},
 };
 
 static const struct snd_soc_dapm_route audio_map[] = {
@@ -1806,122 +2239,60 @@
 	{"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
 	{"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
 	{"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
 	/* SLIM_MIXER("AIF2_CAP Mixer"),*/
 	{"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
 	{"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
 	{"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
 	{"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
 	{"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
 	/* SLIM_MIXER("AIF3_CAP Mixer"),*/
 	{"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
 	{"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
 	{"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
 	{"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
 	{"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
 
 	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX1 MUX", "DEC3", "DEC3 MUX"},
+	{"SLIM TX1 MUX", "DEC4", "DEC4 MUX"},
+	{"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
+	{"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
 
+	{"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
 	{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX2 MUX", "DEC3", "DEC3 MUX"},
+	{"SLIM TX2 MUX", "DEC4", "DEC4 MUX"},
+	{"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
+	{"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
 
 	{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
 	{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
 	{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
 	{"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
 	{"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
-	{"SLIM TX3 MUX", "RMIX5", "RX5 MIX1"},
-	{"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
-	{"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
 
 	{"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
+	{"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
+	{"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
 
-	{"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
+	{"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
 	{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
 	{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
 	{"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
 	{"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
-	{"SLIM TX5 MUX", "RMIX5", "RX5 MIX1"},
-	{"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
-	{"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
-
-	{"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
-
-	{"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
-	{"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
-	{"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
-	{"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
-	{"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
-	{"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
-	{"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
-	{"SLIM TX7 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX7 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX7 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX7 MUX", "RMIX4", "RX4 MIX1"},
-	{"SLIM TX7 MUX", "RMIX5", "RX5 MIX1"},
-	{"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
-	{"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
-
-	{"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
-	{"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
-	{"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
-	{"SLIM TX8 MUX", "DEC7", "DEC7 MUX"},
-	{"SLIM TX8 MUX", "DEC8", "DEC8 MUX"},
-	{"SLIM TX8 MUX", "DEC9", "DEC9 MUX"},
-	{"SLIM TX8 MUX", "DEC10", "DEC10 MUX"},
-
-	{"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
-	{"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
-	{"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
-	{"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
-	{"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
-	{"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
-	{"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
-
-	{"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
-	{"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
-	{"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
-	{"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
-	{"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
-	{"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
-	{"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
 
 	/* Earpiece (RX MIX1) */
 	{"EAR", NULL, "EAR PA"},
 	{"EAR PA", NULL, "EAR_PA_MIXER"},
 	{"EAR_PA_MIXER", NULL, "DAC1"},
-	{"DAC1", NULL, "CP"},
-	{"CP", NULL, "CLASS_H_EAR"},
-	{"CLASS_H_EAR", NULL, "CLASS_H_CLK"},
-
-	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
-	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
-	{"ANC", NULL, "ANC1 FB MUX"},
+	{"DAC1", NULL, "RX_BIAS"},
 
 	/* Headset (RX MIX1 and RX MIX2) */
 	{"HEADPHONE", NULL, "HPHL"},
@@ -1929,93 +2300,47 @@
 
 	{"HPHL", NULL, "HPHL_PA_MIXER"},
 	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+	{"HPHL DAC", NULL, "RX_BIAS"},
 
 	{"HPHR", NULL, "HPHR_PA_MIXER"},
 	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
+	{"HPHR DAC", NULL, "RX_BIAS"},
 
-	{"HPHL DAC", NULL, "CP"},
-	{"CP", NULL, "CLASS_H_HPH_L"},
-	{"CLASS_H_HPH_L", NULL, "CLASS_H_CLK"},
-
-	{"HPHR DAC", NULL, "CP"},
-	{"CP", NULL, "CLASS_H_HPH_R"},
-	{"CLASS_H_HPH_R", NULL, "CLASS_H_CLK"},
-
-	{"ANC", NULL, "ANC1 MUX"},
-	{"ANC", NULL, "ANC2 MUX"},
-	{"ANC1 MUX", "ADC1", "ADC1"},
-	{"ANC1 MUX", "ADC2", "ADC2"},
-	{"ANC1 MUX", "ADC3", "ADC3"},
-	{"ANC1 MUX", "ADC4", "ADC4"},
-	{"ANC2 MUX", "ADC1", "ADC1"},
-	{"ANC2 MUX", "ADC2", "ADC2"},
-	{"ANC2 MUX", "ADC3", "ADC3"},
-	{"ANC2 MUX", "ADC4", "ADC4"},
-
-	{"ANC", NULL, "CDC_CONN"},
-
-	{"DAC1", "Switch", "RX1 CHAIN"},
-	{"HPHL DAC", "Switch", "RX1 CHAIN"},
+	{"DAC1", "Switch", "CLASS_H_DSM MUX"},
+	{"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHR DAC", NULL, "RX2 CHAIN"},
 
 	{"LINEOUT1", NULL, "LINEOUT1 PA"},
 	{"LINEOUT2", NULL, "LINEOUT2 PA"},
-	{"LINEOUT3", NULL, "LINEOUT3 PA"},
-	{"LINEOUT4", NULL, "LINEOUT4 PA"},
 	{"SPK_OUT", NULL, "SPK PA"},
 
-	{"LINEOUT1 PA", NULL, "CP"},
 	{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
 	{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
 
-	{"LINEOUT2 PA", NULL, "CP"},
 	{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
 	{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
 
-	{"LINEOUT3 PA", NULL, "CP"},
-	{"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
-	{"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
-
-	{"LINEOUT4 PA", NULL, "CP"},
-	{"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
-	{"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
-
-	{"CP", NULL, "CLASS_H_LINEOUTS_PA"},
-	{"CLASS_H_LINEOUTS_PA", NULL, "CLASS_H_CLK"},
-
 	{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
 
 	{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
-	{"RDAC5 MUX", "DEM4", "RX4 MIX1"},
+	{"RDAC5 MUX", "DEM4", "RX4 MIX2"},
 
-	{"LINEOUT3 DAC", NULL, "RDAC5 MUX"},
-
-	{"LINEOUT2 DAC", NULL, "RX5 MIX1"},
-
-	{"RDAC7 MUX", "DEM5_INV", "RX5 MIX1"},
-	{"RDAC7 MUX", "DEM6", "RX6 MIX1"},
-
-	{"LINEOUT4 DAC", NULL, "RDAC7 MUX"},
+	{"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
 
 	{"SPK PA", NULL, "SPK DAC"},
-	{"SPK DAC", NULL, "RX7 MIX2"},
+	{"SPK DAC", "Switch", "RX4 MIX2"},
+	{"SPK DAC", NULL, "VDD_SPKDRV"},
 
 	{"RX1 CHAIN", NULL, "RX1 MIX2"},
 	{"RX2 CHAIN", NULL, "RX2 MIX2"},
-	{"RX1 CHAIN", NULL, "ANC"},
-	{"RX2 CHAIN", NULL, "ANC"},
+	{"CLASS_H_DSM MUX", "RX_HPHL", "RX1 CHAIN"},
 
-	{"CLASS_H_CLK", NULL, "RX_BIAS"},
 	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
-	{"LINEOUT3 DAC", NULL, "RX_BIAS"},
-	{"LINEOUT4 DAC", NULL, "RX_BIAS"},
-	{"SPK DAC", NULL, "RX_BIAS"},
 
 	{"RX1 MIX1", NULL, "COMP1_CLK"},
 	{"RX2 MIX1", NULL, "COMP1_CLK"},
 	{"RX3 MIX1", NULL, "COMP2_CLK"},
-	{"RX5 MIX1", NULL, "COMP2_CLK"},
 
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
@@ -2026,21 +2351,15 @@
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
 	{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
 	{"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
-	{"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
-	{"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
-	{"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
-	{"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
-	{"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
-	{"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
 	{"RX1 MIX2", NULL, "RX1 MIX1"},
 	{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
 	{"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
 	{"RX2 MIX2", NULL, "RX2 MIX1"},
 	{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
 	{"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
-	{"RX7 MIX2", NULL, "RX7 MIX1"},
-	{"RX7 MIX2", NULL, "RX7 MIX2 INP1"},
-	{"RX7 MIX2", NULL, "RX7 MIX2 INP2"},
+	{"RX4 MIX2", NULL, "RX4 MIX1"},
+	{"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
+	{"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
 
 	/* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
 	{"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
@@ -2048,198 +2367,128 @@
 	{"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
 	{"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
 	{"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
-	{"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
-	{"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
 	/* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
 	{"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
 	{"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
 	{"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
 	{"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
 	{"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
-	{"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
-	{"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
 	/* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
 	{"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
 	{"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
 	{"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
 	{"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
 	{"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
-	{"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
-	{"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
 
 	{"SLIM RX1", NULL, "SLIM RX1 MUX"},
 	{"SLIM RX2", NULL, "SLIM RX2 MUX"},
 	{"SLIM RX3", NULL, "SLIM RX3 MUX"},
 	{"SLIM RX4", NULL, "SLIM RX4 MUX"},
 	{"SLIM RX5", NULL, "SLIM RX5 MUX"},
-	{"SLIM RX6", NULL, "SLIM RX6 MUX"},
-	{"SLIM RX7", NULL, "SLIM RX7 MUX"},
 
 	{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
 	{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
 	{"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
 	{"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
 	{"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
 	{"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
 	{"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
 	{"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
 	{"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
 	{"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
-	{"RX1 MIX1 INP3", "RX6", "SLIM RX6"},
-	{"RX1 MIX1 INP3", "RX7", "SLIM RX7"},
 	{"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
 	{"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
 	{"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
 	{"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
 	{"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX2 MIX1 INP2", "IIR1", "IIR1"},
 	{"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
 	{"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
 	{"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
 	{"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
 	{"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
 	{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
 	{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
 	{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
 	{"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
 	{"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
 	{"RX4 MIX1 INP1", "IIR1", "IIR1"},
 	{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
 	{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
 	{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
 	{"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX4 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX5 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX5 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX5 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX5 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX6 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX6 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX6 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX6 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX7 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
-	{"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
-	{"RX7 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX7 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
-	{"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
-	{"RX7 MIX1 INP2", "IIR1", "IIR1"},
+
 	{"RX1 MIX2 INP1", "IIR1", "IIR1"},
 	{"RX1 MIX2 INP2", "IIR1", "IIR1"},
 	{"RX2 MIX2 INP1", "IIR1", "IIR1"},
 	{"RX2 MIX2 INP2", "IIR1", "IIR1"},
-	{"RX7 MIX2 INP1", "IIR1", "IIR1"},
-	{"RX7 MIX2 INP2", "IIR1", "IIR1"},
+	{"RX4 MIX2 INP1", "IIR1", "IIR1"},
+	{"RX4 MIX2 INP2", "IIR1", "IIR1"},
 
 	/* Decimator Inputs */
+	{"DEC1 MUX", "ADC1", "ADC1"},
+	{"DEC1 MUX", "ADC2", "ADC2"},
+	{"DEC1 MUX", "ADC3", "ADC3"},
+	{"DEC1 MUX", "ADC4", "ADC4"},
 	{"DEC1 MUX", "DMIC1", "DMIC1"},
-	{"DEC1 MUX", "ADC6", "ADC6"},
+	{"DEC1 MUX", "DMIC2", "DMIC2"},
+	{"DEC1 MUX", "DMIC3", "DMIC3"},
+	{"DEC1 MUX", "DMIC4", "DMIC4"},
 	{"DEC1 MUX", NULL, "CDC_CONN"},
+
+	{"DEC2 MUX", "ADC1", "ADC1"},
+	{"DEC2 MUX", "ADC2", "ADC2"},
+	{"DEC2 MUX", "ADC3", "ADC3"},
+	{"DEC2 MUX", "ADC4", "ADC4"},
+	{"DEC2 MUX", "DMIC1", "DMIC1"},
 	{"DEC2 MUX", "DMIC2", "DMIC2"},
-	{"DEC2 MUX", "ADC5", "ADC5"},
+	{"DEC2 MUX", "DMIC3", "DMIC3"},
+	{"DEC2 MUX", "DMIC4", "DMIC4"},
 	{"DEC2 MUX", NULL, "CDC_CONN"},
-	{"DEC3 MUX", "DMIC3", "DMIC3"},
+
+	{"DEC3 MUX", "ADC1", "ADC1"},
+	{"DEC3 MUX", "ADC2", "ADC2"},
+	{"DEC3 MUX", "ADC3", "ADC3"},
 	{"DEC3 MUX", "ADC4", "ADC4"},
+	{"DEC3 MUX", "ADC5", "ADC5"},
+	{"DEC3 MUX", "DMIC1", "DMIC1"},
+	{"DEC3 MUX", "DMIC2", "DMIC2"},
+	{"DEC3 MUX", "DMIC3", "DMIC3"},
+	{"DEC3 MUX", "DMIC4", "DMIC4"},
 	{"DEC3 MUX", NULL, "CDC_CONN"},
-	{"DEC4 MUX", "DMIC4", "DMIC4"},
+
+	{"DEC4 MUX", "ADC1", "ADC1"},
+	{"DEC4 MUX", "ADC2", "ADC2"},
 	{"DEC4 MUX", "ADC3", "ADC3"},
+	{"DEC4 MUX", "ADC4", "ADC4"},
+	{"DEC4 MUX", "ADC5", "ADC5"},
+	{"DEC4 MUX", "DMIC1", "DMIC1"},
+	{"DEC4 MUX", "DMIC2", "DMIC2"},
+	{"DEC4 MUX", "DMIC3", "DMIC3"},
+	{"DEC4 MUX", "DMIC4", "DMIC4"},
 	{"DEC4 MUX", NULL, "CDC_CONN"},
-	{"DEC5 MUX", "DMIC5", "DMIC5"},
-	{"DEC5 MUX", "ADC2", "ADC2"},
-	{"DEC5 MUX", NULL, "CDC_CONN"},
-	{"DEC6 MUX", "DMIC6", "DMIC6"},
-	{"DEC6 MUX", "ADC1", "ADC1"},
-	{"DEC6 MUX", NULL, "CDC_CONN"},
-	{"DEC7 MUX", "DMIC1", "DMIC1"},
-	{"DEC7 MUX", "DMIC6", "DMIC6"},
-	{"DEC7 MUX", "ADC1", "ADC1"},
-	{"DEC7 MUX", "ADC6", "ADC6"},
-	{"DEC7 MUX", NULL, "CDC_CONN"},
-	{"DEC8 MUX", "DMIC2", "DMIC2"},
-	{"DEC8 MUX", "DMIC5", "DMIC5"},
-	{"DEC8 MUX", "ADC2", "ADC2"},
-	{"DEC8 MUX", "ADC5", "ADC5"},
-	{"DEC8 MUX", NULL, "CDC_CONN"},
-	{"DEC9 MUX", "DMIC4", "DMIC4"},
-	{"DEC9 MUX", "DMIC5", "DMIC5"},
-	{"DEC9 MUX", "ADC2", "ADC2"},
-	{"DEC9 MUX", "ADC3", "ADC3"},
-	{"DEC9 MUX", NULL, "CDC_CONN"},
-	{"DEC10 MUX", "DMIC3", "DMIC3"},
-	{"DEC10 MUX", "DMIC6", "DMIC6"},
-	{"DEC10 MUX", "ADC1", "ADC1"},
-	{"DEC10 MUX", "ADC4", "ADC4"},
-	{"DEC10 MUX", NULL, "CDC_CONN"},
 
 	/* ADC Connections */
 	{"ADC1", NULL, "AMIC1"},
@@ -2247,7 +2496,6 @@
 	{"ADC3", NULL, "AMIC3"},
 	{"ADC4", NULL, "AMIC4"},
 	{"ADC5", NULL, "AMIC5"},
-	{"ADC6", NULL, "AMIC6"},
 
 	/* AUX PGA Connections */
 	{"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
@@ -2255,22 +2503,13 @@
 	{"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
 	{"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
 	{"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
-	{"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
 	{"AUX_PGA_Left", NULL, "AMIC5"},
-	{"AUX_PGA_Right", NULL, "AMIC6"},
 
 	{"IIR1", NULL, "IIR1 INP1 MUX"},
 	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
 	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
 	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
 	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
-	{"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
-	{"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
-	{"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
-	{"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
-	{"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
-	{"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
 
 	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
 	{"MIC BIAS1 Internal2", NULL, "LDO_H"},
@@ -2282,7 +2521,6 @@
 	{"MIC BIAS3 Internal1", NULL, "LDO_H"},
 	{"MIC BIAS3 Internal2", NULL, "LDO_H"},
 	{"MIC BIAS3 External", NULL, "LDO_H"},
-	{"MIC BIAS4 External", NULL, "LDO_H"},
 };
 
 static int tapan_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -2313,7 +2551,7 @@
 static int tapan_volatile(struct snd_soc_codec *ssc, unsigned int reg)
 {
 	/* Registers lower than 0x100 are top level registers which can be
-	 * written by the Taiko core driver.
+	 * written by the Tapan core driver.
 	 */
 
 	if ((reg >= TAPAN_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
@@ -2445,6 +2683,40 @@
 
 static int tapan_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
+	u8 val = 0;
+	struct snd_soc_codec *codec = dai->codec;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s\n", __func__);
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* CPU is master */
+		if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			if (dai->id == AIF1_CAP)
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CLK_I2S_CTL,
+					TAPAN_I2S_MASTER_MODE_MASK, 0);
+			else if (dai->id == AIF1_PB)
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CLK_I2S_CTL,
+					TAPAN_I2S_MASTER_MODE_MASK, 0);
+		}
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+	/* CPU is slave */
+		if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			val = TAPAN_I2S_MASTER_MODE_MASK;
+			if (dai->id == AIF1_CAP)
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CLK_I2S_CTL, val, val);
+			else if (dai->id == AIF1_PB)
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CLK_I2S_CTL, val, val);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
 	return 0;
 }
 
@@ -2490,7 +2762,7 @@
 		}
 		list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
 				    list) {
-			dev_dbg(dai->codec->dev, "%s: rx_slot[%d] %d ch->ch_num %d\n",
+			dev_dbg(dai->codec->dev, "%s: rx_slot[%d] %d, ch->ch_num %d\n",
 				 __func__, i, rx_slot[i], ch->ch_num);
 			rx_slot[i++] = ch->ch_num;
 		}
@@ -2524,7 +2796,7 @@
 }
 
 static int tapan_set_interpolator_rate(struct snd_soc_dai *dai,
-	u8 rx_fs_rate_reg_val, u32 sample_rate)
+	u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
 {
 	u32 j;
 	u8 rx_mix1_inp;
@@ -2540,7 +2812,7 @@
 		rx_mix1_inp = ch->port + RX_MIX1_INP_SEL_RX1 -
 			      TAPAN_TX_PORT_NUMBER;
 		if ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
-			(rx_mix1_inp > RX_MIX1_INP_SEL_RX7)) {
+			(rx_mix1_inp > RX_MIX1_INP_SEL_RX5)) {
 			pr_err("%s: Invalid TAPAN_RX%u port. Dai ID is %d\n",
 				__func__,  rx_mix1_inp - 5 , dai->id);
 			return -EINVAL;
@@ -2572,6 +2844,9 @@
 				snd_soc_update_bits(codec, rx_fs_reg,
 						0xE0, rx_fs_rate_reg_val);
 
+				if (comp_rx_path[j] < COMPANDER_MAX)
+					tapan->comp_fs[comp_rx_path[j]]
+					= compander_fs;
 			}
 			if (j <= 2)
 				rx_mix_1_reg_1 += 3;
@@ -2599,7 +2874,7 @@
 		dev_dbg(codec->dev, "%s: dai->id = %d, tx_port = %d",
 			__func__, dai->id, tx_port);
 
-		if ((tx_port < 1) || (tx_port > NUM_DECIMATORS)) {
+		if ((tx_port < 1) || (tx_port > TAPAN_SLIM_CODEC_TX_PORTS)) {
 			pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
 				__func__, tx_port, dai->id);
 			return -EINVAL;
@@ -2610,23 +2885,15 @@
 
 		decimator = 0;
 
-		if ((tx_port >= 1) && (tx_port <= 6)) {
+		tx_port_reg_val =  tx_port_reg_val & 0x0F;
 
-			tx_port_reg_val =  tx_port_reg_val & 0x0F;
-			if (tx_port_reg_val == 0x8)
-				decimator = tx_port;
-
-		} else if ((tx_port >= 7) && (tx_port <= NUM_DECIMATORS)) {
-
-			tx_port_reg_val =  tx_port_reg_val & 0x1F;
-
-			if ((tx_port_reg_val >= 0x8) &&
+		if ((tx_port_reg_val >= 0x8) &&
 			    (tx_port_reg_val <= 0x11)) {
 
 				decimator = (tx_port_reg_val - 0x8) + 1;
-			}
 		}
 
+
 		if (decimator) { /* SLIM_TX port has a DEC as input */
 
 			tx_fs_reg = TAPAN_A_CDC_TX1_CLK_FS_CTL +
@@ -2640,7 +2907,7 @@
 
 		} else {
 			if ((tx_port_reg_val >= 0x1) &&
-			    (tx_port_reg_val <= 0x7)) {
+			    (tx_port_reg_val <= 0x4)) {
 
 				dev_dbg(codec->dev, "%s: RMIX%u going to SLIM TX%u\n",
 					__func__, tx_port_reg_val, tx_port);
@@ -2673,8 +2940,10 @@
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
 {
+	struct snd_soc_codec *codec = dai->codec;
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
 	u8 tx_fs_rate, rx_fs_rate;
+	u32 compander_fs;
 	int ret;
 
 	dev_dbg(dai->codec->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n",
@@ -2685,26 +2954,32 @@
 	case 8000:
 		tx_fs_rate = 0x00;
 		rx_fs_rate = 0x00;
+		compander_fs = COMPANDER_FS_8KHZ;
 		break;
 	case 16000:
 		tx_fs_rate = 0x01;
 		rx_fs_rate = 0x20;
+		compander_fs = COMPANDER_FS_16KHZ;
 		break;
 	case 32000:
 		tx_fs_rate = 0x02;
 		rx_fs_rate = 0x40;
+		compander_fs = COMPANDER_FS_32KHZ;
 		break;
 	case 48000:
 		tx_fs_rate = 0x03;
 		rx_fs_rate = 0x60;
+		compander_fs = COMPANDER_FS_48KHZ;
 		break;
 	case 96000:
 		tx_fs_rate = 0x04;
 		rx_fs_rate = 0x80;
+		compander_fs = COMPANDER_FS_96KHZ;
 		break;
 	case 192000:
 		tx_fs_rate = 0x05;
 		rx_fs_rate = 0xA0;
+		compander_fs = COMPANDER_FS_192KHZ;
 		break;
 	default:
 		pr_err("%s: Invalid sampling rate %d\n", __func__,
@@ -2722,31 +2997,85 @@
 			return ret;
 		}
 
-		if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
-			pr_err("%s: I2C interface not yet supported\n",
-				   __func__);
-		else
-			tapan->dai[dai->id].rate = params_rate(params);
-
+		if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CLK_I2S_CTL,
+					0x20, 0x20);
+				break;
+			case SNDRV_PCM_FORMAT_S32_LE:
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CLK_I2S_CTL,
+					0x20, 0x00);
+				break;
+			default:
+				pr_err("invalid format\n");
+				break;
+			}
+			snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
+					    0x07, tx_fs_rate);
+		} else {
+			tapan->dai[dai->id].rate   = params_rate(params);
+		}
 		break;
 
 	case SNDRV_PCM_STREAM_PLAYBACK:
 		ret = tapan_set_interpolator_rate(dai, rx_fs_rate,
+						  compander_fs,
 						  params_rate(params));
 		if (ret < 0) {
-			pr_err("%s: set decimator rate failed %d\n", __func__,
-				ret);
+			dev_err(codec->dev, "%s: set decimator rate failed %d\n",
+				__func__, ret);
 			return ret;
 		}
-		if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
-			pr_err("%s: I2C interface not yet supported\n",
-				   __func__);
-		else
+		if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CLK_I2S_CTL,
+					0x20, 0x20);
+				break;
+			case SNDRV_PCM_FORMAT_S32_LE:
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CLK_I2S_CTL,
+					0x20, 0x00);
+				break;
+			default:
+				dev_err(codec->dev, "invalid format\n");
+				break;
+			}
+			snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
+					    0x03, (rx_fs_rate >> 0x05));
+		} else {
+			switch (params_format(params)) {
+			case SNDRV_PCM_FORMAT_S16_LE:
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
+					0xFF, 0xAA);
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
+					0xFF, 0x2A);
+				tapan->dai[dai->id].bit_width = 16;
+				break;
+			case SNDRV_PCM_FORMAT_S24_LE:
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
+					0xFF, 0x00);
+				snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
+					0xFF, 0x00);
+				tapan->dai[dai->id].bit_width = 24;
+				break;
+			default:
+				dev_err(codec->dev, "Invalid format\n");
+				break;
+			}
 			tapan->dai[dai->id].rate   = params_rate(params);
-
+		}
 		break;
 	default:
-		pr_err("%s: Invalid stream type %d\n", __func__,
+		dev_err(codec->dev, "%s: Invalid stream type %d\n", __func__,
 			substream->stream);
 		return -EINVAL;
 	}
@@ -2882,6 +3211,38 @@
 	},
 };
 
+static int tapan_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai,
+					  bool up)
+{
+	int ret = 0;
+	struct wcd9xxx_ch *ch;
+
+	if (up) {
+		list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
+			ret = wcd9xxx_get_slave_port(ch->ch_num);
+			if (ret < 0) {
+				pr_debug("%s: Invalid slave port ID: %d\n",
+				       __func__, ret);
+				ret = -EINVAL;
+			} else {
+				set_bit(ret, &dai->ch_mask);
+			}
+		}
+	} else {
+		ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
+					 msecs_to_jiffies(
+						     TAPAN_SLIM_CLOSE_TIMEOUT));
+		if (!ret) {
+			pr_debug("%s: Slim close tx/rx wait timeout\n",
+					 __func__);
+			ret = -ETIMEDOUT;
+		} else {
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
 static int tapan_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
 				     struct snd_kcontrol *kcontrol,
 				     int event)
@@ -2889,7 +3250,7 @@
 	struct wcd9xxx *core;
 	struct snd_soc_codec *codec = w->codec;
 	struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
-	u32  ret = 0;
+	int ret = 0;
 	struct wcd9xxx_codec_dai_data *dai;
 
 	core = dev_get_drvdata(codec->dev->parent);
@@ -2909,6 +3270,7 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
+		(void) tapan_codec_enable_slim_chmask(dai, true);
 		ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
 					      dai->rate, dai->bit_width,
 					      &dai->grph);
@@ -2916,7 +3278,14 @@
 	case SND_SOC_DAPM_POST_PMD:
 		ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
 						dai->grph);
-		usleep_range(15000, 15000);
+		ret = tapan_codec_enable_slim_chmask(dai, false);
+		if (ret < 0) {
+			ret = wcd9xxx_disconnect_port(core,
+						      &dai->wcd9xxx_ch_list,
+						      dai->grph);
+			dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
+				 __func__, ret);
+		}
 		break;
 	}
 	return ret;
@@ -2938,7 +3307,6 @@
 		__func__, w->codec->name);
 	dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
 		__func__, w->codec->num_dai, w->sname);
-
 	/* Execute the callback only if interface type is slimbus */
 	if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		return 0;
@@ -2949,6 +3317,7 @@
 	dai = &tapan_p->dai[w->shift];
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
+		(void) tapan_codec_enable_slim_chmask(dai, true);
 		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
 					      dai->rate, dai->bit_width,
 					      &dai->grph);
@@ -2956,45 +3325,103 @@
 	case SND_SOC_DAPM_POST_PMD:
 		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
 						dai->grph);
+		ret = tapan_codec_enable_slim_chmask(dai, false);
+		if (ret < 0) {
+			ret = wcd9xxx_disconnect_port(core,
+						      &dai->wcd9xxx_ch_list,
+						      dai->grph);
+			dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
+				 __func__, ret);
+		}
 		break;
 	}
 	return ret;
 }
 
+
 static int tapan_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
 
 	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
-
 	case SND_SOC_DAPM_POST_PMU:
+		wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_EAR,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
 
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_5, 0x02, 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_NCP_STATIC, 0x20, 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x04, 0x04);
-		snd_soc_update_bits(codec, TAPAN_A_BUCK_MODE_3, 0x08, 0x00);
+		usleep_range(5000, 5010);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_EAR,
+						 WCD9XXX_CLSH_REQ_DISABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
+		usleep_range(5000, 5010);
+	}
+	return 0;
+}
 
-		usleep_range(5000, 5000);
+static int tapan_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_EAR,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
+		break;
+	}
+
+	return 0;
+}
+
+static int tapan_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u8 reg_val, zoh_mux_val = 0x00;
+
+	dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		reg_val = snd_soc_read(codec, TAPAN_A_CDC_CONN_CLSH_CTL);
+
+		if ((reg_val & 0x30) == 0x10)
+			zoh_mux_val = 0x04;
+		else if ((reg_val & 0x30) == 0x20)
+			zoh_mux_val = 0x08;
+
+		if (zoh_mux_val != 0x00)
+			snd_soc_update_bits(codec,
+					TAPAN_A_CDC_CONN_CLSH_CTL,
+					0x0C, zoh_mux_val);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAPAN_A_CDC_CONN_CLSH_CTL,
+							0x0C, 0x00);
 		break;
 	}
 	return 0;
 }
 
+
 /* Todo: Have seperate dapm widgets for I2S and Slimbus.
  * Might Need to have callbacks registered only for slimbus
  */
 static const struct snd_soc_dapm_widget tapan_dapm_widgets[] = {
-	/*RX stuff */
-	SND_SOC_DAPM_OUTPUT("EAR"),
-
-	SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
-			tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_MIXER("DAC1", TAPAN_A_RX_EAR_EN, 6, 0, dac1_switch,
-		ARRAY_SIZE(dac1_switch)),
 
 	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
 				AIF1_PB, 0, tapan_codec_enable_slimrx,
@@ -3023,51 +3450,61 @@
 	SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
 
-	/* Headphone */
-	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
-	SND_SOC_DAPM_PGA_E("HPHL", TAPAN_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
-		tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER("HPHL DAC", TAPAN_A_RX_HPH_L_DAC_CTL, 7, 0,
-		hphl_switch, ARRAY_SIZE(hphl_switch)),
 
-	SND_SOC_DAPM_PGA_E("HPHR", TAPAN_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
-		tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU |	SND_SOC_DAPM_POST_PMD),
+	/* RX1 MIX1 mux inputs */
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx_mix1_inp3_mux),
 
-	SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAPAN_A_RX_HPH_R_DAC_CTL, 7, 0,
-		tapan_hphr_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/* RX2 MIX1 mux inputs */
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx2_mix1_inp2_mux),
 
-	/* Speaker */
-	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
-	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
-	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+	/* RX3 MIX1 mux inputs */
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx3_mix1_inp2_mux),
 
-	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TAPAN_A_RX_LINE_CNP_EN, 0, 0, NULL,
-			0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TAPAN_A_RX_LINE_CNP_EN, 1, 0, NULL,
-			0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	/* RX4 MIX1 mux inputs */
+	SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp2_mux),
 
-	SND_SOC_DAPM_PGA_E("SPK PA", TAPAN_A_SPKR_DRV_EN, 7, 0 , NULL,
-			   0, tapan_codec_enable_spk_pa, SND_SOC_DAPM_PRE_PMU |
-			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	/* RX1 MIX2 mux inputs */
+	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx1_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+		&rx1_mix2_inp2_mux),
 
-	SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TAPAN_A_RX_LINE_1_DAC_CTL, 7, 0
-		, tapan_lineout_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
-		, tapan_lineout_dac_event,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/* RX2 MIX2 mux inputs */
+	SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx2_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+		&rx2_mix2_inp2_mux),
 
-	SND_SOC_DAPM_DAC_E("SPK DAC", NULL, SND_SOC_NOPM, 0, 0,
-			   tapan_spk_dac_event,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/* RX4 MIX2 mux inputs */
+	SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx4_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+		&rx4_mix2_inp2_mux),
+
 
 	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 
 	SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
 		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
@@ -3078,94 +3515,116 @@
 	SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
 		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX4 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
-		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX5 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
+	SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
 		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 
-	SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
+						NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0,
+						NULL, 0),
 
-	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-		&rx_mix1_inp3_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx2_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx2_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx3_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx3_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-		&rx1_mix2_inp1_mux),
-	SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
-		&rx1_mix2_inp2_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-		&rx2_mix2_inp1_mux),
-	SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
-		&rx2_mix2_inp2_mux),
+	SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
+		&class_h_dsm_mux, tapan_codec_dsm_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
-		&rx_dac5_mux),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_CLK", TAPAN_A_CDC_CLK_OTHR_CTL, 0, 0,
-		tapan_codec_enable_class_h_clk, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAPAN_A_CDC_CLSH_B1_CTL, 4, 0,
-		tapan_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAPAN_A_CDC_CLSH_B1_CTL, 3, 0,
-		tapan_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAPAN_A_CDC_CLSH_B1_CTL, 2, 0,
-		tapan_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_LINEOUTS_PA", SND_SOC_NOPM, 0, 0,
-		tapan_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CP", TAPAN_A_NCP_EN, 0, 0,
-		tapan_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-
+	/* RX Bias */
 	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
 		tapan_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
 
-	/* TX */
+	/*EAR */
+	SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
+			tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_SUPPLY("CDC_CONN", TAPAN_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+	SND_SOC_DAPM_MIXER_E("DAC1", TAPAN_A_RX_EAR_EN, 6, 0, dac1_switch,
+		ARRAY_SIZE(dac1_switch), tapan_codec_ear_dac_event,
+		SND_SOC_DAPM_PRE_PMU),
+
+	/* Headphone Left */
+	SND_SOC_DAPM_PGA_E("HPHL", TAPAN_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
+		tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER_E("HPHL DAC", TAPAN_A_RX_HPH_L_DAC_CTL, 7, 0,
+		hphl_switch, ARRAY_SIZE(hphl_switch), tapan_hphl_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Headphone Right */
+	SND_SOC_DAPM_PGA_E("HPHR", TAPAN_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
+		tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU |	SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAPAN_A_RX_HPH_R_DAC_CTL, 7, 0,
+		tapan_hphr_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* LINEOUT1*/
+	SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TAPAN_A_RX_LINE_1_DAC_CTL, 7, 0
+		, tapan_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TAPAN_A_RX_LINE_CNP_EN, 0, 0, NULL,
+			0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* LINEOUT2*/
+	SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac5_mux),
+
+	SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
+		, tapan_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TAPAN_A_RX_LINE_CNP_EN, 1, 0, NULL,
+			0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* CLASS-D SPK */
+	SND_SOC_DAPM_MIXER_E("SPK DAC", SND_SOC_NOPM, 0, 0,
+		spk_dac_switch, ARRAY_SIZE(spk_dac_switch), tapan_spk_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0 , NULL,
+			   0, tapan_codec_enable_spk_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
+			    tapan_codec_enable_vdd_spkr,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("EAR"),
+	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+
+	/* TX Path*/
+	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
+		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
+		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+
+	SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TAPAN_TX1, 0,
+		&sb_tx1_mux),
+	SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TAPAN_TX2, 0,
+		&sb_tx2_mux),
+	SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TAPAN_TX3, 0,
+		&sb_tx3_mux),
+	SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TAPAN_TX4, 0,
+		&sb_tx4_mux),
+	SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TAPAN_TX5, 0,
+		&sb_tx5_mux),
+
+	SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
 		0),
 
-	SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
-		tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_INPUT("AMIC1"),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
-		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAPAN_A_MICB_1_CTL, 7, 0,
-		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAPAN_A_MICB_1_CTL, 7, 0,
-		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_INPUT("AMIC3"),
-
-	SND_SOC_DAPM_INPUT("AMIC4"),
-
-	SND_SOC_DAPM_INPUT("AMIC5"),
-
+	/* Decimator MUX */
 	SND_SOC_DAPM_MUX_E("DEC1 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
 		&dec1_mux, tapan_codec_enable_dec,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
@@ -3186,6 +3645,54 @@
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
+	SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
+		tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
+		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
+		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
+		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
+		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAPAN_A_MICB_1_CTL, 7, 0,
+		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAPAN_A_MICB_1_CTL, 7, 0,
+		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, TAPAN_A_TX_1_EN, 7, 0,
+		tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, TAPAN_A_TX_2_EN, 7, 0,
+		tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC3"),
+	SND_SOC_DAPM_ADC_E("ADC3", NULL, TAPAN_A_TX_3_EN, 7, 0,
+		tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC4"),
+	SND_SOC_DAPM_ADC_E("ADC4", NULL, TAPAN_A_TX_4_EN, 7, 0,
+		tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC5"),
+	SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
+		tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
 	SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
 		tapan_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
@@ -3225,25 +3732,7 @@
 		AIF3_CAP, 0, tapan_codec_enable_slimtx,
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
-		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
-
-	SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
-		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
-
-	SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
-		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
-
-	SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TAPAN_TX1, 0,
-		&sb_tx1_mux),
-	SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TAPAN_TX2, 0,
-		&sb_tx2_mux),
-	SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TAPAN_TX3, 0,
-		&sb_tx3_mux),
-	SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TAPAN_TX4, 0,
-		&sb_tx4_mux),
-
-	/* Digital Mic Inputs */
+		/* Digital Mic Inputs */
 	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
 		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
@@ -3289,142 +3778,98 @@
 
 	SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
 		lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
-
 };
 
-static unsigned long slimbus_value;
-
 static irqreturn_t tapan_slimbus_irq(int irq, void *data)
 {
 	struct tapan_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
-	int i, j;
+	unsigned long status = 0;
+	int i, j, port_id, k;
+	u32 bit;
 	u8 val;
+	bool tx, cleared;
 
-	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
-		slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
-			TAPAN_SLIM_PGD_PORT_INT_STATUS0 + i);
-		for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
-			val = wcd9xxx_interface_reg_read(codec->control_data,
-				TAPAN_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
-			if (val & 0x1)
-				pr_err_ratelimited(
-				"overflow error on port %x, value %x\n",
-				i*8 + j, val);
-			if (val & 0x2)
-				pr_err_ratelimited(
-				"underflow error on port %x, value %x\n",
-				i*8 + j, val);
+	for (i = TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
+	     i <= TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
+		val = wcd9xxx_interface_reg_read(codec->control_data, i);
+		status |= ((u32)val << (8 * j));
+	}
+
+	for_each_set_bit(j, &status, 32) {
+		tx = (j >= 16 ? true : false);
+		port_id = (tx ? j - 16 : j);
+		val = wcd9xxx_interface_reg_read(codec->control_data,
+					TAPAN_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
+		if (val & TAPAN_SLIM_IRQ_OVERFLOW)
+			pr_err_ratelimited(
+			    "%s: overflow error on %s port %d, value %x\n",
+			    __func__, (tx ? "TX" : "RX"), port_id, val);
+		if (val & TAPAN_SLIM_IRQ_UNDERFLOW)
+			pr_err_ratelimited(
+			    "%s: underflow error on %s port %d, value %x\n",
+			    __func__, (tx ? "TX" : "RX"), port_id, val);
+		if (val & TAPAN_SLIM_IRQ_PORT_CLOSED) {
+			/*
+			 * INT SOURCE register starts from RX to TX
+			 * but port number in the ch_mask is in opposite way
+			 */
+			bit = (tx ? j - 16 : j + 16);
+			dev_dbg(codec->dev, "%s: %s port %d closed value %x, bit %u\n",
+				 __func__, (tx ? "TX" : "RX"), port_id, val,
+				 bit);
+			for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
+				dev_dbg(codec->dev, "%s: priv->dai[%d].ch_mask = 0x%lx\n",
+					 __func__, k, priv->dai[k].ch_mask);
+				if (test_and_clear_bit(bit,
+						       &priv->dai[k].ch_mask)) {
+					cleared = true;
+					if (!priv->dai[k].ch_mask)
+						wake_up(&priv->dai[k].dai_wait);
+					/*
+					 * There are cases when multiple DAIs
+					 * might be using the same slimbus
+					 * channel. Hence don't break here.
+					 */
+				}
+			}
+			WARN(!cleared,
+			     "Couldn't find slimbus %s port %d for closing\n",
+			     (tx ? "TX" : "RX"), port_id);
 		}
 		wcd9xxx_interface_reg_write(codec->control_data,
-			TAPAN_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
-
+					    TAPAN_SLIM_PGD_PORT_INT_CLR_RX_0 +
+					    (j / 8),
+					    1 << (j % 8));
 	}
+
 	return IRQ_HANDLED;
 }
 
-static const struct tapan_reg_mask_val tapan_1_0_class_h_ear[] = {
-
-	/* CLASS-H EAR  IDLE_THRESHOLD Table */
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_IDLE_EAR_THSD, 0x26),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_FCLKONLY_EAR_THSD, 0x2C),
-
-	/* CLASS-H EAR I_PA_FACT Table. */
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_I_PA_FACT_EAR_L,	0xA9),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_I_PA_FACT_EAR_U, 0x07),
-
-	/* CLASS-H EAR Voltage Headroom , Voltage Min. */
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_EAR, 0x0D),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_EAR, 0x3A),
-
-	/* CLASS-H EAR K values --chnages from load. */
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_ADDR, 0x08),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x1B),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x2D),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x36),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x37),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
-	/** end of Ear PA load 32 */
-};
-
-static const struct tapan_reg_mask_val tapan_1_0_class_h_hph[] = {
-
-	/* CLASS-H HPH  IDLE_THRESHOLD Table */
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_IDLE_HPH_THSD, 0x13),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x19),
-
-	/* CLASS-H HPH I_PA_FACT Table */
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_I_PA_FACT_HPH_L, 0x9A),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_I_PA_FACT_HPH_U, 0x06),
-
-	/* CLASS-H HPH Voltage Headroom , Voltage Min */
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_HPH, 0x0D),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_HPH, 0x1D),
-
-	/* CLASS-H HPH K values --chnages from load .*/
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_ADDR, 0x00),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0xAE),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x01),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x1C),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x25),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x27),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_K_DATA, 0x00),
-};
-
-static int tapan_config_ear_class_h(struct snd_soc_codec *codec, u32 ear_load)
-{
-	u32 i;
-
-	if (ear_load  != 32)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(tapan_1_0_class_h_ear); i++)
-		snd_soc_write(codec, tapan_1_0_class_h_ear[i].reg,
-				tapan_1_0_class_h_ear[i].val);
-	return 0;
-}
-
-static int tapan_config_hph_class_h(struct snd_soc_codec *codec, u32 hph_load)
-{
-	u32 i;
-	if (hph_load  != 16)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(tapan_1_0_class_h_hph); i++)
-		snd_soc_write(codec, tapan_1_0_class_h_hph[i].reg,
-				tapan_1_0_class_h_hph[i].val);
-	return 0;
-}
-
 static int tapan_handle_pdata(struct tapan_priv *tapan)
 {
 	struct snd_soc_codec *codec = tapan->codec;
 	struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
 	int k1, k2, k3, rc = 0;
-	u8 leg_mode, txfe_bypass, txfe_buff, flag;
-	u8 value = 0;
+	u8 txfe_bypass = pdata->amic_settings.txfe_enable;
+	u8 txfe_buff = pdata->amic_settings.txfe_buff;
+	u8 flag = pdata->amic_settings.use_pdata;
+	u8 i = 0, j = 0;
+	u8 val_txfe = 0, value = 0;
 
 	if (!pdata) {
-		pr_err("%s: NULL pdata\n", __func__);
+		dev_err(codec->dev, "%s: NULL pdata\n", __func__);
 		rc = -ENODEV;
 		goto done;
 	}
 
-	leg_mode = pdata->amic_settings.legacy_mode;
-	txfe_bypass = pdata->amic_settings.txfe_enable;
-	txfe_buff = pdata->amic_settings.txfe_buff;
-	flag = pdata->amic_settings.use_pdata;
-
 	/* Make sure settings are correct */
 	if ((pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V) ||
 	    (pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
 	    (pdata->micbias.bias2_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
 	    (pdata->micbias.bias3_cfilt_sel > WCD9XXX_CFILT3_SEL)) {
+		dev_err(codec->dev, "%s: Invalid ldoh voltage or bias cfilt\n",
+				__func__);
 		rc = -EINVAL;
 		goto done;
 	}
@@ -3434,6 +3879,9 @@
 	k3 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt3_mv);
 
 	if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
+		dev_err(codec->dev,
+			"%s: could not get K value. k1 = %d k2 = %d k3 = %d\n",
+			__func__, k1, k2, k3);
 		rc = -EINVAL;
 		goto done;
 	}
@@ -3445,19 +3893,34 @@
 	snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_2_VAL, 0xFC, (k2 << 2));
 	snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_3_VAL, 0xFC, (k3 << 2));
 
-	snd_soc_update_bits(codec, TAPAN_A_MICB_1_CTL, 0x60,
-			    (pdata->micbias.bias1_cfilt_sel << 5));
-	snd_soc_update_bits(codec, TAPAN_A_MICB_2_CTL, 0x60,
-			    (pdata->micbias.bias2_cfilt_sel << 5));
-	snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x60,
-			    (pdata->micbias.bias3_cfilt_sel << 5));
+	i = 0;
+	while (i < 5) {
+		if (flag & (0x01 << i)) {
+			val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
+			val_txfe = val_txfe |
+				((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
+			snd_soc_update_bits(codec,
+				TAPAN_A_TX_1_2_TEST_EN + j * 10,
+				0x30, val_txfe);
+		}
+		if (flag & (0x01 << (i + 1))) {
+			val_txfe = (txfe_bypass &
+					(0x01 << (i + 1))) ? 0x02 : 0x00;
+			val_txfe |= (txfe_buff &
+					(0x01 << (i + 1))) ? 0x01 : 0x00;
+			snd_soc_update_bits(codec,
+				TAPAN_A_TX_1_2_TEST_EN + j * 10,
+				0x03, val_txfe);
+		}
+		/* Tapan only has TAPAN_A_TX_1_2_TEST_EN  and
+		   TAPAN_A_TX_4_5_TEST_EN  reg */
 
-	if (flag & 0x40) {
-		value = (leg_mode & 0x40) ? 0x10 : 0x00;
-		value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
-		value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
-		snd_soc_update_bits(codec, TAPAN_A_TX_7_MBHC_EN,
-			0x13, value);
+		if (i == 0) {
+			i = 3;
+			continue;
+		} else if (i == 3) {
+			break;
+		}
 	}
 
 	if (pdata->ocp.use_pdata) {
@@ -3475,8 +3938,16 @@
 			0xE0, (pdata->ocp.hph_ocp_limit << 5));
 	}
 
-	tapan_config_ear_class_h(codec, 32);
-	tapan_config_hph_class_h(codec, 16);
+	/* Set micbias capless mode with tail current */
+	value = (pdata->micbias.bias1_cap_mode == MICBIAS_EXT_BYP_CAP ?
+		 0x00 : 0x10);
+	snd_soc_update_bits(codec, TAPAN_A_MICB_1_CTL, 0x10, value);
+	value = (pdata->micbias.bias2_cap_mode == MICBIAS_EXT_BYP_CAP ?
+		 0x00 : 0x10);
+	snd_soc_update_bits(codec, TAPAN_A_MICB_2_CTL, 0x10, value);
+	value = (pdata->micbias.bias3_cap_mode == MICBIAS_EXT_BYP_CAP ?
+		 0x00 : 0x10);
+	snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x10, value);
 
 done:
 	return rc;
@@ -3484,60 +3955,54 @@
 
 static const struct tapan_reg_mask_val tapan_reg_defaults[] = {
 
-	/* set MCLk to 9.6 */
-	TAPAN_REG_VAL(TAPAN_A_CHIP_CTL, 0x0A),
+	/* enable QFUSE for wcd9306 */
+	TAPAN_REG_VAL(TAPAN_A_QFUSE_CTL, 0x03),
+
+	/* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
+	TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
+
 	TAPAN_REG_VAL(TAPAN_A_CDC_CLK_POWER_CTL, 0x03),
 
 	/* EAR PA deafults  */
 	TAPAN_REG_VAL(TAPAN_A_RX_EAR_CMBUFF, 0x05),
 
-	/** BUCK and NCP defaults for EAR and HS */
-	TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_4, 0x50),
-	TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_1, 0x5B),
-
-	/* CLASS-H defaults for EAR and HS */
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x04),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x01),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x05),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x35),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x30),
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x3B),
-
-	/*
-	 * For CLASS-H, Enable ANC delay buffer,
-	 * set HPHL and EAR PA ref gain to 0 DB.
-	 */
-	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B1_CTL, 0x26),
-
-	/* RX deafults */
-	TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B5_CTL, 0x78),
-	TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B5_CTL, 0x78),
-	TAPAN_REG_VAL(TAPAN_A_CDC_RX3_B5_CTL, 0x78),
-	TAPAN_REG_VAL(TAPAN_A_CDC_RX4_B5_CTL, 0x78),
-
 	/* RX1 and RX2 defaults */
 	TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B6_CTL, 0xA0),
 	TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0xA0),
 
-	/* RX3 to RX7 defaults */
-	TAPAN_REG_VAL(TAPAN_A_CDC_RX3_B6_CTL, 0x80),
-	TAPAN_REG_VAL(TAPAN_A_CDC_RX4_B6_CTL, 0x80),
+	/* Heaset set Right from RX2 */
+	TAPAN_REG_VAL(TAPAN_A_CDC_CONN_RX2_B2_CTL, 0x10),
+
 
 	/*
-	 * The following only need to be written for Taiko 1.0 parts.
-	 * Taiko 2.0 will have appropriate defaults for these registers.
+	 * The following only need to be written for Tapan 1.0 parts.
+	 * Tapan 2.0 will have appropriate defaults for these registers.
 	 */
+
+	/* Required defaults for class H operation */
+	/* borrowed from Taiko class-h */
+	TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0xF4),
+	TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x08),
+	TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
+	TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
+
+	/* TODO: Check below reg writes conflict with above */
+	/* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
+	TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
+	TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x54),
+	TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0x74),
+	TAPAN_REG_VAL(TAPAN_A_RX_BUCK_BIAS1, 0x62),
+
 	/* Choose max non-overlap time for NCP */
 	TAPAN_REG_VAL(TAPAN_A_NCP_CLK, 0xFC),
 	/* Use 25mV/50mV for deltap/m to reduce ripple */
-	TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_VCL_1, 0x08),
+	TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
 	/*
 	 * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
 	 * Note that the other bits of this register will be changed during
 	 * Rx PA bring up.
 	 */
-	TAPAN_REG_VAL(TAPAN_A_BUCK_MODE_3, 0xCE),
+	TAPAN_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
 	/* Reduce HPH DAC bias to 70% */
 	TAPAN_REG_VAL(TAPAN_A_RX_HPH_BIAS_PA, 0x7A),
 	/*Reduce EAR DAC bias to 70% */
@@ -3553,17 +4018,64 @@
 	 */
 	TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
 
+	/* not needed if MBHC is not needed */
 	/* Disable TX7 internal biasing path which can cause leakage */
 	TAPAN_REG_VAL(TAPAN_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
 };
 
+static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
+
+	TAPAN_REG_VAL(TAPAN_A_TX_7_MBHC_EN, 0x6C),
+	TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_4, 0x51),
+	TAPAN_REG_VAL(TAPAN_A_RX_HPH_CNP_WG_CTL, 0xDA),
+	TAPAN_REG_VAL(TAPAN_A_RX_EAR_CNP, 0xC0),
+	TAPAN_REG_VAL(TAPAN_A_RX_LINE_1_TEST, 0x02),
+	TAPAN_REG_VAL(TAPAN_A_RX_LINE_2_TEST, 0x02),
+	TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_OCP_CTL, 0x97),
+	TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_CLIP_DET, 0x01),
+	TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_IEC, 0x00),
+	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B1_CTL, 0xE4),
+	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x00),
+	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x00),
+	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
+	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_EAR, 0x00),
+	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_HPH, 0x00),
+	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_EAR, 0x00),
+	TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_HPH, 0x00),
+};
+
+static const struct tapan_reg_mask_val tapan_1_0_reg_defaults[] = {
+	/* Close leakage on the spkdrv */
+	TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_PWRSTG, 0x24),
+	TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_DAC, 0xE5),
+
+};
+
 static void tapan_update_reg_defaults(struct snd_soc_codec *codec)
 {
 	u32 i;
+	struct wcd9xxx *tapan_core = dev_get_drvdata(codec->dev->parent);
+
+	if (!TAPAN_IS_1_0(tapan_core->version)) {
+		for (i = 0; i < ARRAY_SIZE(tapan_2_x_reg_reset_values); i++)
+			snd_soc_write(codec, tapan_2_x_reg_reset_values[i].reg,
+				tapan_2_x_reg_reset_values[i].val);
+	}
 
 	for (i = 0; i < ARRAY_SIZE(tapan_reg_defaults); i++)
 		snd_soc_write(codec, tapan_reg_defaults[i].reg,
 				tapan_reg_defaults[i].val);
+
+	if (TAPAN_IS_1_0(tapan_core->version)) {
+		for (i = 0; i < ARRAY_SIZE(tapan_1_0_reg_defaults); i++)
+			snd_soc_write(codec, tapan_1_0_reg_defaults[i].reg,
+				tapan_1_0_reg_defaults[i].val);
+	}
+
+	if (!TAPAN_IS_1_0(tapan_core->version))
+		spkr_drv_wrnd = -1;
+	else if (spkr_drv_wrnd == 1)
+		snd_soc_write(codec, TAPAN_A_SPKR_DRV_EN, 0xEF);
 }
 
 static const struct tapan_reg_mask_val tapan_codec_reg_init_val[] = {
@@ -3578,17 +4090,27 @@
 	{TAPAN_A_RX_HPH_R_GAIN, 0x20, 0x20},
 	{TAPAN_A_RX_LINE_1_GAIN, 0x20, 0x20},
 	{TAPAN_A_RX_LINE_2_GAIN, 0x20, 0x20},
+	{TAPAN_A_SPKR_DRV_GAIN, 0x04, 0x04},
+
+	/*  Set RDAC5 MUX to take input from DEM3_INV.
+	 *  This sets LO2 DAC to get input from DEM3_INV
+	 *  for LO1 and LO2 to work as differential outputs.
+	 */
+	{TAPAN_A_CDC_CONN_MISC, 0x04, 0x04},
 
 	/* CLASS H config */
 	{TAPAN_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
 
-	/* Use 16 bit sample size for TX1 to TX6 */
+	/* Use 16 bit sample size for TX1 to TX5 */
 	{TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
 	{TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
 	{TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
 	{TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
 	{TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
 
+	/* Disable SPK SWITCH */
+	{TAPAN_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
+
 	/* Use 16 bit sample size for RX */
 	{TAPAN_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
 	{TAPAN_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
@@ -3607,8 +4129,14 @@
 
 	/* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
 	{TAPAN_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
-	{TAPAN_A_CDC_CLK_DMIC_B2_CTL, 0x0E, 0x02},
 
+	/* Compander zone selection */
+	{TAPAN_A_CDC_COMP0_B4_CTL, 0x3F, 0x37},
+	{TAPAN_A_CDC_COMP1_B4_CTL, 0x3F, 0x37},
+	{TAPAN_A_CDC_COMP2_B4_CTL, 0x3F, 0x37},
+	{TAPAN_A_CDC_COMP0_B5_CTL, 0x7F, 0x7F},
+	{TAPAN_A_CDC_COMP1_B5_CTL, 0x7F, 0x7F},
+	{TAPAN_A_CDC_COMP2_B5_CTL, 0x7F, 0x7F},
 };
 
 static void tapan_codec_init_reg(struct snd_soc_codec *codec)
@@ -3684,6 +4212,10 @@
 
 	snd_soc_codec_set_drvdata(codec, tapan);
 
+	/* TODO: Read buck voltage from DT property */
+	tapan->clsh_d.buck_mv = WCD9XXX_CDC_BUCK_MV_1P8;
+	wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
+
 	/* codec resmgr module init */
 	wcd9xxx = codec->control_data;
 	pdata = dev_get_platdata(codec->dev->parent);
@@ -3691,28 +4223,44 @@
 				  &tapan_reg_address);
 	if (ret) {
 		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
-		goto err_codec;
+		return ret;
 	}
 
-	/* init and start mbhc */
-	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec);
-	if (ret) {
-		pr_err("%s: mbhc init failed %d\n", __func__, ret);
-		goto err_codec;
-	}
+	/* TODO: wcd9xxx_mbhc_init to enable mbhc */
 
 	tapan->codec = codec;
-
+	for (i = 0; i < COMPANDER_MAX; i++) {
+		tapan->comp_enabled[i] = 0;
+		tapan->comp_fs[i] = COMPANDER_FS_48KHZ;
+	}
 	tapan->intf_type = wcd9xxx_get_intf_type();
 	tapan->aux_pga_cnt = 0;
 	tapan->aux_l_gain = 0x1F;
 	tapan->aux_r_gain = 0x1F;
 	tapan_update_reg_defaults(codec);
+
+	dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
+			__func__, wcd9xxx->mclk_rate);
+
+	if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
+		snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
+		snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
+				0x01);
+	} else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6HZ) {
+		snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
+	}
 	tapan_codec_init_reg(codec);
 	ret = tapan_handle_pdata(tapan);
 	if (IS_ERR_VALUE(ret)) {
-		pr_err("%s: bad pdata\n", __func__);
-		goto err_codec;
+		dev_err(codec->dev, "%s: bad pdata\n", __func__);
+		goto err_pdata;
+	}
+
+	if (spkr_drv_wrnd > 0) {
+		WCD9XXX_BCL_LOCK(&tapan->resmgr);
+		wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
+					   WCD9XXX_BANDGAP_AUDIO_MODE);
+		WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
 	}
 
 	ptr = kmalloc((sizeof(tapan_rx_chs) +
@@ -3724,8 +4272,12 @@
 	}
 
 	if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
-		pr_err("%s: I2C interface not supported yet\n",
-			   __func__);
+		snd_soc_dapm_new_controls(dapm, tapan_dapm_i2s_widgets,
+			ARRAY_SIZE(tapan_dapm_i2s_widgets));
+		snd_soc_dapm_add_routes(dapm, audio_i2s_map,
+			ARRAY_SIZE(audio_i2s_map));
+		for (i = 0; i < ARRAY_SIZE(tapan_i2s_dai); i++)
+			INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
 	} else if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
 		for (i = 0; i < NUM_CODEC_DAIS; i++) {
 			INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
@@ -3744,12 +4296,14 @@
 
 	(void) tapan_setup_irqs(tapan);
 
+	atomic_set(&kp_tapan_priv, (unsigned long)tapan);
+
 	codec->ignore_pmdown_time = 1;
 	return ret;
 
-err_nomem_slimch:
+err_pdata:
 	kfree(ptr);
-err_codec:
+err_nomem_slimch:
 	kfree(tapan);
 	return ret;
 }
@@ -3758,6 +4312,13 @@
 {
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 
+	WCD9XXX_BCL_LOCK(&tapan->resmgr);
+	atomic_set(&kp_tapan_priv, 0);
+
+	if (spkr_drv_wrnd > 0)
+		wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
+					   WCD9XXX_BANDGAP_AUDIO_MODE);
+	WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
 	/* cleanup MBHC */
 	wcd9xxx_mbhc_deinit(&tapan->mbhc);
 	/* cleanup resmgr */
@@ -3801,6 +4362,7 @@
 	struct platform_device *pdev = to_platform_device(dev);
 	struct tapan_priv *tapan = platform_get_drvdata(pdev);
 	dev_dbg(dev, "%s: system resume\n", __func__);
+	/* Notify */
 	wcd9xxx_resmgr_notifier_call(&tapan->resmgr, WCD9XXX_EVENT_POST_RESUME);
 	return 0;
 }
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index af268bd..78d1749 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -38,6 +38,9 @@
 #include "wcd9xxx-resmgr.h"
 #include "wcd9xxx-common.h"
 
+#define TAIKO_MAD_SLIMBUS_TX_PORT 12
+#define TAIKO_MAD_AUDIO_FIRMWARE_PATH "wcd9320/wcd9320_mad_audio.bin"
+
 static atomic_t kp_taiko_priv;
 static int spkr_drv_wrnd_param_set(const char *val,
 				   const struct kernel_param *kp);
@@ -47,6 +50,121 @@
 	.set = spkr_drv_wrnd_param_set,
 	.get = param_get_int,
 };
+
+static struct afe_param_slimbus_slave_port_cfg taiko_slimbus_slave_port_cfg = {
+	.minor_version = 1,
+	.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1,
+	.slave_dev_pgd_la = 0,
+	.slave_dev_intfdev_la = 0,
+	.bit_width = 16,
+	.data_format = 0,
+	.num_channels = 1
+};
+
+enum {
+	RESERVED = 0,
+	AANC_LPF_FF_FB = 1,
+	AANC_LPF_COEFF_MSB,
+	AANC_LPF_COEFF_LSB,
+	HW_MAD_AUDIO_ENABLE,
+	HW_MAD_ULTR_ENABLE,
+	HW_MAD_BEACON_ENABLE,
+	HW_MAD_AUDIO_SLEEP_TIME,
+	HW_MAD_ULTR_SLEEP_TIME,
+	HW_MAD_BEACON_SLEEP_TIME,
+	HW_MAD_TX_AUDIO_SWITCH_OFF,
+	HW_MAD_TX_ULTR_SWITCH_OFF,
+	HW_MAD_TX_BEACON_SWITCH_OFF,
+	MAD_AUDIO_INT_DEST_SELECT_REG,
+	MAD_ULT_INT_DEST_SELECT_REG,
+	MAD_BEACON_INT_DEST_SELECT_REG,
+	MAD_CLIP_INT_DEST_SELECT_REG,
+	MAD_VBAT_INT_DEST_SELECT_REG,
+	MAD_AUDIO_INT_MASK_REG,
+	MAD_ULT_INT_MASK_REG,
+	MAD_BEACON_INT_MASK_REG,
+	MAD_CLIP_INT_MASK_REG,
+	MAD_VBAT_INT_MASK_REG,
+	MAD_AUDIO_INT_STATUS_REG,
+	MAD_ULT_INT_STATUS_REG,
+	MAD_BEACON_INT_STATUS_REG,
+	MAD_CLIP_INT_STATUS_REG,
+	MAD_VBAT_INT_STATUS_REG,
+	MAD_AUDIO_INT_CLEAR_REG,
+	MAD_ULT_INT_CLEAR_REG,
+	MAD_BEACON_INT_CLEAR_REG,
+	MAD_CLIP_INT_CLEAR_REG,
+	MAD_VBAT_INT_CLEAR_REG,
+	SB_PGD_PORT_TX_WATERMARK_n,
+	SB_PGD_PORT_TX_ENABLE_n,
+	SB_PGD_PORT_RX_WATERMARK_n,
+	SB_PGD_PORT_RX_ENABLE_n,
+	MAX_CFG_REGISTERS,
+};
+
+static struct afe_param_cdc_reg_cfg mad_audio_reg_cfg[] = {
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_MAIN_CTL_1),
+		HW_MAD_AUDIO_ENABLE, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_AUDIO_CTL_3),
+		HW_MAD_AUDIO_SLEEP_TIME, 0xF, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_MAD_AUDIO_CTL_4),
+		HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_DESTN3),
+		MAD_AUDIO_INT_DEST_SELECT_REG, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_MASK3),
+		MAD_AUDIO_INT_MASK_REG, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_STATUS3),
+		MAD_AUDIO_INT_STATUS_REG, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_CLEAR3),
+		MAD_AUDIO_INT_CLEAR_REG, 0x1, 8, 0
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_WATERMARK_n, 0x1E, 8, 0x1
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_ENABLE_n, 0x1, 8, 0x1
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_WATERMARK_n, 0x1E, 8, 0x1
+	},
+	{
+		1,
+		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_ENABLE_n, 0x1, 8, 0x1
+	}
+};
+
+static struct afe_param_cdc_reg_cfg_data taiko_mad_audio_reg_cfg = {
+	.num_registers = ARRAY_SIZE(mad_audio_reg_cfg),
+	.reg_data = mad_audio_reg_cfg,
+};
+
 module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
 MODULE_PARM_DESC(spkr_drv_wrnd,
 	       "Run software workaround to avoid leakage on the speaker drive");
@@ -83,6 +201,8 @@
 	AIF2_CAP,
 	AIF3_PB,
 	AIF3_CAP,
+	AIF4_VIFEED,
+	AIF4_MAD_TX,
 	NUM_CODEC_DAIS,
 };
 
@@ -236,6 +356,8 @@
 
 	bool spkr_pa_widget_on;
 
+	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
+
 	/* resmgr module */
 	struct wcd9xxx_resmgr resmgr;
 	/* mbhc module */
@@ -1554,6 +1676,9 @@
 static const struct snd_kcontrol_new lineout4_ground_switch =
 	SOC_DAPM_SINGLE("Switch", TAIKO_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
 
+static const struct snd_kcontrol_new aif4_mad_switch =
+	SOC_DAPM_SINGLE("Switch", TAIKO_A_CDC_CLK_OTHR_CTL, 4, 1, 0);
+
 /* virtual port entries */
 static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
 			     struct snd_ctl_elem_value *ucontrol)
@@ -2154,6 +2279,108 @@
 	return 0;
 }
 
+static int taiko_codec_config_mad(struct snd_soc_codec *codec)
+{
+	int ret;
+	const struct firmware *fw;
+	struct mad_audio_cal *mad_cal;
+	const char *filename = TAIKO_MAD_AUDIO_FIRMWARE_PATH;
+
+	pr_debug("%s: enter\n", __func__);
+	ret = request_firmware(&fw, filename, codec->dev);
+	if (ret != 0) {
+		pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename,
+		       ret);
+		return -ENODEV;
+	}
+
+	if (fw->size < sizeof(struct mad_audio_cal)) {
+		pr_err("%s: incorrect firmware size %u\n", __func__, fw->size);
+		release_firmware(fw);
+		return -ENOMEM;
+	}
+
+	mad_cal = (struct mad_audio_cal *)(fw->data);
+	if (!mad_cal) {
+		pr_err("%s: Invalid calibration data\n", __func__);
+		release_firmware(fw);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_MAD,
+			    0x0F, mad_cal->microphone_info.input_microphone);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_MAIN_CTL_2,
+		      mad_cal->microphone_info.cycle_time);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_MAIN_CTL_1, 0xFF << 3,
+			    ((uint16_t)mad_cal->microphone_info.settle_time)
+			    << 3);
+
+	/* Audio */
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_8,
+		      mad_cal->audio_info.rms_omit_samples);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_1,
+			    0x07 << 4, mad_cal->audio_info.rms_comp_time << 4);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_2, 0x03 << 2,
+			    mad_cal->audio_info.detection_mechanism << 2);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_7,
+		      mad_cal->audio_info.rms_diff_threshold & 0x3F);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_5,
+		      mad_cal->audio_info.rms_threshold_lsb);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_AUDIO_CTL_6,
+		      mad_cal->audio_info.rms_threshold_msb);
+
+
+	/* Beacon */
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_8,
+		      mad_cal->beacon_info.rms_omit_samples);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_1,
+			    0x07 << 4, mad_cal->beacon_info.rms_comp_time);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_2, 0x03 << 2,
+			    mad_cal->beacon_info.detection_mechanism << 2);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_7,
+		      mad_cal->beacon_info.rms_diff_threshold & 0x1F);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_5,
+		      mad_cal->beacon_info.rms_threshold_lsb);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_BEACON_CTL_6,
+		      mad_cal->beacon_info.rms_threshold_msb);
+
+	/* Ultrasound */
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_BEACON_CTL_1,
+			    0x07 << 4, mad_cal->beacon_info.rms_comp_time);
+	snd_soc_update_bits(codec, TAIKO_A_CDC_MAD_ULTR_CTL_2, 0x03 << 2,
+			    mad_cal->ultrasound_info.detection_mechanism);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_7,
+		      mad_cal->ultrasound_info.rms_diff_threshold & 0x1F);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_5,
+		      mad_cal->ultrasound_info.rms_threshold_lsb);
+	snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_6,
+		      mad_cal->ultrasound_info.rms_threshold_msb);
+
+	release_firmware(fw);
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+
+	return ret;
+}
+
+static int taiko_codec_enable_mad(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	int ret = 0;
+
+	pr_debug("%s %d\n", __func__, event);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = taiko_codec_config_mad(codec);
+		if (ret) {
+			pr_err("%s: Failed to config MAD\n", __func__);
+			break;
+		}
+		break;
+	}
+	return ret;
+}
+
 static int taiko_codec_enable_micbias(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -2563,12 +2790,12 @@
 
 	pr_debug("%s: %s event = %d\n", __func__, w->name, event);
 	if (w->shift == 5) {
-		e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
-		e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
-		req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
-	} else if (w->shift == 4) {
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+		req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
+	} else if (w->shift == 4) {
+		e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
+		e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
 		req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
 	} else {
 		pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
@@ -2671,6 +2898,12 @@
 	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
 	{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
 	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
+	{"AIF4 VI", NULL, "SPK_OUT"},
+
+	/* MAD */
+	{"AIF4 MAD", NULL, "CDC_CONN"},
+	{"MADONOFF", "Switch", "MADINPUT"},
+	{"AIF4 MAD", NULL, "MADONOFF"},
 
 	/* SLIM_MIXER("AIF1_CAP Mixer"),*/
 	{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
@@ -3143,6 +3376,7 @@
 	{"MIC BIAS3 Internal2", NULL, "LDO_H"},
 	{"MIC BIAS3 External", NULL, "LDO_H"},
 	{"MIC BIAS4 External", NULL, "LDO_H"},
+
 };
 
 static int taiko_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -3181,6 +3415,8 @@
 
 static int taiko_volatile(struct snd_soc_codec *ssc, unsigned int reg)
 {
+	int i;
+
 	/* Registers lower than 0x100 are top level registers which can be
 	 * written by the Taiko core driver.
 	 */
@@ -3219,6 +3455,11 @@
 		return 1;
 	}
 
+	for (i = 0; i < ARRAY_SIZE(mad_audio_reg_cfg); i++)
+		if (mad_audio_reg_cfg[i].reg_logical_addr -
+		    TAIKO_REGISTER_START_OFFSET == reg)
+			return 1;
+
 	return 0;
 }
 
@@ -3367,6 +3608,7 @@
 				unsigned int rx_num, unsigned int *rx_slot)
 
 {
+	struct wcd9xxx_codec_dai_data *dai_data = NULL;
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(dai->codec);
 	struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
 	if (!tx_slot && !rx_slot) {
@@ -3378,9 +3620,18 @@
 		 __func__, dai->name, dai->id, tx_num, rx_num,
 		 taiko->intf_type);
 
-	if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+	if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
 		wcd9xxx_init_slimslave(core, core->slim->laddr,
-				       tx_num, tx_slot, rx_num, rx_slot);
+					   tx_num, tx_slot, rx_num, rx_slot);
+		/*Reserve tx11 and tx12 for VI feedback path*/
+		dai_data = &taiko->dai[AIF4_VIFEED];
+		if (dai_data) {
+			list_add_tail(&core->tx_chs[TAIKO_TX11].list,
+			&dai_data->wcd9xxx_ch_list);
+			list_add_tail(&core->tx_chs[TAIKO_TX12].list,
+			&dai_data->wcd9xxx_ch_list);
+		}
+	}
 	return 0;
 }
 
@@ -3414,6 +3665,8 @@
 	case AIF1_CAP:
 	case AIF2_CAP:
 	case AIF3_CAP:
+	case AIF4_VIFEED:
+	case AIF4_MAD_TX:
 		if (!tx_slot || !tx_num) {
 			pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
 				 __func__, (u32) tx_slot, (u32) tx_num);
@@ -3639,12 +3892,14 @@
 
 	switch (substream->stream) {
 	case SNDRV_PCM_STREAM_CAPTURE:
-		ret = taiko_set_decimator_rate(dai, tx_fs_rate,
-					       params_rate(params));
-		if (ret < 0) {
-			pr_err("%s: set decimator rate failed %d\n", __func__,
-				ret);
-			return ret;
+		if (dai->id != AIF4_VIFEED) {
+			ret = taiko_set_decimator_rate(dai, tx_fs_rate,
+							   params_rate(params));
+			if (ret < 0) {
+				pr_err("%s: set decimator rate failed %d\n",
+					__func__, ret);
+				return ret;
+			}
 		}
 
 		if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
@@ -3828,6 +4083,34 @@
 		},
 		.ops = &taiko_dai_ops,
 	},
+	{
+		.name = "taiko_vifeedback",
+		.id = AIF4_VIFEED,
+		.capture = {
+			.stream_name = "VIfeed",
+			.rates = SNDRV_PCM_RATE_48000,
+			.formats = TAIKO_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 48000,
+			.channels_min = 2,
+			.channels_max = 2,
+	 },
+		.ops = &taiko_dai_ops,
+	},
+	{
+		.name = "taiko_mad1",
+		.id = AIF4_MAD_TX,
+		.capture = {
+			.stream_name = "AIF4 MAD TX",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = TAIKO_FORMATS,
+			.rate_min = 16000,
+			.rate_max = 16000,
+			.channels_min = 1,
+			.channels_max = 1,
+		},
+		.ops = &taiko_dai_ops,
+	},
 };
 
 static struct snd_soc_dai_driver taiko_i2s_dai[] = {
@@ -3967,6 +4250,89 @@
 	return ret;
 }
 
+static int taiko_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol,
+				int event)
+{
+	struct wcd9xxx *core = NULL;
+	struct snd_soc_codec *codec = NULL;
+	struct taiko_priv *taiko_p = NULL;
+	u32 ret = 0;
+	struct wcd9xxx_codec_dai_data *dai = NULL;
+
+	if (!w || !w->codec) {
+		pr_err("%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	codec = w->codec;
+	taiko_p = snd_soc_codec_get_drvdata(codec);
+	core = dev_get_drvdata(codec->dev->parent);
+
+	pr_debug("%s: event called! codec name %s num_dai %d stream name %s\n",
+		__func__, w->codec->name, w->codec->num_dai, w->sname);
+
+	/* Execute the callback only if interface type is slimbus */
+	if (taiko_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		pr_err("%s Interface is not correct", __func__);
+		return 0;
+	}
+
+	pr_debug("%s(): w->name %s event %d w->shift %d\n",
+		__func__, w->name, event, w->shift);
+	if (w->shift != AIF4_VIFEED) {
+		pr_err("%s Error in enabling the tx path\n", __func__);
+		ret = -EINVAL;
+		goto out_vi;
+	}
+	dai = &taiko_p->dai[w->shift];
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/*Enable Clip Detection*/
+		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
+				0x8, 0x8);
+		/*Enable V&I sensing*/
+		snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
+				0x88, 0x88);
+		/*Enable spkr VI clocks*/
+		snd_soc_update_bits(codec,
+		TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0xC, 0xC);
+		/*Enable Voltage Decimator*/
+		snd_soc_update_bits(codec,
+		TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x12);
+		/*Enable Current Decimator*/
+		snd_soc_update_bits(codec,
+		TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x13);
+		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+					dai->rate, dai->bit_width,
+					&dai->grph);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
+						dai->grph);
+		if (ret)
+			pr_err("%s error in close_slim_sch_tx %d\n",
+				__func__, ret);
+		/*Disable Voltage decimator*/
+		snd_soc_update_bits(codec,
+		TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x0);
+		/*Disable Current decimator*/
+		snd_soc_update_bits(codec,
+		TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x0);
+		/*Disable spkr VI clocks*/
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL,
+				0xC, 0x0);
+		/*Disable V&I sensing*/
+		snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
+				0x88, 0x00);
+		/*Disable clip detection*/
+		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
+				0x8, 0x0);
+		break;
+	}
+out_vi:
+	return ret;
+}
+
 static int taiko_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
 				     struct snd_kcontrol *kcontrol,
 				     int event)
@@ -4440,6 +4806,16 @@
 		AIF3_CAP, 0, taiko_codec_enable_slimtx,
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
+	SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM,
+		AIF4_VIFEED, 0, taiko_codec_enable_slimvi_feedback,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT_E("AIF4 MAD", "AIF4 MAD TX", 0,
+			       SND_SOC_NOPM, 0, 0,
+			       taiko_codec_enable_mad, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SWITCH("MADONOFF", SND_SOC_NOPM, 0, 0,
+			    &aif4_mad_switch),
+	SND_SOC_DAPM_INPUT("MADINPUT"),
+
 	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
 		aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
 
@@ -4529,7 +4905,6 @@
 
 	SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
 		lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
-
 };
 
 static irqreturn_t taiko_slimbus_irq(int irq, void *data)
@@ -4768,6 +5143,26 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
+
+	/* MAD registers */
+	TAIKO_REG_VAL(TAIKO_A_MAD_ANA_CTRL, 0xF1),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_MAIN_CTL_1, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_MAIN_CTL_2, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_1, 0x00),
+	/* Set SAMPLE_TX_EN bit */
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_2, 0x03),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_3, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_4, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_5, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_6, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_7, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_CTL_8, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_PTR, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_VAL, 0x40),
+	TAIKO_REG_VAL(TAIKO_A_CDC_DEBUG_B7_CTL, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_CTL, 0x00),
+	TAIKO_REG_VAL(TAIKO_A_CDC_CONN_MAD, 0x01),
 };
 
 static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -5005,6 +5400,26 @@
 }
 EXPORT_SYMBOL_GPL(taiko_hs_detect);
 
+static void taiko_init_slim_slave_cfg(struct snd_soc_codec *codec)
+{
+	struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct afe_param_cdc_slimbus_slave_cfg *cfg;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	uint64_t eaddr = 0;
+
+	cfg = &priv->slimbus_slave_cfg;
+	cfg->minor_version = 1;
+	cfg->tx_slave_port_offset = 0;
+	cfg->rx_slave_port_offset = 16;
+
+	memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr));
+	WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6);
+	cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF;
+	cfg->device_enum_addr_msw = eaddr >> 32;
+
+	pr_debug("%s: slimbus logical address 0x%llx\n", __func__, eaddr);
+}
+
 static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
@@ -5034,6 +5449,8 @@
 	if (IS_ERR_VALUE(ret))
 		pr_err("%s: bad pdata\n", __func__);
 
+	taiko_init_slim_slave_cfg(codec);
+
 	wcd9xxx_mbhc_deinit(&taiko->mbhc);
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
 	if (ret)
@@ -5044,6 +5461,23 @@
 	return ret;
 }
 
+void *taiko_get_afe_config(struct snd_soc_codec *codec,
+			   enum afe_config_type config_type)
+{
+	struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (config_type) {
+	case AFE_SLIMBUS_SLAVE_CONFIG:
+		return &priv->slimbus_slave_cfg;
+	case AFE_CDC_REGISTERS_CONFIG:
+		return &taiko_mad_audio_reg_cfg;
+	case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+		return &taiko_slimbus_slave_port_cfg;
+	default:
+		pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
+		return NULL;
+	}
+}
 
 static struct wcd9xxx_reg_address taiko_reg_address = {
 	.micb_4_mbhc = TAIKO_A_MICB_4_MBHC,
@@ -5237,6 +5671,14 @@
 			INIT_LIST_HEAD(&taiko->dai[i].wcd9xxx_ch_list);
 			init_waitqueue_head(&taiko->dai[i].dai_wait);
 		}
+		taiko_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+		    control->slim_slave->laddr;
+		taiko_slimbus_slave_port_cfg.slave_dev_pgd_la =
+		    control->slim->laddr;
+		taiko_slimbus_slave_port_cfg.slave_port_mapping[0] =
+		    TAIKO_MAD_SLIMBUS_TX_PORT;
+
+		taiko_init_slim_slave_cfg(codec);
 	}
 
 	if (TAIKO_IS_1_0(control->version))
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 89a0b9f..36310e5 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
 
 #include <sound/soc.h>
 #include <sound/jack.h>
+#include <sound/apr_audio-v2.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 #include "wcd9xxx-mbhc.h"
 #include "wcd9xxx-resmgr.h"
@@ -25,6 +26,10 @@
 #define TAIKO_REG_VAL(reg, val)		{reg, 0, val}
 #define TAIKO_MCLK_ID 0
 
+#define TAIKO_REGISTER_START_OFFSET 0x800
+#define TAIKO_SB_PGD_PORT_RX_BASE   0x40
+#define TAIKO_SB_PGD_PORT_TX_BASE   0x50
+
 extern const u8 taiko_reg_readable[TAIKO_CACHE_SIZE];
 extern const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE];
 struct taiko_codec_dai_data {
@@ -90,9 +95,62 @@
 	u32 num_anc_slots;
 };
 
+struct mad_audio_header {
+	u32 reserved[3];
+	u32 num_reg_cfg;
+};
+
+struct mad_microphone_info {
+	uint8_t input_microphone;
+	uint8_t cycle_time;
+	uint8_t settle_time;
+	uint8_t padding;
+} __packed;
+
+struct mad_micbias_info {
+	uint8_t micbias;
+	uint8_t k_factor;
+	uint8_t external_bypass_capacitor;
+	uint8_t internal_biasing;
+	uint8_t cfilter;
+	uint8_t padding[3];
+} __packed;
+
+struct mad_rms_audio_beacon_info {
+	uint8_t rms_omit_samples;
+	uint8_t rms_comp_time;
+	uint8_t detection_mechanism;
+	uint8_t rms_diff_threshold;
+	uint8_t rms_threshold_lsb;
+	uint8_t rms_threshold_msb;
+	uint8_t padding[2];
+	uint8_t iir_coefficients[36];
+} __packed;
+
+struct mad_rms_ultrasound_info {
+	uint8_t rms_comp_time;
+	uint8_t detection_mechanism;
+	uint8_t rms_diff_threshold;
+	uint8_t rms_threshold_lsb;
+	uint8_t rms_threshold_msb;
+	uint8_t padding[3];
+	uint8_t iir_coefficients[36];
+} __packed;
+
+struct mad_audio_cal {
+	uint32_t version;
+	struct mad_microphone_info microphone_info;
+	struct mad_micbias_info micbias_info;
+	struct mad_rms_audio_beacon_info audio_info;
+	struct mad_rms_audio_beacon_info beacon_info;
+	struct mad_rms_ultrasound_info ultrasound_info;
+} __packed;
+
 extern int taiko_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
 			     bool dapm);
 extern int taiko_hs_detect(struct snd_soc_codec *codec,
 			   struct wcd9xxx_mbhc_config *mbhc_cfg);
+extern void *taiko_get_afe_config(struct snd_soc_codec *codec,
+				  enum afe_config_type config_type);
 
 #endif
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index f1b6203..916ff1a 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -139,7 +139,7 @@
 	if (on && (++cp_count == 1)) {
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
 							0x01, 0x01);
-		dev_info(codec->dev, "%s: Charge Pump enabled, count = %d\n",
+		dev_dbg(codec->dev, "%s: Charge Pump enabled, count = %d\n",
 				__func__, cp_count);
 	}
 
@@ -149,7 +149,7 @@
 					__func__);
 			if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
 					& 0x01) {
-				dev_info(codec->dev, "%s: Actual chargepump is ON\n",
+				dev_dbg(codec->dev, "%s: Actual chargepump is ON\n",
 						__func__);
 			}
 			cp_count = 0;
@@ -526,7 +526,7 @@
 		(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
 							req_state, req_type);
 		cdc_clsh_d->state = new_state;
-		dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+		dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
 			__func__, state_to_str(old_state),
 			state_to_str(cdc_clsh_d->state));
 
@@ -546,7 +546,7 @@
 				(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
 							req_state, req_type);
 				cdc_clsh_d->state = new_state;
-				dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+				dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
 					__func__, state_to_str(old_state),
 					state_to_str(cdc_clsh_d->state));
 
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 88f0567..5b54e1b 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -1039,7 +1039,7 @@
 		goto exit;
 	}
 
-	for (i = 0, d = dt, ch = 0; i < size; i++, d++) {
+	for (i = 0, d = dt; i < size; i++, d++) {
 		if ((i > 0) && (d->_type != dprev->_type)) {
 			pr_debug("%s: Invalid, inconsistent types\n", __func__);
 			type = PLUG_TYPE_INVALID;
@@ -1068,7 +1068,12 @@
 		     maxv))
 			type = PLUG_TYPE_GND_MIC_SWAP;
 	}
-
+	if (((type == PLUG_TYPE_HEADSET || type == PLUG_TYPE_HEADPHONE) &&
+	    ch != size) || (type == PLUG_TYPE_GND_MIC_SWAP && ch)) {
+		pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
+		    __func__, type);
+		type = PLUG_TYPE_INVALID;
+	}
 exit:
 	pr_debug("%s: Plug type %d detected\n", __func__, type);
 	return type;
@@ -2455,8 +2460,10 @@
 
 	if (mbhc) {
 		codec = mbhc->codec;
-		if (mbhc->hphlocp_cnt++ < OCP_ATTEMPT) {
+		if ((mbhc->hphlocp_cnt < OCP_ATTEMPT) &&
+		    (!mbhc->hphrocp_cnt)) {
 			pr_info("%s: retry\n", __func__);
+			mbhc->hphlocp_cnt++;
 			snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
 					    0x10, 0x00);
 			snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
@@ -2464,7 +2471,6 @@
 		} else {
 			wcd9xxx_disable_irq(codec->control_data,
 					  WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
-			mbhc->hphlocp_cnt = 0;
 			mbhc->hph_status |= SND_JACK_OC_HPHL;
 			wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 					    mbhc->hph_status,
@@ -2484,8 +2490,10 @@
 
 	pr_info("%s: received HPHR OCP irq\n", __func__);
 	codec = mbhc->codec;
-	if (mbhc->hphrocp_cnt++ < OCP_ATTEMPT) {
+	if ((mbhc->hphrocp_cnt < OCP_ATTEMPT) &&
+	    (!mbhc->hphlocp_cnt)) {
 		pr_info("%s: retry\n", __func__);
+		mbhc->hphrocp_cnt++;
 		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
 				    0x00);
 		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
@@ -2493,7 +2501,6 @@
 	} else {
 		wcd9xxx_disable_irq(mbhc->resmgr->core,
 				    WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
-		mbhc->hphrocp_cnt = 0;
 		mbhc->hph_status |= SND_JACK_OC_HPHR;
 		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 				    mbhc->hph_status, WCD9XXX_JACK_MASK);
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 39afb73..4e6cbaa 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -788,7 +788,7 @@
 	runtime->private_data = compr;
 	atomic_set(&prtd->eos, 0);
 	compressed_audio.prtd =  &compr->prtd;
-	ret = compressed_set_volume(compressed_audio.volume);
+	ret = compressed_set_volume(0);
 	if (ret < 0)
 		pr_err("%s : Set Volume failed : %d", __func__, ret);
 
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 96709be..e00e409 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -612,6 +612,20 @@
 		.ops = &msm_fe_dai_ops,
 		.name = "DTMF_RX_HOSTLESS",
 	},
+	{
+		.capture = {
+			.stream_name = "Listen Audio Service Capture",
+			.aif_name = "LSM_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM",
+	},
 };
 
 static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 328c380..235b527 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -84,7 +84,7 @@
 static int msm_btsco_ch = 1;
 
 static struct mutex cdc_mclk_mutex;
-static struct q_clkdiv *codec_clk;
+static struct clk *codec_clk;
 static int clk_users;
 
 static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
@@ -98,7 +98,7 @@
 	if (enable) {
 		if (!codec_clk) {
 			dev_err(codec->dev, "%s: did not get Taiko MCLK\n",
-				__func__);
+					__func__);
 			ret = -EINVAL;
 			goto exit;
 		}
@@ -106,17 +106,25 @@
 		clk_users++;
 		if (clk_users != 1)
 			goto exit;
-		/* TODO: qpnp_clkdiv_enable */
-		tapan_mclk_enable(codec, 1, dapm);
+		if (codec_clk) {
+			clk_set_rate(codec_clk, TAPAN_EXT_CLK_RATE);
+			clk_prepare_enable(codec_clk);
+			tapan_mclk_enable(codec, 1, dapm);
+		} else {
+			pr_err("%s: Error setting Tapan MCLK\n", __func__);
+			clk_users--;
+			ret = -EINVAL;
+			goto exit;
+		}
 	} else {
 		if (clk_users > 0) {
 			clk_users--;
 			if (clk_users == 0) {
 				tapan_mclk_enable(codec, 0, dapm);
-				/* TODO: qpnp_clkdiv_disable */
+				clk_disable_unprepare(codec_clk);
 			}
 		} else {
-			pr_err("%s: Error releasing Tabla MCLK\n", __func__);
+			pr_err("%s: Error releasing Tapan MCLK\n", __func__);
 			ret = -EINVAL;
 			goto exit;
 		}
@@ -268,23 +276,6 @@
 	return 0;
 }
 
-static int msm8226_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
-			channels->min, channels->max);
-
-	rate->min = rate->max = 48000;
-
-	return 0;
-}
-
 static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					    struct snd_pcm_hw_params *params)
 {
@@ -335,9 +326,9 @@
 };
 
 static const struct snd_kcontrol_new msm_snd_controls[] = {
-	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
+	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[0],
 		     msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
-	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
+	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[1],
 		     msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
 };
 
@@ -373,13 +364,21 @@
 
 	snd_soc_dapm_sync(dapm);
 
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+	if (codec_clk < 0)
+		pr_err("%s() Failed to get clock for %s\n",
+			   __func__, dev_name(cpu_dai->dev));
+
 	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
 				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
 
 	/* start mbhc */
 	mbhc_cfg.calibration = def_tapan_mbhc_cal();
-	if (mbhc_cfg.calibration)
-		err = tapan_hs_detect(codec, &mbhc_cfg);
+	if (mbhc_cfg.calibration) {
+		pr_info("%s: WCD9306: Headset detection disabled\n",
+				__func__);
+	}
+
 	else
 		err = -ENOMEM;
 
@@ -550,7 +549,7 @@
 		.name = "MSM8226 Media1",
 		.stream_name = "MultiMedia1",
 		.cpu_dai_name	= "MultiMedia1",
-		.platform_name  = "msm-pcm-dsp",
+		.platform_name  = "msm-pcm-dsp.0",
 		.dynamic = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST},
@@ -565,7 +564,7 @@
 		.name = "MSM8226 Media2",
 		.stream_name = "MultiMedia2",
 		.cpu_dai_name   = "MultiMedia2",
-		.platform_name  = "msm-pcm-dsp",
+		.platform_name  = "msm-pcm-dsp.0",
 		.dynamic = 1,
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
@@ -744,6 +743,37 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{
+		.name = "VoLTE",
+		.stream_name = "VoLTE",
+		.cpu_dai_name   = "VoLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOLTE,
+	},
+	{
+		.name = "MSM8226 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name   = "MultiMedia5",
+		.platform_name  = "msm-pcm-dsp.1",
+		.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,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -757,6 +787,7 @@
 		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
 		/* this dainlink has playback support */
 		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_INT_BT_SCO_TX,
@@ -768,6 +799,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
 		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_INT_FM_RX,
@@ -781,6 +813,7 @@
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
 		/* this dainlink has playback support */
 		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_INT_FM_TX,
@@ -792,6 +825,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_INT_FM_TX,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
 	},
 	/* Backend AFE DAI Links */
 	{
@@ -806,6 +840,7 @@
 		.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
 		/* this dainlink has playback support */
 		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_AFE_PCM_TX,
@@ -817,6 +852,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
 		.be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+		.ignore_suspend = 1,
 	},
 	/* HDMI Hostless */
 	{
@@ -833,19 +869,6 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
-	/* HDMI BACK END DAI Link */
-	{
-		.name = LPASS_BE_HDMI,
-		.stream_name = "HDMI Playback",
-		.cpu_dai_name = "msm-dai-q6-hdmi.8",
-		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_HDMI_RX,
-		.be_hw_params_fixup = msm8226_hdmi_be_hw_params_fixup,
-		.ignore_pmdown_time = 1,
-	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
@@ -860,6 +883,7 @@
 		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
 		.ops = &msm8226_be_ops,
 		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_SLIMBUS_0_TX,
@@ -872,6 +896,7 @@
 		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_SLIMBUS_1_RX,
@@ -886,6 +911,7 @@
 		.ops = &msm8226_be_ops,
 		/* dai link has playback support */
 		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_SLIMBUS_1_TX,
@@ -898,6 +924,7 @@
 		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_SLIMBUS_3_RX,
@@ -912,6 +939,7 @@
 		.ops = &msm8226_be_ops,
 		/* dai link has playback support */
 		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_SLIMBUS_3_TX,
@@ -924,6 +952,7 @@
 		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_SLIMBUS_4_RX,
@@ -938,6 +967,7 @@
 		.ops = &msm8226_be_ops,
 		/* dai link has playback support */
 		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
 	},
 	{
 		.name = LPASS_BE_SLIMBUS_4_TX,
@@ -950,6 +980,7 @@
 		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
 	},
 };
 
@@ -961,6 +992,17 @@
 
 static int msm8226_prepare_codec_mclk(struct snd_soc_card *card)
 {
+	struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	int ret;
+	if (pdata->mclk_gpio) {
+		ret = gpio_request(pdata->mclk_gpio, "TAPAN_CODEC_PMIC_MCLK");
+		if (ret) {
+			dev_err(card->dev,
+				"%s: Failed to request taiko mclk gpio %d\n",
+				__func__, pdata->mclk_gpio);
+			return ret;
+		}
+	}
 	return 0;
 }
 
@@ -1012,7 +1054,16 @@
 		goto err;
 	}
 
-	/* TODO: MCLK GPIO */
+	pdata->mclk_gpio = of_get_named_gpio(pdev->dev.of_node,
+				"qcom,cdc-mclk-gpios", 0);
+	if (pdata->mclk_gpio < 0) {
+		dev_err(&pdev->dev,
+			"Looking up %s property in node %s failed %d\n",
+			"qcom, cdc-mclk-gpios", pdev->dev.of_node->full_name,
+			pdata->mclk_gpio);
+		ret = -ENODEV;
+		goto err;
+	}
 
 	ret = msm8226_prepare_codec_mclk(card);
 	if (ret)
@@ -1028,6 +1079,12 @@
 
 	return 0;
 err:
+	if (pdata->mclk_gpio > 0) {
+		dev_dbg(&pdev->dev, "%s free gpio %d\n",
+			__func__, pdata->mclk_gpio);
+		gpio_free(pdata->mclk_gpio);
+		pdata->mclk_gpio = 0;
+	}
 	devm_kfree(&pdev->dev, pdata);
 	return ret;
 }
@@ -1035,8 +1092,9 @@
 static int __devexit msm8226_asoc_machine_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 
-	/* TODO: GPIO MCLK */
+	gpio_free(pdata->mclk_gpio);
 	snd_soc_unregister_card(card);
 
 	return 0;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 4462213..0dbe3f7 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -24,6 +24,7 @@
 #include <sound/soc-dapm.h>
 #include <sound/pcm.h>
 #include <sound/jack.h>
+#include <sound/q6afe-v2.h>
 #include <asm/mach-types.h>
 #include <mach/socinfo.h>
 #include <sound/pcm_params.h>
@@ -1003,6 +1004,33 @@
 	return 0;
 }
 
+static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					    struct snd_pcm_hw_params *params)
+{
+	int rc;
+	void *config;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_interval *rate =
+	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels =
+	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s enter\n", __func__);
+	rate->min = rate->max = 16000;
+	channels->min = channels->max = 1;
+
+	config = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+	rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
+			    SLIMBUS_5_TX);
+	if (rc) {
+		pr_err("%s: Failed to set slimbus slave port config %d\n",
+		       __func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 				struct snd_pcm_hw_params *params)
 {
@@ -1054,6 +1082,7 @@
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
+	void *config_data;
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1108,6 +1137,23 @@
 	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
 				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
 
+
+	config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+	err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+	if (err) {
+		pr_err("%s: Failed to set codec registers config %d\n",
+		       __func__, err);
+		return err;
+	}
+
+	config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+	err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+	if (err) {
+		pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+		       err);
+		return err;
+	}
+
 	/* start mbhc */
 	mbhc_cfg.calibration = def_taiko_mbhc_cal();
 	if (mbhc_cfg.calibration)
@@ -1574,6 +1620,22 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
 	},
+	/* LSM FE */
+	{
+		.name = "Listen Audio Service",
+		.stream_name = "Listen Audio Service",
+		.cpu_dai_name = "LSM",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM1,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1802,13 +1864,13 @@
 		.name = LPASS_BE_SLIMBUS_4_TX,
 		.stream_name = "Slimbus4 Capture",
 		.cpu_dai_name = "msm-dai-q6-dev.16393",
-		.platform_name = "msm-pcm-routing",
+		.platform_name = "msm-pcm-hostless",
 		.codec_name = "taiko_codec",
-		.codec_dai_name	= "taiko_tx1",
-		.no_pcm = 1,
+		.codec_dai_name	= "taiko_vifeedback",
 		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm8974_be_ops,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 	},
 	/* Incall Record Uplink BACK END DAI Link */
@@ -1837,6 +1899,19 @@
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
 		.ignore_suspend = 1,
 	},
+	/* MAD BE */
+	{
+		.name = LPASS_BE_SLIMBUS_5_TX,
+		.stream_name = "Slimbus5 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16395",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name = "taiko_mad1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		.be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
+		.ops = &msm8974_be_ops,
+	},
 	/* Incall Music BACK END DAI Link */
 	{
 		.name = LPASS_BE_VOICE_PLAYBACK_TX,
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 69c0976..391b3da 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,6 +1,11 @@
-snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o msm-compr-q6-v2.o  msm-multi-ch-pcm-q6-v2.o
-snd-soc-qdsp6v2-objs += msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o
-obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o msm-dai-stub-v2.o
-obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o q6voice.o q6core.o audio_acdb.o rtac.o
+snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
+			msm-compr-q6-v2.o msm-multi-ch-pcm-q6-v2.o \
+			msm-pcm-lpa-v2.o msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
+			msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
+			msm-lsm-client.o
+obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
+				 msm-dai-stub-v2.o
+obj-y += q6adm.o q6afe.o q6asm.o q6audio-v2.o q6voice.o q6core.o audio_acdb.o \
+	 rtac.o q6lsm.o
 ocmem-audio-objs += audio_ocmem.o
 obj-$(CONFIG_AUDIO_OCMEM) += ocmem-audio.o
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index b71132e..259f3ed 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -85,6 +85,9 @@
 	atomic64_t			paddr;
 	atomic64_t			kvaddr;
 	atomic64_t			mem_len;
+
+	/* Speaker protection */
+	struct msm_spk_prot_cfg spk_prot_cfg;
 };
 
 static struct acdb_data		acdb_data;
@@ -767,6 +770,34 @@
 done:
 	return;
 }
+void get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg)
+{
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (prot_cfg) {
+		prot_cfg->mode = acdb_data.spk_prot_cfg.mode;
+		prot_cfg->r0 = acdb_data.spk_prot_cfg.r0;
+		prot_cfg->t0 = acdb_data.spk_prot_cfg.t0;
+	} else
+		pr_err("%s prot_cfg is NULL\n", __func__);
+	mutex_unlock(&acdb_data.acdb_mutex);
+}
+static void get_spk_protection_status(struct msm_spk_prot_status *status)
+{
+	/*Call AFE function here to query the status*/
+	struct afe_spkr_prot_get_vi_calib calib_resp;
+	if (status) {
+		status->status = -EINVAL;
+		if (!afe_spk_prot_get_calib_data(&calib_resp)) {
+			if (calib_resp.res_cfg.th_vi_ca_state == 1)
+				status->status = -EAGAIN;
+			else if (calib_resp.res_cfg.th_vi_ca_state == 2) {
+				status->status = 0;
+				status->r0 = calib_resp.res_cfg.r0_cali_q24;
+			}
+		 }
+	} else
+		pr_err("%s invalid params\n", __func__);
+}
 
 static int acdb_open(struct inode *inode, struct file *f)
 {
@@ -808,7 +839,7 @@
 {
 	int			result;
 	int			i;
-	unsigned long		paddr;
+	ion_phys_addr_t		paddr;
 	void                    *kvptr;
 	unsigned long		kvaddr;
 	unsigned long		mem_len;
@@ -880,6 +911,8 @@
 	int32_t			map_fd;
 	uint32_t		topology;
 	uint32_t		data[MAX_IOCTL_DATA];
+	struct msm_spk_prot_status prot_status;
+	struct msm_spk_prot_status acdb_spk_status;
 	pr_debug("%s\n", __func__);
 
 	switch (cmd) {
@@ -943,6 +976,43 @@
 		}
 		store_asm_topology(topology);
 		goto done;
+	case AUDIO_SET_SPEAKER_PROT:
+		mutex_lock(&acdb_data.acdb_mutex);
+		if (copy_from_user(&acdb_data.spk_prot_cfg, (void *)arg,
+				sizeof(acdb_data.spk_prot_cfg))) {
+			pr_err("%s fail to copy spk_prot_cfg\n", __func__);
+			result = -EFAULT;
+		}
+		mutex_unlock(&acdb_data.acdb_mutex);
+		goto done;
+	case AUDIO_GET_SPEAKER_PROT:
+		mutex_lock(&acdb_data.acdb_mutex);
+		/*Indicates calibration was succesfull*/
+		if (!acdb_data.spk_prot_cfg.mode) {
+			prot_status.r0 = acdb_data.spk_prot_cfg.r0;
+			prot_status.status = 0;
+		} else if (acdb_data.spk_prot_cfg.mode == 1) {
+			/*Call AFE to query the status*/
+			acdb_spk_status.status = -EINVAL;
+			acdb_spk_status.r0 = -1;
+			get_spk_protection_status(&acdb_spk_status);
+			prot_status.r0 = acdb_spk_status.r0;
+			prot_status.status = acdb_spk_status.status;
+			if (!acdb_spk_status.status) {
+				acdb_data.spk_prot_cfg.mode = 0;
+				acdb_data.spk_prot_cfg.r0 = prot_status.r0;
+			}
+		} else {
+			/*Indicates calibration data is invalid*/
+			prot_status.status = -EINVAL;
+			prot_status.r0 = -1;
+		}
+		if (copy_to_user((void *)arg, &prot_status,
+			sizeof(prot_status))) {
+			pr_err("%s Failed to update prot_status\n", __func__);
+		}
+		mutex_unlock(&acdb_data.acdb_mutex);
+		goto done;
 	}
 
 	if (copy_from_user(&size, (void *) arg, sizeof(size))) {
@@ -1110,6 +1180,8 @@
 static int __init acdb_init(void)
 {
 	memset(&acdb_data, 0, sizeof(acdb_data));
+	/*Speaker protection disabled*/
+	acdb_data.spk_prot_cfg.mode = -1;
 	mutex_init(&acdb_data.acdb_mutex);
 	atomic_set(&usage_count, 0);
 	atomic_set(&acdb_data.valid_adm_custom_top, 1);
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 0b6110d..4834855 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -63,5 +63,6 @@
 void get_vocstrm_cal(struct acdb_cal_block *cal_block);
 void get_vocvol_cal(struct acdb_cal_block *cal_block);
 void get_sidetone_cal(struct sidetone_cal *cal_data);
+void get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
 
 #endif
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index d0b5500..f6e571b8 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -754,7 +754,7 @@
 			prtd->session_id,
 			substream->stream);
 
-		ret = compressed_set_volume(compressed_audio.volume);
+		ret = compressed_set_volume(0);
 		if (ret < 0)
 			pr_err("%s : Set Volume failed : %d", __func__, ret);
 
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index c300a9f..916be0b 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -485,6 +485,7 @@
 
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FMTBIT_SPECIAL:
 		dai_data->port_config.i2s.bit_width = 16;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
@@ -560,6 +561,7 @@
 
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FMTBIT_SPECIAL:
 		dai_data->port_config.slim_sch.bit_width = 16;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
@@ -699,6 +701,7 @@
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_TX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 		rc = msm_dai_q6_slim_bus_hw_params(params, dai,
 				substream->stream);
 		break;
@@ -829,6 +832,7 @@
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_TX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 		/*
 		 * channel number to be between 128 and 255.
 		 * For TX port use channel numbers
@@ -1978,6 +1982,7 @@
 		break;
 	case SLIMBUS_0_TX:
 	case SLIMBUS_2_TX:
+	case SLIMBUS_5_TX:
 		rc = snd_soc_register_dai(&pdev->dev,
 					  &msm_dai_q6_slimbus_tx_dai);
 		break;
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
new file mode 100644
index 0000000..ea6f390
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/timer.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6lsm.h>
+#include <sound/lsm_params.h>
+#include "msm-pcm-routing-v2.h"
+
+struct lsm_priv {
+	struct snd_pcm_substream *substream;
+	struct lsm_client *lsm_client;
+
+	struct snd_lsm_event_status *event_status;
+	spinlock_t event_lock;
+	wait_queue_head_t event_wait;
+	unsigned long event_avail;
+	atomic_t event_wait_stop;
+};
+
+static void lsm_event_handler(uint32_t opcode, uint32_t token,
+			      void *payload, void *priv)
+{
+	unsigned long flags;
+	struct snd_lsm_event_status *event_status;
+	struct lsm_priv *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+
+	pr_debug("%s: enter opcode 0x%x\n", __func__, opcode);
+	switch (opcode) {
+	case LSM_SESSION_EVENT_DETECTION_STATUS:
+		event_status = payload;
+
+		spin_lock_irqsave(&prtd->event_lock, flags);
+		prtd->event_status = krealloc(prtd->event_status,
+					      sizeof(*event_status) +
+					      event_status->payload_size,
+					      GFP_ATOMIC);
+		if (likely(prtd->event_status)) {
+			memcpy(prtd->event_status, event_status,
+			       sizeof(*event_status) +
+			       event_status->payload_size);
+			prtd->event_avail = 1;
+			spin_unlock_irqrestore(&prtd->event_lock, flags);
+			wake_up(&prtd->event_wait);
+		} else {
+			spin_unlock_irqrestore(&prtd->event_lock, flags);
+			pr_err("%s: Couldn't allocate %d bytes of memory\n",
+			       __func__, event_status->payload_size);
+		}
+		if (substream->timer_running)
+			snd_timer_interrupt(substream->timer, 1);
+		break;
+	default:
+		pr_debug("%s: Unsupported Event opcode 0x%x\n", __func__,
+			 opcode);
+		break;
+	}
+}
+
+static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
+			 unsigned int cmd, void *arg)
+{
+	unsigned long flags;
+	int ret;
+	struct snd_lsm_sound_model snd_model;
+	int rc = 0;
+	int xchg = 0;
+	int size = 0;
+	struct snd_lsm_event_status *event_status = NULL;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd = runtime->private_data;
+	struct snd_lsm_event_status *user = arg;
+
+	pr_debug("%s: enter cmd %x\n", __func__, cmd);
+	switch (cmd) {
+	case SNDRV_LSM_REG_SND_MODEL:
+		pr_debug("%s: Registering sound model\n", __func__);
+		if (copy_from_user(&snd_model, (void *)arg,
+				   sizeof(struct snd_lsm_sound_model))) {
+			rc = -EFAULT;
+			pr_err("%s: copy from user failed, size %d\n", __func__,
+			       sizeof(struct snd_lsm_sound_model));
+			break;
+		}
+
+		rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
+					       snd_model.data_size);
+		if (rc) {
+			pr_err("%s: q6lsm buffer alloc failed, size %d\n",
+			       __func__, snd_model.data_size);
+			break;
+		}
+
+		if (copy_from_user(prtd->lsm_client->sound_model.data,
+				   snd_model.data, snd_model.data_size)) {
+			pr_err("%s: copy from user data failed size %d\n",
+			       __func__, snd_model.data_size);
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = q6lsm_register_sound_model(prtd->lsm_client,
+						snd_model.detection_mode,
+						snd_model.min_keyw_confidence,
+						snd_model.min_user_confidence,
+						snd_model.detect_failure);
+		if (rc < 0)
+			pr_err("%s: q6lsm_register_sound_model failed =%d\n",
+			       __func__, rc);
+		break;
+
+	case SNDRV_LSM_DEREG_SND_MODEL:
+		pr_debug("%s: Deregistering sound model\n", __func__);
+		rc = q6lsm_deregister_sound_model(prtd->lsm_client);
+		break;
+
+	case SNDRV_LSM_EVENT_STATUS:
+		pr_debug("%s: Get event status\n", __func__);
+		atomic_set(&prtd->event_wait_stop, 0);
+		rc = wait_event_interruptible(prtd->event_wait,
+				(cmpxchg(&prtd->event_avail, 1, 0) ||
+				 (xchg = atomic_cmpxchg(&prtd->event_wait_stop,
+							1, 0))));
+		pr_debug("%s: wait_event_interruptible %d event_wait_stop %d\n",
+			 __func__, rc, xchg);
+		if (!rc && !xchg) {
+			pr_debug("%s: New event available %ld\n", __func__,
+				 prtd->event_avail);
+			spin_lock_irqsave(&prtd->event_lock, flags);
+			if (prtd->event_status) {
+				size = sizeof(*event_status) +
+				       prtd->event_status->payload_size;
+				event_status = kmemdup(prtd->event_status, size,
+						       GFP_ATOMIC);
+			}
+			spin_unlock_irqrestore(&prtd->event_lock, flags);
+			if (!event_status) {
+				pr_err("%s: Couldn't allocate %d bytes\n",
+				       __func__, size);
+				/*
+				 * Don't use -ENOMEM as userspace will check
+				 * it for increasing buffer
+				 */
+				rc = -EFAULT;
+			} else {
+				if (user->payload_size <
+				    event_status->payload_size) {
+					pr_debug("%s: provided %dbytes isn't enough, needs %dbytes\n",
+						 __func__, user->payload_size,
+						 size);
+					rc = -ENOMEM;
+				} else if (!access_ok(VERIFY_WRITE, arg,
+						      size)) {
+					rc = -EFAULT;
+				} else {
+					rc = copy_to_user(arg, event_status,
+							  size);
+					if (rc)
+						pr_err("%s: copy to user failed %d\n",
+						       __func__, rc);
+				}
+				kfree(event_status);
+			}
+		} else if (xchg) {
+			pr_debug("%s: Wait aborted\n", __func__);
+			rc = 0;
+		}
+		break;
+
+	case SNDRV_LSM_ABORT_EVENT:
+		pr_debug("%s: Aborting event status wait\n", __func__);
+		atomic_set(&prtd->event_wait_stop, 1);
+		wake_up(&prtd->event_wait);
+		break;
+
+	case SNDRV_LSM_START:
+		pr_debug("%s: Starting LSM client session\n", __func__);
+		if (!prtd->lsm_client->started) {
+			ret = q6lsm_start(prtd->lsm_client, true);
+			if (!ret) {
+				prtd->lsm_client->started = true;
+				pr_debug("%s: LSM client session started\n",
+					 __func__);
+			}
+		}
+		break;
+
+	case SNDRV_LSM_STOP:
+		pr_debug("%s: Stopping LSM client session\n", __func__);
+		if (prtd->lsm_client->started) {
+			ret = q6lsm_stop(prtd->lsm_client, true);
+			if (!ret) {
+				prtd->lsm_client->started = false;
+				pr_debug("%s: LSM client session stopped\n",
+					 __func__);
+			}
+		}
+		break;
+
+	default:
+		pr_debug("%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
+			 __func__, cmd);
+		rc = snd_pcm_lib_ioctl(substream, cmd, arg);
+		break;
+	}
+
+	if (!rc)
+		pr_debug("%s: leave (%d)\n", __func__, rc);
+	else
+		pr_err("%s: cmd 0x%x failed %d\n", __func__, cmd, rc);
+
+	return rc;
+}
+
+static int msm_lsm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+	prtd = kzalloc(sizeof(struct lsm_priv), GFP_KERNEL);
+	if (!prtd) {
+		pr_err("%s: Failed to allocate memory for lsm_priv\n",
+		       __func__);
+		return -ENOMEM;
+	}
+	prtd->substream = substream;
+	prtd->lsm_client = q6lsm_client_alloc((app_cb)lsm_event_handler, prtd);
+	if (!prtd->lsm_client) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	ret = q6lsm_open(prtd->lsm_client);
+	if (ret < 0) {
+		pr_err("%s: lsm out open failed\n", __func__);
+		q6lsm_client_free(prtd->lsm_client);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+
+	pr_debug("%s: Session ID %d\n", __func__, prtd->lsm_client->session);
+	prtd->lsm_client->started = false;
+	spin_lock_init(&prtd->event_lock);
+	init_waitqueue_head(&prtd->event_wait);
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int msm_lsm_close(struct snd_pcm_substream *substream)
+{
+	unsigned long flags;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+
+	q6lsm_close(prtd->lsm_client);
+	q6lsm_client_free(prtd->lsm_client);
+
+	spin_lock_irqsave(&prtd->event_lock, flags);
+	kfree(prtd->event_status);
+	prtd->event_status = NULL;
+	spin_unlock_irqrestore(&prtd->event_lock, flags);
+	kfree(prtd);
+
+	return 0;
+}
+
+static struct snd_pcm_ops msm_lsm_ops = {
+	.open           = msm_lsm_open,
+	.close          = msm_lsm_close,
+	.ioctl          = msm_lsm_ioctl,
+};
+
+static int msm_asoc_lsm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	return 0;
+}
+
+static int msm_asoc_lsm_probe(struct snd_soc_platform *platform)
+{
+	pr_debug("enter %s\n", __func__);
+
+	return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_lsm_ops,
+	.pcm_new	= msm_asoc_lsm_new,
+	.probe		= msm_asoc_lsm_probe,
+};
+
+static __devinit int msm_lsm_probe(struct platform_device *pdev)
+{
+	if (pdev->dev.of_node)
+		dev_set_name(&pdev->dev, "%s", "msm-lsm-client");
+
+	return snd_soc_register_platform(&pdev->dev, &msm_soc_platform);
+}
+
+static int msm_lsm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id msm_lsm_client_dt_match[] = {
+	{.compatible = "qcom,msm-lsm-client" },
+	{ }
+};
+
+static struct platform_driver msm_lsm_driver = {
+	.driver = {
+		.name = "msm-lsm-client",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(msm_lsm_client_dt_match),
+	},
+	.probe = msm_lsm_probe,
+	.remove = __devexit_p(msm_lsm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_lsm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_lsm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("LSM client platform driver");
+MODULE_DEVICE_TABLE(of, msm_lsm_client_dt_match);
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index e05e58d..4ca96d7 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -459,19 +459,20 @@
 
 	pr_debug("%s\n", __func__);
 
-	dir = IN;
-	ret = wait_event_timeout(the_locks.eos_wait,
-				prtd->cmd_ack, 5 * HZ);
-	if (ret < 0)
-		pr_err("%s: CMD_EOS failed\n", __func__);
-	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
-	q6asm_audio_client_buf_free_contiguous(dir,
-				prtd->audio_client);
-
+	if (prtd->audio_client) {
+		dir = IN;
+		ret = wait_event_timeout(the_locks.eos_wait,
+					prtd->cmd_ack, 5 * HZ);
+		if (ret < 0)
+			pr_err("%s: CMD_EOS failed\n", __func__);
+		q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+		q6asm_audio_client_buf_free_contiguous(dir,
+					prtd->audio_client);
+		pcm_audio.prtd = NULL;
+		q6asm_audio_client_free(prtd->audio_client);
+	}
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
 						SNDRV_PCM_STREAM_PLAYBACK);
-	pcm_audio.prtd = NULL;
-	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
 }
@@ -678,7 +679,7 @@
 		if (ret < 0) {
 			pr_err("%s: q6asm_open_write_v2 failed\n", __func__);
 			q6asm_audio_client_free(prtd->audio_client);
-			kfree(prtd);
+			prtd->audio_client = NULL;
 			return -ENOMEM;
 		}
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 02c3457..819512d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -55,6 +55,27 @@
 static int fm_switch_enable;
 static int fm_pcmrx_switch_enable;
 static int srs_alsa_ctrl_ever_called;
+static int lsm_mux_slim_port;
+
+enum {
+	MADNONE,
+	MADAUDIO,
+	MADBEACON,
+	MADULTRASOUND
+};
+
+#define SLIMBUS_0_TX_TEXT "SLIMBUS_0_TX"
+#define SLIMBUS_1_TX_TEXT "SLIMBUS_1_TX"
+#define SLIMBUS_2_TX_TEXT "SLIMBUS_2_TX"
+#define SLIMBUS_3_TX_TEXT "SLIMBUS_3_TX"
+#define SLIMBUS_4_TX_TEXT "SLIMBUS_4_TX"
+#define SLIMBUS_5_TX_TEXT "SLIMBUS_5_TX"
+#define LSM_FUNCTION_TEXT "LSM Function"
+static const char * const mad_audio_mux_text[] = {
+	"None",
+	SLIMBUS_0_TX_TEXT, SLIMBUS_1_TX_TEXT, SLIMBUS_2_TX_TEXT,
+	SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT
+};
 
 #define INT_RX_VOL_MAX_STEPS 0x2000
 #define INT_RX_VOL_GAIN 0x2000
@@ -190,6 +211,7 @@
 	{ SLIMBUS_4_TX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_3_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_3_TX, 0, 0, 0, 0, 0},
+	{ SLIMBUS_5_TX, 0, 0, 0, 0, 0 },
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
@@ -731,6 +753,118 @@
 	return 1;
 }
 
+static int msm_routing_lsm_mux_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = lsm_mux_slim_port;
+	return 0;
+}
+
+static int msm_routing_lsm_mux_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	int mux = ucontrol->value.enumerated.item[0];
+
+	pr_debug("%s: LSM enable %ld\n", __func__,
+		 ucontrol->value.integer.value[0]);
+	if (ucontrol->value.integer.value[0]) {
+		lsm_mux_slim_port = ucontrol->value.integer.value[0];
+		snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+	} else {
+		snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
+		lsm_mux_slim_port = ucontrol->value.integer.value[0];
+	}
+
+	return 0;
+}
+
+static int msm_routing_lsm_func_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+	u16 port_id;
+	enum afe_mad_type mad_type;
+
+	pr_debug("%s: enter\n", __func__);
+	for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+		if (!strncmp(kcontrol->id.name, mad_audio_mux_text[i],
+			    strlen(mad_audio_mux_text[i])))
+			break;
+
+	if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+		WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+		return -EINVAL;
+	}
+
+	port_id = i * 2 + 1 + SLIMBUS_0_RX;
+	mad_type = afe_port_get_mad_type(port_id);
+	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+		 mad_type);
+	switch (mad_type) {
+	case MAD_HW_NONE:
+		ucontrol->value.integer.value[0] = MADNONE;
+		break;
+	case MAD_HW_AUDIO:
+		ucontrol->value.integer.value[0] = MADAUDIO;
+		break;
+	case MAD_HW_BEACON:
+		ucontrol->value.integer.value[0] = MADBEACON;
+		break;
+	case MAD_HW_ULTRASOUND:
+		ucontrol->value.integer.value[0] = MADULTRASOUND;
+		break;
+	default:
+		WARN(1, "Unknown\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msm_routing_lsm_func_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+	u16 port_id;
+	enum afe_mad_type mad_type;
+
+	pr_debug("%s: enter\n", __func__);
+	for (i = 0; i < ARRAY_SIZE(mad_audio_mux_text); i++)
+		if (!strncmp(kcontrol->id.name, mad_audio_mux_text[i],
+			    strlen(mad_audio_mux_text[i])))
+			break;
+
+	if (i-- == ARRAY_SIZE(mad_audio_mux_text)) {
+		WARN(1, "Invalid id name %s\n", kcontrol->id.name);
+		return -EINVAL;
+	}
+
+	port_id = i * 2 + 1 + SLIMBUS_0_RX;
+	switch (ucontrol->value.integer.value[0]) {
+	case MADNONE:
+		mad_type = MAD_HW_NONE;
+		break;
+	case MADAUDIO:
+		mad_type = MAD_HW_AUDIO;
+		break;
+	case MADBEACON:
+		mad_type = MAD_HW_BEACON;
+		break;
+	case MADULTRASOUND:
+		mad_type = MAD_HW_ULTRASOUND;
+		break;
+	default:
+		WARN(1, "Unknown\n");
+		return -EINVAL;
+	}
+
+	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+		 mad_type);
+	return afe_port_set_mad_type(port_id, mad_type);
+}
+
 static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1734,6 +1868,33 @@
 	0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
 	msm_routing_put_fm_pcmrx_switch_mixer);
 
+static const struct soc_enum lsm_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
+static const struct snd_kcontrol_new lsm_mux =
+	SOC_DAPM_ENUM_EXT("LSM1 MUX", lsm_mux_enum,
+			  msm_routing_lsm_mux_get,
+			  msm_routing_lsm_mux_put);
+
+static const char * const lsm_func_text[] = {
+	"None", "AUDIO", "BEACON", "ULTRASOUND"
+};
+static const struct soc_enum lsm_func_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_func_text), lsm_func_text);
+static const struct snd_kcontrol_new lsm_function[] = {
+	SOC_ENUM_EXT(SLIMBUS_0_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_1_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_2_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_3_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_4_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+	SOC_ENUM_EXT(SLIMBUS_5_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+		     msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+};
+
 static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
 	SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
 	INT_RX_VOL_GAIN, 0, msm_routing_get_fm_vol_mixer,
@@ -2004,6 +2165,60 @@
 	msm_routing_put_eq_band_audio_mixer),
 };
 
+static int spkr_prot_put_vi_lch_port(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = 0;
+	int item;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	pr_debug("%s item is %d\n", __func__,
+		   ucontrol->value.enumerated.item[0]);
+	mutex_lock(&routing_lock);
+	item = ucontrol->value.enumerated.item[0];
+	if (item < e->max) {
+		pr_debug("%s RX DAI ID %d TX DAI id %d\n",
+			__func__, e->shift_l , e->values[item]);
+		if (e->shift_l < MSM_BACKEND_DAI_MAX &&
+			e->values[item] < MSM_BACKEND_DAI_MAX)
+			ret = afe_spk_prot_feed_back_cfg(
+			   msm_bedais[e->values[item]].port_id,
+			   msm_bedais[e->shift_l].port_id, 1, 0);
+		else {
+			pr_err("%s values are out of range\n", __func__);
+			ret = -EINVAL;
+		}
+	} else {
+		pr_err("%s item value is out of range\n", __func__);
+		ret = -EINVAL;
+	}
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
+static int spkr_prot_get_vi_lch_port(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static const char * const slim0_rx_vi_fb_tx_lch_mux_text[] = {
+	"SLIM4_TX",
+};
+
+static const int const slim0_rx_vi_fb_tx_lch_value[] = {
+	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,
+	ARRAY_SIZE(slim0_rx_vi_fb_tx_lch_mux_text),
+	slim0_rx_vi_fb_tx_lch_mux_text, slim0_rx_vi_fb_tx_lch_value);
+
+static const struct snd_kcontrol_new slim0_rx_vi_fb_lch_mux =
+	SOC_DAPM_ENUM_EXT("SLIM0_RX_VI_FB_LCH_MUX",
+	slim0_rx_vi_fb_lch_mux_enum, spkr_prot_get_vi_lch_port,
+	spkr_prot_put_vi_lch_port);
+
 static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
 	/* Frontend AIF */
 	/* Widget name equals to Front-End DAI name<Need confirmation>,
@@ -2057,6 +2272,9 @@
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
 		0, 0, 0, 0),
+	/* LSM */
+	SND_SOC_DAPM_AIF_OUT("LSM_UL_HL", "Listen Audio Service Capture",
+			     0, 0, 0, 0),
 	/* Backend AIF */
 	/* Stream name equals to backend dai link stream name
 	*/
@@ -2102,6 +2320,7 @@
 				0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIMBUS_4_TX", "Slimbus4 Capture",
 				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLIMBUS_5_TX", "Slimbus5 Capture", 0, 0, 0, 0),
 
 	SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
@@ -2126,6 +2345,10 @@
 				&fm_switch_mixer_controls),
 	SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
 				&pcm_rx_switch_mixer_controls),
+
+	/* Mux Definitions */
+	SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm_mux),
+
 	/* Mixer definitions */
 	SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	pri_i2s_rx_mixer_controls, ARRAY_SIZE(pri_i2s_rx_mixer_controls)),
@@ -2249,6 +2472,9 @@
 	SND_SOC_DAPM_OUTPUT("BE_OUT"),
 	SND_SOC_DAPM_INPUT("BE_IN"),
 
+	SND_SOC_DAPM_MUX("SLIM0_RX_VI_FB_LCH_MUX", SND_SOC_NOPM, 0, 0,
+				&slim0_rx_vi_fb_lch_mux),
+
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
@@ -2457,6 +2683,14 @@
 	{"SLIM1_UL_HL", NULL, "SLIMBUS_1_TX"},
 	{"SLIM3_UL_HL", NULL, "SLIMBUS_3_TX"},
 	{"SLIM4_UL_HL", NULL, "SLIMBUS_4_TX"},
+
+	{"LSM1 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM1 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM1 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM1 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM_UL_HL", NULL, "LSM1 MUX"},
+
 	{"INT_FM_RX", NULL, "INTFM_DL_HL"},
 	{"INTFM_UL_HL", NULL, "INT_FM_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
@@ -2543,6 +2777,7 @@
 	{"SLIMBUS_1_TX", NULL, "BE_IN" },
 	{"SLIMBUS_3_TX", NULL, "BE_IN" },
 	{"SLIMBUS_4_TX", NULL, "BE_IN" },
+	{"SLIMBUS_5_TX", NULL, "BE_IN" },
 	{"BE_OUT", NULL, "INT_BT_SCO_RX"},
 	{"INT_BT_SCO_TX", NULL, "BE_IN"},
 	{"BE_OUT", NULL, "INT_FM_RX"},
@@ -2554,7 +2789,9 @@
 	{"AUX_PCM_TX", NULL, "BE_IN"},
 	{"INCALL_RECORD_TX", NULL, "BE_IN"},
 	{"INCALL_RECORD_RX", NULL, "BE_IN"},
-	{"BE_OUT", NULL, "VOICE_PLAYBACK_TX"}
+	{"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"},
 };
 
 static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
@@ -2762,6 +2999,9 @@
 	snd_soc_add_platform_controls(platform,
 				multi_ch_channel_map_mixer_controls,
 			ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
+
+	snd_soc_add_platform_controls(platform, lsm_function,
+				      ARRAY_SIZE(lsm_function));
 	return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 7ecdff3..798f676 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -51,6 +51,7 @@
 #define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
 #define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
 #define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
+#define LPASS_BE_SLIMBUS_5_TX "SLIMBUS_5_TX"
 
 /* For multimedia front-ends, asm session is allocated dynamically.
  * Hence, asm session/multimedia front-end mapping has to be maintained.
@@ -71,6 +72,7 @@
 	MSM_FRONTEND_DAI_VOICE_STUB,
 	MSM_FRONTEND_DAI_VOLTE,
 	MSM_FRONTEND_DAI_DTMF_RX,
+	MSM_FRONTEND_DAI_LSM1,
 	MSM_FRONTEND_DAI_MAX,
 };
 
@@ -103,6 +105,7 @@
 	MSM_BACKEND_DAI_SLIMBUS_4_TX,
 	MSM_BACKEND_DAI_SLIMBUS_3_RX,
 	MSM_BACKEND_DAI_SLIMBUS_3_TX,
+	MSM_BACKEND_DAI_SLIMBUS_5_TX,
 	MSM_BACKEND_DAI_EXTPROC_RX,
 	MSM_BACKEND_DAI_EXTPROC_TX,
 	MSM_BACKEND_DAI_EXTPROC_EC_TX,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index d0b119c..a25fb2a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,7 +11,7 @@
  */
 #ifndef _MSM_PCM_VOICE_H
 #define _MSM_PCM_VOICE_H
-#include <sound/apr_audio.h>
+#include <sound/apr_audio-v2.h>
 
 enum {
 	VOICE_SESSION_INDEX,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 1b5ad17..97cd3fc 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -9,7 +9,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/kernel.h>
@@ -22,10 +21,10 @@
 #include <sound/apr_audio-v2.h>
 #include <sound/q6afe-v2.h>
 #include <sound/q6audio-v2.h>
+#include "msm-pcm-routing-v2.h"
 
 #include "audio_acdb.h"
 
-
 struct afe_ctl {
 	void *apr;
 	atomic_t state;
@@ -44,8 +43,12 @@
 	atomic_t mem_map_cal_handles[MAX_AUDPROC_TYPES];
 	atomic_t mem_map_cal_index;
 	u16 dtmf_gen_rx_portid;
+	struct afe_spkr_prot_calib_get_resp calib_data;
+	int vi_tx_port;
 };
 
+static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
+
 static struct afe_ctl this_afe;
 
 #define TIMEOUT_MS 1000
@@ -56,6 +59,10 @@
 
 static int32_t afe_callback(struct apr_client_data *data, void *priv)
 {
+	if (!data) {
+		pr_err("%s: Invalid param data\n", __func__);
+		return -EINVAL;
+	}
 	if (data->opcode == RESET_EVENTS) {
 		pr_debug("q6afe: reset event = %d %d apr[%p]\n",
 			data->reset_event, data->reset_proc, this_afe.apr);
@@ -69,11 +76,30 @@
 			this_afe.task->comm, this_afe.task->pid);
 		return 0;
 	}
-	pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x\n",
-				__func__, data->opcode,
-				((uint32_t *)(data->payload))[0],
-				((uint32_t *)(data->payload))[1]);
-	if (data->payload_size) {
+	pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x size = %d\n",
+			__func__, data->opcode,
+			((uint32_t *)(data->payload))[0],
+			((uint32_t *)(data->payload))[1],
+			 data->payload_size);
+	if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V2) {
+		u8 *payload = data->payload;
+		if ((data->payload_size < sizeof(this_afe.calib_data))
+			|| !payload || (data->token >= AFE_MAX_PORTS)) {
+			pr_err("%s size %d payload %p token %d\n",
+			__func__, data->payload_size, payload, data->token);
+			return -EINVAL;
+		}
+		memcpy(&this_afe.calib_data, payload,
+			   sizeof(this_afe.calib_data));
+		if (!this_afe.calib_data.status) {
+			atomic_set(&this_afe.state, 0);
+			pr_err("%s rest %d state %x\n" , __func__
+			, this_afe.calib_data.res_cfg.r0_cali_q24,
+			this_afe.calib_data.res_cfg.th_vi_ca_state);
+		} else
+			atomic_set(&this_afe.state, -1);
+		wake_up(&this_afe.wait[data->token]);
+	} else if (data->payload_size) {
 		uint32_t *payload;
 		uint16_t port_id = 0;
 		payload = data->payload;
@@ -97,6 +123,7 @@
 			case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS:
 			case AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER:
 			case AFE_PORTS_CMD_DTMF_CTL:
+			case AFE_SVC_CMD_SET_PARAM:
 				atomic_set(&this_afe.state, 0);
 				wake_up(&this_afe.wait[data->token]);
 				break;
@@ -194,6 +221,7 @@
 	case SLIMBUS_2_TX:
 	case SLIMBUS_3_TX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 	case INT_FM_TX:
 	case VOICE_RECORD_RX:
 	case INT_BT_SCO_TX:
@@ -274,6 +302,37 @@
 	return ret;
 }
 
+/*
+ * afe_apr_send_pkt : returns 0 on success, negative otherwise.
+ */
+static int afe_apr_send_pkt(void *data, wait_queue_head_t *wait)
+{
+	int ret;
+
+	atomic_set(&this_afe.state, 1);
+	atomic_set(&this_afe.status, 0);
+	ret = apr_send_pkt(this_afe.apr, data);
+	if (ret > 0) {
+		if (wait) {
+			ret = wait_event_timeout(*wait,
+					(atomic_read(&this_afe.state) == 0),
+					msecs_to_jiffies(TIMEOUT_MS));
+			if (ret)
+				ret = 0;
+			else
+				ret = -ETIMEDOUT;
+		} else {
+			ret = 0;
+		}
+	} else if (ret == 0) {
+		/* apr_send_pkt can return 0 when nothing is transmitted */
+		ret = -EINVAL;
+	}
+
+	pr_debug("%s: leave %d\n", __func__, ret);
+	return ret;
+}
+
 static void afe_send_cal_block(int32_t path, u16 port_id)
 {
 	int						result = 0;
@@ -326,44 +385,466 @@
 		__func__, port_id, path,
 		cal_block.cal_size, cal_block.cal_paddr);
 
-	atomic_set(&this_afe.state, 1);
-	result = apr_send_pkt(this_afe.apr, (uint32_t *) &afe_cal);
-	if (result < 0) {
-		pr_err("%s: AFE cal for port %d failed\n",
-			__func__, port_id);
-	}
-
-	result = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!result) {
-		pr_err("%s: wait_event timeout SET AFE CAL\n", __func__);
-		goto done;
-	}
-
-	pr_debug("%s: AFE cal sent for path %d device!\n", __func__, path);
+	result = afe_apr_send_pkt(&afe_cal, &this_afe.wait[index]);
+	if (result)
+		pr_err("%s: AFE cal for port %d failed %d\n",
+		       __func__, port_id, result);
+	else
+		pr_debug("%s: AFE cal sent for path %d device!\n", __func__,
+			 path);
 done:
 	return;
 }
 
+static int afe_spk_prot_prepare(int port, int param_id,
+		union afe_spkr_prot_config *prot_config)
+{
+	int ret = -EINVAL;
+	int index = 0;
+	struct afe_spkr_prot_config_command config;
+
+	if (!prot_config) {
+		pr_err("%s Invalid params\n", __func__);
+		goto fail_cmd;
+	}
+	if ((q6audio_validate_port(port) < 0)) {
+		pr_err("%s invalid port %d", __func__, port);
+		goto fail_cmd;
+	}
+	memset(&config, 0 , sizeof(config));
+	index = q6audio_get_port_index(port);
+	switch (param_id) {
+	case AFE_PARAM_ID_FBSP_MODE_RX_CFG:
+		config.pdata.module_id = AFE_MODULE_FB_SPKR_PROT_RX;
+		break;
+	case AFE_PARAM_ID_FEEDBACK_PATH_CFG:
+		this_afe.vi_tx_port = port;
+	case AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG:
+	case AFE_PARAM_ID_MODE_VI_PROC_CFG:
+		config.pdata.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC;
+		break;
+	default:
+		goto fail_cmd;
+		break;
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = index;
+
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = q6audio_get_port_id(port);
+	config.param.payload_size = sizeof(config) - sizeof(config.hdr)
+		- sizeof(config.param);
+	config.pdata.param_id = param_id;
+	config.pdata.param_size = sizeof(config.prot_config);
+	config.prot_config = *prot_config;
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+	if (ret < 0) {
+		pr_err("%s: Setting param for port %d param[0x%x]failed\n",
+		 __func__, port, param_id);
+		goto fail_cmd;
+	}
+	ret = wait_event_timeout(this_afe.wait[index],
+		(atomic_read(&this_afe.state) == 0),
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	ret = 0;
+fail_cmd:
+	pr_err("%s config.pdata.param_id %x status %d\n",
+	__func__, config.pdata.param_id, ret);
+	return ret;
+}
+
+static void afe_send_cal_spkr_prot_tx(int port_id)
+{
+	struct msm_spk_prot_cfg prot_cfg;
+	union afe_spkr_prot_config afe_spk_config;
+
+	/*Get spkr protection cfg data*/
+	get_spk_protection_cfg(&prot_cfg);
+
+	if ((!prot_cfg.mode || prot_cfg.mode == 1) &&
+		(this_afe.vi_tx_port == port_id)) {
+		afe_spk_config.mode_rx_cfg.minor_version = 1;
+		afe_spk_config.mode_rx_cfg.mode =
+		(uint32_t)prot_cfg.mode;
+		if (afe_spk_prot_prepare(port_id,
+			AFE_PARAM_ID_MODE_VI_PROC_CFG,
+			&afe_spk_config))
+			pr_err("%s TX VI_PROC_CFG failed\n", __func__);
+		afe_spk_config.vi_proc_cfg.minor_version = 1;
+		afe_spk_config.vi_proc_cfg.r0_cali_q24 =
+		(uint32_t) prot_cfg.r0;
+		afe_spk_config.vi_proc_cfg.t0_cali_q6 =
+		(uint32_t) prot_cfg.t0;
+		if (afe_spk_prot_prepare(port_id,
+			AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG,
+			&afe_spk_config))
+			pr_err("%s SPKR_CALIB_VI_PROC_CFG failed\n",
+				__func__);
+	}
+}
+
+static void afe_send_cal_spkr_prot_rx(int port_id)
+{
+	struct msm_spk_prot_cfg prot_cfg;
+	union afe_spkr_prot_config afe_spk_config;
+
+	/*Get spkr protection cfg data*/
+	get_spk_protection_cfg(&prot_cfg);
+
+	if (!prot_cfg.mode || prot_cfg.mode == 1) {
+		afe_spk_config.mode_rx_cfg.mode =
+		(uint32_t)prot_cfg.mode;
+		afe_spk_config.mode_rx_cfg.minor_version = 1;
+		if (afe_spk_prot_prepare(port_id,
+			AFE_PARAM_ID_FBSP_MODE_RX_CFG,
+			&afe_spk_config))
+			pr_err("%s RX MODE_VI_PROC_CFG failed\n",
+				   __func__);
+	}
+}
+
 void afe_send_cal(u16 port_id)
 {
 	pr_debug("%s\n", __func__);
 
-	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) {
+		afe_send_cal_spkr_prot_tx(port_id);
 		afe_send_cal_block(TX_CAL, port_id);
-	else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+	} else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) {
+		afe_send_cal_spkr_prot_rx(port_id);
 		afe_send_cal_block(RX_CAL, port_id);
+	}
+}
+
+int afe_turn_onoff_hw_mad(u16 mad_type, u16 enable)
+{
+	int ret;
+	struct afe_cmd_hw_mad_ctrl config;
+
+	pr_debug("%s: enter\n", __func__);
+	memset(&config, 0, sizeof(config));
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					     APR_HDR_LEN(APR_HDR_SIZE),
+					     APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = IDX_GLOBAL_CFG;
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = SLIMBUS_5_TX;
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_HW_MAD;
+	config.pdata.param_id = AFE_PARAM_ID_HW_MAD_CTRL;
+	config.pdata.param_size = sizeof(config.payload);
+	config.payload.minor_version = 1;
+	config.payload.mad_type = mad_type;
+	config.payload.mad_enable = enable;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+	if (ret)
+		pr_err("%s: AFE_PARAM_ID_HW_MAD_CTRL failed %d\n", __func__,
+		       ret);
+	return ret;
+}
+
+static int afe_send_slimbus_slave_cfg(
+	struct afe_param_cdc_slimbus_slave_cfg *sb_slave_cfg)
+{
+	int ret;
+	struct afe_svc_cmd_sb_slave_cfg config;
+
+	pr_debug("%s: enter\n", __func__);
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					     APR_HDR_LEN(APR_HDR_SIZE),
+					     APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = IDX_GLOBAL_CFG;
+	config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+	config.pdata.param_id = AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG;
+	config.pdata.param_size =
+	    sizeof(struct afe_param_cdc_slimbus_slave_cfg);
+	config.sb_slave_cfg = *sb_slave_cfg;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+	if (ret)
+		pr_err("%s: AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG failed %d\n",
+		       __func__, ret);
+
+	pr_debug("%s: leave %d\n", __func__, ret);
+	return ret;
+}
+
+static int afe_send_codec_reg_config(
+	struct afe_param_cdc_reg_cfg_data *cdc_reg_cfg)
+{
+	int i, ret;
+	int pkt_size, payload_size;
+	struct afe_svc_cmd_cdc_reg_cfg *config;
+	struct afe_svc_cmd_set_param *param;
+
+	pr_debug("%s: enter\n", __func__);
+	payload_size = sizeof(struct afe_param_cdc_reg_cfg_payload) *
+		       cdc_reg_cfg->num_registers;
+	pkt_size = sizeof(*config) + payload_size;
+
+	pr_debug("%s: pkt_size %d, payload %d\n", __func__, pkt_size,
+		 payload_size);
+	config = kzalloc(pkt_size, GFP_KERNEL);
+	if (!config) {
+		pr_warn("%s: Not enought memory, pkt_size %d\n", __func__,
+			pkt_size);
+		return -ENOMEM;
+	}
+
+	config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+	config->hdr.pkt_size = pkt_size;
+	config->hdr.src_port = 0;
+	config->hdr.dest_port = 0;
+	config->hdr.token = IDX_GLOBAL_CFG;
+	config->hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+	param = &config->param;
+	param->payload_size = payload_size;
+	param->payload_address_lsw = 0x00;
+	param->payload_address_msw = 0x00;
+	param->mem_map_handle = 0x00;
+
+	for (i = 0; i < cdc_reg_cfg->num_registers; i++) {
+		config->reg_data[i].common.module_id = AFE_MODULE_CDC_DEV_CFG;
+		config->reg_data[i].common.param_id = AFE_PARAM_ID_CDC_REG_CFG;
+		config->reg_data[i].common.param_size =
+		    sizeof(config->reg_data[i].reg_cfg);
+		config->reg_data[i].reg_cfg = cdc_reg_cfg->reg_data[i];
+	}
+
+	ret = afe_apr_send_pkt(config, &this_afe.wait[IDX_GLOBAL_CFG]);
+	if (ret)
+		pr_err("%s: AFE_PARAM_ID_CDC_REG_CFG failed %d\n", __func__,
+		       ret);
+
+	kfree(config);
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+	return ret;
+}
+
+static int afe_init_cdc_reg_config(void)
+{
+	int ret;
+	struct afe_svc_cmd_init_cdc_reg_cfg config;
+
+	pr_debug("%s: enter\n", __func__);
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					     APR_HDR_LEN(APR_HDR_SIZE),
+					     APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = IDX_GLOBAL_CFG;
+	config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+	config.param.payload_size = sizeof(struct afe_port_param_data_v2);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+
+	config.init.module_id = AFE_MODULE_CDC_DEV_CFG;
+	config.init.param_id = AFE_PARAM_ID_CDC_REG_CFG_INIT;
+	config.init.param_size = 0;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+	if (ret) {
+		pr_err("%s: AFE_PARAM_ID_CDC_INIT_REG_CFG failed %d\n",
+		       __func__, ret);
+	} else if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+	}
+
+	pr_debug("%s: leave ret %d\n", __func__, 0);
+	return ret;
+}
+
+static int afe_send_slimbus_slave_port_cfg(
+	struct afe_param_slimbus_slave_port_cfg *port_config, u16 port_id)
+{
+	int ret, index;
+	struct afe_cmd_hw_mad_slimbus_slave_port_cfg config;
+
+	pr_debug("%s: enter, port_id %u\n", __func__, port_id);
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s: port id: %#x\n", __func__, port_id);
+		return -EINVAL;
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					     APR_HDR_LEN(APR_HDR_SIZE),
+					     APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = index;
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = port_id;
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_HW_MAD;
+	config.pdata.param_id = AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG;
+	config.pdata.param_size = sizeof(*port_config);
+	config.sb_port_cfg = *port_config;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE_PARAM_ID_SLIMBUS_SLAVE_PORT_CFG failed %d\n",
+			__func__, ret);
+	} else if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+	}
+	pr_debug("%s: leave %d\n", __func__, ret);
+	return ret;
+}
+
+int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type)
+{
+	int i;
+
+	i = port_id - SLIMBUS_0_RX;
+	if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+		pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+		return -EINVAL;
+	}
+	atomic_set(&afe_ports_mad_type[i], mad_type);
+	return 0;
+}
+
+enum afe_mad_type afe_port_get_mad_type(u16 port_id)
+{
+	int i;
+
+	i = port_id - SLIMBUS_0_RX;
+	if (i < 0 || i > ARRAY_SIZE(afe_ports_mad_type)) {
+		pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
+		return MAD_HW_NONE;
+	}
+	return (enum afe_mad_type) atomic_read(&afe_ports_mad_type[i]);
+}
+
+int afe_set_config(enum afe_config_type config_type, void *config_data, int arg)
+{
+	int ret;
+
+	pr_debug("%s: enter config_type %d\n", __func__, config_type);
+	ret = afe_q6_interface_prepare();
+	if (ret) {
+		pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	switch (config_type) {
+	case AFE_SLIMBUS_SLAVE_CONFIG:
+		ret = afe_send_slimbus_slave_cfg(config_data);
+		if (!ret)
+			ret = afe_init_cdc_reg_config();
+		else
+			pr_err("%s: Sending slimbus slave config failed %d\n",
+			       __func__, ret);
+		break;
+	case AFE_CDC_REGISTERS_CONFIG:
+		ret = afe_send_codec_reg_config(config_data);
+		break;
+	case AFE_SLIMBUS_SLAVE_PORT_CONFIG:
+		ret = afe_send_slimbus_slave_port_cfg(config_data, arg);
+		break;
+	default:
+		pr_err("%s: unknown configuration type", __func__);
+		ret = -EINVAL;
+	}
+
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+	return ret;
+}
+
+static int afe_send_cmd_port_start(u16 port_id)
+{
+	struct afe_port_cmd_device_start start;
+	int ret, index;
+
+	pr_debug("%s: enter\n", __func__);
+	index = q6audio_get_port_index(port_id);
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_err("%s: port id: %#x\n", __func__, port_id);
+		return -EINVAL;
+	}
+
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					    APR_HDR_LEN(APR_HDR_SIZE),
+					    APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = index;
+	start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+	start.port_id = q6audio_get_port_id(port_id);
+	pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
+		 __func__, start.hdr.opcode, start.port_id);
+
+	ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE enable for port %#x failed %d\n", __func__,
+		       port_id, ret);
+	} else if (this_afe.task != current) {
+		this_afe.task = current;
+		pr_debug("task_name = %s pid = %d\n",
+			 this_afe.task->comm, this_afe.task->pid);
+	}
+
+	pr_debug("%s: leave %d\n", __func__, ret);
+	return ret;
 }
 
 int afe_port_start(u16 port_id, union afe_port_config *afe_config,
 	u32 rate) /* This function is no blocking */
 {
-	struct afe_port_cmd_device_start start;
 	struct afe_audioif_config_command config;
-	int ret;
+	int ret = 0;
 	int cfg_type;
 	int index = 0;
+	enum afe_mad_type mad_type;
 
 	if (!afe_config) {
 		pr_err("%s: Error, no configuration data\n", __func__);
@@ -379,6 +860,7 @@
 		port_id = VIRTUAL_ID_TO_PORTID(port_id);
 
 	pr_debug("%s: port id: %#x\n", __func__, port_id);
+
 	index = q6audio_get_port_index(port_id);
 	if (q6audio_validate_port(port_id) < 0) {
 		pr_err("%s: port id: %#x\n", __func__, port_id);
@@ -389,11 +871,19 @@
 	if (IS_ERR_VALUE(ret))
 		return ret;
 
-	if (q6audio_validate_port(port_id) < 0) {
-		pr_err("%s: Failed : Invalid Port id = %#x\n", __func__,
-				port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
+	afe_send_cal(port_id);
+
+	/* Start SW MAD module */
+	mad_type = afe_port_get_mad_type(port_id);
+	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+		 mad_type);
+	if (mad_type != MAD_HW_NONE) {
+		ret = afe_turn_onoff_hw_mad(mad_type, true);
+		if (ret) {
+			pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+			       __func__, ret);
+			return ret;
+		}
 	}
 
 	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -443,6 +933,7 @@
 	case SLIMBUS_3_TX:
 	case SLIMBUS_4_RX:
 	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 		cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
 		break;
 	case RT_PROXY_PORT_001_RX:
@@ -473,69 +964,17 @@
 
 	config.port = *afe_config;
 
-	atomic_set(&this_afe.state, 1);
-	atomic_set(&this_afe.status, 0);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
 		pr_err("%s: AFE enable for port %#x failed\n", __func__,
 				port_id);
-		ret = -EINVAL;
 		goto fail_cmd;
-	}
-	ret = wait_event_timeout(this_afe.wait[index],
-				(atomic_read(&this_afe.state) == 0),
-					msecs_to_jiffies(TIMEOUT_MS));
-
-	if (!ret) {
-		pr_err("%s: wait_event timeout IF CONFIG\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	if (atomic_read(&this_afe.status) != 0) {
+	} else if (atomic_read(&this_afe.status) != 0) {
 		pr_err("%s: config cmd failed\n", __func__);
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-	/* send AFE cal */
-	afe_send_cal(port_id);
-
-	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	start.hdr.pkt_size = sizeof(start);
-	start.hdr.src_port = 0;
-	start.hdr.dest_port = 0;
-	start.hdr.token = index;
-	start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
-	start.port_id = q6audio_get_port_id(port_id);
-	pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
-		 __func__, start.hdr.opcode, start.port_id);
-
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-
-	if (IS_ERR_VALUE(ret)) {
-		pr_err("%s: AFE enable for port %#x failed\n", __func__,
-				port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-				(atomic_read(&this_afe.state) == 0),
-					msecs_to_jiffies(TIMEOUT_MS));
-
-	if (!ret) {
-		pr_err("%s: wait_event timeout PORT START\n", __func__);
-		 ret = -EINVAL;
-		goto fail_cmd;
-	}
-	if (this_afe.task != current)
-		this_afe.task = current;
-
-	pr_debug("task_name = %s pid = %d\n",
-		this_afe.task->comm, this_afe.task->pid);
-
-	return 0;
+	return afe_send_cmd_port_start(port_id);
 
 fail_cmd:
 	return ret;
@@ -575,6 +1014,7 @@
 	case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
 	case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
 	case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+	case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
 	case AFE_PORT_ID_PRIMARY_MI2S_RX:
 		return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
 	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
@@ -687,25 +1127,13 @@
 		__func__, config.param.payload_size, config.pdata.param_size,
 		sizeof(config), sizeof(config.param), sizeof(config.port),
 		sizeof(struct apr_hdr), config.pdata.param_id);
-	atomic_set(&this_afe.state, 1);
-	atomic_set(&this_afe.status, 0);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
 		pr_err("%s: AFE enable for port %d opcode[0x%x]failed\n",
 			__func__, port_id, cfg_type);
-		ret = -EINVAL;
 		goto fail_cmd;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-			(atomic_read(&this_afe.state) == 0),
-				msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	if (atomic_read(&this_afe.status) != 0) {
+	} else if (atomic_read(&this_afe.status) != 0) {
 		pr_err("%s: config cmd failed\n", __func__);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -720,24 +1148,14 @@
 	start.port_id = q6audio_get_port_id(port_id);
 	pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
 		__func__, start.hdr.opcode, start.port_id);
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+	if (ret) {
 		pr_err("%s: AFE enable for port %d failed\n", __func__,
 				port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	ret = wait_event_timeout(this_afe.wait[index],
-			(atomic_read(&this_afe.state) == 0),
-				msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
 		goto fail_cmd;
 	}
 
-	return 0;
 fail_cmd:
 	return ret;
 }
@@ -784,23 +1202,10 @@
 	lb_cmd.routing_mode = LB_MODE_DEFAULT;
 	lb_cmd.enable = (enable ? 1 : 0);
 	lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
-	atomic_set(&this_afe.state, 1);
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
-	if (ret < 0) {
-		pr_err("%s: AFE loopback failed\n", __func__);
-		ret = -EINVAL;
-		goto done;
-	}
-	pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-	}
-done:
+	ret = afe_apr_send_pkt(&lb_cmd, &this_afe.wait[index]);
+	if (ret)
+		pr_err("%s: AFE loopback failed %d\n", __func__, ret);
 	return ret;
 }
 
@@ -866,24 +1271,13 @@
 	set_param.rx_port_id = port_id;
 	set_param.gain = volume;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&set_param, &this_afe.wait[index]);
+	if (ret) {
 		pr_err("%s: AFE param set failed for port %d\n",
 					__func__, port_id);
-		ret = -EINVAL;
 		goto fail_cmd;
 	}
 
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (ret < 0) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	return 0;
 fail_cmd:
 	return ret;
 }
@@ -910,9 +1304,8 @@
 	start.port_id = port_id;
 	start.timing = 1;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&start, NULL);
+	if (ret) {
 		pr_err("%s: AFE enable for port %d failed %d\n",
 		       __func__, port_id, ret);
 		return -EINVAL;
@@ -945,25 +1338,13 @@
 	start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
 	start.port_id = port_id;
 	start.timing = 1;
-
 	start.hdr.token = index;
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&start, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE enable for port %d failed %d\n",
 		       __func__, port_id, ret);
-		return -EINVAL;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
+	return ret;
 }
 
 int afe_pseudo_port_stop_nowait(u16 port_id)
@@ -991,17 +1372,13 @@
 	stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
 	stop.port_id = port_id;
 	stop.reserved = 0;
-
 	stop.hdr.token = index;
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&stop, NULL);
+	if (ret)
 		pr_err("%s: AFE close failed %d\n", __func__, ret);
-		return -EINVAL;
-	}
 
-	return 0;
-
+	return ret;
 }
 
 int afe_stop_pseudo_port(u16 port_id)
@@ -1030,24 +1407,13 @@
 	stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
 	stop.port_id = port_id;
 	stop.reserved = 0;
-
 	stop.hdr.token = index;
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
-	if (ret < 0) {
+
+	ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE close failed %d\n", __func__, ret);
-		return -EINVAL;
-	}
 
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
+	return ret;
 }
 
 uint32_t afe_req_mmap_handle(struct afe_audio_client *ac)
@@ -1330,15 +1696,11 @@
 	mregion_pl->shm_addr_msw = 0x00;
 	mregion_pl->mem_size_bytes = dma_buf_sz;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(mmap_region_cmd, NULL);
+	if (ret)
 		pr_err("%s: AFE memory map cmd failed %d\n",
 		       __func__, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
 			struct afe_audio_client *ac)
@@ -1426,24 +1788,11 @@
 	/* Todo */
 	index = mregion.hdr.token = IDX_RSVD_2;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&mregion, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE memory unmap cmd failed %d\n",
 		       __func__, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 
 int afe_cmd_memory_unmap_nowait(u32 mem_map_handle)
@@ -1473,13 +1822,11 @@
 	mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
 	mregion.mem_map_handle = mem_map_handle;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&mregion, NULL);
+	if (ret)
 		pr_err("%s: AFE memory unmap cmd failed %d\n",
 			__func__, ret);
-		ret = -EINVAL;
-	}
-	return 0;
+	return ret;
 }
 
 int afe_register_get_events(u16 port_id,
@@ -1525,14 +1872,11 @@
 	rtproxy.port_id = port_id;
 	rtproxy.reserved = 0;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&rtproxy, NULL);
+	if (ret)
 		pr_err("%s: AFE  reg. rtproxy_event failed %d\n",
 			   __func__, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 
 int afe_unregister_get_events(u16 port_id)
@@ -1584,24 +1928,11 @@
 		this_afe.rx_private_data = NULL;
 	}
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&rtproxy, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
 			   __func__, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-				 (atomic_read(&this_afe.state) == 0),
-				 msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 
 int afe_rt_proxy_port_write(u32 buf_addr_p, u32 mem_map_handle, int bytes)
@@ -1631,14 +1962,11 @@
 	afecmd_wr.available_bytes = bytes;
 	afecmd_wr.reserved = 0;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&afecmd_wr, NULL);
+	if (ret)
 		pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
 			   __func__, afecmd_wr.port_id, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 
 }
 
@@ -1668,14 +1996,11 @@
 	afecmd_rd.available_bytes = bytes;
 	afecmd_rd.mem_map_handle = mem_map_handle;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&afecmd_rd, NULL);
+	if (ret)
 		pr_err("%s: AFE rtproxy read  cmd to port 0x%x failed %d\n",
 			   __func__, afecmd_rd.port_id, ret);
-		ret = -EINVAL;
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -1952,25 +2277,10 @@
 	cmd_sidetone.routing_mode = LB_MODE_SIDETONE;
 	cmd_sidetone.enable = enable;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
-	if (ret < 0) {
+	ret = afe_apr_send_pkt(&cmd_sidetone, &this_afe.wait[index]);
+	if (ret)
 		pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
 					__func__, tx_port_id, rx_port_id);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-		(atomic_read(&this_afe.state) == 0),
-			msecs_to_jiffies(TIMEOUT_MS));
-	if (ret < 0) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-	return 0;
-fail_cmd:
 	return ret;
 }
 
@@ -2067,12 +2377,9 @@
 	stop.port_id = port_id;
 	stop.reserved = 0;
 
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
-
-	if (IS_ERR_VALUE(ret)) {
+	ret = afe_apr_send_pkt(&stop, NULL);
+	if (ret)
 		pr_err("%s: AFE close failed\n", __func__);
-		ret = -EINVAL;
-	}
 
 fail_cmd:
 	return ret;
@@ -2082,10 +2389,10 @@
 int afe_close(int port_id)
 {
 	struct afe_port_cmd_device_stop stop;
+	enum afe_mad_type mad_type;
 	int ret = 0;
 	int index = 0;
 
-
 	if (this_afe.apr == NULL) {
 		pr_err("AFE is already closed\n");
 		ret = -EINVAL;
@@ -2095,9 +2402,25 @@
 
 	port_id = q6audio_convert_virtual_to_portid(port_id);
 	index = q6audio_get_port_index(port_id);
-	if (q6audio_validate_port(port_id) < 0)
+	if (q6audio_validate_port(port_id) < 0) {
+		pr_warn("%s: Not a valid port id 0x0%x\n", __func__, port_id);
 		return -EINVAL;
+	}
 
+	mad_type = afe_port_get_mad_type(port_id);
+	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
+		 mad_type);
+	if (mad_type != MAD_HW_NONE) {
+		pr_debug("%s: Turn off MAD\n", __func__);
+		ret = afe_turn_onoff_hw_mad(mad_type, false);
+		if (ret) {
+			pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
+			       __func__, ret);
+			return ret;
+		}
+	} else {
+		pr_debug("%s: Not a MAD port\n", __func__);
+	}
 
 	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -2109,23 +2432,10 @@
 	stop.port_id = q6audio_get_port_id(port_id);
 	stop.reserved = 0;
 
-	atomic_set(&this_afe.state, 1);
-	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+	ret = afe_apr_send_pkt(&stop, &this_afe.wait[index]);
+	if (ret)
+		pr_err("%s: AFE close failed %d\n", __func__, ret);
 
-	if (ret < 0) {
-		pr_err("%s: AFE close failed\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
-
-	ret = wait_event_timeout(this_afe.wait[index],
-			(atomic_read(&this_afe.state) == 0),
-					msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		goto fail_cmd;
-	}
 fail_cmd:
 	return ret;
 }
@@ -2299,6 +2609,107 @@
 	return ret;
 }
 
+int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp)
+{
+	int ret = -EINVAL;
+	int index = 0, port = SLIMBUS_4_TX;
+
+	if (!calib_resp) {
+		pr_err("%s Invalid params\n", __func__);
+		goto fail_cmd;
+	}
+	if ((q6audio_validate_port(port) < 0)) {
+		pr_err("%s invalid port %d\n", __func__, port);
+		goto fail_cmd;
+	}
+	index = q6audio_get_port_index(port);
+	calib_resp->get_param.hdr.hdr_field =
+	APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+	APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	calib_resp->get_param.hdr.pkt_size = sizeof(*calib_resp);
+	calib_resp->get_param.hdr.src_port = 0;
+	calib_resp->get_param.hdr.dest_port = 0;
+	calib_resp->get_param.hdr.token = index;
+	calib_resp->get_param.hdr.opcode =  AFE_PORT_CMD_GET_PARAM_V2;
+	calib_resp->get_param.mem_map_handle = 0;
+	calib_resp->get_param.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC;
+	calib_resp->get_param.param_id = AFE_PARAM_ID_CALIB_RES_CFG;
+	calib_resp->get_param.payload_address_lsw = 0;
+	calib_resp->get_param.payload_address_msw = 0;
+	calib_resp->get_param.payload_size = sizeof(*calib_resp)
+		- sizeof(calib_resp->get_param);
+	calib_resp->get_param.port_id = q6audio_get_port_id(port);
+	calib_resp->pdata.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC;
+	calib_resp->pdata.param_id = AFE_PARAM_ID_CALIB_RES_CFG;
+	calib_resp->pdata.param_size = sizeof(calib_resp->res_cfg);
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *)calib_resp);
+	if (ret < 0) {
+		pr_err("%s: get param port %d param id[0x%x]failed\n",
+			   __func__, port, calib_resp->get_param.param_id);
+		goto fail_cmd;
+	}
+	ret = wait_event_timeout(this_afe.wait[index],
+		(atomic_read(&this_afe.state) == 0),
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	memcpy(&calib_resp->res_cfg , &this_afe.calib_data.res_cfg,
+		sizeof(this_afe.calib_data.res_cfg));
+	pr_debug("%s state %d resistance %d\n", __func__,
+			 calib_resp->res_cfg.th_vi_ca_state,
+			 calib_resp->res_cfg.r0_cali_q24);
+	ret = 0;
+fail_cmd:
+	return ret;
+}
+
+int afe_spk_prot_feed_back_cfg(int src_port, int dst_port,
+	int l_ch, int r_ch)
+{
+	int ret = -EINVAL;
+	union afe_spkr_prot_config prot_config;
+	int index = 0;
+
+	if ((q6audio_validate_port(src_port) < 0) ||
+		(q6audio_validate_port(dst_port) < 0)) {
+		pr_err("%s invalid ports src %d dst %d",
+			__func__, src_port, dst_port);
+		goto fail_cmd;
+	}
+	if (!l_ch && !r_ch) {
+		pr_err("%s error ch values zero\n", __func__);
+		goto fail_cmd;
+	}
+	pr_debug("%s src_port %x  dst_port %x l_ch %d r_ch %d\n",
+		 __func__, src_port, dst_port, l_ch, r_ch);
+	memset(&prot_config, 0, sizeof(prot_config));
+	prot_config.feedback_path_cfg.dst_portid =
+		q6audio_get_port_id(dst_port);
+	if (l_ch) {
+		prot_config.feedback_path_cfg.chan_info[index++] = 1;
+		prot_config.feedback_path_cfg.chan_info[index++] = 2;
+	}
+	if (r_ch) {
+		prot_config.feedback_path_cfg.chan_info[index++] = 3;
+		prot_config.feedback_path_cfg.chan_info[index++] = 4;
+	}
+	prot_config.feedback_path_cfg.num_channels = index;
+	prot_config.feedback_path_cfg.minor_version = 1;
+	ret = afe_spk_prot_prepare(src_port,
+			AFE_PARAM_ID_FEEDBACK_PATH_CFG, &prot_config);
+fail_cmd:
+	return ret;
+}
+
 static int __init afe_init(void)
 {
 	int i = 0;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 4e7455b..0549671 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -2344,7 +2344,7 @@
 	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
 					sizeof(fmt.fmt_blk);
 	fmt.num_channels = channels;
-	fmt.bits_per_sample = 16;
+	fmt.bits_per_sample = bits_per_sample;
 	fmt.sample_rate = rate;
 	fmt.is_signed = 1;
 
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 99cb6a6..d3d335d 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -43,6 +43,8 @@
 	case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
 	case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
 	case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
+	case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+	case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
 	case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
 	case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
 	case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -89,6 +91,8 @@
 	case SLIMBUS_1_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX;
 	case SLIMBUS_2_RX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX;
 	case SLIMBUS_2_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX;
+	case SLIMBUS_4_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX;
+	case SLIMBUS_5_TX: return AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
 	case INT_BT_SCO_RX: return AFE_PORT_ID_INTERNAL_BT_SCO_RX;
 	case INT_BT_SCO_TX: return AFE_PORT_ID_INTERNAL_BT_SCO_TX;
 	case INT_BT_A2DP_RX: return AFE_PORT_ID_INTERNAL_BT_A2DP_RX;
@@ -107,7 +111,9 @@
 	case AFE_PORT_ID_SECONDARY_MI2S_TX:
 			     return AFE_PORT_ID_SECONDARY_MI2S_TX;
 
-	default: return -EINVAL;
+	default:
+		pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
+		return -EINVAL;
 	}
 }
 int q6audio_convert_virtual_to_portid(u16 port_id)
@@ -182,6 +188,8 @@
 	case SLIMBUS_1_TX:
 	case SLIMBUS_2_RX:
 	case SLIMBUS_2_TX:
+	case SLIMBUS_4_TX:
+	case SLIMBUS_5_TX:
 	case INT_BT_SCO_RX:
 	case INT_BT_SCO_TX:
 	case INT_BT_A2DP_RX:
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
new file mode 100644
index 0000000..f2b531a
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/memory_alloc.h>
+#include <linux/debugfs.h>
+#include <linux/time.h>
+#include <linux/atomic.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/lsm_params.h>
+#include <sound/q6lsm.h>
+#include <asm/ioctls.h>
+#include <mach/memory.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_subsystem_map.h>
+#include "audio_acdb.h"
+
+#define APR_TIMEOUT	(5 * HZ)
+#define LSM_CAL_SIZE	4096
+
+enum {
+	CMD_STATE_CLEARED = 0,
+	CMD_STATE_WAIT_RESP = 1,
+};
+
+enum {
+	LSM_INVALID_SESSION_ID = 0,
+	LSM_MIN_SESSION_ID = 1,
+	LSM_MAX_SESSION_ID = 8,
+};
+
+struct lsm_common {
+	void *apr;
+	atomic_t apr_users;
+	uint32_t lsm_cal_addr;
+	uint32_t lsm_cal_size;
+	uint32_t mmap_handle_for_cal;
+	struct mutex apr_lock;
+};
+
+static struct lsm_common lsm_common;
+
+/*
+ * mmap_handle_p can point either client->sound_model.mem_map_handle or
+ * lsm_common.mmap_handle_for_cal.
+ * mmap_lock must be held while accessing this.
+ */
+static spinlock_t mmap_lock;
+static uint32_t *mmap_handle_p;
+
+static spinlock_t lsm_session_lock;
+static struct lsm_client *lsm_session[LSM_MAX_SESSION_ID + 1];
+
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
+static int q6lsm_send_cal(struct lsm_client *client);
+static int q6lsm_snd_model_buf_free(struct lsm_client *client);
+
+static int q6lsm_callback(struct apr_client_data *data, void *priv)
+{
+	struct lsm_client *client = (struct lsm_client *)priv;
+	uint32_t token;
+	uint32_t *payload;
+
+	if (!client || !data) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	payload = data->payload;
+	pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n",
+		__func__, client->session,
+		data->opcode, data->token, data->payload_size);
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		token = data->token;
+		switch (payload[0]) {
+		case LSM_SESSION_CMD_START:
+		case LSM_SESSION_CMD_STOP:
+		case LSM_SESSION_CMD_SET_PARAMS:
+		case LSM_SESSION_CMD_OPEN_TX:
+		case LSM_SESSION_CMD_CLOSE_TX:
+		case LSM_SESSION_CMD_REGISTER_SOUND_MODEL:
+		case LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL:
+		case LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS:
+			if (token != client->session &&
+			    payload[0] !=
+				LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL) {
+				pr_err("%s: Invalid session %d receivced expected %d\n",
+					__func__, token, client->session);
+				return -EINVAL;
+			}
+			if (atomic_cmpxchg(&client->cmd_state,
+					   CMD_STATE_WAIT_RESP,
+					   CMD_STATE_CLEARED) ==
+					       CMD_STATE_WAIT_RESP)
+				wake_up(&client->cmd_wait);
+			break;
+		default:
+			pr_debug("%s: Unknown command 0x%x\n",
+				__func__, payload[0]);
+			break;
+		}
+		return 0;
+	}
+
+	if (client->cb)
+		client->cb(data->opcode, data->token, data->payload,
+			   client->priv);
+
+	return 0;
+}
+
+static int q6lsm_session_alloc(struct lsm_client *client)
+{
+	unsigned long flags;
+	int n, ret = -ENOMEM;
+
+	spin_lock_irqsave(&lsm_session_lock, flags);
+	for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
+		if (!lsm_session[n]) {
+			lsm_session[n] = client;
+			ret = n;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&lsm_session_lock, flags);
+	return ret;
+}
+
+static void q6lsm_session_free(struct lsm_client *client)
+{
+	unsigned long flags;
+
+	pr_debug("%s: Freeing session ID %d\n", __func__, client->session);
+	spin_lock_irqsave(&lsm_session_lock, flags);
+	lsm_session[client->session] = LSM_INVALID_SESSION_ID;
+	spin_unlock_irqrestore(&lsm_session_lock, flags);
+	client->session = LSM_INVALID_SESSION_ID;
+}
+
+static void *q6lsm_mmap_apr_reg(void)
+{
+	if (atomic_inc_return(&lsm_common.apr_users) == 1) {
+		lsm_common.apr =
+		    apr_register("ADSP", "LSM", q6lsm_mmapcallback,
+				 0x0FFFFFFFF, &lsm_common);
+		if (!lsm_common.apr) {
+			pr_debug("%s Unable to register APR LSM common port\n",
+				 __func__);
+			atomic_dec(&lsm_common.apr_users);
+		}
+	}
+
+	return lsm_common.apr;
+}
+
+static int q6lsm_mmap_apr_dereg(void)
+{
+	if (atomic_read(&lsm_common.apr_users) <= 0) {
+		WARN("%s: APR common port already closed\n", __func__);
+	} else {
+		if (atomic_dec_return(&lsm_common.apr_users) == 0) {
+			apr_deregister(lsm_common.apr);
+			pr_debug("%s:APR De-Register common port\n", __func__);
+		}
+	}
+	return 0;
+}
+
+struct lsm_client *q6lsm_client_alloc(app_cb cb, void *priv)
+{
+	struct lsm_client *client;
+	int n;
+
+	pr_debug("%s: enter\n", __func__);
+	client = kzalloc(sizeof(struct lsm_client), GFP_KERNEL);
+	if (!client)
+		return NULL;
+	n = q6lsm_session_alloc(client);
+	if (n <= 0) {
+		kfree(client);
+		return NULL;
+	}
+
+	pr_debug("%s: New client session %d\n", __func__, client->session);
+	client->session = n;
+	client->cb = cb;
+	client->priv = priv;
+	client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
+				   ((client->session) << 8 | 0x0001), client);
+
+	if (client->apr == NULL) {
+		pr_err("%s: Registration with APR failed\n", __func__);
+		goto fail;
+	}
+
+	pr_debug("%s Registering the common port with APR\n", __func__);
+	client->mmap_apr = q6lsm_mmap_apr_reg();
+	if (!client->mmap_apr) {
+		pr_err("%s: APR registration failed\n", __func__);
+		goto fail;
+	}
+
+	init_waitqueue_head(&client->cmd_wait);
+	mutex_init(&client->cmd_lock);
+	atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+	pr_debug("%s: New client allocated\n", __func__);
+	return client;
+fail:
+	q6lsm_client_free(client);
+	return NULL;
+}
+
+void q6lsm_client_free(struct lsm_client *client)
+{
+	if (!client || !client->session)
+		return;
+
+	apr_deregister(client->apr);
+	client->mmap_apr = NULL;
+	q6lsm_session_free(client);
+	q6lsm_mmap_apr_dereg();
+	mutex_destroy(&client->cmd_lock);
+	kfree(client);
+}
+
+/*
+ * q6lsm_apr_send_pkt : If wait == true, hold mutex to prevent from preempting
+ *			other thread's wait.
+ *			If mmap_handle_p != NULL, disable irq and spin lock to
+ *			protect mmap_handle_p
+ */
+static int q6lsm_apr_send_pkt(struct lsm_client *client, void *handle,
+			      void *data, bool wait, uint32_t *mmap_p)
+{
+	int ret;
+	unsigned long flags = 0;
+
+	pr_debug("%s: enter wait %d\n", __func__, wait);
+	if (wait)
+		mutex_lock(&lsm_common.apr_lock);
+	if (mmap_p) {
+		WARN_ON(!wait);
+		spin_lock_irqsave(&mmap_lock, flags);
+		mmap_handle_p = mmap_p;
+	}
+	atomic_set(&client->cmd_state, CMD_STATE_WAIT_RESP);
+	ret = apr_send_pkt(client->apr, data);
+	if (mmap_p)
+		spin_unlock_irqrestore(&mmap_lock, flags);
+
+	if (ret < 0) {
+		pr_err("%s: apr_send_pkt failed %d\n", __func__, ret);
+	} else if (wait) {
+		ret = wait_event_timeout(client->cmd_wait,
+					 (atomic_read(&client->cmd_state) ==
+					      CMD_STATE_CLEARED),
+					 APR_TIMEOUT);
+		if (likely(ret))
+			ret = 0;
+		else
+			pr_err("%s: wait timedout\n", __func__);
+	} else {
+		ret = 0;
+	}
+	if (wait)
+		mutex_unlock(&lsm_common.apr_lock);
+
+	pr_debug("%s: leave ret %d\n", __func__, ret);
+	return ret;
+}
+
+static void q6lsm_add_hdr(struct lsm_client *client, struct apr_hdr *hdr,
+			uint32_t pkt_size, bool cmd_flg)
+{
+	pr_debug("%s: pkt_size %d cmd_flg %d session %d\n", __func__,
+		pkt_size, cmd_flg, client->session);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				       APR_HDR_LEN(sizeof(struct apr_hdr)),
+				       APR_PKT_VER);
+	hdr->src_svc = APR_SVC_LSM;
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->dest_svc = APR_SVC_LSM;
+	hdr->dest_domain = APR_DOMAIN_ADSP;
+	hdr->src_port = ((client->session << 8) & 0xFF00) | 0x01;
+	hdr->dest_port = ((client->session << 8) & 0xFF00) | 0x01;
+	hdr->pkt_size = pkt_size;
+	if (cmd_flg)
+		hdr->token = client->session;
+}
+
+int q6lsm_open(struct lsm_client *client)
+{
+	int rc;
+	struct lsm_stream_cmd_open_tx open;
+
+	memset(&open, 0, sizeof(open));
+	q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
+
+	open.hdr.opcode = LSM_SESSION_CMD_OPEN_TX;
+	open.app_id = 1;
+	open.sampling_rate = 16000;
+
+	rc = q6lsm_apr_send_pkt(client, client->apr, &open, true, NULL);
+	if (rc)
+		pr_err("%s: Open failed opcode 0x%x, rc %d\n",
+		       __func__, open.hdr.opcode, rc);
+
+	pr_debug("%s: leave %d\n", __func__, rc);
+	return rc;
+}
+
+static int q6lsm_set_params(struct lsm_client *client)
+{
+	int rc;
+	struct lsm_cmd_set_params params;
+	struct lsm_params_payload *payload = &params.payload;
+
+	pr_debug("%s: enter\n", __func__);
+	q6lsm_add_hdr(client, &params.hdr, sizeof(params), true);
+
+	params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+	params.data_payload_addr_lsw = 0;
+	params.data_payload_addr_msw = 0;
+	params.mem_map_handle = 0;
+	params.data_payload_size = sizeof(struct lsm_params_payload);
+
+	payload->op_mode.common.module_id  = LSM_MODULE_ID_VOICE_WAKEUP;
+	payload->op_mode.common.param_id = LSM_PARAM_ID_OPERATION_MODE;
+	payload->op_mode.common.param_size =
+	    sizeof(struct lsm_param_op_mode) - sizeof(payload->op_mode.common);
+	payload->op_mode.common.reserved = 0;
+	payload->op_mode.minor_version = 1;
+	payload->op_mode.mode = client->mode;
+	payload->op_mode.reserved = 0;
+
+	payload->connect_to_port.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+	payload->connect_to_port.common.param_id = LSM_PARAM_ID_CONNECT_TO_PORT;
+	payload->connect_to_port.common.param_size =
+	    sizeof(payload->connect_to_port) - sizeof(payload->op_mode.common);
+	payload->connect_to_port.common.reserved = 0;
+	payload->connect_to_port.minor_version = 1;
+	payload->connect_to_port.port_id = client->connect_to_port;
+	payload->connect_to_port.reserved = 0;
+
+	payload->kwds.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+	payload->kwds.common.param_id = LSM_PARAM_ID_KEYWORD_DETECT_SENSITIVITY;
+	payload->kwds.common.param_size =
+	    sizeof(payload->kwds) - sizeof(payload->op_mode.common);
+	payload->kwds.common.reserved = 0;
+	payload->kwds.minor_version = 1;
+	payload->kwds.keyword_sensitivity = client->kw_sensitivity;
+	payload->kwds.reserved = 0;
+
+	payload->uds.common.module_id = LSM_MODULE_ID_VOICE_WAKEUP;
+	payload->uds.common.param_id = LSM_PARAM_ID_USER_DETECT_SENSITIVITY;
+	payload->uds.common.param_size =
+	    sizeof(payload->uds) - sizeof(payload->op_mode.common);
+	payload->uds.common.reserved = 0;
+	payload->uds.minor_version = 1;
+	payload->uds.user_sensitivity = client->user_sensitivity;
+	payload->uds.reserved = 0;
+
+	rc = q6lsm_apr_send_pkt(client, client->apr, &params, true, NULL);
+	if (rc)
+		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+		       __func__, params.hdr.opcode, rc);
+
+	pr_debug("%s: leave %d\n", __func__, rc);
+	return rc;
+}
+
+int q6lsm_register_sound_model(struct lsm_client *client,
+			       enum lsm_detection_mode mode, u16 minkeyword,
+			       u16 minuser, bool detectfailure)
+{
+	int rc;
+	struct lsm_cmd_reg_snd_model cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (mode == LSM_MODE_KEYWORD_ONLY_DETECTION) {
+		client->mode = 0x01;
+	} else if (mode == LSM_MODE_USER_KEYWORD_DETECTION) {
+		client->mode = 0x03;
+	} else {
+		pr_err("%s: Incorrect detection mode %d\n", __func__, mode);
+		return -EINVAL;
+	}
+	client->mode |= detectfailure << 2;
+	client->kw_sensitivity = minkeyword;
+	client->user_sensitivity = minuser;
+	client->connect_to_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX;
+
+	rc = q6lsm_set_params(client);
+	if (rc < 0) {
+		pr_err("%s: Failed to set lsm config params\n", __func__);
+		return rc;
+	}
+	rc = q6lsm_send_cal(client);
+	if (rc < 0) {
+		pr_err("%s: Failed to send calibration data\n", __func__);
+		return rc;
+	}
+
+	q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
+	cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
+	cmd.model_addr_lsw = client->sound_model.phys;
+	cmd.model_addr_msw = 0;
+	cmd.model_size = client->sound_model.size;
+	/* read updated mem_map_handle by q6lsm_mmapcallback */
+	rmb();
+	cmd.mem_map_handle = client->sound_model.mem_map_handle;
+
+	pr_debug("%s: lsw %x, size %d, handle %x\n", __func__,
+		 cmd.model_addr_lsw, cmd.model_size, cmd.mem_map_handle);
+	rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
+	if (rc)
+		pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
+		       cmd.hdr.opcode, rc);
+	else
+		pr_debug("%s: Register sound model succeeded\n", __func__);
+
+	return rc;
+}
+
+int q6lsm_deregister_sound_model(struct lsm_client *client)
+{
+	int rc;
+	struct lsm_cmd_reg_snd_model cmd;
+
+	if (!client || !client->apr) {
+		pr_err("APR handle NULL\n");
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d]", __func__, client->session);
+
+	memset(&cmd, 0, sizeof(cmd));
+	q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
+	cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
+
+	rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
+	if (rc < 0) {
+		pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
+		       cmd.hdr.opcode, rc);
+	} else {
+		pr_debug("%s: Deregister sound model succeeded\n", __func__);
+		q6lsm_snd_model_buf_free(client);
+	}
+
+	return rc;
+}
+
+static void q6lsm_add_mmaphdr(struct lsm_client *client, struct apr_hdr *hdr,
+			      u32 pkt_size, u32 cmd_flg, u32 token)
+{
+	pr_debug("%s:pkt size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
+		 cmd_flg, client->session);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	hdr->src_port = 0x00;
+	hdr->dest_port = client->session;
+	if (cmd_flg)
+		hdr->token = token;
+	hdr->pkt_size = pkt_size;
+	return;
+}
+
+static int q6lsm_memory_map_regions(struct lsm_client *client,
+				    uint32_t dma_addr_p, uint32_t dma_buf_sz,
+				    uint32_t *mmap_p)
+{
+	struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
+	struct avs_shared_map_region_payload *mregions = NULL;
+	void *mmap_region_cmd = NULL;
+	void *payload = NULL;
+	int rc;
+	int cmd_size = 0;
+
+	pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, session %d\n",
+		 __func__, dma_addr_p, dma_buf_sz, client->session);
+
+	cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
+		   sizeof(struct avs_shared_map_region_payload);
+
+	mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+	if (!mmap_region_cmd)
+		return -ENOMEM;
+
+	mmap_regions = (struct avs_cmd_shared_mem_map_regions *)mmap_region_cmd;
+	q6lsm_add_mmaphdr(client, &mmap_regions->hdr, cmd_size, true,
+			  (client->session << 8));
+
+	mmap_regions->hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_MAP_REGIONS;
+	mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+	mmap_regions->num_regions = 1;
+	mmap_regions->property_flag = 0x00;
+	payload = ((u8 *)mmap_region_cmd +
+		   sizeof(struct avs_cmd_shared_mem_map_regions));
+	mregions = (struct avs_shared_map_region_payload *)payload;
+
+	mregions->shm_addr_lsw = dma_addr_p;
+	mregions->shm_addr_msw = 0;
+	mregions->mem_size_bytes = dma_buf_sz;
+
+	rc = q6lsm_apr_send_pkt(client, client->mmap_apr, mmap_region_cmd,
+				true, mmap_p);
+	if (rc)
+		pr_err("%s: Failed mmap_regions opcode 0x%x, rc %d\n",
+			__func__, mmap_regions->hdr.opcode, rc);
+
+	pr_debug("%s: leave %d\n", __func__, rc);
+	kfree(mmap_region_cmd);
+	return rc;
+}
+
+static int q6lsm_send_cal(struct lsm_client *client)
+{
+	int rc;
+
+	struct lsm_cmd_set_params params;
+	struct acdb_cal_block lsm_cal;
+
+	pr_debug("%s: enter\n", __func__);
+
+	memset(&lsm_cal, 0, sizeof(lsm_cal));
+	get_lsm_cal(&lsm_cal);
+	if (!lsm_cal.cal_size) {
+		pr_err("%s: Could not get LSM calibration data\n", __func__);
+		rc = -EINVAL;
+		goto bail;
+	}
+
+	/* Cache mmap address, only map once or if new addr */
+	if ((lsm_common.lsm_cal_addr != lsm_cal.cal_paddr) ||
+	    (lsm_cal.cal_size > lsm_common.lsm_cal_size)) {
+		if (lsm_common.lsm_cal_addr != 0)
+			afe_cmd_memory_unmap(lsm_cal.cal_paddr);
+
+		rc = q6lsm_memory_map_regions(client, lsm_cal.cal_paddr,
+					      LSM_CAL_SIZE,
+					      &lsm_common.mmap_handle_for_cal);
+		if (rc < 0) {
+			pr_err("%s: Calibration data memory map failed\n",
+			       __func__);
+			goto bail;
+		}
+		lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
+		lsm_common.lsm_cal_size = LSM_CAL_SIZE;
+	}
+
+	q6lsm_add_hdr(client, &params.hdr, sizeof(params), true);
+	params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
+	params.data_payload_addr_lsw = lsm_cal.cal_paddr;
+	params.data_payload_addr_msw = 0;
+	/* read updated mem_map_handle by q6lsm_mmapcallback */
+	rmb();
+	params.mem_map_handle = lsm_common.mmap_handle_for_cal;
+	params.data_payload_size = lsm_cal.cal_size;
+
+	rc = q6lsm_apr_send_pkt(client, client->apr, &params, true, NULL);
+	if (rc)
+		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
+		       __func__, params.hdr.opcode, rc);
+bail:
+	return rc;
+}
+
+static int q6lsm_memory_unmap_regions(struct lsm_client *client)
+{
+	struct avs_cmd_shared_mem_unmap_regions unmap;
+	int rc = 0;
+	int cmd_size = 0;
+
+	cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+	q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
+			  true, (client->session << 8));
+	unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
+	unmap.mem_map_handle = client->sound_model.mem_map_handle;
+
+	pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
+	rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
+				NULL);
+	if (rc)
+		pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
+		       __func__, unmap.hdr.opcode, rc);
+
+	return rc;
+}
+
+static int q6lsm_snd_model_buf_free(struct lsm_client *client)
+{
+	int rc;
+
+	pr_debug("%s: Session id %d\n", __func__, client->session);
+	mutex_lock(&client->cmd_lock);
+	rc = q6lsm_memory_unmap_regions(client);
+	if (rc < 0) {
+		pr_err("%s CMD Memory_unmap_regions failed\n", __func__);
+	} else if (client->sound_model.data) {
+		ion_unmap_kernel(client->sound_model.client,
+				 client->sound_model.handle);
+		ion_free(client->sound_model.client,
+			 client->sound_model.handle);
+		ion_client_destroy(client->sound_model.client);
+		client->sound_model.data = NULL;
+		client->sound_model.phys = 0;
+	}
+	mutex_unlock(&client->cmd_lock);
+	return rc;
+}
+
+static struct lsm_client *q6lsm_get_lsm_client(int session_id)
+{
+	unsigned long flags;
+	struct lsm_client *client = NULL;
+
+	spin_lock_irqsave(&lsm_session_lock, flags);
+	if (session_id < LSM_MIN_SESSION_ID || session_id > LSM_MAX_SESSION_ID)
+		pr_err("%s: Invalid session %d\n", __func__, session_id);
+	else if (!lsm_session[session_id])
+		pr_err("%s: Not an active session %d\n", __func__, session_id);
+	else
+		client = lsm_session[session_id];
+	spin_unlock_irqrestore(&lsm_session_lock, flags);
+
+	return client;
+}
+
+/*
+ * q6lsm_mmapcallback : atomic context
+ */
+static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+	unsigned long flags;
+	uint32_t sid = 0;
+	const uint32_t *payload = data->payload;
+	const uint32_t command = payload[0];
+	const uint32_t retcode = payload[1];
+	struct lsm_client *client = NULL;
+
+	pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x\n", __func__,
+		 data->opcode, command, retcode);
+
+	sid = (data->token >> 8) & 0x0F;
+	client = q6lsm_get_lsm_client(sid);
+	if (!client) {
+		pr_debug("%s: Session %d already freed\n", __func__, sid);
+		return 0;
+	}
+
+	switch (data->opcode) {
+	case LSM_SESSION_CMDRSP_SHARED_MEM_MAP_REGIONS:
+		if (atomic_read(&client->cmd_state) == CMD_STATE_WAIT_RESP) {
+			spin_lock_irqsave(&mmap_lock, flags);
+			*mmap_handle_p = command;
+			/* spin_unlock_irqrestore implies barrier */
+			spin_unlock_irqrestore(&mmap_lock, flags);
+			atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+			wake_up(&client->cmd_wait);
+		}
+		break;
+	case APR_BASIC_RSP_RESULT:
+		if (command == LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS) {
+			atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
+			wake_up(&client->cmd_wait);
+		} else {
+			pr_warn("%s: Unexpected command 0x%x\n", __func__,
+				command);
+		}
+		break;
+	default:
+		pr_debug("%s: command 0x%x return code 0x%x\n",
+			 __func__, command, retcode);
+		break;
+	}
+	if (client->cb)
+		client->cb(data->opcode, data->token,
+			   data->payload, client->priv);
+	return 0;
+}
+
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len)
+{
+	int rc = -EINVAL;
+
+	if (!client)
+		goto fail;
+
+	mutex_lock(&client->cmd_lock);
+	if (!client->sound_model.data) {
+		client->sound_model.client =
+		    msm_ion_client_create(UINT_MAX, "lsm_client");
+		if (IS_ERR_OR_NULL(client->sound_model.client)) {
+			pr_err("%s: ION create client for AUDIO failed\n",
+			       __func__);
+			goto fail;
+		}
+		client->sound_model.handle =
+			ion_alloc(client->sound_model.client,
+				  len, SZ_4K, (0x1 << ION_AUDIO_HEAP_ID), 0);
+		if (IS_ERR_OR_NULL(client->sound_model.handle)) {
+			pr_err("%s: ION memory allocation for AUDIO failed\n",
+			       __func__);
+			goto fail;
+		}
+
+		rc = ion_phys(client->sound_model.client,
+			      client->sound_model.handle,
+			      (ion_phys_addr_t *)&client->sound_model.phys,
+			      (size_t *)&len);
+		if (rc) {
+			pr_err("%s: ION get physical mem failed, rc%d\n",
+			       __func__, rc);
+			goto fail;
+		}
+
+		client->sound_model.data =
+		    ion_map_kernel(client->sound_model.client,
+				   client->sound_model.handle);
+		if (IS_ERR_OR_NULL(client->sound_model.data)) {
+			pr_err("%s: ION memory mapping failed\n", __func__);
+			goto fail;
+		}
+		memset(client->sound_model.data, 0, len);
+		client->sound_model.size = len;
+	} else {
+		rc = -EBUSY;
+		goto fail;
+	}
+	mutex_unlock(&client->cmd_lock);
+
+	rc = q6lsm_memory_map_regions(client, client->sound_model.phys,
+				      client->sound_model.size,
+				      &client->sound_model.mem_map_handle);
+	if (rc < 0) {
+		pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	q6lsm_snd_model_buf_free(client);
+	return rc;
+}
+
+static int q6lsm_cmd(struct lsm_client *client, int opcode, bool wait)
+{
+	struct apr_hdr hdr;
+	int rc;
+
+	pr_debug("%s: enter opcode %d wait %d\n", __func__, opcode, wait);
+	q6lsm_add_hdr(client, &hdr, sizeof(hdr), true);
+	switch (opcode) {
+	case LSM_SESSION_CMD_START:
+	case LSM_SESSION_CMD_STOP:
+	case LSM_SESSION_CMD_CLOSE_TX:
+		hdr.opcode = opcode;
+		break;
+	default:
+		pr_err("%s: Invalid opcode %d\n", __func__, opcode);
+		return -EINVAL;
+	}
+	rc = q6lsm_apr_send_pkt(client, client->apr, &hdr, wait, NULL);
+	if (rc)
+		pr_err("%s: Failed commmand 0x%x\n", __func__, hdr.opcode);
+
+	pr_debug("%s: leave %d\n", __func__, rc);
+	return rc;
+}
+
+int q6lsm_start(struct lsm_client *client, bool wait)
+{
+	return q6lsm_cmd(client, LSM_SESSION_CMD_START, wait);
+}
+
+int q6lsm_stop(struct lsm_client *client, bool wait)
+{
+	return q6lsm_cmd(client, LSM_SESSION_CMD_STOP, wait);
+}
+
+int q6lsm_close(struct lsm_client *client)
+{
+	return q6lsm_cmd(client, LSM_SESSION_CMD_CLOSE_TX, true);
+}
+
+static int __init q6lsm_init(void)
+{
+	pr_debug("%s\n", __func__);
+	spin_lock_init(&lsm_session_lock);
+	spin_lock_init(&mmap_lock);
+	mutex_init(&lsm_common.apr_lock);
+	return 0;
+}
+
+device_initcall(q6lsm_init);