Merge "vidc: Enable error concealment in video core" into msm-3.0
diff --git a/Documentation/devicetree/bindings/spmi/msm-spmi.txt b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
index fa91514..8fe415b 100644
--- a/Documentation/devicetree/bindings/spmi/msm-spmi.txt
+++ b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
@@ -25,8 +25,8 @@
 Second level
 
 Required properties :
- - spmi-dev-container: Used by the parser to understand that this is the second
-   level of the tree.
+ - spmi-slave-container: Used by the parser to understand that this is the
+   second level of the tree.
  - reg: <a b> where a is < 65536 and b is a size. Each device supports an
    arbitrary number of address ranges.
  - compatible : "qcom," prefixed string to match against the driver.
@@ -50,7 +50,7 @@
 			#address-cells = <1>;
 			#size-cells = <1>;
 			reg = <0xd>;
-			spmi-dev-container;
+			spmi-slave-container;
 
 			coincell@2800 {
 				compatible = "qcom,qpnp-coincell";
diff --git a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
index 8cc3c54..b5ca08e 100644
--- a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
+++ b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
@@ -17,6 +17,13 @@
 Up to a maximum of 256 peripherals are supported and the mapping is target
 specific.
 
+Data format of pmic-arb-ppid-map:
+<0x13100001>
+value is 32 bit.
+MSB 12 bits are the PPID
+12 bits padding
+LSB 8 bit are the APID
+
 Example:
 
 	qcom,spmi@fc4c0000 {
@@ -27,6 +34,8 @@
 		interrupts = <0>;
 		qcom,pmic-arb-ee = <0>;
 		qcom,pmic-arb-channel = <0>;
-		qcom,pmic-arb-ppid-map = <0x130 0x00>, /* PPID 0x130, APID 0 */
-					 <0x131 0x01>; /* PPID 0x131, APID 1 */
+		qcom,pmic-arb-ppid-map = <0x13000000>, /* PPID 0x130, APID 0 */
+					 <0x13100001>, /* PPID 0x131, APID 1 */
 	};
+
+
diff --git a/Documentation/usb/dwc3.txt b/Documentation/usb/dwc3.txt
new file mode 100644
index 0000000..7b590ed
--- /dev/null
+++ b/Documentation/usb/dwc3.txt
@@ -0,0 +1,45 @@
+
+ TODO
+~~~~~~
+Please pick something while reading :)
+
+- Convert interrupt handler to per-ep-thread-irq
+
+  As it turns out some DWC3-commands ~1ms to complete. Currently we spin
+  until the command completes which is bad.
+
+  Implementation idea:
+  - dwc core implements a demultiplexing irq chip for interrupts per
+    endpoint. The interrupt numbers are allocated during probe and belong
+    to the device. If MSI provides per-endpoint interrupt this dummy
+    interrupt chip can be replaced with "real" interrupts.
+  - interrupts are requested / allocated on usb_ep_enable() and removed on
+    usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
+    for ep0/1.
+  - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
+    until the command completes.
+  - the interrupt handler is split into the following pieces:
+    - primary handler of the device
+      goes through every event and calls generic_handle_irq() for event
+      it. On return from generic_handle_irq() in acknowledges the event
+      counter so interrupt goes away (eventually).
+
+    - threaded handler of the device
+      none
+
+    - primary handler of the EP-interrupt
+      reads the event and tries to process it. Everything that requries
+      sleeping is handed over to the Thread. The event is saved in an
+      per-endpoint data-structure.
+      We probably have to pay attention not to process events once we
+      handed something to thread so we don't process event X prio Y
+      where X > Y.
+
+    - threaded handler of the EP-interrupt
+      handles the remaining EP work which might sleep such as waiting
+      for command completion.
+
+  Latency:
+   There should be no increase in latency since the interrupt-thread has a
+   high priority and will be run before an average task in user land
+   (except the user changed priorities).
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0a7fe5f..f5046dc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -131,7 +131,7 @@
 
 config GENERIC_LOCKBREAK
 	bool
-	default y
+	default y if !ARM_TICKET_LOCKS
 	depends on SMP && PREEMPT
 
 config ARM_TICKET_LOCKS
@@ -140,7 +140,7 @@
 	  Enable ticket locks, which help preserve fairness among
 	  contended locks and prevent livelock in multicore systems.
 	  Say 'y' if system stability is important.
-	default y if ARCH_MSM_SCORPIONMP
+	default y if ARCH_MSM_SCORPIONMP || ARCH_MSM_KRAITMP
 	depends on SMP
 
 config RWSEM_GENERIC_SPINLOCK
diff --git a/arch/arm/boot/dts/msmcopper.dts b/arch/arm/boot/dts/msmcopper.dts
index 725971d..b9179a3 100644
--- a/arch/arm/boot/dts/msmcopper.dts
+++ b/arch/arm/boot/dts/msmcopper.dts
@@ -80,7 +80,7 @@
 	spi@f9924000 {
 		compatible = "qcom,spi-qup-v2";
 		reg = <0xf9924000 0x1000>;
-		interrupts = <96>;
+		interrupts = <0 96 0>;
 		spi-max-frequency = <24000000>;
 	};
 
@@ -94,93 +94,96 @@
 		interrupts = <0 190 0 0 187 0>;
 		qcom,pmic-arb-ee = <0>;
 		qcom,pmic-arb-channel = <0>;
-		qcom,pmic-arb-ppid-map = <0x130 0x00>, /* PM8941_LDO1 */
-					 <0x131 0x01>, /* PM8941_LDO2 */
-					 <0x132 0x02>, /* PM8941_LDO3 */
-					 <0x133 0x03>, /* PM8941_LDO4 */
-					 <0x134 0x04>, /* PM8941_LDO5 */
-					 <0x135 0x05>, /* PM8941_LDO6 */
-					 <0x136 0x06>, /* PM8941_LDO7 */
-					 <0x137 0x07>, /* PM8941_LDO8 */
-					 <0x138 0x08>, /* PM8941_LDO9 */
-					 <0x139 0x09>, /* PM8941_LDO10 */
-					 <0x13a 0x0a>, /* PM8941_LDO11 */
-					 <0x13b 0x0b>, /* PM8941_LDO12 */
-					 <0x13c 0x0c>, /* PM8941_LDO13 */
-					 <0x13d 0x0d>, /* PM8941_LDO14 */
-					 <0x13e 0x0e>, /* PM8941_LDO15 */
-					 <0x13f 0x0f>, /* PM8941_LDO16 */
-					 <0x140 0x10>, /* PM8941_LDO17 */
-					 <0x141 0x11>, /* PM8941_LDO18 */
-					 <0x142 0x12>, /* PM8941_LDO19 */
-					 <0x143 0x13>, /* PM8941_LDO20 */
-					 <0x144 0x14>, /* PM8941_LDO21 */
-					 <0x145 0x15>, /* PM8941_LDO22 */
-					 <0x146 0x16>, /* PM8941_LDO23 */
-					 <0x147 0x17>, /* PM8941_LDO24 */
-					 <0x148 0x18>, /* PM8941_LDO25 */
-					 <0x149 0x19>, /* PM8941_LDO26 */
-					 <0x0c0 0x1a>, /* PM8941_GPIO1 */
-					 <0x0c1 0x1b>, /* PM8941_GPIO2 */
-					 <0x0c2 0x1c>, /* PM8941_GPIO3 */
-					 <0x0c3 0x1d>, /* PM8941_GPIO4 */
-					 <0x0c4 0x1e>, /* PM8941_GPIO5 */
-					 <0x0c5 0x1f>, /* PM8941_GPIO6 */
-					 <0x0c6 0x20>, /* PM8941_GPIO7 */
-					 <0x0c7 0x21>, /* PM8941_GPIO8 */
-					 <0x0c8 0x22>, /* PM8941_GPIO9 */
-					 <0x0c9 0x23>, /* PM8941_GPIO10 */
-					 <0x0ca 0x24>, /* PM8941_GPIO11 */
-					 <0x0cb 0x25>, /* PM8941_GPIO12 */
-					 <0x0cc 0x26>, /* PM8941_GPIO13 */
-					 <0x0cd 0x27>, /* PM8941_GPIO14 */
-					 <0x0ce 0x28>, /* PM8941_GPIO15 */
-					 <0x0cf 0x29>, /* PM8941_GPIO16 */
-					 <0x0d0 0x2a>, /* PM8941_GPIO17 */
-					 <0x0d1 0x2b>, /* PM8941_GPIO18 */
-					 <0x0d2 0x2c>, /* PM8941_GPIO19 */
-					 <0x0d3 0x2d>, /* PM8941_GPIO20 */
-					 <0x0d4 0x2e>, /* PM8941_GPIO21 */
-					 <0x0d5 0x2f>, /* PM8941_GPIO22 */
-					 <0x0d6 0x30>, /* PM8941_GPIO23 */
-					 <0x0d7 0x31>, /* PM8941_GPIO24 */
-					 <0x0d8 0x32>, /* PM8941_GPIO25 */
-					 <0x0d9 0x33>, /* PM8941_GPIO26 */
-					 <0x0da 0x34>, /* PM8941_GPIO27 */
-					 <0x0db 0x35>, /* PM8941_GPIO28 */
-					 <0x0dc 0x36>, /* PM8941_GPIO29 */
-					 <0x0dd 0x37>, /* PM8941_GPIO30 */
-					 <0x0de 0x38>, /* PM8941_GPIO31 */
-					 <0x0df 0x39>, /* PM8941_GPIO32 */
-					 <0x0e0 0x3a>, /* PM8941_GPIO33 */
-					 <0x0e1 0x3b>, /* PM8941_GPIO34 */
-					 <0x0e2 0x3c>, /* PM8941_GPIO35 */
-					 <0x0e3 0x3d>, /* PM8941_GPIO36 */
-					 <0x028 0x3e>, /* COINCELL */
-					 <0x005 0x3f>, /* INTERRUPT */
-					 <0x001 0x40>, /* PM8941_0 */
-					 <0x201 0x41>, /* PM8841_0 */
-					 <0x101 0x42>, /* PM8941_1 */
-					 <0x301 0x43>, /* PM8841_1 */
-					 <0x008 0x44>, /* PON0 */
-					 <0x208 0x45>, /* PON1 */
-					 <0x110 0x46>, /* PM8941_SMPS1 */
-					 <0x111 0x47>, /* PM8941_SMPS2 */
-					 <0x112 0x48>, /* PM8941_SMPS3 */
-					 <0x310 0x49>, /* PM8841_SMPS1 */
-					 <0x311 0x4a>, /* PM8841_SMPS2 */
-					 <0x312 0x4b>, /* PM8841_SMPS3 */
-					 <0x313 0x4c>, /* PM8841_SMPS4 */
-					 <0x314 0x4d>, /* PM8841_SMPS5 */
-					 <0x315 0x4e>, /* PM8841_SMPS6 */
-					 <0x316 0x4f>, /* PM8841_SMPS7 */
-					 <0x317 0x50>, /* PM8841_SMPS8 */
-					 <0x050 0x51>, /* SHARED_XO */
-					 <0x051 0x52>, /* BB_CLK1 */
-					 <0x052 0x53>, /* BB_CLK2 */
-					 <0x059 0x54>, /* SLEEP_CLK */
-					 <0x010 0x55>, /* SMBC_OVP */
-					 <0x011 0x56>, /* SMBC_CHG */
-					 <0x012 0x57>; /* SMBC_BIF */
+		qcom,pmic-arb-ppid-map = <0x13000000>, /* PM8941_LDO1 */
+					 <0x13100001>, /* PM8941_LDO2 */
+					 <0x13200002>, /* PM8941_LDO3 */
+					 <0x13300003>, /* PM8941_LDO4 */
+					 <0x13400004>, /* PM8941_LDO5 */
+					 <0x13500005>, /* PM8941_LDO6 */
+					 <0x13600006>, /* PM8941_LDO7 */
+					 <0x13700007>, /* PM8941_LDO8 */
+					 <0x13800008>, /* PM8941_LDO9 */
+					 <0x13900009>, /* PM8941_LDO10 */
+					 <0x13a0000a>, /* PM8941_LDO11 */
+					 <0x13b0000b>, /* PM8941_LDO12 */
+					 <0x13c0000c>, /* PM8941_LDO13 */
+					 <0x13d0000d>, /* PM8941_LDO14 */
+					 <0x13e0000e>, /* PM8941_LDO15 */
+					 <0x13f0000f>, /* PM8941_LDO16 */
+					 <0x14000010>, /* PM8941_LDO17 */
+					 <0x14100011>, /* PM8941_LDO18 */
+					 <0x14200012>, /* PM8941_LDO19 */
+					 <0x14300013>, /* PM8941_LDO20 */
+					 <0x14400014>, /* PM8941_LDO21 */
+					 <0x14500015>, /* PM8941_LDO22 */
+					 <0x14600016>, /* PM8941_LDO23 */
+					 <0x14700017>, /* PM8941_LDO24 */
+					 <0x14800018>, /* PM8941_LDO25 */
+					 <0x14900019>, /* PM8941_LDO26 */
+					 <0x0c00001a>, /* PM8941_GPIO1 */
+					 <0x0c10001b>, /* PM8941_GPIO2 */
+					 <0x0c20001c>, /* PM8941_GPIO3 */
+					 <0x0c30001d>, /* PM8941_GPIO4 */
+					 <0x0c40001e>, /* PM8941_GPIO5 */
+					 <0x0c50001f>, /* PM8941_GPIO6 */
+					 <0x0c600020>, /* PM8941_GPIO7 */
+					 <0x0c700021>, /* PM8941_GPIO8 */
+					 <0x0c800022>, /* PM8941_GPIO9 */
+					 <0x0c900023>, /* PM8941_GPIO10 */
+					 <0x0ca00024>, /* PM8941_GPIO11 */
+					 <0x0cb00025>, /* PM8941_GPIO12 */
+					 <0x0cc00026>, /* PM8941_GPIO13 */
+					 <0x0cd00027>, /* PM8941_GPIO14 */
+					 <0x0ce00028>, /* PM8941_GPIO15 */
+					 <0x0cf00029>, /* PM8941_GPIO16 */
+					 <0x0d00002a>, /* PM8941_GPIO17 */
+					 <0x0d10002b>, /* PM8941_GPIO18 */
+					 <0x0d20002c>, /* PM8941_GPIO19 */
+					 <0x0d30002d>, /* PM8941_GPIO20 */
+					 <0x0d40002e>, /* PM8941_GPIO21 */
+					 <0x0d50002f>, /* PM8941_GPIO22 */
+					 <0x0d600030>, /* PM8941_GPIO23 */
+					 <0x0d700031>, /* PM8941_GPIO24 */
+					 <0x0d800032>, /* PM8941_GPIO25 */
+					 <0x0d900033>, /* PM8941_GPIO26 */
+					 <0x0da00034>, /* PM8941_GPIO27 */
+					 <0x0db00035>, /* PM8941_GPIO28 */
+					 <0x0dc00036>, /* PM8941_GPIO29 */
+					 <0x0dd00037>, /* PM8941_GPIO30 */
+					 <0x0de00038>, /* PM8941_GPIO31 */
+					 <0x0df00039>, /* PM8941_GPIO32 */
+					 <0x0e00003a>, /* PM8941_GPIO33 */
+					 <0x0e10003b>, /* PM8941_GPIO34 */
+					 <0x0e20003c>, /* PM8941_GPIO35 */
+					 <0x0e30003d>, /* PM8941_GPIO36 */
+					 <0x0280003e>, /* COINCELL */
+					 <0x0100003f>, /* SMBC_OVP */
+					 <0x01100040>, /* SMBC_CHG */
+					 <0x01200041>, /* SMBC_BIF */
+					 <0x00500042>, /* INTERRUPT */
+					 <0x00100043>, /* PM8941_0 */
+					 <0x20100044>, /* PM8841_0 */
+					 <0x10100045>, /* PM8941_1 */
+					 <0x30100046>, /* PM8841_1 */
+					 <0x00800047>, /* PON0 */
+					 <0x20800048>, /* PON1 */
+					 <0x11000049>, /* PM8941_SMPS1 */
+					 <0x1110004a>, /* PM8941_SMPS2 */
+					 <0x1120004b>, /* PM8941_SMPS3 */
+					 <0x3100004c>, /* PM8841_SMPS1 */
+					 <0x3110004d>, /* PM8841_SMPS2 */
+					 <0x3120004e>, /* PM8841_SMPS3 */
+					 <0x3130004f>, /* PM8841_SMPS4 */
+					 <0x31400050>, /* PM8841_SMPS5 */
+					 <0x31500051>, /* PM8841_SMPS6 */
+					 <0x31600052>, /* PM8841_SMPS7 */
+					 <0x31700053>, /* PM8841_SMPS8 */
+					 <0x05000054>, /* SHARED_XO */
+					 <0x05100055>, /* BB_CLK1 */
+					 <0x05200056>, /* BB_CLK2 */
+					 <0x05900057>, /* SLEEP_CLK */
+					 <0x07000058>, /* PBS_CORE */
+					 <0x07100059>, /* PBS_CLIENT1 */
+					 <0x0720005a>; /* PBS_CLIENT2 */
 	};
 };
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 3d4b37d..c671d32 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -114,7 +114,6 @@
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 # CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_PMIC8058 is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index ebff2d2..80252d8 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -112,7 +112,6 @@
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 # CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_PMIC8058 is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 58aece2..0b89d45 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -37,6 +37,10 @@
 CONFIG_CPU_HAS_L2_PMU=y
 # CONFIG_MSM_FIQ_SUPPORT is not set
 # CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_NO_HZ=y
@@ -102,6 +106,8 @@
 # CONFIG_MFD_SUPPORT is not set
 CONFIG_ION=y
 CONFIG_ION_MSM=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_CI13XXX_MSM=y
@@ -168,13 +174,3 @@
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG4=y
-CONFIG_MSM_SMD_PKT=y
-CONFIG_MSM_SMD_DEBUG=y
-CONFIG_MSM_SMD_TTY=y
-CONFIG_MSM_N_WAY_SMD=y
-CONFIG_MSM_N_WAY_SMSM=y
-CONFIG_MSM_SMD_LOGGING=y
-CONFIG_MSM_IPC_ROUTER=y
-CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 446423d..2af5ce4 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -19,6 +19,7 @@
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
@@ -327,14 +328,13 @@
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_FTRACE is not set
+CONFIG_ENABLE_DEFAULT_TRACERS=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 642d843..0bbad62 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -19,6 +19,7 @@
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
@@ -45,7 +46,6 @@
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM7X27A_AUDIO=y
 CONFIG_MSM_DMA_TEST=y
-# CONFIG_MSM_JTAG_V7 is not set
 CONFIG_MSM_SLEEP_STATS_DEVICE=y
 CONFIG_BT_MSM_PINTEST=y
 CONFIG_MSM_RPC_VIBRATOR=y
@@ -235,6 +235,7 @@
 # CONFIG_MT9T013 is not set
 # CONFIG_MT9D112 is not set
 CONFIG_OV5640=y
+CONFIG_OV5647=y
 CONFIG_WEBCAM_OV7692_QRD=y
 CONFIG_WEBCAM_OV9726=y
 # CONFIG_MT9P012 is not set
@@ -327,12 +328,11 @@
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_SHIRQ=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_LOCKUP_DETECTOR=y
 CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_SLAB=y
 CONFIG_DEBUG_SLAB_LEAK=y
@@ -342,9 +342,8 @@
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_LIST=y
-CONFIG_LATENCYTOP=y
 CONFIG_DEBUG_PAGEALLOC=y
-# CONFIG_FTRACE is not set
+CONFIG_ENABLE_DEFAULT_TRACERS=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_LL=y
@@ -352,4 +351,3 @@
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_CRC_CCITT=y
-CONFIG_OV5647=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index e319f0d..5466498 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -40,7 +40,6 @@
 CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
 CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
 CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
-# CONFIG_MSM_JTAG_V7 is not set
 CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -223,7 +222,6 @@
 CONFIG_INPUT_EVBUG=m
 # CONFIG_KEYBOARD_ATKBD is not set
 CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_KEYBOARD_PMIC8058 is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_MSM=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index b4babeb..1a70816 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -40,7 +40,6 @@
 CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
 CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
 CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
-# CONFIG_MSM_JTAG_V7 is not set
 CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
@@ -224,7 +223,6 @@
 CONFIG_INPUT_EVBUG=m
 # CONFIG_KEYBOARD_ATKBD is not set
 CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_KEYBOARD_PMIC8058 is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_MSM=y
@@ -371,7 +369,6 @@
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_LOCKUP_DETECTOR=y
 CONFIG_DETECT_HUNG_TASK=y
 # CONFIG_SCHED_DEBUG is not set
@@ -380,7 +377,6 @@
 CONFIG_DEBUG_SLAB=y
 CONFIG_DEBUG_SLAB_LEAK=y
 # CONFIG_DEBUG_PREEMPT is not set
-CONFIG_DEBUG_SPINLOCK=y
 CONFIG_PROVE_LOCKING=y
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
 CONFIG_DEBUG_STACK_USAGE=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index b3a45d2..13656418 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -70,7 +70,6 @@
 CONFIG_MSM_RPM_STATS_LOG=y
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_DLOAD_MODE=y
-# CONFIG_MSM_JTAG_V7 is not set
 CONFIG_MSM_ETM=y
 CONFIG_MSM_SLEEP_STATS=y
 CONFIG_MSM_GSBI9_UART=y
@@ -272,7 +271,6 @@
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_KEYBOARD_MATRIX=y
 CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_KEYBOARD_PMIC8058 is not set
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
@@ -299,7 +297,6 @@
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_SX150X=y
-# CONFIG_MPP_PMIC8901 is not set
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
 CONFIG_BATTERY_MSM8X60=y
@@ -324,9 +321,9 @@
 CONFIG_VIDEO_DEV=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_USB_VIDEO_CLASS=y
+CONFIG_IMX074=y
 CONFIG_WEBCAM_OV9726=y
 CONFIG_MT9E013=y
-CONFIG_IMX074=y
 CONFIG_MSM_GEMINI=y
 CONFIG_RADIO_TAVARUA=y
 CONFIG_ION=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 1f511bb..fa4ba4e 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -271,7 +271,6 @@
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_KEYBOARD_MATRIX=y
 CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_KEYBOARD_PMIC8058 is not set
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
@@ -299,7 +298,6 @@
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_SX150X=y
-# CONFIG_MPP_PMIC8901 is not set
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
 CONFIG_BATTERY_MSM8X60=y
@@ -324,9 +322,9 @@
 CONFIG_VIDEO_DEV=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_USB_VIDEO_CLASS=y
+CONFIG_IMX074=y
 CONFIG_WEBCAM_OV9726=y
 CONFIG_MT9E013=y
-CONFIG_IMX074=y
 CONFIG_MSM_GEMINI=y
 CONFIG_RADIO_TAVARUA=y
 CONFIG_ION=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 152cb86..d14757b 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -191,8 +191,10 @@
 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_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
@@ -227,7 +229,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_HAPTIC_ISA1200=y
 CONFIG_PMIC8XXX_VIBRATOR=y
-CONFIG_TZCOM=y
+CONFIG_QSEECOM=y
 CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -311,14 +313,13 @@
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 CONFIG_USB_VIDEO_CLASS=y
 CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_IMX074=y
 CONFIG_MT9M114=y
+CONFIG_IMX074_ACT=y
 CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_OV2720=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
-CONFIG_IMX074=y
-CONFIG_IMX074_ACT=y
-CONFIG_OV2720=y
-CONFIG_S5K3L1YX=y
 CONFIG_MSM_GEMINI=y
 CONFIG_S5K3L1YX=y
 CONFIG_RADIO_IRIS=y
@@ -337,9 +338,8 @@
 CONFIG_FB_MSM_OVERLAY=y
 CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
 CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y
-CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
 CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
-CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
+CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
 CONFIG_FB_MSM_HDMI_MSM_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index a326de6..dafaffc 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -193,8 +193,10 @@
 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_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
@@ -229,7 +231,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_HAPTIC_ISA1200=y
 CONFIG_PMIC8XXX_VIBRATOR=y
-CONFIG_TZCOM=y
+CONFIG_QSEECOM=y
 CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -311,15 +313,15 @@
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 CONFIG_USB_VIDEO_CLASS=y
 CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_IMX074=y
 CONFIG_MT9M114=y
+CONFIG_IMX074_ACT=y
 CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_OV2720=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
-CONFIG_IMX074=y
-CONFIG_IMX074_ACT=y
-CONFIG_OV2720=y
-CONFIG_S5K3L1YX=y
 CONFIG_MSM_GEMINI=y
+CONFIG_S5K3L1YX=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 7ba17e6..d4552f8 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -70,6 +70,7 @@
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 65c3f24..4e25f18 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -137,6 +137,11 @@
 	disable_irq
 	.endm
 
+	.macro	save_and_disable_irqs_notrace, oldcpsr
+	mrs	\oldcpsr, cpsr
+	disable_irq_notrace
+	.endm
+
 /*
  * Restore interrupt state previously stored in a register.  We don't
  * guarantee that this will preserve the flags.
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 0083033..de314ea 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -763,6 +763,7 @@
 			break;
 		case 0x0490:    /* 8960 sim */
 		case 0x04D0:    /* 8960 */
+		case 0x06F0:    /* 8064 */
 			armpmu = armv7_krait_pmu_init();
 			krait_l2_pmu_init();
 			break;
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
index 1ce4dd6..09cc127d 100644
--- a/arch/arm/kernel/perf_event_msm_krait.c
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -280,9 +280,9 @@
 	u32 v_orig_val;
 	u32 f_orig_val;
 
-	/* CPACR Enable CP10 access */
+	/* CPACR Enable CP10 and CP11 access */
 	v_orig_val = get_copro_access();
-	venum_new_val = v_orig_val | CPACC_SVC(10);
+	venum_new_val = v_orig_val | CPACC_SVC(10) | CPACC_SVC(11);
 	set_copro_access(venum_new_val);
 	/* Store orig venum val */
 	__get_cpu_var(venum_orig_val) = v_orig_val;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 18fbcf6..1004683 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -222,6 +222,7 @@
 	select MSM_SPM_V2
 	select MSM_L2_SPM
 	select MSM_PM8X60 if PM
+	select CPU_HAS_L2_PMU
 
 config ARCH_MSMCOPPER
 	bool "MSM Copper"
@@ -477,6 +478,22 @@
 	help
 	  Support for the Qualcomm MSM8625 RUMI3 Emulation Platform.
 
+config MACH_MSM8625_SURF
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 SURF"
+	help
+	  Support for the Qualcomm MSM8625 SURF.
+
+config MACH_MSM8625_EVB
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 EVB"
+	help
+	  Support for the Qualcomm MSM8625 Reference Design.
+
 config MACH_MSM7X30_SURF
        depends on ARCH_MSM7X30
        depends on !MSM_STACKED_MEMORY
@@ -2082,6 +2099,7 @@
 config MSM_RTB_SEPARATE_CPUS
 	bool "Separate entries for each cpu"
 	depends on MSM_RTB
+	depends on SMP
 	help
 	  Under some circumstances, it may be beneficial to give dedicated space
 	  for each cpu to log accesses. Selecting this option will log each cpu
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 8347a25..525dce4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -23,7 +23,7 @@
 obj-y += acpuclock.o
 obj-$(CONFIG_ARCH_MSM7X01A) += acpuclock-7201.o
 obj-$(CONFIG_ARCH_MSM7X25) += acpuclock-7201.o
-obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7201.o
+obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7201.o clock-pll.o
 obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
 obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o
 obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
@@ -54,7 +54,7 @@
 
 msm-etm-objs := etm.o
 obj-$(CONFIG_MSM_ETM) += msm-etm.o
-obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-ptm.o
+obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-etm.o
 
 quiet_cmd_mkrpcsym = MKCAP   $@
       cmd_mkrpcsym = $(PERL) $(srctree)/$(src)/mkrpcsym.pl $< $@
@@ -221,14 +221,18 @@
 obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7x27.o devices-msm7x27.o
 obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o devices-msm7x27.o
 obj-$(CONFIG_ARCH_MSM7X27A) += clock-pcom-lookup.o devices-msm7x27a.o
-obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7627A_QRD3) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7627A_EVB) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
+board-7627a-all-objs += board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+board-7627a-all-objs += board-msm7627a-display.o board-msm7627a-wlan.o
+obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7627A_QRD3) += board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7627A_EVB) += board-qrd7627a.o board-7627a-all.o
 obj-$(CONFIG_ARCH_MSM8625) += devices-msm7x27a.o clock-pcom-lookup.o
 obj-$(CONFIG_MACH_MSM8625_RUMI3) += board-msm7x27a.o
+obj-$(CONFIG_MACH_MSM8625_SURF) +=  board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM8625_EVB) +=  board-qrd7627a.o board-7627a-all.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o memory_topology.o
 obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o
 obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 5a21407..ae4b084 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -27,7 +27,6 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <linux/sort.h>
-#include <linux/remote_spinlock.h>
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach-types.h>
@@ -39,36 +38,36 @@
 #define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
 #define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
 #define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
-#define PLLn_MODE(n)	(MSM_CLK_CTL_BASE + 0x300 + 28 * (n))
-#define PLLn_L_VAL(n)	(MSM_CLK_CTL_BASE + 0x304 + 28 * (n))
 
-#define PLL4_MODE	(MSM_CLK_CTL_BASE + 0x374)
-#define PLL4_L_VAL	(MSM_CLK_CTL_BASE + 0x378)
 
 #define POWER_COLLAPSE_KHZ 19200
 
 /* Max CPU frequency allowed by hardware while in standby waiting for an irq. */
 #define MAX_WAIT_FOR_IRQ_KHZ 128000
 
+/**
+ * enum - For acpuclock PLL IDs
+ */
 enum {
-	ACPU_PLL_TCXO	= -1,
 	ACPU_PLL_0	= 0,
 	ACPU_PLL_1,
 	ACPU_PLL_2,
 	ACPU_PLL_3,
 	ACPU_PLL_4,
+	ACPU_PLL_TCXO,
 	ACPU_PLL_END,
 };
 
-static const struct pll {
-	void __iomem *mod_reg;
-	const uint32_t l_val_mask;
-} soc_pll[ACPU_PLL_END] = {
-	[ACPU_PLL_0] = {PLLn_MODE(ACPU_PLL_0), 0x3f},
-	[ACPU_PLL_1] = {PLLn_MODE(ACPU_PLL_1), 0x3f},
-	[ACPU_PLL_2] = {PLLn_MODE(ACPU_PLL_2), 0x3f},
-	[ACPU_PLL_3] = {PLLn_MODE(ACPU_PLL_3), 0x3f},
-	[ACPU_PLL_4] = {PLL4_MODE, 0x3ff},
+struct acpu_clk_src {
+	struct clk *clk;
+	const char *name;
+};
+
+static struct acpu_clk_src pll_clk[ACPU_PLL_END] = {
+	[ACPU_PLL_0] = { .name = "pll0_clk" },
+	[ACPU_PLL_1] = { .name = "pll1_clk" },
+	[ACPU_PLL_2] = { .name = "pll2_clk" },
+	[ACPU_PLL_4] = { .name = "pll4_clk" },
 };
 
 struct clock_state {
@@ -78,24 +77,6 @@
 	struct clk			*ebi1_clk;
 };
 
-#define PLL_BASE	7
-
-struct shared_pll_control {
-	uint32_t	version;
-	struct {
-		/* Denotes if the PLL is ON. Technically, this can be read
-		 * directly from the PLL registers, but this feild is here,
-		 * so let's use it.
-		 */
-		uint32_t	on;
-		/* One bit for each processor core. The application processor
-		 * is allocated bit position 1. All other bits should be
-		 * considered as votes from other processors.
-		 */
-		uint32_t	votes;
-	} pll[PLL_BASE + ACPU_PLL_END];
-};
-
 struct clkctl_acpu_speed {
 	unsigned int	use_for_scaling;
 	unsigned int	a11clk_khz;
@@ -106,14 +87,11 @@
 	unsigned int	ahbclk_div;
 	int		vdd;
 	unsigned int	axiclk_khz;
-	unsigned long	lpj; /* loops_per_jiffy */
 	/* Pointers in acpu_freq_tbl[] for max up/down steppings. */
 	struct clkctl_acpu_speed *down[ACPU_PLL_END];
 	struct clkctl_acpu_speed *up[ACPU_PLL_END];
 };
 
-static remote_spinlock_t pll_lock;
-static struct shared_pll_control *pll_control;
 static struct clock_state drv_state = { 0 };
 static struct clkctl_acpu_speed *acpu_freq_tbl;
 
@@ -136,7 +114,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627 with CDMA capable modem */
@@ -150,7 +128,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627 with GSM capable modem - PLL2 @ 800 */
@@ -164,7 +142,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
 	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627 with CDMA capable modem - PLL2 @ 800 */
@@ -178,7 +156,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
 	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627a PLL2 @ 1200MHz with GSM capable modem */
@@ -193,7 +171,7 @@
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627a PLL2 @ 1200MHz with CDMA capable modem */
@@ -208,7 +186,7 @@
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627aa PLL4 @ 1008MHz with GSM capable modem */
@@ -223,7 +201,7 @@
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
@@ -238,7 +216,7 @@
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7625a PLL2 @ 1200MHz with GSM capable modem */
@@ -252,7 +230,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627a PLL2 @ 1200MHz with GSM capable modem */
@@ -267,7 +245,7 @@
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627a PLL2 @ 1200MHz with CDMA capable modem */
@@ -282,7 +260,7 @@
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627aa PLL4 @ 1008MHz with GSM capable modem */
@@ -297,7 +275,7 @@
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
@@ -312,7 +290,7 @@
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
 /* 7625a PLL2 @ 1200MHz with GSM capable modem */
@@ -326,29 +304,19 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-#define PLL_0_MHZ	0
-#define PLL_196_MHZ	10
-#define PLL_245_MHZ	12
-#define PLL_589_MHZ	30
-#define PLL_737_MHZ	38
-#define PLL_800_MHZ	41
-#define PLL_960_MHZ	50
-#define PLL_1008_MHZ	52
-#define PLL_1200_MHZ	62
-
 #define PLL_CONFIG(m0, m1, m2, m4) { \
-	PLL_##m0##_MHZ, PLL_##m1##_MHZ, PLL_##m2##_MHZ, PLL_##m4##_MHZ, \
+	m0, m1, m2, m4, \
 	pll0_##m0##_pll1_##m1##_pll2_##m2##_pll4_##m4 \
 }
 
 struct pll_freq_tbl_map {
-	unsigned int	pll0_l;
-	unsigned int	pll1_l;
-	unsigned int	pll2_l;
-	unsigned int	pll4_l;
+	unsigned int	pll0_rate;
+	unsigned int	pll1_rate;
+	unsigned int	pll2_rate;
+	unsigned int	pll4_rate;
 	struct clkctl_acpu_speed *tbl;
 };
 
@@ -405,59 +373,6 @@
 }
 #endif
 
-static void pll_enable(void __iomem *addr, unsigned on)
-{
-	if (on) {
-		writel_relaxed(2, addr);
-		mb();
-		udelay(5);
-		writel_relaxed(6, addr);
-		mb();
-		udelay(50);
-		writel_relaxed(7, addr);
-	} else {
-		writel_relaxed(0, addr);
-	}
-}
-
-static int pc_pll_request(unsigned id, unsigned on)
-{
-	int res = 0;
-	on = !!on;
-
-	if (on)
-		pr_debug("Enabling PLL %d\n", id);
-	else
-		pr_debug("Disabling PLL %d\n", id);
-
-	if (id >= ACPU_PLL_END)
-		return -EINVAL;
-
-	remote_spin_lock(&pll_lock);
-	if (on) {
-		pll_control->pll[PLL_BASE + id].votes |= 2;
-		if (!pll_control->pll[PLL_BASE + id].on) {
-			pll_enable(soc_pll[id].mod_reg, 1);
-			pll_control->pll[PLL_BASE + id].on = 1;
-		}
-	} else {
-		pll_control->pll[PLL_BASE + id].votes &= ~2;
-		if (pll_control->pll[PLL_BASE + id].on
-		    && !pll_control->pll[PLL_BASE + id].votes) {
-			pll_enable(soc_pll[id].mod_reg, 0);
-			pll_control->pll[PLL_BASE + id].on = 0;
-		}
-	}
-	remote_spin_unlock(&pll_lock);
-
-	if (on)
-		pr_debug("PLL enabled\n");
-	else
-		pr_debug("PLL disabled\n");
-
-	return res;
-}
-
 static int acpuclk_set_vdd_level(int vdd)
 {
 	uint32_t current_vdd;
@@ -576,7 +491,7 @@
 
 	if (reason == SETRATE_CPUFREQ) {
 		if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) {
-			rc = pc_pll_request(tgt_s->pll, 1);
+			rc = clk_prepare_enable(pll_clk[tgt_s->pll].clk);
 			if (rc < 0) {
 				pr_err("PLL%d enable failed (%d)\n",
 					tgt_s->pll, rc);
@@ -651,7 +566,7 @@
 
 		if (cur_s->pll != ACPU_PLL_TCXO
 		    && !(plls_enabled & (1 << cur_s->pll))) {
-			rc = pc_pll_request(cur_s->pll, 1);
+			rc = clk_prepare_enable(pll_clk[cur_s->pll].clk);
 			if (rc < 0) {
 				pr_err("PLL%d enable failed (%d)\n",
 					cur_s->pll, rc);
@@ -662,8 +577,6 @@
 
 		acpuclk_set_div(cur_s);
 		drv_state.current_speed = cur_s;
-		/* Re-adjust lpj for the new clock speed. */
-		loops_per_jiffy = cur_s->lpj;
 		mb();
 		udelay(50);
 	}
@@ -684,12 +597,8 @@
 	if (tgt_s->pll != ACPU_PLL_TCXO)
 		plls_enabled &= ~(1 << tgt_s->pll);
 	for (pll = ACPU_PLL_0; pll < ACPU_PLL_END; pll++)
-		if (plls_enabled & (1 << pll)) {
-			res = pc_pll_request(pll, 0);
-			if (res < 0)
-				pr_warning("PLL%d disable failed (%d)\n",
-						pll, res);
-		}
+		if (plls_enabled & (1 << pll))
+			clk_disable_unprepare(pll_clk[pll].clk);
 
 	/* Nothing else to do for power collapse. */
 	if (reason == SETRATE_PC)
@@ -742,9 +651,10 @@
 	}
 
 	drv_state.current_speed = speed;
-	if (speed->pll != ACPU_PLL_TCXO)
-		if (pc_pll_request(speed->pll, 1))
+	if (speed->pll != ACPU_PLL_TCXO) {
+		if (clk_prepare_enable(pll_clk[speed->pll].clk))
 			pr_warning("Failed to vote for boot PLL\n");
+	}
 
 	/* Fix div2 to 2 for 7x27/5a(aa) targets */
 	if (!cpu_is_msm7x27()) {
@@ -777,64 +687,52 @@
 /*----------------------------------------------------------------------------
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
-
-static void __init acpu_freq_tbl_fixup(void)
+#define MHZ 1000000
+static void __init select_freq_plan(void)
 {
-	unsigned long pll0_l, pll1_l, pll2_l, pll4_l;
-	struct pll_freq_tbl_map *lst;
+	unsigned long pll_mhz[ACPU_PLL_END];
+	struct pll_freq_tbl_map *t;
+	int i;
 
-	/* Wait for the PLLs to be initialized and then read their frequency.
-	 */
-	do {
-		pll0_l = readl_relaxed(PLLn_L_VAL(0)) &
-				soc_pll[ACPU_PLL_0].l_val_mask;
-		cpu_relax();
-		udelay(50);
-	} while (pll0_l == 0);
-	do {
-		pll1_l = readl_relaxed(PLLn_L_VAL(1)) &
-				soc_pll[ACPU_PLL_1].l_val_mask;
-		cpu_relax();
-		udelay(50);
-	} while (pll1_l == 0);
-	do {
-		pll2_l = readl_relaxed(PLLn_L_VAL(2)) &
-				soc_pll[ACPU_PLL_2].l_val_mask;
-		cpu_relax();
-		udelay(50);
-	} while (pll2_l == 0);
-
-	pr_info("L val: PLL0: %d, PLL1: %d, PLL2: %d\n",
-			(int)pll0_l, (int)pll1_l, (int)pll2_l);
-
-	if (!cpu_is_msm7x27() && !cpu_is_msm7x25a()) {
-		do {
-			pll4_l = readl_relaxed(PLL4_L_VAL) &
-				soc_pll[ACPU_PLL_4].l_val_mask;
-			cpu_relax();
-			udelay(50);
-		} while (pll4_l == 0);
-		pr_info("L val: PLL4: %d\n", (int)pll4_l);
-	} else {
-		pll4_l = 0;
+	/* Get PLL clocks */
+	for (i = 0; i < ACPU_PLL_END; i++) {
+		if (pll_clk[i].name) {
+			pll_clk[i].clk = clk_get_sys("acpu", pll_clk[i].name);
+			if (IS_ERR(pll_clk[i].clk)) {
+				pll_mhz[i] = 0;
+				continue;
+			}
+			/* Get PLL's Rate */
+			pll_mhz[i] = clk_get_rate(pll_clk[i].clk)/MHZ;
+		}
 	}
 
-	/* Fix the tables for 7x25a variant to not conflict with 7x27 ones */
+	/*
+	 * For the pll configuration used in acpuclock table e.g.
+	 * pll0_960_pll1_245_pll2_1200" is same for 7627 and
+	 * 7625a (as pll0,pll1,pll2) having same rates, but frequency
+	 * table is different for both targets.
+	 *
+	 * Hence below for loop will not be able to select correct
+	 * table based on PLL rates as rates are same. Hence we need
+	 * to add this cpu check for selecting the correct acpuclock table.
+	 */
 	if (cpu_is_msm7x25a()) {
-		if (pll1_l == PLL_245_MHZ) {
+		if (pll_mhz[ACPU_PLL_1] == 245) {
 			acpu_freq_tbl =
 				pll0_960_pll1_245_pll2_1200_25a;
-		} else if (pll1_l == PLL_737_MHZ) {
+		} else if (pll_mhz[ACPU_PLL_1] == 737) {
 			acpu_freq_tbl =
 				pll0_960_pll1_737_pll2_1200_25a;
 		}
 	} else {
 		/* Select the right table to use. */
-		for (lst = acpu_freq_tbl_list; lst->tbl != 0; lst++) {
-			if (lst->pll0_l == pll0_l && lst->pll1_l == pll1_l
-					&& lst->pll2_l == pll2_l
-					&& lst->pll4_l == pll4_l) {
-				acpu_freq_tbl = lst->tbl;
+		for (t = acpu_freq_tbl_list; t->tbl != 0; t++) {
+			if (t->pll0_rate == pll_mhz[ACPU_PLL_0]
+				&& t->pll1_rate == pll_mhz[ACPU_PLL_1]
+				&& t->pll2_rate == pll_mhz[ACPU_PLL_2]
+				&& t->pll4_rate == pll_mhz[ACPU_PLL_4]) {
+				acpu_freq_tbl = t->tbl;
 				break;
 			}
 		}
@@ -862,18 +760,6 @@
 	return found_khz;
 }
 
-/* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
-{
-	int i;
-	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
-	for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) {
-		acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
-						base_clk->a11clk_khz,
-						acpu_freq_tbl[i].a11clk_khz);
-	}
-}
-
 static void __init precompute_stepping(void)
 {
 	int i, step_idx;
@@ -945,33 +831,6 @@
 	}
 }
 
-static void shared_pll_control_init(void)
-{
-#define PLL_REMOTE_SPINLOCK_ID "S:7"
-	unsigned smem_size;
-
-	remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
-	pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
-
-	if (!pll_control) {
-		pr_err("Can't find shared PLL control data structure!\n");
-		BUG();
-	/* There might be more PLLs than what the application processor knows
-	 * about. But the index used for each PLL is guaranteed to remain the
-	 * same. */
-	} else if (smem_size < sizeof(struct shared_pll_control)) {
-			pr_err("Shared PLL control data"
-					"structure too small!\n");
-			BUG();
-	} else if (pll_control->version != 0xCCEE0001) {
-			pr_err("Shared PLL control version mismatch!\n");
-			BUG();
-	} else {
-		pr_info("Shared PLL control available.\n");
-		return;
-	}
-
-}
 
 static struct acpuclk_data acpuclk_7627_data = {
 	.set_rate = acpuclk_7627_set_rate,
@@ -988,13 +847,11 @@
 	BUG_ON(IS_ERR(drv_state.ebi1_clk));
 
 	mutex_init(&drv_state.lock);
-	shared_pll_control_init();
 	drv_state.max_speed_delta_khz = soc_data->max_speed_delta_khz;
-	acpu_freq_tbl_fixup();
+	select_freq_plan();
 	acpuclk_7627_data.wait_for_irq_khz = find_wait_for_irq_khz();
 	precompute_stepping();
 	acpuclk_hw_init();
-	lpj_init();
 	print_acpu_freq_tbl();
 	acpuclk_register(&acpuclk_7627_data);
 
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index 7ee4e5b..f2fb292 100644
--- a/arch/arm/mach-msm/acpuclock-7x30.c
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -1,7 +1,7 @@
 /*
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -76,7 +76,6 @@
 	unsigned int	vdd_mv;
 	unsigned int	vdd_raw;
 	struct pll	*pll_rate;
-	unsigned long	lpj; /* loops_per_jiffy */
 };
 
 static struct clock_state drv_state = { 0 };
@@ -259,7 +258,6 @@
 	/* Perform the frequency switch */
 	acpuclk_set_src(tgt_s);
 	drv_state.current_speed = tgt_s;
-	loops_per_jiffy = tgt_s->lpj;
 
 	if (tgt_s->src == PLL_2 && strt_s->src == PLL_2)
 		clk_disable(acpuclk_sources[backup_s->src]);
@@ -392,19 +390,6 @@
 	return;
 }
 
-/* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
-{
-	int i;
-	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
-
-	for (i = 0; acpu_freq_tbl[i].acpu_clk_khz; i++) {
-		acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
-						base_clk->acpu_clk_khz,
-						acpu_freq_tbl[i].acpu_clk_khz);
-	}
-}
-
 #ifdef CONFIG_CPU_FREQ_MSM
 static struct cpufreq_frequency_table cpufreq_tbl[ARRAY_SIZE(acpu_freq_tbl)];
 
@@ -479,7 +464,6 @@
 	pll2_fixup();
 	populate_plls();
 	acpuclk_hw_init();
-	lpj_init();
 	setup_cpufreq_table();
 	acpuclk_register(&acpuclk_7x30_data);
 
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 99c3d78..8d35148 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -194,7 +194,7 @@
 			.hfpll_base      = MSM_HFPLL_BASE + 0x200,
 			.aux_clk_sel     = MSM_ACC0_BASE  + 0x014,
 			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
-			.vreg[VREG_CORE] = { "krait0",     1150000 },
+			.vreg[VREG_CORE] = { "krait0",     1300000 },
 			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
 					     RPM_VREG_VOTER1,
 					     RPM_VREG_ID_PM8921_L24 },
@@ -209,7 +209,7 @@
 			.hfpll_base      = MSM_HFPLL_BASE + 0x240,
 			.aux_clk_sel     = MSM_ACC1_BASE  + 0x014,
 			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
-			.vreg[VREG_CORE] = { "krait1",     1150000 },
+			.vreg[VREG_CORE] = { "krait1",     1300000 },
 			.vreg[VREG_MEM]  = { "krait1_mem", 1150000,
 					     RPM_VREG_VOTER2,
 					     RPM_VREG_ID_PM8921_L24 },
@@ -224,7 +224,7 @@
 			.hfpll_base      = MSM_HFPLL_BASE + 0x280,
 			.aux_clk_sel     = MSM_ACC2_BASE  + 0x014,
 			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
-			.vreg[VREG_CORE] = { "krait2",     1150000 },
+			.vreg[VREG_CORE] = { "krait2",     1300000 },
 			.vreg[VREG_MEM]  = { "krait2_mem", 1150000,
 					     RPM_VREG_VOTER4,
 					     RPM_VREG_ID_PM8921_L24 },
@@ -239,7 +239,7 @@
 			.hfpll_base      = MSM_HFPLL_BASE + 0x2C0,
 			.aux_clk_sel     = MSM_ACC3_BASE  + 0x014,
 			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
-			.vreg[VREG_CORE] = { "krait3",     1150000 },
+			.vreg[VREG_CORE] = { "krait3",     1300000 },
 			.vreg[VREG_MEM]  = { "krait3_mem", 1150000,
 					     RPM_VREG_VOTER5,
 					     RPM_VREG_ID_PM8921_L24 },
@@ -375,6 +375,7 @@
 	[4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
 	[5] = BW_MBPS(3600), /* At least 450 MHz on bus. */
 	[6] = BW_MBPS(3936), /* At least 492 MHz on bus. */
+	[7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
 };
 
 static struct msm_bus_scale_pdata bus_client_pdata = {
@@ -546,47 +547,48 @@
 #define L2(x) (&l2_freq_tbl_8064[(x)])
 static struct l2_level l2_freq_tbl_8064[] = {
 	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 }, 1050000, 1050000, 0 },
-	[1]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 0 },
-	[2]  = { {  432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
-	[3]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 1 },
-	[4]  = { {  540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 1 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
 	[5]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
-	[6]  = { {  648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 2 },
-	[7]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 2 },
-	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 3 },
-	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 3 },
-	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 3 },
-	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 3 },
-	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 3 },
-	[13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 3 },
-	[14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 4 },
-	[15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 4 },
-	[16] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 4 },
-	[17] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 4 },
-	[18] = { { 1296000, HFPLL, 1, 0, 0x30 }, 1150000, 1150000, 4 },
-	[19] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 4 },
-	[20] = { { 1404000, HFPLL, 1, 0, 0x34 }, 1150000, 1150000, 4 },
-	[21] = { { 1458000, HFPLL, 1, 0, 0x36 }, 1150000, 1150000, 5 },
-	[22] = { { 1512000, HFPLL, 1, 0, 0x38 }, 1150000, 1150000, 5 },
-	[23] = { { 1566000, HFPLL, 1, 0, 0x3A }, 1150000, 1150000, 5 },
-	[24] = { { 1620000, HFPLL, 1, 0, 0x3C }, 1150000, 1150000, 5 },
-	[25] = { { 1674000, HFPLL, 1, 0, 0x3E }, 1150000, 1150000, 5 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
+	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
+	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
+	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 7 },
+	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 7 },
+	[13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 7 },
+	[14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 7 },
+	[15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 7 },
 };
 
 /* TODO: Update core voltages when data is available. */
 static struct acpu_level acpu_freq_tbl_8064[] = {
-	{ 0, {STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),  1050000 },
-	{ 1, {  384000, PLL_8, 0, 2, 0x00 }, L2(1),  1050000 },
-	{ 1, {  432000, HFPLL, 2, 0, 0x20 }, L2(2),  1050000 },
-	{ 1, {  486000, HFPLL, 2, 0, 0x24 }, L2(3),  1050000 },
-	{ 1, {  540000, HFPLL, 2, 0, 0x28 }, L2(4),  1050000 },
-	{ 1, {  594000, HFPLL, 1, 0, 0x16 }, L2(5),  1050000 },
-	{ 1, {  648000, HFPLL, 1, 0, 0x18 }, L2(6),  1050000 },
-	{ 1, {  702000, HFPLL, 1, 0, 0x1A }, L2(7),  1050000 },
-	{ 1, {  756000, HFPLL, 1, 0, 0x1C }, L2(8),  1150000 },
-	{ 1, {  810000, HFPLL, 1, 0, 0x1E }, L2(9),  1150000 },
-	{ 1, {  864000, HFPLL, 1, 0, 0x20 }, L2(10), 1150000 },
-	{ 1, {  918000, HFPLL, 1, 0, 0x22 }, L2(11), 1150000 },
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   950000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(7),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(7),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(7),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(7),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(7),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(7),  1025000 },
+	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(7),  1075000 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(7),  1075000 },
+	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(7),  1100000 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(7),  1100000 },
+	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(7),  1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(7),  1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 5bef079..97f8722 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -556,8 +556,7 @@
 
 		if (!a2_pc_disabled) {
 			a2_pc_disabled = 1;
-			schedule_delayed_work(&ul_timeout_work,
-				msecs_to_jiffies(UL_TIMEOUT_DELAY));
+			ul_wakeup();
 		}
 
 		handle_bam_mux_cmd_open(rx_hdr);
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 486ebd3..f23bf2a 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -102,6 +102,13 @@
 
 static struct msm_gpiomux_config apq8064_cam_common_configs[] = {
 	{
+		.gpio = 1,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
 		.gpio = 2,
 		.settings = {
 			[GPIOMUX_ACTIVE]    = &cam_settings[12],
@@ -111,7 +118,7 @@
 	{
 		.gpio = 3,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
 			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
@@ -173,6 +180,16 @@
 	},
 };
 
+
+#define VFE_CAMIF_TIMER1_GPIO 3
+#define VFE_CAMIF_TIMER2_GPIO 1
+
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
+	._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+};
+
 static struct msm_gpiomux_config apq8064_cam_2d_configs[] = {
 };
 
@@ -419,7 +436,8 @@
 };
 
 static struct msm_camera_sensor_flash_data flash_imx074 = {
-	.flash_type	= MSM_CAMERA_FLASH_NONE,
+	.flash_type	= MSM_CAMERA_FLASH_LED,
+	.flash_src	= &msm_flash_src
 };
 
 static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
@@ -518,6 +536,9 @@
 	I2C_BOARD_INFO("ov2720", 0x6C),
 	.platform_data = &msm_camera_sensor_ov2720_data,
 	},
+	{
+	I2C_BOARD_INFO("sc628a", 0x6E),
+	},
 };
 
 struct msm_camera_board_info apq8064_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 604769d..a5376e3 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -23,6 +23,7 @@
 #include <mach/gpiomux.h>
 #include <mach/ion.h>
 #include <mach/msm_bus_board.h>
+#include <mach/socinfo.h>
 
 #include "devices.h"
 #include "board-8064.h"
@@ -66,7 +67,6 @@
 	}
 };
 
-#define PANEL_NAME_MAX_LEN 30
 #define LVDS_CHIMEI_PANEL_NAME "lvds_chimei_wxga"
 #define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
 #define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga"
@@ -528,8 +528,21 @@
 	return 0;
 }
 
+static int lvds_pixel_remap(void)
+{
+	if (machine_is_apq8064_cdp() ||
+	    machine_is_apq8064_liquid()) {
+		u32 ver = socinfo_get_platform_version();
+		if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
+		    (SOCINFO_VERSION_MINOR(ver) == 0))
+			return 1;
+	}
+	return 0;
+}
+
 static struct lcdc_platform_data lvds_pdata = {
 	.lcdc_power_save = lvds_panel_power,
+	.lvds_pixel_remap = lvds_pixel_remap
 };
 
 #define LPM_CHANNEL 2
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index e9b497b..9fbb1c7 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -151,17 +151,17 @@
 	.pwrlevel = {
 		{
 			.gpu_freq = 400000000,
-			.bus_freq = 4,
+			.bus_freq = 3,
 			.io_fraction = 0,
 		},
 		{
 			.gpu_freq = 320000000,
-			.bus_freq = 3,
+			.bus_freq = 2,
 			.io_fraction = 33,
 		},
 		{
 			.gpu_freq = 1920000000,
-			.bus_freq = 2,
+			.bus_freq = 1,
 			.io_fraction = 100,
 		},
 		{
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index bd5f703..f4650a9 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -141,6 +141,8 @@
 	/* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
 	PM8921_MPP_INIT(7, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_LOW),
 	PM8921_MPP_INIT(8, D_OUTPUT, PM8921_MPP_DIG_LEVEL_S4, DOUT_CTRL_LOW),
+	/*MPP9 is used to detect docking station connection/removal on Liquid*/
+	PM8921_MPP_INIT(9, D_INPUT, PM8921_MPP_DIG_LEVEL_S4, DIN_TO_INT),
 };
 
 void __init apq8064_pm8xxx_gpio_mpp_init(void)
@@ -310,8 +312,8 @@
 static struct pm8xxx_irq_platform_data
 apq8064_pm8921_irq_pdata __devinitdata = {
 	.irq_base		= PM8921_IRQ_BASE,
-	.devirq			= PM8921_USR_IRQ_N,
-	.irq_trigger_flag	= IRQF_TRIGGER_HIGH,
+	.devirq			= MSM_GPIO_TO_INT(74),
+	.irq_trigger_flag	= IRQF_TRIGGER_LOW,
 	.dev_id			= 0,
 };
 
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 247b230..e25f418 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -226,6 +226,7 @@
 };
 VREG_CONSUMERS(EXT_MPP8) = {
 	REGULATOR_SUPPLY("ext_mpp8",		NULL),
+	REGULATOR_SUPPLY("vbus",		"msm_ehci_host.1"),
 };
 VREG_CONSUMERS(EXT_3P3V) = {
 	REGULATOR_SUPPLY("ext_3p3v",		NULL),
@@ -469,15 +470,15 @@
 /* SAW regulator constraints */
 struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5 =
 	/*	      ID  vreg_name	       min_uV   max_uV */
-	SAW_VREG_INIT(S5, "8921_s5",	       950000, 1150000);
+	SAW_VREG_INIT(S5, "8921_s5",	       950000, 1300000);
 struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6 =
-	SAW_VREG_INIT(S6, "8921_s6",	       950000, 1150000);
+	SAW_VREG_INIT(S6, "8921_s6",	       950000, 1300000);
 
 struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0 =
 	/*	      ID       vreg_name	min_uV  max_uV */
-	SAW_VREG_INIT(8821_S0, "8821_s0",       950000, 1150000);
+	SAW_VREG_INIT(8821_S0, "8821_s0",       950000, 1300000);
 struct regulator_init_data msm8064_saw_regulator_pdata_8821_s1 =
-	SAW_VREG_INIT(8821_S1, "8821_s1",       950000, 1150000);
+	SAW_VREG_INIT(8821_S1, "8821_s1",       950000, 1300000);
 
 /* PM8921 regulator constraints */
 struct pm8xxx_regulator_platform_data
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 41be3e7..e9c455d 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -210,6 +210,8 @@
 #endif
 	.sup_clk_table	= sdc1_sup_clk_rates,
 	.sup_clk_cnt	= ARRAY_SIZE(sdc1_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+	.nonremovable	= 1,
 	.pin_data	= &mmc_slot_pin_data[SDCC1],
 	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
 };
@@ -228,6 +230,7 @@
 	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
 	.sup_clk_table	= sdc3_sup_clk_rates,
 	.sup_clk_cnt	= ARRAY_SIZE(sdc3_sup_clk_rates),
+	.pclk_src_dfab	= 1,
 	.pin_data	= &mmc_slot_pin_data[SDCC3],
 	.vreg_data	= &mmc_slot_vreg_data[SDCC3],
 	.status_gpio	= 26,
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 3848262..2358645 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -54,10 +54,12 @@
 #include <linux/bootmem.h>
 #include <asm/setup.h>
 #include <mach/dma.h>
+#include <mach/msm_dsps.h>
 #include <mach/msm_bus_board.h>
 #include <mach/cpuidle.h>
 #include <mach/mdm2.h>
 #include <linux/msm_tsens.h>
+#include <mach/msm_xo.h>
 
 #include "msm_watchdog.h"
 #include "board-8064.h"
@@ -467,24 +469,75 @@
 	},
 };
 
+/* Bandwidth requests (zero) if no vote placed */
+static struct msm_bus_vectors usb_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+/* Bus bandwidth requests in Bytes/sec */
+static struct msm_bus_vectors usb_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_SPS,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 60000000,		/* At least 480Mbps on bus. */
+		.ib = 960000000,	/* MAX bursts rate */
+	},
+};
+
+static struct msm_bus_paths usb_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(usb_init_vectors),
+		usb_init_vectors,
+	},
+	{
+		ARRAY_SIZE(usb_max_vectors),
+		usb_max_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata usb_bus_scale_pdata = {
+	usb_bus_scale_usecases,
+	ARRAY_SIZE(usb_bus_scale_usecases),
+	.name = "usb",
+};
+
 static struct msm_otg_platform_data msm_otg_pdata = {
 	.mode			= USB_OTG,
 	.otg_control		= OTG_PMIC_CONTROL,
 	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
 	.pmic_id_irq		= PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
 	.power_budget		= 750,
+	.bus_scale_table	= &usb_bus_scale_pdata,
 };
 
-static struct msm_usb_host_platform_data msm_ehci_host_pdata = {
+static struct msm_usb_host_platform_data msm_ehci_host_pdata3 = {
 	.power_budget = 500,
 };
 
+#ifdef CONFIG_USB_EHCI_MSM_HOST4
+static struct msm_usb_host_platform_data msm_ehci_host_pdata4;
+#endif
+
 static void __init apq8064_ehci_host_init(void)
 {
 	if (machine_is_apq8064_liquid()) {
+		msm_ehci_host_pdata3.dock_connect_irq =
+				PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9);
+
 		apq8064_device_ehci_host3.dev.platform_data =
-				&msm_ehci_host_pdata;
+				&msm_ehci_host_pdata3;
 		platform_device_register(&apq8064_device_ehci_host3);
+
+#ifdef CONFIG_USB_EHCI_MSM_HOST4
+		apq8064_device_ehci_host4.dev.platform_data =
+				&msm_ehci_host_pdata4;
+		platform_device_register(&apq8064_device_ehci_host4);
+#endif
 	}
 }
 
@@ -1143,56 +1196,62 @@
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		100, 8000, 100000, 1,
+		100, 650, 801, 200,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		2000, 6000, 60100000, 3000,
+		2000, 200, 576000, 2000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
 		false,
-		4200, 5000, 60350000, 3500,
+		8500, 51, 1122000, 8500,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
 		false,
-		6300, 4500, 65350000, 4800,
+		9000, 51, 1130300, 9000,
+	},
+	{
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
+		false,
+		10000, 51, 1130300, 10000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
 		false,
-		11700, 2500, 67850000, 5500,
+		12000, 14, 2205900, 12000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
 		false,
-		13800, 2000, 71850000, 6800,
+		18000, 12, 2364250, 18000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		29700, 500, 75850000, 8800,
+		23500, 10, 2667000, 23500,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
 		false,
-		29700, 0, 76350000, 9800,
+		29700, 5, 2867000, 30000,
 	},
 };
 
@@ -1846,6 +1905,18 @@
 	},
 };
 
+/* Sensors DSPS platform data */
+#define DSPS_PIL_GENERIC_NAME		"dsps"
+static void __init apq8064_init_dsps(void)
+{
+	struct msm_dsps_platform_data *pdata =
+		msm_dsps_device_8064.dev.platform_data;
+	pdata->pil_name = DSPS_PIL_GENERIC_NAME;
+	pdata->gpios = NULL;
+	pdata->gpios_num = 0;
+
+	platform_device_register(&msm_dsps_device_8064);
+}
 
 static void __init apq8064_clock_init(void)
 {
@@ -1939,6 +2010,8 @@
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 	regulator_suppress_info_printing();
 	platform_device_register(&apq8064_device_rpm_regulator);
+	if (msm_xo_init())
+		pr_err("Failed to initialize XO votes\n");
 	apq8064_clock_init();
 	apq8064_init_gpiomux();
 	apq8064_i2c_init();
@@ -1967,6 +2040,7 @@
 	platform_device_register(&apq8064_slim_ctrl);
 	slim_register_board_info(apq8064_slim_devices,
 		ARRAY_SIZE(apq8064_slim_devices));
+	apq8064_init_dsps();
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	acpuclk_init(&acpuclk_8064_soc_data);
 	msm_spm_l2_init(msm_spm_l2_data);
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index a840877..2f188970 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -68,7 +68,6 @@
 
 #define MDP_VSYNC_GPIO 0
 
-#define PANEL_NAME_MAX_LEN	30
 #define MIPI_CMD_NOVATEK_QHD_PANEL_NAME	"mipi_cmd_novatek_qhd"
 #define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME	"mipi_video_novatek_qhd"
 #define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME	"mipi_video_toshiba_wsvga"
@@ -781,8 +780,7 @@
 	platform_device_register(&mipi_dsi_novatek_panel_device);
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-	if (!cpu_is_msm8930())
-		platform_device_register(&hdmi_msm_device);
+	platform_device_register(&hdmi_msm_device);
 #endif
 
 	platform_device_register(&mipi_dsi_toshiba_panel_device);
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index dee1e98..26211bf 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -52,7 +52,7 @@
 		.name = "sdc_vdd",
 		.high_vol_level = 2950000,
 		.low_vol_level = 2950000,
-		.hpm_uA = 600000, /* 600mA */
+		.hpm_uA = 800000, /* 800mA */
 	}
 };
 
@@ -122,8 +122,8 @@
 
 static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
 	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
-	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
-	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
 };
 
 /* SDC3 pad data */
@@ -208,11 +208,11 @@
 };
 
 static unsigned int sdc1_sup_clk_rates[] = {
-	400000, 24000000, 48000000
+	400000, 24000000, 48000000,
 };
 
 static unsigned int sdc3_sup_clk_rates[] = {
-	400000, 24000000, 48000000, 96000000
+	400000, 24000000, 48000000, 96000000, 192000000,
 };
 
 #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
@@ -264,7 +264,7 @@
 	.xpc_cap	= 1,
 	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
 			MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
-			MMC_CAP_MAX_CURRENT_600),
+			MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 278c08c..2c81e66 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1938,62 +1938,62 @@
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		100, 8000, 100000, 1,
+		100, 650, 801, 200,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 		MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
 		true,
-		2000, 6000, 60100000, 3000,
+		2000, 200, 576000, 2000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
 		false,
-		4200, 5000, 60350000, 3500,
+		8500, 51, 1122000, 8500,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
 		false,
-		6300, 4500, 65350000, 4800,
+		9000, 51, 1130300, 9000,
 	},
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		7000, 3500, 66600000, 5150,
+		10000, 51, 1130300, 10000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
 		false,
-		11700, 2500, 67850000, 5500,
+		12000, 14, 2205900, 12000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
 		false,
-		13800, 2000, 71850000, 6800,
+		18000, 12, 2364250, 18000,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
 		false,
-		29700, 500, 75850000, 8800,
+		23500, 10, 2667000, 23500,
 	},
 
 	{
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 		MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
 		false,
-		29700, 0, 76350000, 9800,
+		29700, 5, 2867000, 30000,
 	},
 };
 
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 37a988a..7e92266 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -46,13 +46,8 @@
 #define MSM_FB_EXT_BUF_SIZE	0
 #endif
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-/* 4 bpp x 2 page HDMI case */
-#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
-#else
 /* Note: must be multiple of 4096 */
 #define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
-#endif
 
 #ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
 #define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1920 * 1200 * 3 * 2), 4096)
@@ -68,7 +63,6 @@
 
 #define MDP_VSYNC_GPIO 0
 
-#define PANEL_NAME_MAX_LEN	30
 #define MIPI_CMD_NOVATEK_QHD_PANEL_NAME	"mipi_cmd_novatek_qhd"
 #define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME	"mipi_video_novatek_qhd"
 #define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME	"mipi_video_toshiba_wsvga"
@@ -77,9 +71,17 @@
 #define MIPI_VIDEO_CHIMEI_WUXGA_PANEL_NAME	"mipi_video_chimei_wuxga"
 #define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME	"mipi_video_simulator_vga"
 #define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME	"mipi_cmd_renesas_fwvga"
+#define MIPI_VIDEO_ORISE_720P_PANEL_NAME	"mipi_video_orise_720p"
+#define MIPI_CMD_ORISE_720P_PANEL_NAME		"mipi_cmd_orise_720p"
 #define HDMI_PANEL_NAME	"hdmi_msm"
 #define TVOUT_PANEL_NAME	"tvout_msm"
 
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+unsigned char hdmi_is_primary = 1;
+#else
+unsigned char hdmi_is_primary;
+#endif
+
 static struct resource msm_fb_resources[] = {
 	{
 		.flags = IORESOURCE_DMA,
@@ -139,6 +141,16 @@
 			set_mdp_clocks_for_wuxga();
 			return 0;
 		}
+
+		if (!strncmp(name, MIPI_VIDEO_ORISE_720P_PANEL_NAME,
+				strnlen(MIPI_VIDEO_ORISE_720P_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
+
+		if (!strncmp(name, MIPI_CMD_ORISE_720P_PANEL_NAME,
+				strnlen(MIPI_CMD_ORISE_720P_PANEL_NAME,
+					PANEL_NAME_MAX_LEN)))
+			return 0;
 #endif
 	}
 
@@ -624,29 +636,16 @@
 
 #endif
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static int mdp_core_clk_rate_table[] = {
-	200000000,
-	200000000,
-	200000000,
-	200000000,
-};
-#else
 static int mdp_core_clk_rate_table[] = {
 	85330000,
 	128000000,
 	160000000,
 	200000000,
 };
-#endif
 
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-	.mdp_core_clk_rate = 200000000,
-#else
 	.mdp_core_clk_rate = 85330000,
-#endif
 	.mdp_core_clk_table = mdp_core_clk_rate_table,
 	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -670,6 +669,12 @@
 
 	mdp_ui_vectors[0].ab = 2000000000;
 	mdp_ui_vectors[0].ib = 2000000000;
+	mdp_vga_vectors[0].ab = 2000000000;
+	mdp_vga_vectors[0].ib = 2000000000;
+	mdp_720p_vectors[0].ab = 2000000000;
+	mdp_720p_vectors[0].ib = 2000000000;
+	mdp_1080p_vectors[0].ab = 2000000000;
+	mdp_1080p_vectors[0].ib = 2000000000;
 
 	mdp_pdata.mdp_core_clk_rate = 200000000;
 
@@ -762,6 +767,11 @@
 	.dev.platform_data = &mipi_dsi2lvds_pdata,
 };
 
+static struct platform_device mipi_dsi_orise_panel_device = {
+	.name = "mipi_orise",
+	.id = 0,
+};
+
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
 static struct resource hdmi_msm_resources[] = {
 	{
@@ -827,16 +837,6 @@
 	},
 };
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors dtv_bus_def_vectors[] = {
-	{
-		.src = MSM_BUS_MASTER_MDP_PORT0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 2000000000,
-		.ib = 2000000000,
-	},
-};
-#else
 static struct msm_bus_vectors dtv_bus_def_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_MDP_PORT0,
@@ -845,7 +845,6 @@
 		.ib = 707616000 * 2,
 	},
 };
-#endif
 
 static struct msm_bus_paths dtv_bus_scale_usecases[] = {
 	{
@@ -1068,6 +1067,7 @@
 
 	if (!machine_is_msm8960_sim() && !machine_is_msm8960_rumi3()) {
 		platform_device_register(&mipi_dsi_novatek_panel_device);
+		platform_device_register(&mipi_dsi_orise_panel_device);
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
 		platform_device_register(&hdmi_msm_device);
@@ -1102,3 +1102,27 @@
 	pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
 			size, addr, __pa(addr));
 }
+
+void __init msm8960_set_display_params(char *prim_panel, char *ext_panel)
+{
+	if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+			msm_fb_pdata.prim_panel_name);
+
+		if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+			HDMI_PANEL_NAME, strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+			pr_debug("HDMI is the primary display by"
+				" boot parameter\n");
+			hdmi_is_primary = 1;
+		}
+	}
+	if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.ext_panel_name, ext_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.ext_panel_name %s\n",
+			msm_fb_pdata.ext_panel_name);
+	}
+}
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index d98ae56..9c1a439 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -221,7 +221,6 @@
 };
 VREG_CONSUMERS(USB_OTG) = {
 	REGULATOR_SUPPLY("8921_usb_otg",	NULL),
-	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
 };
 VREG_CONSUMERS(HDMI_MVS) = {
 	REGULATOR_SUPPLY("8921_hdmi_mvs",	NULL),
@@ -245,12 +244,12 @@
 };
 VREG_CONSUMERS(EXT_OTG_SW) = {
 	REGULATOR_SUPPLY("ext_otg_sw",		NULL),
+	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
 };
 
 #define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
 			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
-			 _system_uA, _enable_time, _reg_id, _ocp_enable, \
-			 _ocp_enable_time) \
+			 _system_uA, _enable_time, _reg_id) \
 	{ \
 		.init_data = { \
 			.constraints = { \
@@ -272,8 +271,6 @@
 		.pull_down_enable	= _pull_down, \
 		.system_uA		= _system_uA, \
 		.enable_time		= _enable_time, \
-		.ocp_enable		= _ocp_enable, \
-		.ocp_enable_time	= _ocp_enable_time, \
 	}
 
 #define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
@@ -282,7 +279,7 @@
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time, _reg_id, 0, 0)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
 #define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
 		_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
@@ -290,7 +287,7 @@
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time, _reg_id, 0, 0)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
 #define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
 		_enable_time, _supply_regulator, _system_uA, _reg_id) \
@@ -298,32 +295,32 @@
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time, _reg_id, 0, 0)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
 #define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
 		_enable_time, _supply_regulator, _system_uA, _reg_id) \
 	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
 		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
 		| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time, _reg_id, 0, 0)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
 #define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
-		_ocp_enable, _ocp_enable_time, _supply_regulator, _reg_id) \
+		_supply_regulator, _reg_id) \
 	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
 		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
-		_reg_id, _ocp_enable, _ocp_enable_time)
+		_reg_id)
 
 #define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
-		_ocp_enable, _ocp_enable_time, _supply_regulator, _reg_id) \
+		_supply_regulator, _reg_id) \
 	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
 		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
-		_reg_id, _ocp_enable, _ocp_enable_time)
+		_reg_id)
 
 #define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
 		_supply_regulator, _reg_id) \
 	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
 		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
-		_always_on, _supply_regulator, 0, _enable_time, _reg_id, 0, 0)
+		_always_on, _supply_regulator, 0, _enable_time, _reg_id)
 
 /* Pin control initialization */
 #define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
@@ -472,7 +469,7 @@
 	GPIO_VREG(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
 		PM8921_GPIO_PM_TO_SYS(17), NULL),
 	GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en",
-		PM8921_GPIO_PM_TO_SYS(42), "ext_5v"),
+		PM8921_GPIO_PM_TO_SYS(42), "8921_usb_otg"),
 };
 
 /* SAW regulator constraints */
@@ -498,13 +495,9 @@
 	PM8XXX_LDO(L29,      "8921_l29", 0, 1, 2050000, 2100000, 200, "8921_s8",
 		0, 4),
 
-	/*
-	 *	     ID       name      always_on pd en_t ocp ocp_t supply
-	 *	reg_ID
-	 */
-	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 0,   0, 1, 500, "ext_otg_sw",
-		5),
-	PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1,   0, 0,   0, "ext_5v", 6),
+	/*	     ID        name      always_on pd en_t supply    reg_ID */
+	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 1, 0,   "ext_5v", 5),
+	PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0,   "ext_5v", 6),
 };
 
 static struct rpm_regulator_init_data
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 7fd6820..3b0f8be 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -131,12 +131,9 @@
 
 #define MSM_PMEM_ADSP_SIZE         0x7800000
 #define MSM_PMEM_AUDIO_SIZE        0x2B4000
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
-#else
 #define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
-#endif
 #define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#define MSM_HDMI_PRIM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x280000
@@ -148,7 +145,9 @@
 #define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
 #define MSM_ION_HEAP_NUM	8
 #define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000)
-static unsigned int msm_ion_cp_mm_size = MSM_ION_MM_SIZE;
+#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
+#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
+static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
 #else
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
 #define MSM_ION_HEAP_NUM	1
@@ -308,8 +307,13 @@
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	android_pmem_adsp_pdata.size = pmem_adsp_size;
 
-	if (!pmem_param_set && machine_is_msm8960_liquid())
-		pmem_size = MSM_LIQUID_PMEM_SIZE;
+	if (!pmem_param_set) {
+		if (machine_is_msm8960_liquid())
+			pmem_size = MSM_LIQUID_PMEM_SIZE;
+		if (hdmi_is_primary)
+			pmem_size = MSM_HDMI_PRIM_PMEM_SIZE;
+	}
+
 	android_pmem_pdata.size = pmem_size;
 #endif
 	android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
@@ -463,14 +467,22 @@
 {
 	unsigned int i;
 
-	if (!pmem_param_set && machine_is_msm8960_liquid()) {
-		msm_ion_cp_mm_size = MSM_LIQUID_ION_MM_SIZE;
-		for (i = 0; i < ion_pdata.nr; i++) {
-			if (ion_pdata.heaps[i].id == ION_CP_MM_HEAP_ID) {
-				ion_pdata.heaps[i].size = msm_ion_cp_mm_size;
-				pr_debug("msm_ion_cp_mm_size 0x%x\n",
-					msm_ion_cp_mm_size);
-				break;
+	if (!pmem_param_set) {
+		if (machine_is_msm8960_liquid())
+			msm_ion_sf_size = MSM_LIQUID_ION_SF_SIZE;
+
+		if (hdmi_is_primary)
+			msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE;
+
+		if (machine_is_msm8960_liquid() || hdmi_is_primary) {
+			for (i = 0; i < ion_pdata.nr; i++) {
+				if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) {
+					ion_pdata.heaps[i].size =
+						msm_ion_sf_size;
+					pr_debug("msm_ion_sf_size 0x%x\n",
+						msm_ion_sf_size);
+					break;
+				}
 			}
 		}
 	}
@@ -633,8 +645,27 @@
 	place_movable_zone();
 }
 
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static char ext_panel_name[PANEL_NAME_MAX_LEN];
+static int __init prim_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+static int __init ext_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("ext_display", ext_display_setup);
+
 static void __init msm8960_reserve(void)
 {
+	msm8960_set_display_params(prim_panel_name, ext_panel_name);
 	msm_reserve();
 	fmem_pdata.phys = reserve_memory_for_fmem(fmem_pdata.size);
 }
@@ -1884,6 +1915,7 @@
 		.variant_id	= 0x0,
 		.version	= 0x10,
 		.build		= 0xAA,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386,
 	},
 	{
 		.config		= mxt1386e_config_data_v1_0,
@@ -1892,6 +1924,8 @@
 		.variant_id	= 0x2,
 		.version	= 0x10,
 		.build		= 0xAA,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386E,
+		.fw_name	= "atmel_8960_liquid_v2_1_AA.hex",
 	},
 	{
 		.config		= mxt1386e_config_data_v2_1,
@@ -1900,6 +1934,7 @@
 		.variant_id	= 0x7,
 		.version	= 0x21,
 		.build		= 0xAA,
+		.bootldr_id	= MXT_BOOTLOADER_ID_1386E,
 	},
 };
 
@@ -2080,8 +2115,8 @@
 	&msm_device_saw_core0,
 	&msm_device_saw_core1,
 	&msm8960_device_ext_5v_vreg,
-	&msm8960_device_ext_otg_sw_vreg,
 	&msm8960_device_ssbi_pmic,
+	&msm8960_device_ext_otg_sw_vreg,
 	&msm8960_device_qup_spi_gsbi1,
 	&msm8960_device_qup_i2c_gsbi3,
 	&msm8960_device_qup_i2c_gsbi4,
@@ -2119,6 +2154,14 @@
 	&msm_device_bam_dmux,
 	&msm_fm_platform_init,
 
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+#ifdef CONFIG_MSM_USE_TSIF1
+	&msm_device_tsif[1],
+#else
+	&msm_device_tsif[0],
+#endif
+#endif
+
 #ifdef CONFIG_HW_RANDOM_MSM
 	&msm_device_rng,
 #endif
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index 20af7b8..dc63fee 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -73,12 +73,15 @@
 
 extern struct sx150x_platform_data msm8960_sx150x_data[];
 extern struct msm_camera_board_info msm8960_camera_board_info;
+extern unsigned char hdmi_is_primary;
+
 void msm8960_init_cam(void);
 void msm8960_init_fb(void);
 void msm8960_init_pmic(void);
 void msm8960_init_mmc(void);
 int msm8960_init_gpiomux(void);
 void msm8960_allocate_fb_region(void);
+void msm8960_set_display_params(char *prim_panel, char *ext_panel);
 void msm8960_pm8921_gpio_mpp_init(void);
 void msm8960_mdp_writeback(struct memtype_reserve *reserve_table);
 uint32_t msm_rpm_get_swfi_latency(void);
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index dc26d72..c30be16 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -37,6 +37,7 @@
 #endif
 #include <mach/msm_memtypes.h>
 #include <mach/msm_smd.h>
+#include <mach/qpnp-int.h>
 #include "clock.h"
 
 #define MSM_KERNEL_EBI1_MEM_SIZE	0x280000
@@ -361,6 +362,7 @@
 static struct of_device_id irq_match[] __initdata  = {
 	{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
 	{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+	{ .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
 	{}
 };
 
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index c70b30e..a8ab81a 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -32,7 +32,7 @@
 	{"bt", 21, 2900000, 3300000, 1, NULL}
 };
 
-struct platform_device msm_bt_power_device = {
+static struct platform_device msm_bt_power_device = {
 	.name = "bt_power",
 };
 
@@ -100,7 +100,7 @@
 {
 	if (machine_is_msm7627a_qrd1())
 		gpio_bt_sys_rest_en = 114;
-	if (machine_is_msm7627a_evb())
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
 		gpio_bt_sys_rest_en = 16;
 }
 
@@ -109,14 +109,36 @@
 	int rc = 0;
 	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
 
+	pr_debug("%s: Setting SYS_RST_PIN(%d) to %d\n",
+			__func__, gpio_bt_sys_rest_en, on);
 	if (on) {
-		rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+
+		if (machine_is_msm7627a_evb()) {
+			rc = gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
+					GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+					GPIO_CFG_2MA),
+					GPIO_CFG_ENABLE);
+
+			gpio_set_value(gpio_bt_sys_rest_en, 1);
+		} else {
+			rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+		}
 		msleep(100);
 	} else {
+
 		if (!marimba_get_fm_status(&config) &&
 				!marimba_get_bt_status(&config)) {
-			gpio_set_value_cansleep(gpio_bt_sys_rest_en, 0);
-			rc = gpio_direction_input(gpio_bt_sys_rest_en);
+			if (machine_is_msm7627a_evb()) {
+				gpio_set_value(gpio_bt_sys_rest_en, 0);
+				rc = gpio_tlmm_config(GPIO_CFG(
+					gpio_bt_sys_rest_en, 0,
+					GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN,
+					GPIO_CFG_2MA),
+					GPIO_CFG_ENABLE);
+			} else {
+				gpio_set_value_cansleep(gpio_bt_sys_rest_en, 0);
+				rc = gpio_direction_input(gpio_bt_sys_rest_en);
+			}
 			msleep(100);
 		}
 	}
@@ -324,7 +346,8 @@
 	int pin, rc = 0;
 
 	if (mode == FM_I2S_ON) {
-		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+				|| machine_is_msm8625_surf())
 			config_pcm_i2s_mode(0);
 		pr_err("%s mode = FM_I2S_ON", __func__);
 
@@ -367,7 +390,8 @@
 	int pin, rc = 0;
 
 	if (mode == BT_PCM_ON) {
-		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+				|| machine_is_msm8625_surf())
 			config_pcm_i2s_mode(1);
 		pr_err("%s mode =BT_PCM_ON", __func__);
 		rc = switch_pcm_i2s_reg_mode(1);
@@ -940,9 +964,20 @@
 
 	gpio_bt_config();
 
-	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
-			bahama_devices,
-			ARRAY_SIZE(bahama_devices));
+	rc = i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+				bahama_devices,
+				ARRAY_SIZE(bahama_devices));
+	if (rc < 0) {
+		pr_err("%s: I2C Register failed\n", __func__);
+		return;
+	}
+
+	rc = platform_device_register(&msm_bt_power_device);
+	if (rc < 0) {
+		pr_err("%s: device register failed\n", __func__);
+		return;
+	}
+
 	dev = &msm_bt_power_device.dev;
 
 	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
@@ -964,6 +999,6 @@
 		regulator_put(bt_vregs[i].reg);
 		bt_vregs[i].reg = NULL;
 	}
-	return;
+	platform_device_unregister(&msm_bt_power_device);
 }
 #endif
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 06fbb7b..7b075cd 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -1041,7 +1041,7 @@
 
 	pr_debug("msm7627a_camera_init Entered\n");
 	/* LCD and camera power (VREG & LDO) init */
-	if (machine_is_msm7627a_evb())
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
 		lcd_camera_power_init();
 
 #ifndef CONFIG_MSM_CAMERA_V4L2
@@ -1049,7 +1049,7 @@
 		qrd1_camera_gpio_cfg();
 		platform_add_devices(camera_devices_qrd,
 				ARRAY_SIZE(camera_devices_qrd));
-	} else if (machine_is_msm7627a_evb()) {
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
 		evb_camera_gpio_cfg();
 		platform_add_devices(camera_devices_evb,
 				ARRAY_SIZE(camera_devices_evb));
@@ -1059,7 +1059,8 @@
 		platform_add_devices(camera_devices_msm,
 				ARRAY_SIZE(camera_devices_msm));
 #endif
-	if (!machine_is_msm7627a_qrd1() || !machine_is_msm7627a_evb())
+	if (!machine_is_msm7627a_qrd1() || !machine_is_msm7627a_evb()
+					|| !machine_is_msm8625_evb())
 		register_i2c_devices();
 	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
 
@@ -1083,7 +1084,7 @@
 		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
 				i2c_camera_devices_qrd,
 				ARRAY_SIZE(i2c_camera_devices_qrd));
-	} else if (machine_is_msm7627a_evb()) {
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
 		pr_debug("machine_is_msm7627a_evb i2c_register_board_info\n");
 		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
 				i2c_camera_devices_evb,
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 4e856b1..b1fe0c7 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -208,7 +208,6 @@
 	}
 };
 
-#define PANEL_NAME_MAX_LEN      30
 #define LCDC_TOSHIBA_FWVGA_PANEL_NAME   "lcdc_toshiba_fwvga_pt"
 #define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME       "mipi_cmd_renesas_fwvga"
 
@@ -216,7 +215,8 @@
 {
 	int ret = -ENODEV;
 
-	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) {
+	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() ||
+			machine_is_msm8625_surf()) {
 		if (!strncmp(name, "lcdc_toshiba_fwvga_pt", 21) ||
 				!strncmp(name, "mipi_cmd_renesas_fwvga", 22))
 			ret = 0;
@@ -226,7 +226,7 @@
 	} else if (machine_is_msm7627a_qrd1()) {
 		if (!strncmp(name, "mipi_video_truly_wvga", 21))
 			ret = 0;
-	} else if (machine_is_msm7627a_evb()) {
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
 		if (!strncmp(name, "mipi_cmd_nt35510_wvga", 21))
 			ret = 0;
 	}
@@ -235,7 +235,8 @@
 	!defined(CONFIG_FB_MSM_MIPI_PANEL_AUTO_DETECT) && \
 	!defined(CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT)
 		if (machine_is_msm7x27a_surf() ||
-			machine_is_msm7625a_surf()) {
+			machine_is_msm7625a_surf() ||
+			machine_is_msm8625_surf()) {
 			if (!strncmp(name, LCDC_TOSHIBA_FWVGA_PANEL_NAME,
 				strnlen(LCDC_TOSHIBA_FWVGA_PANEL_NAME,
 					PANEL_NAME_MAX_LEN)))
@@ -427,7 +428,8 @@
 	gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 0);
 
 	if (!rc) {
-		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) {
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+				|| machine_is_msm8625_surf()) {
 			lcdc_reset_ptr = ioremap_nocache(LCDC_RESET_PHYS,
 				sizeof(uint32_t));
 
@@ -555,7 +557,7 @@
 
 	if (machine_is_msm7627a_qrd1())
 		rc = msm_fb_dsi_client_qrd1_reset();
-	else if (machine_is_msm7627a_evb())
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
 		rc = msm_fb_dsi_client_qrd3_reset();
 	else
 		rc = msm_fb_dsi_client_msm_reset();
@@ -586,7 +588,8 @@
 			return rc;
 		}
 
-		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) {
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+				|| machine_is_msm8625_surf()) {
 			rc = gpio_direction_output(GPIO_DISPLAY_PWR_EN, 1);
 			if (rc < 0) {
 				pr_err("failed to enable display pwr\n");
@@ -625,7 +628,8 @@
 
 		dsi_gpio_initialized = 1;
 	}
-	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) {
+	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() ||
+			machine_is_msm8625_surf()) {
 		gpio_set_value_cansleep(GPIO_DISPLAY_PWR_EN, on);
 		gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, on);
 	} else if (machine_is_msm7x27a_ffa() ||
@@ -649,7 +653,8 @@
 		gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 0);
 
 		if (machine_is_msm7x27a_surf() ||
-				 machine_is_msm7625a_surf()) {
+				 machine_is_msm7625a_surf() ||
+				 machine_is_msm8625_surf()) {
 			lcdc_reset_cfg = readl_relaxed(lcdc_reset_ptr);
 			rmb();
 			lcdc_reset_cfg &= ~1;
@@ -817,7 +822,7 @@
 
 	if (machine_is_msm7627a_qrd1())
 		rc = mipi_dsi_panel_qrd1_power(on);
-	else if (machine_is_msm7627a_evb())
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
 		rc = mipi_dsi_panel_qrd3_power(on);
 	else
 		rc = mipi_dsi_panel_msm_power(on);
@@ -840,7 +845,7 @@
 	if (machine_is_msm7627a_qrd1())
 		platform_add_devices(qrd_fb_devices,
 				ARRAY_SIZE(qrd_fb_devices));
-	else if (machine_is_msm7627a_evb())
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
 		platform_add_devices(evb_fb_devices,
 				ARRAY_SIZE(evb_fb_devices));
 	else if (machine_is_msm7627a_qrd3())
@@ -850,7 +855,8 @@
 				ARRAY_SIZE(msm_fb_devices));
 
 	msm_fb_register_device("mdp", &mdp_pdata);
-	if (machine_is_msm7625a_surf() || machine_is_msm7x27a_surf())
+	if (machine_is_msm7625a_surf() || machine_is_msm7x27a_surf() ||
+			machine_is_msm8625_surf())
 		msm_fb_register_device("lcdc", &lcdc_pdata);
 #ifdef CONFIG_FB_MSM_MDP303
 	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index 3bb9c8b..e4ee52e 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -150,7 +150,8 @@
 static int gpio_sdc1_hw_det = 85;
 static void gpio_sdc1_config(void)
 {
-	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb())
+	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+					|| machine_is_msm8625_evb())
 		gpio_sdc1_hw_det = 42;
 }
 
@@ -251,7 +252,8 @@
 		status = gpio_direction_input(gpio_sdc1_hw_det);
 		if (!status) {
 			if (machine_is_msm7627a_qrd1() ||
-					machine_is_msm7627a_evb())
+					machine_is_msm7627a_evb() ||
+					machine_is_msm8625_evb())
 				status = !gpio_get_value(gpio_sdc1_hw_det);
 			else
 				status = gpio_get_value(gpio_sdc1_hw_det);
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
index 6df7626..53d3c56 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -48,7 +48,8 @@
 int gpio_wlan_sys_rest_en = 134;
 static void gpio_wlan_config(void)
 {
-	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb())
+	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+					|| machine_is_msm8625_evb())
 		gpio_wlan_sys_rest_en = 124;
 }
 
@@ -229,7 +230,8 @@
 	 * gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
 	 * EVB1.0 and QRD8625,so the below step is required for those devices.
 	 */
-	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()) {
+	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+					|| machine_is_msm8625_evb()) {
 		rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
 					GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
 					GPIO_CFG_2MA), GPIO_CFG_ENABLE);
@@ -302,7 +304,8 @@
 	 * gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
 	 * EVB1.0 and QRD8625,so the below step is required for those devices.
 	 */
-	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()) {
+	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+					|| machine_is_msm8625_evb()) {
 		rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
 					GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
 					GPIO_CFG_2MA), GPIO_CFG_ENABLE);
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index dfd013c..bde9b61 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -66,6 +66,7 @@
 	QRD_GPIO_CAM_GP_CAMIF_RESET,
 };
 
+#define ADSP_RPC_PROG           0x3000000a
 #if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
 
 #define FPGA_MSM_CNTRL_REG2 0x90008010
@@ -98,8 +99,6 @@
 	struct regulator *reg;
 };
 
-extern struct platform_device msm_bt_power_device;
-
 void __init msm7627a_bt_power_init(void);
 #endif
 
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index d1c68f3..b44b03f 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -14,6 +14,7 @@
 #include <linux/gpio_event.h>
 #include <linux/memblock.h>
 #include <asm/mach-types.h>
+#include <linux/memblock.h>
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
 #include <mach/board.h>
@@ -60,7 +61,6 @@
 
 #define PMEM_KERNEL_EBI1_SIZE	0x3A000
 #define MSM_PMEM_AUDIO_SIZE	0x5B000
-#define ADSP_RPC_PROG           0x3000000a
 
 #if defined(CONFIG_GPIO_SX150X)
 enum {
@@ -94,7 +94,8 @@
 
 static void __init register_i2c_devices(void)
 {
-	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() ||
+			machine_is_msm8625_surf())
 		sx150x_data[SX150X_CORE].io_open_drain_ena = 0xe0f0;
 
 	core_exp_i2c_info[0].platform_data =
@@ -154,10 +155,6 @@
 	.msm_i2c_config_gpio	= gsbi_qup_i2c_gpio_config,
 };
 
-static struct msm_i2c_platform_data msm8625_gsbi0_qup_i2c_pdata = {
-	.clk_freq		= 100000,
-};
-
 #ifdef CONFIG_ARCH_MSM7X27A
 #define MSM_PMEM_MDP_SIZE       0x2300000
 #define MSM7x25A_MSM_PMEM_MDP_SIZE       0x1500000
@@ -387,6 +384,72 @@
 	.p_addr = 0,
 };
 
+/* 8625 PM platform data */
+static struct msm_pm_platform_data msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
+	/* CORE0 entries */
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 16000,
+					.residency = 20000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 12000,
+					.residency = 20000,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+};
+
+static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
+	.v_addr = MSM_CFG_CTL_BASE,
+};
+
 static struct android_pmem_platform_data android_pmem_adsp_pdata = {
 	.name = "pmem_adsp",
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -718,37 +781,51 @@
 
 static struct platform_device *msm8625_rumi3_devices[] __initdata = {
 	&msm8625_device_dmov,
+	&msm8625_device_smd,
 	&msm8625_device_uart1,
-	&msm8625_device_qup_i2c_gsbi0,
+	&msm8625_gsbi0_qup_i2c_device,
 };
 
-static struct platform_device *surf_ffa_devices[] __initdata = {
+static struct platform_device *msm7627a_surf_ffa_devices[] __initdata = {
 	&msm_device_dmov,
 	&msm_device_smd,
 	&msm_device_uart1,
 	&msm_device_uart_dm1,
 	&msm_device_uart_dm2,
-	&msm_device_nand,
 	&msm_gsbi0_qup_i2c_device,
 	&msm_gsbi1_qup_i2c_device,
 	&msm_device_otg,
 	&msm_device_gadget_peripheral,
-	&fmem_device,
+	&smsc911x_device,
+	&msm_kgsl_3d0,
+};
+
+static struct platform_device *common_devices[] __initdata = {
 	&android_usb_device,
 	&android_pmem_device,
 	&android_pmem_adsp_device,
 	&android_pmem_audio_device,
+	&fmem_device,
+	&msm_device_nand,
 	&msm_device_snd,
 	&msm_device_adspdec,
-	&msm_batt_device,
-	&smsc911x_device,
-	&msm_kgsl_3d0,
-#ifdef CONFIG_BT
-	&msm_bt_power_device,
-#endif
 	&asoc_msm_pcm,
 	&asoc_msm_dai0,
 	&asoc_msm_dai1,
+	&msm_batt_device,
+};
+
+static struct platform_device *msm8625_surf_devices[] __initdata = {
+	&msm8625_device_dmov,
+	&msm8625_device_uart1,
+	&msm8625_device_uart_dm1,
+	&msm8625_device_uart_dm2,
+	&msm8625_gsbi0_qup_i2c_device,
+	&msm8625_gsbi1_qup_i2c_device,
+	&msm8625_device_smd,
+	&msm8625_device_otg,
+	&msm8625_device_gadget_peripheral,
+	&msm8625_kgsl_3d0,
 };
 
 static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
@@ -870,21 +947,25 @@
 
 static void __init msm8625_reserve(void)
 {
+	msm7x27a_reserve();
 	memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+	msm_pm_8625_boot_pdata.p_addr = memblock_alloc(SZ_8, SZ_64K);
 }
 
-static void __init msm_device_i2c_init(void)
+static void __init msm7x27a_device_i2c_init(void)
 {
-	if (machine_is_msm8625_rumi3()) {
-		msm8625_device_qup_i2c_gsbi0.dev.platform_data =
-			&msm8625_gsbi0_qup_i2c_pdata;
-		return;
-	}
-
 	msm_gsbi0_qup_i2c_device.dev.platform_data = &msm_gsbi0_qup_i2c_pdata;
 	msm_gsbi1_qup_i2c_device.dev.platform_data = &msm_gsbi1_qup_i2c_pdata;
 }
 
+static void __init msm8625_device_i2c_init(void)
+{
+	msm8625_gsbi0_qup_i2c_device.dev.platform_data =
+		&msm_gsbi0_qup_i2c_pdata;
+	msm8625_gsbi1_qup_i2c_device.dev.platform_data =
+		&msm_gsbi1_qup_i2c_pdata;
+}
+
 #define MSM_EBI2_PHYS			0xa0d00000
 #define MSM_EBI2_XMEM_CS2_CFG1		0xa0d10030
 
@@ -899,7 +980,7 @@
 
 	ebi2_cfg = readl(ebi2_cfg_ptr);
 	if (machine_is_msm7x27a_rumi3() || machine_is_msm7x27a_surf() ||
-			machine_is_msm7625a_surf())
+		machine_is_msm7625a_surf() || machine_is_msm8625_surf())
 		ebi2_cfg |= (1 << 4); /* CS2 */
 
 	writel(ebi2_cfg, ebi2_cfg_ptr);
@@ -1147,7 +1228,11 @@
 		return;
 	}
 	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
-	rpc_adsp_pdev->pdev = msm_adsp_device;
+
+	if (cpu_is_msm8625())
+		rpc_adsp_pdev->pdev = msm8625_device_adsp;
+	else
+		rpc_adsp_pdev->pdev = msm_adsp_device;
 	rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
 	if (rc < 0) {
 		pr_err("%s: return val: %d\n",	__func__, rc);
@@ -1155,25 +1240,6 @@
 	}
 }
 
-static void msm_adsp_8625_add_pdev(void)
-{
-	int rc = 0;
-	struct rpc_board_dev *rpc_adsp_pdev;
-
-	rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
-	if (rpc_adsp_pdev == NULL) {
-		pr_err("%s: Memory Allocation failure\n", __func__);
-		return;
-	}
-	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
-	rpc_adsp_pdev->pdev = msm8625_device_adsp;
-	rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
-	if (rc < 0) {
-		pr_err("%s: return val: %d\n", __func__, rc);
-		kfree(rpc_adsp_pdev);
-	}
-}
-
 static void __init msm7627a_rumi3_init(void)
 {
 	msm7x27a_init_ebi2();
@@ -1184,10 +1250,15 @@
 static void __init msm8625_rumi3_init(void)
 {
 	msm7x2x_misc_init();
-	msm_adsp_8625_add_pdev();
-	msm_device_i2c_init();
+	msm_adsp_add_pdev();
+	msm8625_device_i2c_init();
 	platform_add_devices(msm8625_rumi3_devices,
 			ARRAY_SIZE(msm8625_rumi3_devices));
+
+	msm_pm_set_platform_data(msm8625_pm_data,
+			 ARRAY_SIZE(msm8625_pm_data));
+	BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
+	msm8x25_spm_device_init();
 }
 
 #define LED_GPIO_PDM		96
@@ -1211,56 +1282,56 @@
 				__func__, rc);
 }
 
-static void __init msm7x2x_init(void)
+static void __init msm7x27a_add_footswitch_devices(void)
 {
-	msm7x2x_misc_init();
-
-	/* Initialize regulators first so that other devices can use them */
-	msm7x27a_init_regulators();
-
-	/* Common functions for SURF/FFA/RUMI3 */
-	msm_adsp_add_pdev();
-	msm_device_i2c_init();
-	msm7x27a_init_ebi2();
-	msm7x27a_cfg_uart2dm_serial();
-#ifdef CONFIG_SERIAL_MSM_HS
-	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
-	msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
-#endif
-
-#ifdef CONFIG_USB_MSM_OTG_72K
-	msm_otg_pdata.swfi_latency =
-		msm7x27a_pm_data
-		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
-	msm_device_otg.dev.platform_data = &msm_otg_pdata;
-#endif
-	msm_device_gadget_peripheral.dev.platform_data =
-		&msm_gadget_pdata;
-	msm7x27a_cfg_smsc911x();
 	platform_add_devices(msm_footswitch_devices,
 			msm_num_footswitch_devices);
-	platform_add_devices(surf_ffa_devices,
-			ARRAY_SIZE(surf_ffa_devices));
-	/* Ensure ar6000pm device is registered before MMC/SDC */
-	msm7x27a_init_ar6000pm();
-#ifdef CONFIG_MMC_MSM
-	msm7627a_init_mmc();
-#endif
-	msm_fb_add_devices();
-#ifdef CONFIG_USB_EHCI_MSM_72K
-	msm7x2x_init_host();
-#endif
+}
 
-	msm_pm_set_platform_data(msm7x27a_pm_data,
-				ARRAY_SIZE(msm7x27a_pm_data));
-	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+static void __init msm7x27a_add_platform_devices(void)
+{
+	if (machine_is_msm8625_surf()) {
+		platform_add_devices(msm8625_surf_devices,
+			ARRAY_SIZE(msm8625_surf_devices));
+	} else {
+		platform_add_devices(msm7627a_surf_ffa_devices,
+			ARRAY_SIZE(msm7627a_surf_ffa_devices));
+	}
 
-#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
-	register_i2c_devices();
-#endif
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-	msm7627a_bt_power_init();
-#endif
+	platform_add_devices(common_devices,
+			ARRAY_SIZE(common_devices));
+}
+
+static void __init msm7x27a_uartdm_config(void)
+{
+	msm7x27a_cfg_uart2dm_serial();
+	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
+	if (cpu_is_msm8625())
+		msm8625_device_uart_dm1.dev.platform_data =
+			&msm_uart_dm1_pdata;
+	else
+		msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+}
+
+static void __init msm7x27a_otg_gadget(void)
+{
+	msm_otg_pdata.swfi_latency =
+		msm7x27a_pm_data[
+		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+	if (cpu_is_msm8625()) {
+		msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
+		msm8625_device_gadget_peripheral.dev.platform_data =
+			&msm_gadget_pdata;
+	} else {
+		msm_device_otg.dev.platform_data = &msm_otg_pdata;
+		msm_device_gadget_peripheral.dev.platform_data =
+			&msm_gadget_pdata;
+	}
+}
+
+static void __init msm7x27a_add_io_devices(void)
+{
+	/* touchscreen */
 	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
 		atmel_ts_pdata.min_x = 0;
 		atmel_ts_pdata.max_x = 480;
@@ -1269,16 +1340,15 @@
 	}
 
 	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
-		atmel_ts_i2c_info,
-		ARRAY_SIZE(atmel_ts_i2c_info));
-
-#if defined(CONFIG_MSM_CAMERA)
-	msm7627a_camera_init();
-#endif
+				atmel_ts_i2c_info,
+				ARRAY_SIZE(atmel_ts_i2c_info));
+	/* keypad */
 	platform_device_register(&kp_pdev);
+
+	/* headset */
 	platform_device_register(&hs_pdev);
 
-	/* configure it as a pdm function*/
+	/* LED: configure it as a pdm function */
 	if (gpio_tlmm_config(GPIO_CFG(LED_GPIO_PDM, 3,
 				GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
 				GPIO_CFG_8MA), GPIO_CFG_ENABLE))
@@ -1287,10 +1357,50 @@
 	else
 		platform_device_register(&led_pdev);
 
-#ifdef CONFIG_MSM_RPC_VIBRATOR
+	/* Vibrator */
 	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
 		msm_init_pmic_vibrator();
-#endif
+}
+
+static void __init msm7x27a_pm_init(void)
+{
+	if (machine_is_msm8625_surf())
+		return;
+
+	msm_pm_set_platform_data(msm7x27a_pm_data,
+			ARRAY_SIZE(msm7x27a_pm_data));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+}
+
+static void __init msm7x2x_init(void)
+{
+	msm7x2x_misc_init();
+
+	/* Initialize regulators first so that other devices can use them */
+	msm7x27a_init_regulators();
+	msm_adsp_add_pdev();
+	if (cpu_is_msm8625())
+		msm8625_device_i2c_init();
+	else
+		msm7x27a_device_i2c_init();
+	msm7x27a_init_ebi2();
+	msm7x27a_uartdm_config();
+
+	msm7x27a_otg_gadget();
+	msm7x27a_cfg_smsc911x();
+
+	msm7x27a_add_footswitch_devices();
+	msm7x27a_add_platform_devices();
+	/* Ensure ar6000pm device is registered before MMC/SDC */
+	msm7x27a_init_ar6000pm();
+	msm7627a_init_mmc();
+	msm_fb_add_devices();
+	msm7x2x_init_host();
+	msm7x27a_pm_init();
+	register_i2c_devices();
+	msm7627a_bt_power_init();
+	msm7627a_camera_init();
+	msm7x27a_add_io_devices();
 	/*7x25a kgsl initializations*/
 	msm7x25a_kgsl_3d0_init();
 }
@@ -1359,3 +1469,13 @@
 	.timer          = &msm_timer,
 	.handle_irq	= gic_handle_irq,
 MACHINE_END
+MACHINE_START(MSM8625_SURF, "QCT MSM8625 SURF")
+	.boot_params    = PHYS_OFFSET + 0x100,
+	.map_io         = msm8625_map_io,
+	.reserve        = msm8625_reserve,
+	.init_irq       = msm8625_init_irq,
+	.init_machine   = msm7x2x_init,
+	.timer          = &msm_timer,
+	.init_early     = msm7x2x_init_early,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 260c880..9f7104f 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -5236,7 +5236,8 @@
 	&msm_batt_device,
 	&msm_adc_device,
 	&msm_ebi0_thermal,
-	&msm_ebi1_thermal
+	&msm_ebi1_thermal,
+	&msm_adsp_device
 };
 
 static struct msm_gpio msm_i2c_gpios_hw[] = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index e3fc97f..9b5e1e2 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -119,7 +119,6 @@
 #define LCDC_AUO_SPI_DEVICE_NAME		"lcdc_auo_nt35582"
 #define LCDC_NT35582_PANEL_NAME			"lcdc_nt35582_wvga"
 
-#define PANEL_NAME_MAX_LEN	30
 #define MIPI_CMD_NOVATEK_QHD_PANEL_NAME	"mipi_cmd_novatek_qhd"
 #define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME	"mipi_video_novatek_qhd"
 #define MIPI_VIDEO_TOSHIBA_WVGA_PANEL_NAME	"mipi_video_toshiba_wvga"
@@ -2660,19 +2659,17 @@
 #define MSM_FB_EXT_BUFT_SIZE	0
 #endif
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-/* 4 bpp x 2 page HDMI case */
-#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
-#else
 /* Note: must be multiple of 4096 */
 #define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
 				MSM_FB_DSUB_PMEM_ADDER, 4096)
-#endif
+
+#define MSM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
+#define MSM_HDMI_PRIM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
 
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-#define MSM_PMEM_SF_SIZE 0x8000000 /* 128 Mbytes */
+unsigned char hdmi_is_primary = 1;
 #else
-#define MSM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
+unsigned char hdmi_is_primary;
 #endif
 
 #ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
@@ -2712,6 +2709,8 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define MSM_ION_HEAP_NUM	9
+#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SF_SIZE
+static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
 #else
 #define MSM_ION_HEAP_NUM	1
 #endif
@@ -3159,7 +3158,11 @@
 	void *addr;
 	unsigned long size;
 
-	size = MSM_FB_SIZE;
+	if (hdmi_is_primary)
+		size = roundup((1920 * 1088 * 4 * 2), 4096);
+	else
+		size = MSM_FB_SIZE;
+
 	addr = alloc_bootmem_align(size, 0x1000);
 	msm_fb_resources[0].start = __pa(addr);
 	msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
@@ -3168,6 +3171,30 @@
 
 }
 
+void __init msm8x60_set_display_params(char *prim_panel, char *ext_panel)
+{
+	if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+			msm_fb_pdata.prim_panel_name);
+
+		if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+			HDMI_PANEL_NAME, strnlen(HDMI_PANEL_NAME,
+				PANEL_NAME_MAX_LEN))) {
+			pr_debug("HDMI is the primary display by"
+				" boot parameter\n");
+			hdmi_is_primary = 1;
+		}
+	}
+	if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
+		strlcpy(msm_fb_pdata.ext_panel_name, ext_panel,
+			PANEL_NAME_MAX_LEN);
+		pr_debug("msm_fb_pdata.ext_panel_name %s\n",
+			msm_fb_pdata.ext_panel_name);
+	}
+}
+
 #if defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C) || \
 		defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C_MODULE)
 /*virtual key support */
@@ -5410,7 +5437,21 @@
 static void reserve_ion_memory(void)
 {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
-	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
+	unsigned int i;
+
+	if (hdmi_is_primary) {
+		msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE;
+		for (i = 0; i < ion_pdata.nr; i++) {
+			if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) {
+				ion_pdata.heaps[i].size = msm_ion_sf_size;
+				pr_debug("msm_ion_sf_size 0x%x\n",
+					msm_ion_sf_size);
+				break;
+			}
+		}
+	}
+
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
 	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_FW_SIZE;
 	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_SIZE;
 	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MFC_SIZE;
@@ -5426,6 +5467,9 @@
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	android_pmem_adsp_pdata.size = pmem_adsp_size;
 	android_pmem_smipool_pdata.size = MSM_PMEM_SMIPOOL_SIZE;
+
+	if (hdmi_is_primary)
+		pmem_sf_size = MSM_HDMI_PRIM_PMEM_SF_SIZE;
 	android_pmem_pdata.size = pmem_sf_size;
 #endif
 	android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
@@ -5475,8 +5519,27 @@
 	.paddr_to_memtype = msm8x60_paddr_to_memtype,
 };
 
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static char ext_panel_name[PANEL_NAME_MAX_LEN];
+static int __init prim_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+static int __init ext_display_setup(char *param)
+{
+	if (strnlen(param, PANEL_NAME_MAX_LEN))
+		strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN);
+	return 0;
+}
+early_param("ext_display", ext_display_setup);
+
 static void __init msm8x60_reserve(void)
 {
+	msm8x60_set_display_params(prim_panel_name, ext_panel_name);
 	reserve_info = &msm8x60_reserve_info;
 	msm_reserve();
 }
@@ -9422,26 +9485,7 @@
 		.ib = 0,
 	},
 };
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors dtv_bus_def_vectors[] = {
-	/* For now, 0th array entry is reserved.
-	 * Please leave 0 as is and don't use it
-	 */
-	{
-		.src = MSM_BUS_MASTER_MDP_PORT0,
-		.dst = MSM_BUS_SLAVE_SMI,
-		.ab = 2000000000,
-		.ib = 2000000000,
-	},
-	/* Master and slaves can be from different fabrics */
-	{
-		.src = MSM_BUS_MASTER_MDP_PORT0,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 2000000000,
-		.ib = 2000000000,
-	},
-};
-#else
+
 static struct msm_bus_vectors dtv_bus_def_vectors[] = {
 	/* For now, 0th array entry is reserved.
 	 * Please leave 0 as is and don't use it
@@ -9460,7 +9504,26 @@
 		.ib = 707616000,
 	},
 };
-#endif
+
+static struct msm_bus_vectors dtv_bus_hdmi_prim_vectors[] = {
+	/* For now, 0th array entry is reserved.
+	 * Please leave 0 as is and don't use it
+	 */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_SMI,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+	/* Master and slaves can be from different fabrics */
+	{
+		.src = MSM_BUS_MASTER_MDP_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 2000000000,
+		.ib = 2000000000,
+	},
+};
+
 static struct msm_bus_paths dtv_bus_scale_usecases[] = {
 	{
 		ARRAY_SIZE(dtv_bus_init_vectors),
@@ -9471,6 +9534,7 @@
 		dtv_bus_def_vectors,
 	},
 };
+
 static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
 	dtv_bus_scale_usecases,
 	ARRAY_SIZE(dtv_bus_scale_usecases),
@@ -9480,6 +9544,27 @@
 static struct lcdc_platform_data dtv_pdata = {
 	.bus_scale_table = &dtv_bus_scale_pdata,
 };
+
+static struct msm_bus_paths dtv_hdmi_prim_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(dtv_bus_init_vectors),
+		dtv_bus_init_vectors,
+	},
+	{
+		ARRAY_SIZE(dtv_bus_hdmi_prim_vectors),
+		dtv_bus_hdmi_prim_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata dtv_hdmi_prim_bus_scale_pdata = {
+	dtv_hdmi_prim_bus_scale_usecases,
+	ARRAY_SIZE(dtv_hdmi_prim_bus_scale_usecases),
+	.name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_hdmi_prim_pdata = {
+	.bus_scale_table = &dtv_hdmi_prim_bus_scale_pdata,
+};
 #endif
 
 
@@ -9601,13 +9686,6 @@
 	160000000,
 	200000000,
 };
-#elif defined(CONFIG_FB_MSM_HDMI_AS_PRIMARY)
-int mdp_core_clk_rate_table[] = {
-	200000000,
-	200000000,
-	200000000,
-	200000000,
-};
 #else
 int mdp_core_clk_rate_table[] = {
 	59080000,
@@ -9619,11 +9697,7 @@
 
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-	.mdp_core_clk_rate = 200000000,
-#else
 	.mdp_core_clk_rate = 59080000,
-#endif
 	.mdp_core_clk_table = mdp_core_clk_rate_table,
 	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -9729,7 +9803,10 @@
 	msm_fb_register_device("lcdc", &lcdc_pdata);
 	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
 #ifdef CONFIG_MSM_BUS_SCALING
-	msm_fb_register_device("dtv", &dtv_pdata);
+	if (hdmi_is_primary)
+		msm_fb_register_device("dtv", &dtv_hdmi_prim_pdata);
+	else
+		msm_fb_register_device("dtv", &dtv_pdata);
 #endif
 #ifdef CONFIG_FB_MSM_TVOUT
 	msm_fb_register_device("tvenc", &atv_pdata);
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 0427632..ac590d3 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -28,9 +28,11 @@
 #include <linux/input/rmi_i2c.h>
 #include <linux/i2c/atmel_mxt_ts.h>
 #include <linux/regulator/consumer.h>
+#include <linux/memblock.h>
 #include <asm/mach/mmc.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_hsusb.h>
@@ -659,7 +661,20 @@
 	.dev.platform_data  = &msm_psy_batt_data,
 };
 
-static struct platform_device *qrd_common_devices[] __initdata = {
+static struct platform_device *common_devices[] __initdata = {
+	&android_usb_device,
+	&android_pmem_device,
+	&android_pmem_adsp_device,
+	&android_pmem_audio_device,
+	&msm_batt_device,
+	&msm_device_adspdec,
+	&msm_device_snd,
+	&asoc_msm_pcm,
+	&asoc_msm_dai0,
+	&asoc_msm_dai1,
+};
+
+static struct platform_device *qrd7627a_devices[] __initdata = {
 	&msm_device_dmov,
 	&msm_device_smd,
 	&msm_device_uart1,
@@ -668,26 +683,24 @@
 	&msm_gsbi1_qup_i2c_device,
 	&msm_device_otg,
 	&msm_device_gadget_peripheral,
-	&android_usb_device,
-	&android_pmem_device,
-	&android_pmem_adsp_device,
-	&android_pmem_audio_device,
-	&msm_device_snd,
-	&msm_device_adspdec,
-	&msm_batt_device,
 	&msm_kgsl_3d0,
-#ifdef CONFIG_BT
-	&msm_bt_power_device,
-#endif
-	&asoc_msm_pcm,
-	&asoc_msm_dai0,
-	&asoc_msm_dai1,
 };
 
 static struct platform_device *qrd3_devices[] __initdata = {
 	&msm_device_nand,
 };
 
+static struct platform_device *msm8625_evb_devices[] __initdata = {
+	&msm8625_device_dmov,
+	&msm8625_device_smd,
+	&msm8625_gsbi0_qup_i2c_device,
+	&msm8625_gsbi1_qup_i2c_device,
+	&msm8625_device_uart1,
+	&msm8625_device_otg,
+	&msm8625_device_gadget_peripheral,
+	&msm8625_kgsl_3d0,
+};
+
 static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
 static int __init pmem_kernel_ebi1_size_setup(char *p)
 {
@@ -762,12 +775,49 @@
 	msm_reserve();
 }
 
-static void __init msm_device_i2c_init(void)
+static void __init msm8625_reserve(void)
+{
+	memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+	msm7627a_reserve();
+}
+
+static void msmqrd_adsp_add_pdev(void)
+{
+	int rc = 0;
+	struct rpc_board_dev *rpc_adsp_pdev;
+
+	rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+	if (rpc_adsp_pdev == NULL) {
+		pr_err("%s: Memory Allocation failure\n", __func__);
+		return;
+	}
+	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+
+	if (cpu_is_msm8625())
+		rpc_adsp_pdev->pdev = msm8625_device_adsp;
+	else
+		rpc_adsp_pdev->pdev = msm_adsp_device;
+	rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+	if (rc < 0) {
+		pr_err("%s: return val: %d\n",	__func__, rc);
+		kfree(rpc_adsp_pdev);
+	}
+}
+
+static void __init msm7627a_device_i2c_init(void)
 {
 	msm_gsbi0_qup_i2c_device.dev.platform_data = &msm_gsbi0_qup_i2c_pdata;
 	msm_gsbi1_qup_i2c_device.dev.platform_data = &msm_gsbi1_qup_i2c_pdata;
 }
 
+static void __init msm8625_device_i2c_init(void)
+{
+	msm8625_gsbi0_qup_i2c_device.dev.platform_data
+					= &msm_gsbi0_qup_i2c_pdata;
+	msm8625_gsbi1_qup_i2c_device.dev.platform_data
+					= &msm_gsbi1_qup_i2c_pdata;
+}
+
 static struct msm_handset_platform_data hs_platform_data = {
 	.hs_name = "7k_handset",
 	.pwr_key_delay_ms = 500, /* 0 will disable end key */
@@ -958,7 +1008,7 @@
 		i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
 					synaptic_i2c_clearpad3k,
 					ARRAY_SIZE(synaptic_i2c_clearpad3k));
-	} else if (machine_is_msm7627a_evb()) {
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
 		rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_IRQ_GPIO, 0,
 				GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
 				GPIO_CFG_8MA), GPIO_CFG_ENABLE);
@@ -989,11 +1039,11 @@
 #endif
 
 	/* keypad */
-	if (machine_is_msm7627a_evb())
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
 		platform_device_register(&kp_pdev_8625);
 
 	/* leds */
-	if (machine_is_msm7627a_evb()) {
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
 		rc = gpio_tlmm_config(GPIO_CFG(LED_RED_GPIO_8625, 0,
 				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
 				GPIO_CFG_16MA), GPIO_CFG_ENABLE);
@@ -1022,32 +1072,63 @@
 
 static void add_platform_devices(void)
 {
-	platform_add_devices(qrd_common_devices,
-			ARRAY_SIZE(qrd_common_devices));
-
-	if (machine_is_msm7627a_qrd3())
-		platform_add_devices(qrd3_devices,
-				ARRAY_SIZE(qrd3_devices));
+	if (machine_is_msm8625_evb())
+		platform_add_devices(msm8625_evb_devices,
+				ARRAY_SIZE(msm8625_evb_devices));
+	else {
+		platform_add_devices(qrd7627a_devices,
+				ARRAY_SIZE(qrd7627a_devices));
+		if (machine_is_msm7627a_qrd3())
+			platform_add_devices(qrd3_devices,
+					ARRAY_SIZE(qrd3_devices));
+	}
+	platform_add_devices(common_devices,
+			ARRAY_SIZE(common_devices));
 }
 
 #define UART1DM_RX_GPIO		45
+static void __init qrd7627a_uart1dm_config(void)
+{
+	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
+	if (cpu_is_msm8625())
+		msm8625_device_uart_dm1.dev.platform_data =
+			&msm_uart_dm1_pdata;
+	else
+		msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+}
+
+static void __init qrd7627a_otg_gadget(void)
+{
+	msm_otg_pdata.swfi_latency = msm7627a_pm_data
+		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+
+	if (cpu_is_msm8625()) {
+		msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
+		msm8625_device_gadget_peripheral.dev.platform_data =
+					&msm_gadget_pdata;
+
+	} else {
+		msm_device_otg.dev.platform_data = &msm_otg_pdata;
+		msm_device_gadget_peripheral.dev.platform_data =
+					&msm_gadget_pdata;
+	}
+}
+
 static void __init msm_qrd_init(void)
 {
 	msm7x2x_misc_init();
 	msm7627a_init_regulators();
-	msm_device_i2c_init();
-#ifdef CONFIG_SERIAL_MSM_HS
-	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
-	msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
-#endif
+	msmqrd_adsp_add_pdev();
 
-#ifdef CONFIG_USB_MSM_OTG_72K
-	msm_otg_pdata.swfi_latency = msm7627a_pm_data
-		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
-	msm_device_otg.dev.platform_data = &msm_otg_pdata;
-#endif
-	msm_device_gadget_peripheral.dev.platform_data =
-		&msm_gadget_pdata;
+	if (cpu_is_msm8625())
+		msm8625_device_i2c_init();
+	else
+		msm7627a_device_i2c_init();
+
+	/* uart1dm*/
+	qrd7627a_uart1dm_config();
+	/*OTG gadget*/
+	qrd7627a_otg_gadget();
 
 	add_platform_devices();
 
@@ -1058,9 +1139,11 @@
 #ifdef CONFIG_USB_EHCI_MSM_72K
 	msm7627a_init_host();
 #endif
-	msm_pm_set_platform_data(msm7627a_pm_data,
+	if (!machine_is_msm8625_evb()) {
+		msm_pm_set_platform_data(msm7627a_pm_data,
 				ARRAY_SIZE(msm7627a_pm_data));
-	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+		BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	}
 
 	msm_fb_add_devices();
 
@@ -1069,8 +1152,8 @@
 #endif
 
 	msm7627a_camera_init();
-
 	msm7627a_add_io_devices();
+	msm7x25a_kgsl_3d0_init();
 }
 
 static void __init qrd7627a_init_early(void)
@@ -1108,3 +1191,13 @@
 	.init_early	= qrd7627a_init_early,
 	.handle_irq	= vic_handle_irq,
 MACHINE_END
+MACHINE_START(MSM8625_EVB, "QRD MSM8625 EVB")
+	.boot_params	= PHYS_OFFSET + 0x100,
+	.map_io		= msm8625_map_io,
+	.reserve	= msm8625_reserve,
+	.init_irq	= msm8625_init_irq,
+	.init_machine	= msm_qrd_init,
+	.timer		= &msm_timer,
+	.init_early	= qrd7627a_init_early,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 5996388..a2e2c4c 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -365,9 +365,6 @@
 };
 #define PLL_RATE(l, m, n, v, d, i) { l, m, n, v, (d>>1), i }
 
-static int rpm_vreg_id_vdd_dig;
-static int rpm_vreg_id_vdd_sr2_pll;
-
 enum vdd_dig_levels {
 	VDD_DIG_NONE,
 	VDD_DIG_LOW,
@@ -375,7 +372,7 @@
 	VDD_DIG_HIGH
 };
 
-static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
+static int set_vdd_dig_8960(struct clk_vdd_class *vdd_class, int level)
 {
 	static const int vdd_uv[] = {
 		[VDD_DIG_NONE]    =       0,
@@ -383,11 +380,23 @@
 		[VDD_DIG_NOMINAL] = 1050000,
 		[VDD_DIG_HIGH]    = 1150000
 	};
-	return rpm_vreg_set_voltage(rpm_vreg_id_vdd_dig, RPM_VREG_VOTER3,
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S3, RPM_VREG_VOTER3,
 				    vdd_uv[level], 1150000, 1);
 }
 
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960);
+
+static int set_vdd_dig_8930(struct clk_vdd_class *vdd_class, int level)
+{
+	static const int vdd_uv[] = {
+		[VDD_DIG_NONE]    =       0,
+		[VDD_DIG_LOW]     =  945000,
+		[VDD_DIG_NOMINAL] = 1050000,
+		[VDD_DIG_HIGH]    = 1150000
+	};
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_S1, RPM_VREG_VOTER3,
+				    vdd_uv[level], 1150000, 1);
+}
 
 #define VDD_DIG_FMAX_MAP1(l1, f1) \
 	.vdd_class = &vdd_dig, \
@@ -407,49 +416,53 @@
 	VDD_SR2_PLL_ON
 };
 
-static int set_vdd_sr2_pll(struct clk_vdd_class *vdd_class, int level)
+static int set_vdd_sr2_pll_8960(struct clk_vdd_class *vdd_class, int level)
 {
 	int rc = 0;
-	if (cpu_is_msm8960()) {
-		if (level == VDD_SR2_PLL_OFF) {
-			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
-					RPM_VREG_VOTER3, 0, 0, 1);
-			if (rc)
-				return rc;
-			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
-					RPM_VREG_VOTER3, 0, 0, 1);
-			if (rc)
-				rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
-					RPM_VREG_VOTER3, 1800000, 1800000, 1);
-		} else {
-			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
-					RPM_VREG_VOTER3, 2100000, 2100000, 1);
-			if (rc)
-				return rc;
-			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
-					RPM_VREG_VOTER3, 1800000, 1800000, 1);
-			if (rc)
-				rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
-						RPM_VREG_VOTER3, 0, 0, 1);
-		}
+
+	if (level == VDD_SR2_PLL_OFF) {
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+				RPM_VREG_VOTER3, 0, 0, 1);
+		if (rc)
+			return rc;
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+				RPM_VREG_VOTER3, 0, 0, 1);
+		if (rc)
+			rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+				RPM_VREG_VOTER3, 1800000, 1800000, 1);
 	} else {
-		if (level == VDD_SR2_PLL_OFF) {
-			rc = rpm_vreg_set_voltage(rpm_vreg_id_vdd_sr2_pll,
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+				RPM_VREG_VOTER3, 2100000, 2100000, 1);
+		if (rc)
+			return rc;
+		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+				RPM_VREG_VOTER3, 1800000, 1800000, 1);
+		if (rc)
+			rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
 					RPM_VREG_VOTER3, 0, 0, 1);
-			if (rc)
-				return rc;
-		} else {
-			rc = rpm_vreg_set_voltage(rpm_vreg_id_vdd_sr2_pll,
-					RPM_VREG_VOTER3, 1800000, 1800000, 1);
-			if (rc)
-				return rc;
-		}
 	}
 
 	return rc;
 }
 
-static DEFINE_VDD_CLASS(vdd_sr2_pll, set_vdd_sr2_pll);
+static DEFINE_VDD_CLASS(vdd_sr2_pll, set_vdd_sr2_pll_8960);
+
+static int sr2_lreg_uv[] = {
+	[VDD_SR2_PLL_OFF] = 0,
+	[VDD_SR2_PLL_ON] = 1800000,
+};
+
+static int set_vdd_sr2_pll_8064(struct clk_vdd_class *vdd_class, int level)
+{
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_LVS7, RPM_VREG_VOTER3,
+				    sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
+}
+
+static int set_vdd_sr2_pll_8930(struct clk_vdd_class *vdd_class, int level)
+{
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23, RPM_VREG_VOTER3,
+				    sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
+}
 
 /*
  * Clock Descriptions
@@ -4461,6 +4474,9 @@
 DEFINE_CLK_RPM(sfab_clk, sfab_a_clk, SYSTEM_FABRIC, NULL);
 DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
 
+static DEFINE_CLK_VOTER(sfab_msmbus_a_clk, &sfab_a_clk.c);
+static DEFINE_CLK_VOTER(sfab_tmr_a_clk, &sfab_a_clk.c);
+
 static DEFINE_CLK_VOTER(dfab_dsps_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_usb_hs3_clk, &dfab_clk.c);
@@ -4898,7 +4914,7 @@
 	CLK_LOOKUP("bus_clk",		cfpb_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
-	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_msmbus_a_clk.c,	"msm_sys_fab"),
 	CLK_LOOKUP("bus_clk",		sfpb_clk.c,		"msm_sys_fpb"),
 	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,		"msm_sys_fpb"),
 	CLK_LOOKUP("bus_clk",		mmfab_clk.c,		"msm_mm_fab"),
@@ -5045,7 +5061,7 @@
 	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		""),
 	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,		""),
-	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		""),
+	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		"msm_vpe.0"),
 	CLK_LOOKUP("core_clk",		vpe_clk.c,	"footswitch-8x60.9"),
 	CLK_LOOKUP("vfe_clk",		vfe_clk.c,		"msm_vfe.0"),
 	CLK_LOOKUP("core_clk",		vfe_clk.c,	"footswitch-8x60.8"),
@@ -5082,7 +5098,7 @@
 	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"footswitch-8x60.7"),
 	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		"msm_vfe.0"),
 	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
-	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		""),
+	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		"msm_vpe.0"),
 	CLK_LOOKUP("iface_clk",		vpe_p_clk.c,	"footswitch-8x60.9"),
 
 	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,		"msm-dai-q6.6"),
@@ -5175,7 +5191,7 @@
 	CLK_LOOKUP("bus_clk",		cfpb_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_a_clk",		cfpb_a_clk.c,		"msm_cpss_fpb"),
 	CLK_LOOKUP("bus_clk",		sfab_clk.c,		"msm_sys_fab"),
-	CLK_LOOKUP("bus_a_clk",		sfab_a_clk.c,		"msm_sys_fab"),
+	CLK_LOOKUP("bus_a_clk",		sfab_msmbus_a_clk.c,	"msm_sys_fab"),
 	CLK_LOOKUP("bus_clk",		sfpb_clk.c,		"msm_sys_fpb"),
 	CLK_LOOKUP("bus_a_clk",		sfpb_a_clk.c,		"msm_sys_fpb"),
 	CLK_LOOKUP("bus_clk",		mmfab_clk.c,		"msm_mm_fab"),
@@ -5676,16 +5692,11 @@
 static void __init msm8960_clock_init(void)
 {
 
-	if (cpu_is_msm8960()) {
-		rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3;
-	} else if (cpu_is_apq8064()) {
-		rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3;
-		rpm_vreg_id_vdd_sr2_pll = RPM_VREG_ID_PM8921_LVS7;
+	if (cpu_is_apq8064()) {
+		vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8064;
 	} else if (cpu_is_msm8930() || cpu_is_msm8627()) {
-		rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8038_S1;
-		rpm_vreg_id_vdd_sr2_pll = RPM_VREG_ID_PM8038_L23;
-	} else {
-		BUG();
+		vdd_dig.set_vdd = set_vdd_dig_8930;
+		vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8930;
 	}
 
 	xo_pxo = msm_xo_get(MSM_XO_PXO, "clock-8960");
@@ -5763,6 +5774,14 @@
 	rcg_clk_disable(&tssc_clk.c);
 	clk_enable(&usb_hsic_hsic_clk.c);
 	clk_disable(&usb_hsic_hsic_clk.c);
+
+	/*
+	 * Keep sfab floor @ 54MHz so that Krait AHB is at least 27MHz at all
+	 * times when Apps CPU is active. This ensures the timer's requirement
+	 * of Krait AHB running 4 times as fast as the timer itself.
+	 */
+	clk_set_rate(&sfab_tmr_a_clk.c, 54000000);
+	clk_enable(&sfab_tmr_a_clk.c);
 }
 
 static int __init msm8960_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index d3f5396..9ab3de8 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3765,6 +3765,12 @@
 	CLK_LOOKUP("core_clk",		gfx2d0_clk.c,		"msm_iommu.10"),
 	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,		"msm_iommu.11"),
 
+	CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("rot_iommu_clk",	rot_axi_clk.c,	"msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_clk.c, "msm_vidc.0"),
+	CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c,	"msm_vidc.0"),
+
 	CLK_LOOKUP("dfab_dsps_clk",	dfab_dsps_clk.c, NULL),
 	CLK_LOOKUP("core_clk",		dfab_usb_hs_clk.c,	"msm_otg"),
 	CLK_LOOKUP("bus_clk",		dfab_sdc1_clk.c, "msm_sdcc.1"),
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index 200cbfe..c20b7e4 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -11,9 +11,16 @@
  */
 
 #include "clock.h"
+#include "clock-pll.h"
 #include "clock-pcom.h"
 #include "clock-voter.h"
 
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+
+#define PLLn_MODE(n)	(MSM_CLK_CTL_BASE + 0x300 + 28 * (n))
+#define PLL4_MODE	(MSM_CLK_CTL_BASE + 0x374)
+
 static DEFINE_CLK_PCOM(adm_clk,		ADM_CLK,	CLKFLAG_SKIP_AUTO_OFF);
 static DEFINE_CLK_PCOM(adsp_clk,	ADSP_CLK,	CLKFLAG_SKIP_AUTO_OFF);
 static DEFINE_CLK_PCOM(ahb_m_clk,	AHB_M_CLK,	CLKFLAG_SKIP_AUTO_OFF);
@@ -28,6 +35,46 @@
 static DEFINE_CLK_PCOM(csi1_p_clk,	CSI1_P_CLK,	CLKFLAG_SKIP_AUTO_OFF);
 static DEFINE_CLK_PCOM(csi1_vfe_clk,	CSI1_VFE_CLK,	CLKFLAG_SKIP_AUTO_OFF);
 
+static struct pll_shared_clk pll0_clk = {
+	.id = PLL_0,
+	.mode_reg = PLLn_MODE(0),
+	.c = {
+		.ops = &clk_pll_ops,
+		.dbg_name = "pll0_clk",
+		CLK_INIT(pll0_clk.c),
+	},
+};
+
+static struct pll_shared_clk pll1_clk = {
+	.id = PLL_1,
+	.mode_reg = PLLn_MODE(1),
+	.c = {
+		.ops = &clk_pll_ops,
+		.dbg_name = "pll1_clk",
+		CLK_INIT(pll1_clk.c),
+	},
+};
+
+static struct pll_shared_clk pll2_clk = {
+	.id = PLL_2,
+	.mode_reg = PLLn_MODE(2),
+	.c = {
+		.ops = &clk_pll_ops,
+		.dbg_name = "pll2_clk",
+		CLK_INIT(pll2_clk.c),
+	},
+};
+
+static struct pll_shared_clk pll4_clk = {
+	.id = PLL_4,
+	.mode_reg = PLL4_MODE,
+	.c = {
+		.ops = &clk_pll_ops,
+		.dbg_name = "pll4_clk",
+		CLK_INIT(pll4_clk.c),
+	},
+};
+
 static struct pcom_clk dsi_byte_clk = {
 	.id = P_DSI_BYTE_CLK,
 	.c = {
@@ -251,14 +298,20 @@
 	CLK_LOOKUP("core_clk",		ebi_usb_clk.c,	"msm_otg"),
 	CLK_LOOKUP("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL),
 	CLK_LOOKUP("mem_clk",		ebi_adm_clk.c,	"msm_dmov"),
+
+	CLK_LOOKUP("pll0_clk",		pll0_clk.c,	"acpu"),
+	CLK_LOOKUP("pll1_clk",		pll1_clk.c,	"acpu"),
+	CLK_LOOKUP("pll2_clk",		pll2_clk.c,	"acpu"),
 };
 
 struct clock_init_data msm7x27_clock_init_data __initdata = {
 	.table = msm_clocks_7x27,
 	.size = ARRAY_SIZE(msm_clocks_7x27),
+	.init = msm_shared_pll_control_init,
 };
 
-static struct clk_lookup msm_clocks_7x27a[] = {
+/* Clock table for common clocks between 7627a and 7625a */
+static struct clk_lookup msm_cmn_clk_7625a_7627a[] __initdata = {
 	CLK_LOOKUP("core_clk",		adm_clk.c,	"msm_dmov"),
 	CLK_LOOKUP("adsp_clk",		adsp_clk.c,	NULL),
 	CLK_LOOKUP("ahb_m_clk",		ahb_m_clk.c,	NULL),
@@ -340,11 +393,41 @@
 	CLK_LOOKUP("ebi1_mddi_clk",	ebi_mddi_clk.c,	NULL),
 	CLK_LOOKUP("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL),
 	CLK_LOOKUP("mem_clk",		ebi_adm_clk.c,	"msm_dmov"),
+
+	CLK_LOOKUP("pll0_clk",		pll0_clk.c,	"acpu"),
+	CLK_LOOKUP("pll1_clk",		pll1_clk.c,	"acpu"),
+	CLK_LOOKUP("pll2_clk",		pll2_clk.c,	"acpu"),
+
 };
 
+/* PLL 4 clock is available for 7627a target. */
+static struct clk_lookup msm_clk_7627a[] __initdata = {
+	CLK_LOOKUP("pll4_clk",		pll4_clk.c,	"acpu"),
+};
+
+static struct clk_lookup msm_clk_7627a_7625a[ARRAY_SIZE(msm_cmn_clk_7625a_7627a)
+					+ ARRAY_SIZE(msm_clk_7627a)];
+
+static void __init msm7627a_clock_init(void)
+{
+	int size = ARRAY_SIZE(msm_cmn_clk_7625a_7627a);
+
+	/* Intialize shared PLL control structure */
+	msm_shared_pll_control_init();
+
+	memcpy(&msm_clk_7627a_7625a, &msm_cmn_clk_7625a_7627a,
+					sizeof(msm_cmn_clk_7625a_7627a));
+	if (!cpu_is_msm7x25a()) {
+		memcpy(&msm_clk_7627a_7625a[size],
+				&msm_clk_7627a, sizeof(msm_clk_7627a));
+		size += ARRAY_SIZE(msm_clk_7627a);
+	}
+	msm7x27a_clock_init_data.size = size;
+}
+
 struct clock_init_data msm7x27a_clock_init_data __initdata = {
-	.table = msm_clocks_7x27a,
-	.size = ARRAY_SIZE(msm_clocks_7x27a),
+	.table = msm_clk_7627a_7625a,
+	.init = msm7627a_clock_init,
 };
 
 static struct clk_lookup msm_clocks_8x50[] = {
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
new file mode 100644
index 0000000..f6b2b45
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/remote_spinlock.h>
+
+#include <mach/socinfo.h>
+#include <mach/msm_iomap.h>
+
+#include "clock.h"
+#include "clock-pll.h"
+#include "smd_private.h"
+
+struct pll_rate {
+	unsigned int lvalue;
+	unsigned long rate;
+};
+
+static struct pll_rate pll_l_rate[] = {
+	{10, 196000000},
+	{12, 245760000},
+	{30, 589820000},
+	{38, 737280000},
+	{41, 800000000},
+	{50, 960000000},
+	{52, 1008000000},
+	{62, 1200000000},
+	{0, 0},
+};
+
+#define PLL_BASE	7
+
+struct shared_pll_control {
+	uint32_t	version;
+	struct {
+		/*
+		 * Denotes if the PLL is ON. Technically, this can be read
+		 * directly from the PLL registers, but this feild is here,
+		 * so let's use it.
+		 */
+		uint32_t	on;
+		/*
+		 * One bit for each processor core. The application processor
+		 * is allocated bit position 1. All other bits should be
+		 * considered as votes from other processors.
+		 */
+		uint32_t	votes;
+	} pll[PLL_BASE + PLL_END];
+};
+
+static remote_spinlock_t pll_lock;
+static struct shared_pll_control *pll_control;
+
+void __init msm_shared_pll_control_init(void)
+{
+#define PLL_REMOTE_SPINLOCK_ID "S:7"
+	unsigned smem_size;
+
+	remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
+
+	pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
+	if (!pll_control) {
+		pr_err("Can't find shared PLL control data structure!\n");
+		BUG();
+	/*
+	 * There might be more PLLs than what the application processor knows
+	 * about. But the index used for each PLL is guaranteed to remain the
+	 * same.
+	 */
+	} else if (smem_size < sizeof(struct shared_pll_control)) {
+			pr_err("Shared PLL control data"
+					 "structure too small!\n");
+			BUG();
+	} else if (pll_control->version != 0xCCEE0001) {
+			pr_err("Shared PLL control version mismatch!\n");
+			BUG();
+	} else {
+		pr_info("Shared PLL control available.\n");
+		return;
+	}
+
+}
+
+static void pll_enable(void __iomem *addr, unsigned on)
+{
+	if (on) {
+		writel_relaxed(2, addr);
+		mb();
+		udelay(5);
+		writel_relaxed(6, addr);
+		mb();
+		udelay(50);
+		writel_relaxed(7, addr);
+	} else {
+		writel_relaxed(0, addr);
+	}
+}
+
+static int pll_clk_enable(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+	unsigned int pll_id = pll->id;
+
+	remote_spin_lock(&pll_lock);
+
+	pll_control->pll[PLL_BASE + pll_id].votes |= BIT(1);
+	if (!pll_control->pll[PLL_BASE + pll_id].on) {
+		pll_enable(pll->mode_reg, 1);
+		pll_control->pll[PLL_BASE + pll_id].on = 1;
+	}
+
+	remote_spin_unlock(&pll_lock);
+	return 0;
+}
+
+static void pll_clk_disable(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+	unsigned int pll_id = pll->id;
+
+	remote_spin_lock(&pll_lock);
+
+	pll_control->pll[PLL_BASE + pll_id].votes &= ~BIT(1);
+	if (pll_control->pll[PLL_BASE + pll_id].on
+	    && !pll_control->pll[PLL_BASE + pll_id].votes) {
+		pll_enable(pll->mode_reg, 0);
+		pll_control->pll[PLL_BASE + pll_id].on = 0;
+	}
+
+	remote_spin_unlock(&pll_lock);
+}
+
+static int pll_clk_is_enabled(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+
+	return readl_relaxed(pll->mode_reg) & BIT(0);
+}
+
+static bool pll_clk_is_local(struct clk *clk)
+{
+	return true;
+}
+
+static int pll_clk_handoff(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+	unsigned int pll_lval;
+	struct pll_rate *l;
+
+	/*
+	 * Wait for the PLLs to be initialized and then read their frequency.
+	 */
+	do {
+		pll_lval = readl_relaxed(pll->mode_reg + 4) & 0x3ff;
+		cpu_relax();
+		udelay(50);
+	} while (pll_lval == 0);
+
+	/* Convert PLL L values to PLL Output rate */
+	for (l = pll_l_rate; l->rate != 0; l++) {
+		if (l->lvalue == pll_lval) {
+			clk->rate = l->rate;
+			break;
+		}
+	}
+
+	if (!clk->rate) {
+		pr_crit("Unknown PLL's L value!\n");
+		BUG();
+	}
+
+	return 0;
+}
+
+struct clk_ops clk_pll_ops = {
+	.enable = pll_clk_enable,
+	.disable = pll_clk_disable,
+	.handoff = pll_clk_handoff,
+	.is_local = pll_clk_is_local,
+	.is_enabled = pll_clk_is_enabled,
+};
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
new file mode 100644
index 0000000..ae0ca17
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/**
+ * enum - For PLL IDs
+ */
+enum {
+	PLL_TCXO	= -1,
+	PLL_0	= 0,
+	PLL_1,
+	PLL_2,
+	PLL_3,
+	PLL_4,
+	PLL_END,
+};
+
+/**
+ * struct pll_shared_clk -  PLL shared with other processors without
+ * any HW voting
+ * @id: PLL ID
+ * @mode_reg: enable register
+ * @parent: clock source
+ * @c: clk
+ */
+struct pll_shared_clk {
+	unsigned int id;
+	void __iomem *const mode_reg;
+	struct clk c;
+};
+
+extern struct clk_ops clk_pll_ops;
+
+static inline struct pll_shared_clk *to_pll_shared_clk(struct clk *clk)
+{
+	return container_of(clk, struct pll_shared_clk, c);
+}
+
+/**
+ * msm_shared_pll_control_init() - Initialize shared pll control structure
+ */
+void msm_shared_pll_control_init(void);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index ca85a0a..657751b 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -23,11 +23,13 @@
 #include <mach/usbdiag.h>
 #include <mach/msm_sps.h>
 #include <mach/dma.h>
+#include <mach/msm_dsps.h>
 #include <sound/msm-dai-q6.h>
 #include <sound/apr_audio.h>
 #include <mach/msm_bus_board.h>
 #include <mach/rpm.h>
 #include <mach/mdm2.h>
+#include <mach/msm_smd.h>
 #include <linux/ion.h>
 #include "clock.h"
 #include "devices.h"
@@ -72,6 +74,11 @@
 #define MSM_HSUSB3_PHYS		0x12520000
 #define MSM_HSUSB3_SIZE		SZ_4K
 
+/* Address of HS USB4 */
+#define MSM_HSUSB4_PHYS		0x12530000
+#define MSM_HSUSB4_SIZE		SZ_4K
+
+
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
 	.pet_time = 10000,
 	.bark_time = 11000,
@@ -678,6 +685,30 @@
 	},
 };
 
+static struct resource resources_ehci_host4[] = {
+{
+		.start  = MSM_HSUSB4_PHYS,
+		.end    = MSM_HSUSB4_PHYS + MSM_HSUSB4_SIZE - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = USB4_HS_IRQ,
+		.end    = USB4_HS_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device apq8064_device_ehci_host4 = {
+	.name           = "msm_ehci_host",
+	.id             = 1,
+	.num_resources  = ARRAY_SIZE(resources_ehci_host4),
+	.resource       = resources_ehci_host4,
+	.dev            = {
+		.dma_mask               = &dma_mask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+};
+
 /* MSM Video core device */
 #ifdef CONFIG_MSM_BUS_SCALING
 static struct msm_bus_vectors vidc_init_vectors[] = {
@@ -1217,9 +1248,157 @@
 	.dev.platform_data = &msm_sps_pdata,
 };
 
+static struct resource smd_resource[] = {
+	{
+		.name   = "a9_m2a_0",
+		.start  = INT_A9_M2A_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "a9_m2a_5",
+		.start  = INT_A9_M2A_5,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "adsp_a11",
+		.start  = INT_ADSP_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "adsp_a11_smsm",
+		.start  = INT_ADSP_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "dsps_a11",
+		.start  = INT_DSPS_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "dsps_a11_smsm",
+		.start  = INT_DSPS_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "wcnss_a11",
+		.start  = INT_WCNSS_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "wcnss_a11_smsm",
+		.start  = INT_WCNSS_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+	{
+		.irq_config_id = SMD_MODEM,
+		.subsys_name = "gss",
+		.edge = SMD_APPS_MODEM,
+
+		.smd_int.irq_name = "a9_m2a_0",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 3,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "a9_m2a_5",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 4,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_Q6,
+		.subsys_name = "q6",
+		.edge = SMD_APPS_QDSP,
+
+		.smd_int.irq_name = "adsp_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 15,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "adsp_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 14,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_DSPS,
+		.subsys_name = "dsps",
+		.edge = SMD_APPS_DSPS,
+
+		.smd_int.irq_name = "dsps_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1,
+		.smd_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+		.smd_int.out_offset = 0x4080,
+
+		.smsm_int.irq_name = "dsps_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1,
+		.smsm_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+		.smsm_int.out_offset = 0x4094,
+	},
+	{
+		.irq_config_id = SMD_WCNSS,
+		.subsys_name = "wcnss",
+		.edge = SMD_APPS_WCNSS,
+
+		.smd_int.irq_name = "wcnss_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 25,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "wcnss_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 23,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+};
+
+static struct smd_platform smd_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_config_list),
+	.smd_ss_configs = smd_config_list,
+};
+
 struct platform_device msm_device_smd_apq8064 = {
 	.name		= "msm_smd",
 	.id		= -1,
+	.resource = smd_resource,
+	.num_resources = ARRAY_SIZE(smd_resource),
+	.dev = {
+		.platform_data = &smd_platform_data,
+	},
 };
 
 #ifdef CONFIG_HW_RANDOM_MSM
@@ -1752,6 +1931,53 @@
 	},
 };
 
+/* Sensors DSPS platform data */
+
+#define PPSS_REG_PHYS_BASE	0x12080000
+
+static struct dsps_clk_info dsps_clks[] = {};
+static struct dsps_regulator_info dsps_regs[] = {};
+
+/*
+ * Note: GPIOs field is	intialized in run-time at the function
+ * apq8064_init_dsps().
+ */
+
+struct msm_dsps_platform_data msm_dsps_pdata_8064 = {
+	.clks = dsps_clks,
+	.clks_num = ARRAY_SIZE(dsps_clks),
+	.gpios = NULL,
+	.gpios_num = 0,
+	.regs = dsps_regs,
+	.regs_num = ARRAY_SIZE(dsps_regs),
+	.dsps_pwr_ctl_en = 1,
+	.signature = DSPS_SIGNATURE,
+};
+
+static struct resource msm_dsps_resources[] = {
+	{
+		.start = PPSS_REG_PHYS_BASE,
+		.end   = PPSS_REG_PHYS_BASE + SZ_8K - 1,
+		.name  = "ppss_reg",
+		.flags = IORESOURCE_MEM,
+	},
+
+	{
+		.start = PPSS_WDOG_TIMER_IRQ,
+		.end   = PPSS_WDOG_TIMER_IRQ,
+		.name  = "ppss_wdog",
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_dsps_device_8064 = {
+	.name          = "msm_dsps",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(msm_dsps_resources),
+	.resource      = msm_dsps_resources,
+	.dev.platform_data = &msm_dsps_pdata_8064,
+};
+
 #ifdef CONFIG_MSM_MPM
 static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS] __initdata = {
 	[1] = MSM_GPIO_TO_INT(26),
@@ -1891,4 +2117,3 @@
 	.num_resources	= ARRAY_SIZE(mdm_resources),
 	.resource	= mdm_resources,
 };
-
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 19a8db7..718cfb1 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -30,8 +30,10 @@
 #include <mach/rpm.h>
 #include <mach/msm_bus_board.h>
 #include <mach/msm_memtypes.h>
+#include <mach/msm_smd.h>
 #include <sound/msm-dai-q6.h>
 #include <sound/apr_audio.h>
+#include <mach/msm_tsif.h>
 #include "clock.h"
 #include "devices.h"
 #include "devices-msm8x60.h"
@@ -950,9 +952,158 @@
 	.id = -1,
 };
 
+static struct resource smd_resource[] = {
+	{
+		.name   = "a9_m2a_0",
+		.start  = INT_A9_M2A_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "a9_m2a_5",
+		.start  = INT_A9_M2A_5,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "adsp_a11",
+		.start  = INT_ADSP_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "adsp_a11_smsm",
+		.start  = INT_ADSP_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "dsps_a11",
+		.start  = INT_DSPS_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "dsps_a11_smsm",
+		.start  = INT_DSPS_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "wcnss_a11",
+		.start  = INT_WCNSS_A11,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "wcnss_a11_smsm",
+		.start  = INT_WCNSS_A11_SMSM,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+	{
+		.irq_config_id = SMD_MODEM,
+		.subsys_name = "modem",
+		.edge = SMD_APPS_MODEM,
+
+		.smd_int.irq_name = "a9_m2a_0",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 3,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "a9_m2a_5",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 4,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_Q6,
+		.subsys_name = "q6",
+		.edge = SMD_APPS_QDSP,
+
+		.smd_int.irq_name = "adsp_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 15,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "adsp_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 14,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+	{
+		.irq_config_id = SMD_DSPS,
+		.subsys_name = "dsps",
+		.edge = SMD_APPS_DSPS,
+
+		.smd_int.irq_name = "dsps_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1,
+		.smd_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+		.smd_int.out_offset = 0x4080,
+
+		.smsm_int.irq_name = "dsps_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1,
+		.smsm_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+		.smsm_int.out_offset = 0x4094,
+	},
+	{
+		.irq_config_id = SMD_WCNSS,
+		.subsys_name = "wcnss",
+		.edge = SMD_APPS_WCNSS,
+
+		.smd_int.irq_name = "wcnss_a11",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+		.smd_int.out_bit_pos =  1 << 25,
+		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smd_int.out_offset = 0x8,
+
+		.smsm_int.irq_name = "wcnss_a11_smsm",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smd_smsm",
+		.smsm_int.dev_id = 0,
+		.smsm_int.out_bit_pos =  1 << 23,
+		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+		.smsm_int.out_offset = 0x8,
+	},
+};
+
+static struct smd_platform smd_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_config_list),
+	.smd_ss_configs = smd_config_list,
+};
+
+
 struct platform_device msm_device_smd = {
 	.name		= "msm_smd",
 	.id		= -1,
+	.resource = smd_resource,
+	.num_resources = ARRAY_SIZE(smd_resource),
+	.dev = {
+		.platform_data = &smd_platform_data,
+	},
 };
 
 struct platform_device msm_device_bam_dmux = {
@@ -1355,6 +1506,111 @@
 };
 #endif
 
+#define MSM_TSIF0_PHYS       (0x18200000)
+#define MSM_TSIF1_PHYS       (0x18201000)
+#define MSM_TSIF_SIZE        (0x200)
+
+#define TSIF_0_CLK       GPIO_CFG(75, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_EN        GPIO_CFG(76, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_DATA      GPIO_CFG(77, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_SYNC      GPIO_CFG(82, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_CLK       GPIO_CFG(79, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_EN        GPIO_CFG(80, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_DATA      GPIO_CFG(81, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_SYNC      GPIO_CFG(78, 1, GPIO_CFG_INPUT, \
+	GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static const struct msm_gpio tsif0_gpios[] = {
+	{ .gpio_cfg = TSIF_0_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_0_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_0_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_0_SYNC, .label =  "tsif_sync", },
+};
+
+static const struct msm_gpio tsif1_gpios[] = {
+	{ .gpio_cfg = TSIF_1_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_1_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_1_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_1_SYNC, .label =  "tsif_sync", },
+};
+
+struct msm_tsif_platform_data tsif1_platform_data = {
+	.num_gpios = ARRAY_SIZE(tsif1_gpios),
+	.gpios = tsif1_gpios,
+	.tsif_pclk = "tsif_pclk",
+	.tsif_ref_clk = "tsif_ref_clk",
+};
+
+struct resource tsif1_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF2_IRQ,
+		.end   = TSIF2_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF1_PHYS,
+		.end   = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+struct msm_tsif_platform_data tsif0_platform_data = {
+	.num_gpios = ARRAY_SIZE(tsif0_gpios),
+	.gpios = tsif0_gpios,
+	.tsif_pclk = "tsif_pclk",
+	.tsif_ref_clk = "tsif_ref_clk",
+};
+struct resource tsif0_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF1_IRQ,
+		.end   = TSIF1_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF0_PHYS,
+		.end   = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_DMA,
+		.start = DMOV_TSIF_CHAN,
+		.end   = DMOV_TSIF_CRCI,
+	},
+};
+
+struct platform_device msm_device_tsif[2] = {
+	{
+		.name          = "msm_tsif",
+		.id            = 0,
+		.num_resources = ARRAY_SIZE(tsif0_resources),
+		.resource      = tsif0_resources,
+		.dev = {
+			.platform_data = &tsif0_platform_data
+		},
+	},
+	{
+		.name          = "msm_tsif",
+		.id            = 1,
+		.num_resources = ARRAY_SIZE(tsif1_resources),
+		.resource      = tsif1_resources,
+		.dev = {
+			.platform_data = &tsif1_platform_data
+		},
+	}
+};
+
 static struct resource resources_ssbi_pmic[] = {
 	{
 		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index cc1e7c5..c19c133 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -33,6 +33,7 @@
 #include "devices-msm7x2xa.h"
 #include "footswitch.h"
 #include "acpuclock.h"
+#include "spm.h"
 
 /* Address of GSBI blocks */
 #define MSM_GSBI0_PHYS		0xA1200000
@@ -210,6 +211,63 @@
 	.id	= -1,
 };
 
+static struct resource smd_8625_resource[] = {
+	{
+		.name   = "a9_m2a_0",
+		.start  = MSM8625_INT_A9_M2A_0,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.name   = "a9_m2a_5",
+		.start  = MSM8625_INT_A9_M2A_5,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct smd_subsystem_config smd_8625_config_list[] = {
+	{
+		.irq_config_id = SMD_MODEM,
+		.subsys_name = "modem",
+		.edge = SMD_APPS_MODEM,
+
+		.smd_int.irq_name = "a9_m2a_0",
+		.smd_int.flags = IRQF_TRIGGER_RISING,
+		.smd_int.irq_id = -1,
+		.smd_int.device_name = "smd_dev",
+		.smd_int.dev_id = 0,
+
+		.smd_int.out_bit_pos =  1,
+		.smd_int.out_base = (void __iomem *)MSM_CSR_BASE,
+		.smd_int.out_offset = 0x400 + (0) * 4,
+
+		.smsm_int.irq_name = "a9_m2a_5",
+		.smsm_int.flags = IRQF_TRIGGER_RISING,
+		.smsm_int.irq_id = -1,
+		.smsm_int.device_name = "smsm_dev",
+		.smsm_int.dev_id = 0,
+
+		.smsm_int.out_bit_pos =  1,
+		.smsm_int.out_base = (void __iomem *)MSM_CSR_BASE,
+		.smsm_int.out_offset = 0x400 + (5) * 4,
+
+	}
+};
+
+static struct smd_platform smd_8625_platform_data = {
+	.num_ss_configs = ARRAY_SIZE(smd_8625_config_list),
+	.smd_ss_configs = smd_8625_config_list,
+};
+
+struct platform_device msm8625_device_smd = {
+	.name	= "msm_smd",
+	.id	= -1,
+	.resource = smd_8625_resource,
+	.num_resources = ARRAY_SIZE(smd_8625_resource),
+	.dev = {
+		.platform_data = &smd_8625_platform_data,
+	}
+};
+
 static struct resource resources_adsp[] = {
 	{
 		.start  = INT_ADSP_A9_A11,
@@ -584,6 +642,55 @@
 
 #endif
 
+/* Command sequence for simple WFI */
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+	0x00, 0x40, 0x40, 0x03,
+	0x00, 0x40, 0x40, 0x0f,
+};
+
+/* Command sequence for GDFS, this won't send any interrupt to the modem */
+static uint8_t spm_pc_without_modem[] __initdata = {
+	0x20, 0x00, 0x30, 0x10,
+	0x40, 0x40, 0x03, 0x10,
+	0x00, 0x30, 0x2E, 0x40,
+	0x40, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+	[0] = {
+		.mode = MSM_SPM_MODE_CLOCK_GATING,
+		.notify_rpm = false,
+		.cmd = spm_wfi_cmd_sequence,
+	},
+	[1] = {
+		.mode = MSM_SPM_MODE_POWER_COLLAPSE,
+		.notify_rpm = false,
+		.cmd = spm_pc_without_modem,
+	},
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+	[0] = {
+		.reg_base_addr = MSM_SAW0_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x0,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+	[1] = {
+		.reg_base_addr = MSM_SAW1_BASE,
+		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x0,
+		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+		.num_modes = ARRAY_SIZE(msm_spm_seq_list),
+		.modes = msm_spm_seq_list,
+	},
+};
+
+void __init msm8x25_spm_device_init(void)
+{
+	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+}
+
 #define MDP_BASE		0xAA200000
 #define MIPI_DSI_HW_BASE	0xA1100000
 
@@ -690,7 +797,9 @@
 		kgsl_3d0_pdata.pwrlevel[0].bus_freq = 160000000;
 		kgsl_3d0_pdata.pwrlevel[1].gpu_freq = 96000000;
 		kgsl_3d0_pdata.pwrlevel[1].bus_freq = 0;
-	}
+	} else if (cpu_is_msm8625())
+		/* msm8625 has an idle_timout of 50 hours */
+		kgsl_3d0_pdata.idle_timeout = 18000000;
 }
 
 static void __init msm_register_device(struct platform_device *pdev, void *data)
@@ -917,7 +1026,7 @@
 };
 
 /* Use GSBI0 QUP for /dev/i2c-0 */
-struct platform_device msm8625_device_qup_i2c_gsbi0 = {
+struct platform_device msm8625_gsbi0_qup_i2c_device = {
 	.name		= "qup_i2c",
 	.id		= MSM_GSBI0_QUP_I2C_BUS_ID,
 	.num_resources	= ARRAY_SIZE(gsbi0_msm8625_qup_resources),
@@ -946,7 +1055,7 @@
 };
 
 /* Use GSBI1 QUP for /dev/i2c-1 */
-struct platform_device msm8625_device_qup_i2c_gsbi1 = {
+struct platform_device msm8625_gsbi1_qup_i2c_device = {
 	.name		= "qup_i2c",
 	.id		= MSM_GSBI1_QUP_I2C_BUS_ID,
 	.num_resources	= ARRAY_SIZE(gsbi1_qup_i2c_resources),
@@ -1431,7 +1540,7 @@
 	}
 
 	msm_clock_init(&msm7x27a_clock_init_data);
-	if (cpu_is_msm7x27aa())
+	if (cpu_is_msm7x27aa() || cpu_is_msm8625())
 		acpuclk_init(&acpuclk_7x27aa_soc_data);
 	else
 		acpuclk_init(&acpuclk_7x27a_soc_data);
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index c2383c6..3c81ccf 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -30,4 +30,5 @@
 void __init msm8625_init_irq(void);
 void __init msm8625_map_io(void);
 int  ar600x_wlan_power(bool on);
+void __init msm8x25_spm_device_init(void);
 #endif
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index e9b94f6..89c8aaf 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -74,6 +74,20 @@
 	.resource       = msm_ebi1_thermal_resources
 };
 
+static struct resource resources_adsp[] = {
+{
+	.start  = INT_ADSP_A9_A11,
+	.end    = INT_ADSP_A9_A11,
+	.flags  = IORESOURCE_IRQ,
+},
+};
+
+struct platform_device msm_adsp_device = {
+	.name           = "msm_adsp",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(resources_adsp),
+	.resource       = resources_adsp,
+};
 
 static struct resource resources_uart1[] = {
 	{
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index ed48659..4371c23 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -112,6 +112,7 @@
 extern struct platform_device apq8064_device_hsusb_host;
 extern struct platform_device apq8064_device_hsic_host;
 extern struct platform_device apq8064_device_ehci_host3;
+extern struct platform_device apq8064_device_ehci_host4;
 
 extern struct platform_device msm_device_i2c;
 
@@ -128,8 +129,8 @@
 extern struct platform_device msm_gsbi9_qup_i2c_device;
 extern struct platform_device msm_gsbi12_qup_i2c_device;
 
-extern struct platform_device msm8625_device_qup_i2c_gsbi0;
-extern struct platform_device msm8625_device_qup_i2c_gsbi1;
+extern struct platform_device msm8625_gsbi0_qup_i2c_device;
+extern struct platform_device msm8625_gsbi1_qup_i2c_device;
 extern struct platform_device msm8625_device_uart_dm1;
 extern struct platform_device msm8625_device_uart_dm2;
 extern struct platform_device msm8625_device_sdc1;
@@ -149,6 +150,7 @@
 extern struct platform_device msm_device_bam_dmux;
 extern struct platform_device msm_device_smd;
 extern struct platform_device msm_device_smd_apq8064;
+extern struct platform_device msm8625_device_smd;
 extern struct platform_device msm_device_dmov;
 extern struct platform_device msm8960_device_dmov;
 extern struct platform_device apq8064_device_dmov;
@@ -322,3 +324,5 @@
 extern struct platform_device msm_bus_8064_cpss_fpb;
 
 extern struct platform_device mdm_8064_device;
+
+extern struct platform_device msm_dsps_device_8064;
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 830e36b..6311b3c 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009,2011 Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2007-2009,2012 Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,15 @@
 {
 	/* empty */
 }
+static inline void msm_pm_boot_entry(void)
+{
+	/* empty */
+}
+static inline void msm_pm_write_boot_vector(unsigned int cpu,
+						unsigned long address)
+{
+	/* empty */
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 96b0083..a87a759 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -367,6 +367,7 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	struct msm_bus_scale_pdata *bus_scale_table;
 #endif
+	int (*lvds_pixel_remap)(void);
 };
 
 struct tvenc_platform_data {
@@ -417,10 +418,13 @@
 	int *gpio;
 };
 
+#define PANEL_NAME_MAX_LEN 50
 struct msm_fb_platform_data {
 	int (*detect_client)(const char *name);
 	int mddi_prescan;
 	int (*allow_set_offset)(void);
+	char prim_panel_name[PANEL_NAME_MAX_LEN];
+	char ext_panel_name[PANEL_NAME_MAX_LEN];
 };
 
 struct msm_hdmi_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/diag_bridge.h b/arch/arm/mach-msm/include/mach/diag_bridge.h
index a39ed25..b06f020 100644
--- a/arch/arm/mach-msm/include/mach/diag_bridge.h
+++ b/arch/arm/mach-msm/include/mach/diag_bridge.h
@@ -19,6 +19,8 @@
 			int buf_size, int actual);
 	void (*write_complete_cb)(void *ctxt, char *buf,
 			int buf_size, int actual);
+	int (*suspend)(void *ctxt);
+	void (*resume)(void *ctxt);
 };
 
 #if defined(CONFIG_USB_QCOM_DIAG_BRIDGE) \
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 3cb79b7..d170f5f 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -177,6 +177,9 @@
 #define DMOV_CE_OUT_CHAN       1
 #define DMOV_CE_OUT_CRCI       3
 
+#define DMOV_TSIF_CHAN         2
+#define DMOV_TSIF_CRCI         11
+
 #define DMOV_HSUART_GSBI6_TX_CHAN	7
 #define DMOV_HSUART_GSBI6_TX_CRCI	6
 
diff --git a/arch/arm/mach-msm/include/mach/irqs-copper.h b/arch/arm/mach-msm/include/mach/irqs-copper.h
index 821eaeb..c961804 100644
--- a/arch/arm/mach-msm/include/mach/irqs-copper.h
+++ b/arch/arm/mach-msm/include/mach/irqs-copper.h
@@ -36,7 +36,8 @@
 
 #define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
 #define NR_GPIO_IRQS 156
-#define NR_BOARD_IRQS 100
+#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
+#define NR_BOARD_IRQS NR_QPNP_IRQS
 #define NR_TLMM_MSM_DIR_CONN_IRQ 8
 #define NR_MSM_GPIOS NR_GPIO_IRQS
 
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-copper.h b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
index 6311dbe..b560276 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
@@ -34,7 +34,7 @@
 #define COPPER_APCS_GCC_PHYS	0xF9011000
 #define COPPER_APCS_GCC_SIZE	SZ_4K
 
-#define COPPER_TLMM_PHYS	0xFD400000
+#define COPPER_TLMM_PHYS	0xFD510000
 #define COPPER_TLMM_SIZE	SZ_16K
 
 #ifdef CONFIG_DEBUG_MSMCOPPER_UART
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 4be6d9ea..8d3e640 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -236,6 +236,22 @@
  */
 int smd_write_end(smd_channel_t *ch);
 
+/*
+ * Returns a pointer to the subsystem name or NULL if no
+ * subsystem name is available.
+ *
+ * @type - Edge definition
+ */
+const char *smd_edge_to_subsystem(uint32_t type);
+
+/*
+ * Returns a pointer to the subsystem name given the
+ * remote processor ID.
+ *
+ * @pid     Remote processor ID
+ * @returns Pointer to subsystem name or NULL if not found
+ */
+const char *smd_pid_to_subsystem(uint32_t pid);
 #else
 
 static inline int smd_open(const char *name, smd_channel_t **ch, void *priv,
@@ -337,6 +353,16 @@
 {
 	return -ENODEV;
 }
+
+static inline const char *smd_edge_to_subsystem(uint32_t type)
+{
+	return NULL;
+}
+
+static inline const char *smd_pid_to_subsystem(uint32_t pid)
+{
+	return NULL;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h
index 71f2bd9..20c6fc4 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -96,6 +96,8 @@
 
 int msm_reset_all_device(void);
 
+int reset_device(void);
+
 int msm_clear_all_session(void);
 
 struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id);
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 6aa944f..af4691a 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,6 +22,7 @@
 #define SCM_SVC_FUSE			0x8
 #define SCM_SVC_PWR			0x9
 #define SCM_SVC_CP			0xC
+#define SCM_SVC_DCVS			0xD
 #define SCM_SVC_TZSCHEDULER		0xFC
 
 #ifdef CONFIG_MSM_SCM
@@ -30,6 +31,8 @@
 
 extern s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1);
 extern s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2);
+extern s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3,
+		u32 arg4, u32 *ret1, u32 *ret2);
 
 #define SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF))
 
@@ -54,6 +57,12 @@
 	return 0;
 }
 
+static inline s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2,
+		u32 arg3, u32 arg4, u32 *ret1, u32 *ret2)
+{
+	return 0;
+}
+
 static inline u32 scm_get_version(void)
 {
 	return 0;
diff --git a/arch/arm/mach-msm/include/mach/timex.h b/arch/arm/mach-msm/include/mach/timex.h
index 61f1996..ca7c4c7 100644
--- a/arch/arm/mach-msm/include/mach/timex.h
+++ b/arch/arm/mach-msm/include/mach/timex.h
@@ -18,8 +18,6 @@
 
 #define CLOCK_TICK_RATE		1000000
 
-#ifdef CONFIG_MSM_SMP
 #define ARCH_HAS_READ_CURRENT_TIMER
-#endif
 
 #endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index c8bf194..a643c68 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -420,6 +420,7 @@
 	MSM_CHIP_DEVICE(SAW0, MSM8625),
 	MSM_CHIP_DEVICE(SAW1, MSM8625),
 	MSM_CHIP_DEVICE(AD5, MSM7XXX),
+	MSM_CHIP_DEVICE(MDC, MSM7XXX),
 #if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
 	defined(CONFIG_DEBUG_MSM_UART3)
 	MSM_CHIP_DEVICE(DEBUG_UART, MSM7XXX),
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 7445a61..04c29cc 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -242,6 +242,8 @@
 
 static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
 {
+	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
+	gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
 	mdm_drv->ops->power_on_mdm_cb(mdm_drv);
 	mdm_drv->boot_type = CHARM_NORMAL_BOOT;
 	complete(&mdm_needs_reload);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index feabe04..56aba3e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -9,6 +9,9 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_config.c b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
index 7d9d18f..28f3073 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_config.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -9,6 +9,9 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.c b/arch/arm/mach-msm/msm_bus/msm_bus_core.c
index 9fe05b7..4d73b03 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -9,6 +9,9 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 50afa81..e35130e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,22 +20,14 @@
 #include <mach/msm_bus_board.h>
 #include <mach/msm_bus.h>
 
-#if defined DEBUG
-
 #define MSM_BUS_DBG(msg, ...) \
-	printk(KERN_DEBUG "AXI: %s(): " msg, __func__, ## __VA_ARGS__)
-
-#else
-#define MSM_BUS_DBG(msg, ...) no_printk("AXI")
-#endif
-
+	pr_debug(msg, ## __VA_ARGS__)
 #define MSM_BUS_ERR(msg, ...) \
-	printk(KERN_ERR "AXI: %s(): " msg, __func__, ## __VA_ARGS__)
+	pr_err(msg, ## __VA_ARGS__)
 #define MSM_BUS_WARN(msg, ...) \
-	printk(KERN_WARNING "AXI: %s(): " msg, __func__, ## __VA_ARGS__)
+	pr_warn(msg, ## __VA_ARGS__)
 #define MSM_FAB_ERR(msg, ...) \
-	dev_err(&fabric->fabdev.dev, "AXI: %s(): " msg, __func__, ## \
-	__VA_ARGS__)
+	dev_err(&fabric->fabdev.dev, msg, ## __VA_ARGS__)
 
 enum msm_bus_dbg_op_type {
 	MSM_BUS_DBG_UNREGISTER = -2,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
index abd986b..e63df1b 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,6 +10,9 @@
  * GNU General Public License for more details.
  *
  */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 3b178b5..2c69914 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/device.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
index a8dc7c8..b13037e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,6 +11,8 @@
  *
  */
 
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/device.h>
@@ -342,7 +344,7 @@
 		fab_pdata->nmasters) + 1);
 	ret = memcmp(cd1->arb, cd2->arb, n);
 	if (ret) {
-		MSM_BUS_DBG("Commit Data arb[%d] not equal\n", i);
+		MSM_BUS_DBG("Commit Data arb[%d] not equal\n", n);
 		return ret;
 	}
 
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index 5bff832..28b5995 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -304,6 +304,9 @@
 static void init_watchdog_work(struct work_struct *work)
 {
 	u64 timeout = (bark_time * WDT_HZ)/1000;
+
+	configure_bark_dump();
+
 	__raw_writel(timeout, msm_tmr0_base + WDT0_BARK_TIME);
 	__raw_writel(timeout + 3*WDT_HZ, msm_tmr0_base + WDT0_BITE_TIME);
 
@@ -366,8 +369,6 @@
 	if (pdata->needs_expired_enable)
 		__raw_writel(0x1, MSM_CLK_CTL_BASE + 0x3820);
 
-	configure_bark_dump();
-
 	delay_time = msecs_to_jiffies(pdata->pet_time);
 	schedule_work_on(0, &init_dogwork_struct);
 	return 0;
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 74c64c1..f7d2bcb 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -237,13 +237,6 @@
 	unsigned long flags;
 	struct msm_xo_voter *xo_voter;
 
-	/*
-	 * TODO: Remove early return for 8064 once RPM XO voting support
-	 * is available.
-	 */
-	if (cpu_is_apq8064())
-		return NULL;
-
 	if (xo_id >= NUM_MSM_XO_IDS) {
 		ret = -EINVAL;
 		goto err;
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 1004e01..6d1a5f0 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -20,9 +20,11 @@
 #include <linux/mutex.h>
 #include <linux/memblock.h>
 #include <linux/slab.h>
+#include <linux/atomic.h>
 
 #include <asm/uaccess.h>
 #include <asm/setup.h>
+#include <mach/peripheral-loader.h>
 
 #include "peripheral-loader.h"
 
@@ -30,34 +32,35 @@
 	struct pil_desc *desc;
 	int count;
 	struct mutex lock;
-	struct list_head list;
+	struct device dev;
+	struct module *owner;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
 };
 
-static DEFINE_MUTEX(pil_list_lock);
-static LIST_HEAD(pil_list);
+#define to_pil_device(d) container_of(d, struct pil_device, dev)
 
-static struct pil_device *__find_peripheral(const char *str)
+struct bus_type pil_bus_type = {
+	.name		= "pil",
+};
+
+static int __find_peripheral(struct device *dev, void *data)
 {
-	struct pil_device *dev;
-
-	list_for_each_entry(dev, &pil_list, list)
-		if (!strcmp(dev->desc->name, str))
-			return dev;
-	return NULL;
+	struct pil_device *pdev = to_pil_device(dev);
+	return !strncmp(pdev->desc->name, data, INT_MAX);
 }
 
 static struct pil_device *find_peripheral(const char *str)
 {
-	struct pil_device *dev;
+	struct device *dev;
 
 	if (!str)
 		return NULL;
 
-	mutex_lock(&pil_list_lock);
-	dev = __find_peripheral(str);
-	mutex_unlock(&pil_list_lock);
-
-	return dev;
+	dev = bus_find_device(&pil_bus_type, NULL, (void *)str,
+			__find_peripheral);
+	return dev ? to_pil_device(dev) : NULL;
 }
 
 #define IOMAP_SIZE SZ_4M
@@ -71,24 +74,23 @@
 	const u8 *data;
 
 	if (memblock_is_region_memory(phdr->p_paddr, phdr->p_memsz)) {
-		dev_err(pil->desc->dev, "Kernel memory would be overwritten");
+		dev_err(&pil->dev, "Kernel memory would be overwritten");
 		return -EPERM;
 	}
 
 	if (phdr->p_filesz) {
 		snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d",
 				pil->desc->name, num);
-		ret = request_firmware(&fw, fw_name, pil->desc->dev);
+		ret = request_firmware(&fw, fw_name, &pil->dev);
 		if (ret) {
-			dev_err(pil->desc->dev, "Failed to locate blob %s\n",
+			dev_err(&pil->dev, "Failed to locate blob %s\n",
 					fw_name);
 			return ret;
 		}
 
 		if (fw->size != phdr->p_filesz) {
-			dev_err(pil->desc->dev,
-				"Blob size %u doesn't match %u\n", fw->size,
-				phdr->p_filesz);
+			dev_err(&pil->dev, "Blob size %u doesn't match %u\n",
+					fw->size, phdr->p_filesz);
 			ret = -EPERM;
 			goto release_fw;
 		}
@@ -105,7 +107,7 @@
 		size = min_t(size_t, IOMAP_SIZE, count);
 		buf = ioremap(paddr, size);
 		if (!buf) {
-			dev_err(pil->desc->dev, "Failed to map memory\n");
+			dev_err(&pil->dev, "Failed to map memory\n");
 			ret = -ENOMEM;
 			goto release_fw;
 		}
@@ -126,7 +128,7 @@
 		size = min_t(size_t, IOMAP_SIZE, count);
 		buf = ioremap(paddr, size);
 		if (!buf) {
-			dev_err(pil->desc->dev, "Failed to map memory\n");
+			dev_err(&pil->dev, "Failed to map memory\n");
 			ret = -ENOMEM;
 			goto release_fw;
 		}
@@ -140,7 +142,7 @@
 	ret = pil->desc->ops->verify_blob(pil->desc, phdr->p_paddr,
 					  phdr->p_memsz);
 	if (ret)
-		dev_err(pil->desc->dev, "Blob %u failed verification\n", num);
+		dev_err(&pil->dev, "Blob %u failed verification\n", num);
 
 release_fw:
 	release_firmware(fw);
@@ -163,40 +165,40 @@
 	const struct firmware *fw;
 
 	snprintf(fw_name, sizeof(fw_name), "%s.mdt", pil->desc->name);
-	ret = request_firmware(&fw, fw_name, pil->desc->dev);
+	ret = request_firmware(&fw, fw_name, &pil->dev);
 	if (ret) {
-		dev_err(pil->desc->dev, "Failed to locate %s\n", fw_name);
+		dev_err(&pil->dev, "Failed to locate %s\n", fw_name);
 		goto out;
 	}
 
 	if (fw->size < sizeof(*ehdr)) {
-		dev_err(pil->desc->dev, "Not big enough to be an elf header\n");
+		dev_err(&pil->dev, "Not big enough to be an elf header\n");
 		ret = -EIO;
 		goto release_fw;
 	}
 
 	ehdr = (struct elf32_hdr *)fw->data;
 	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(pil->desc->dev, "Not an elf header\n");
+		dev_err(&pil->dev, "Not an elf header\n");
 		ret = -EIO;
 		goto release_fw;
 	}
 
 	if (ehdr->e_phnum == 0) {
-		dev_err(pil->desc->dev, "No loadable segments\n");
+		dev_err(&pil->dev, "No loadable segments\n");
 		ret = -EIO;
 		goto release_fw;
 	}
 	if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
 	    sizeof(struct elf32_hdr) > fw->size) {
-		dev_err(pil->desc->dev, "Program headers not within mdt\n");
+		dev_err(&pil->dev, "Program headers not within mdt\n");
 		ret = -EIO;
 		goto release_fw;
 	}
 
 	ret = pil->desc->ops->init_image(pil->desc, fw->data, fw->size);
 	if (ret) {
-		dev_err(pil->desc->dev, "Invalid firmware metadata\n");
+		dev_err(&pil->dev, "Invalid firmware metadata\n");
 		goto release_fw;
 	}
 
@@ -207,7 +209,7 @@
 
 		ret = load_segment(phdr, i, pil);
 		if (ret) {
-			dev_err(pil->desc->dev, "Failed to load segment %d\n",
+			dev_err(&pil->dev, "Failed to load segment %d\n",
 					i);
 			goto release_fw;
 		}
@@ -215,10 +217,10 @@
 
 	ret = pil->desc->ops->auth_and_reset(pil->desc);
 	if (ret) {
-		dev_err(pil->desc->dev, "Failed to bring out of reset\n");
+		dev_err(&pil->dev, "Failed to bring out of reset\n");
 		goto release_fw;
 	}
-	dev_info(pil->desc->dev, "brought out of reset\n");
+	dev_info(&pil->dev, "brought %s out of reset\n", pil->desc->name);
 
 release_fw:
 	release_firmware(fw);
@@ -242,33 +244,41 @@
 	struct pil_device *pil_d;
 	void *retval;
 
+	if (!name)
+		return NULL;
+
 	pil = retval = find_peripheral(name);
 	if (!pil)
 		return ERR_PTR(-ENODEV);
+	if (!try_module_get(pil->owner)) {
+		put_device(&pil->dev);
+		return ERR_PTR(-ENODEV);
+	}
 
-	pil_d = find_peripheral(pil->desc->depends_on);
-	if (pil_d) {
-		void *p = pil_get(pil_d->desc->name);
-		if (IS_ERR(p))
-			return p;
+	pil_d = pil_get(pil->desc->depends_on);
+	if (IS_ERR(pil_d)) {
+		retval = pil_d;
+		goto err_depends;
 	}
 
 	mutex_lock(&pil->lock);
-	if (pil->count) {
-		pil->count++;
-		goto unlock;
+	if (!pil->count++) {
+		ret = load_image(pil);
+		if (ret) {
+			retval = ERR_PTR(ret);
+			goto err_load;
+		}
 	}
-
-	ret = load_image(pil);
-	if (ret) {
-		retval = ERR_PTR(ret);
-		goto unlock;
-	}
-
-	pil->count++;
-unlock:
 	mutex_unlock(&pil->lock);
+out:
 	return retval;
+err_load:
+	mutex_unlock(&pil->lock);
+	pil_put(pil_d);
+err_depends:
+	put_device(&pil->dev);
+	module_put(pil->owner);
+	goto out;
 }
 EXPORT_SYMBOL(pil_get);
 
@@ -281,22 +291,29 @@
  */
 void pil_put(void *peripheral_handle)
 {
-	struct pil_device *pil_d;
-	struct pil_device *pil = peripheral_handle;
-	if (!pil || IS_ERR(pil))
+	struct pil_device *pil_d, *pil = peripheral_handle;
+
+	if (IS_ERR_OR_NULL(pil))
 		return;
 
 	mutex_lock(&pil->lock);
-	WARN(!pil->count, "%s: Reference count mismatch\n", __func__);
-	if (pil->count)
-		pil->count--;
-	if (pil->count == 0)
+	if (WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
+		goto err_out;
+	if (!--pil->count)
 		pil->desc->ops->shutdown(pil->desc);
 	mutex_unlock(&pil->lock);
 
 	pil_d = find_peripheral(pil->desc->depends_on);
-	if (pil_d)
+	module_put(pil->owner);
+	if (pil_d) {
 		pil_put(pil_d);
+		put_device(&pil_d->dev);
+	}
+	put_device(&pil->dev);
+	return;
+err_out:
+	mutex_unlock(&pil->lock);
+	return;
 }
 EXPORT_SYMBOL(pil_put);
 
@@ -312,6 +329,7 @@
 	if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
 		pil->desc->ops->shutdown(pil->desc);
 	mutex_unlock(&pil->lock);
+	put_device(&pil->dev);
 }
 EXPORT_SYMBOL(pil_force_shutdown);
 
@@ -328,13 +346,14 @@
 	if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
 		ret = load_image(pil);
 	mutex_unlock(&pil->lock);
+	put_device(&pil->dev);
 
 	return ret;
 }
 EXPORT_SYMBOL(pil_force_boot);
 
 #ifdef CONFIG_DEBUG_FS
-int msm_pil_debugfs_open(struct inode *inode, struct file *filp)
+static int msm_pil_debugfs_open(struct inode *inode, struct file *filp)
 {
 	filp->private_data = inode->i_private;
 	return 0;
@@ -384,7 +403,7 @@
 
 static struct dentry *pil_base_dir;
 
-static int msm_pil_debugfs_init(void)
+static int __init msm_pil_debugfs_init(void)
 {
 	pil_base_dir = debugfs_create_dir("pil", NULL);
 	if (!pil_base_dir) {
@@ -394,52 +413,119 @@
 
 	return 0;
 }
-arch_initcall(msm_pil_debugfs_init);
+
+static void __exit msm_pil_debugfs_exit(void)
+{
+	debugfs_remove_recursive(pil_base_dir);
+}
 
 static int msm_pil_debugfs_add(struct pil_device *pil)
 {
 	if (!pil_base_dir)
 		return -ENOMEM;
 
-	if (!debugfs_create_file(pil->desc->name, S_IRUGO | S_IWUSR,
-				pil_base_dir, pil, &msm_pil_debugfs_fops))
-		return -ENOMEM;
-	return 0;
+	pil->dentry = debugfs_create_file(pil->desc->name, S_IRUGO | S_IWUSR,
+				pil_base_dir, pil, &msm_pil_debugfs_fops);
+	return !pil->dentry ? -ENOMEM : 0;
+}
+
+static void msm_pil_debugfs_remove(struct pil_device *pil)
+{
+	debugfs_remove(pil->dentry);
 }
 #else
+static int __init msm_pil_debugfs_init(void) { return 0; };
+static void __exit msm_pil_debugfs_exit(void) { return 0; };
 static int msm_pil_debugfs_add(struct pil_device *pil) { return 0; }
+static void msm_pil_debugfs_remove(struct pil_device *pil) { }
 #endif
 
+static int __msm_pil_shutdown(struct device *dev, void *data)
+{
+	struct pil_device *pil = to_pil_device(dev);
+	pil->desc->ops->shutdown(pil->desc);
+	return 0;
+}
+
 static int msm_pil_shutdown_at_boot(void)
 {
-	struct pil_device *pil;
-
-	mutex_lock(&pil_list_lock);
-	list_for_each_entry(pil, &pil_list, list)
-		pil->desc->ops->shutdown(pil->desc);
-	mutex_unlock(&pil_list_lock);
-
-	return 0;
+	return bus_for_each_dev(&pil_bus_type, NULL, NULL, __msm_pil_shutdown);
 }
 late_initcall(msm_pil_shutdown_at_boot);
 
-int msm_pil_register(struct pil_desc *desc)
+static void pil_device_release(struct device *dev)
 {
+	struct pil_device *pil = to_pil_device(dev);
+	mutex_destroy(&pil->lock);
+	kfree(pil);
+}
+
+struct pil_device *msm_pil_register(struct pil_desc *desc)
+{
+	int err;
+	static atomic_t pil_count = ATOMIC_INIT(-1);
 	struct pil_device *pil = kzalloc(sizeof(*pil), GFP_KERNEL);
+
 	if (!pil)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	mutex_init(&pil->lock);
-	INIT_LIST_HEAD(&pil->list);
 	pil->desc = desc;
+	pil->owner = desc->owner;
+	pil->dev.parent = desc->dev;
+	pil->dev.bus = &pil_bus_type;
+	pil->dev.release = pil_device_release;
 
-	mutex_lock(&pil_list_lock);
-	list_add(&pil->list, &pil_list);
-	mutex_unlock(&pil_list_lock);
+	dev_set_name(&pil->dev, "pil%d", atomic_inc_return(&pil_count));
+	err = device_register(&pil->dev);
+	if (err) {
+		put_device(&pil->dev);
+		mutex_destroy(&pil->lock);
+		kfree(pil);
+		return ERR_PTR(err);
+	}
 
-	return msm_pil_debugfs_add(pil);
+	err = msm_pil_debugfs_add(pil);
+	if (err) {
+		device_unregister(&pil->dev);
+		return ERR_PTR(err);
+	}
+
+	return pil;
 }
 EXPORT_SYMBOL(msm_pil_register);
 
+void msm_pil_unregister(struct pil_device *pil)
+{
+	if (IS_ERR_OR_NULL(pil))
+		return;
+
+	if (get_device(&pil->dev)) {
+		mutex_lock(&pil->lock);
+		WARN_ON(pil->count);
+		msm_pil_debugfs_remove(pil);
+		device_unregister(&pil->dev);
+		mutex_unlock(&pil->lock);
+		put_device(&pil->dev);
+	}
+}
+EXPORT_SYMBOL(msm_pil_unregister);
+
+static int __init msm_pil_init(void)
+{
+	int ret = msm_pil_debugfs_init();
+	if (ret)
+		return ret;
+	return bus_register(&pil_bus_type);
+}
+subsys_initcall(msm_pil_init);
+
+static void __exit msm_pil_exit(void)
+{
+	bus_unregister(&pil_bus_type);
+	msm_pil_debugfs_exit();
+}
+module_exit(msm_pil_exit);
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Load peripheral images and bring peripherals out of reset");
diff --git a/arch/arm/mach-msm/peripheral-loader.h b/arch/arm/mach-msm/peripheral-loader.h
index 3d4b4b2..cc00446 100644
--- a/arch/arm/mach-msm/peripheral-loader.h
+++ b/arch/arm/mach-msm/peripheral-loader.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,12 +13,14 @@
 #define __MSM_PERIPHERAL_LOADER_H
 
 struct device;
+struct module;
 
 struct pil_desc {
 	const char *name;
 	const char *depends_on;
 	struct device *dev;
 	const struct pil_reset_ops *ops;
+	struct module *owner;
 };
 
 struct pil_reset_ops {
@@ -29,6 +31,9 @@
 	int (*shutdown)(struct pil_desc *pil);
 };
 
-extern int msm_pil_register(struct pil_desc *desc);
+struct pil_device;
+
+extern struct pil_device *msm_pil_register(struct pil_desc *desc);
+extern void msm_pil_unregister(struct pil_device *pil);
 
 #endif
diff --git a/arch/arm/mach-msm/peripheral-reset-8960.c b/arch/arm/mach-msm/peripheral-reset-8960.c
index 6fd8464..7965193 100644
--- a/arch/arm/mach-msm/peripheral-reset-8960.c
+++ b/arch/arm/mach-msm/peripheral-reset-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -91,6 +91,7 @@
 	.name = "dsps",
 	.dev = &pil_dsps.dev,
 	.ops = &pil_dsps_ops,
+	.owner = THIS_MODULE,
 };
 
 static void __init use_secure_pil(void)
@@ -114,8 +115,8 @@
 	use_secure_pil();
 
 	BUG_ON(platform_device_register(&pil_dsps));
-	BUG_ON(msm_pil_register(&pil_dsps_desc));
+	BUG_ON(IS_ERR(msm_pil_register(&pil_dsps_desc)));
 
 	return 0;
 }
-arch_initcall(msm_peripheral_reset_init);
+module_init(msm_peripheral_reset_init);
diff --git a/arch/arm/mach-msm/peripheral-reset.c b/arch/arm/mach-msm/peripheral-reset.c
index 88b07a5..45617e3 100644
--- a/arch/arm/mach-msm/peripheral-reset.c
+++ b/arch/arm/mach-msm/peripheral-reset.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -101,6 +101,7 @@
 	.name = "dsps",
 	.dev = &pil_dsps.dev,
 	.ops = &pil_dsps_ops,
+	.owner = THIS_MODULE,
 };
 
 static int __init msm_peripheral_reset_init(void)
@@ -114,12 +115,12 @@
 	if (machine_is_msm8x60_fluid())
 		pil_dsps_desc.name = "dsps_fluid";
 	BUG_ON(platform_device_register(&pil_dsps));
-	BUG_ON(msm_pil_register(&pil_dsps_desc));
+	BUG_ON(IS_ERR(msm_pil_register(&pil_dsps_desc)));
 
 	return 0;
 }
 
-arch_initcall(msm_peripheral_reset_init);
+module_init(msm_peripheral_reset_init);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Validate and bring peripherals out of reset");
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 26b97fa..c4477ff 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -64,6 +64,7 @@
 	unsigned long start_addr;
 	struct delayed_work work;
 	struct clk *xo;
+	struct pil_device *pil;
 };
 
 static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
@@ -329,7 +330,6 @@
 	struct gss_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
-	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -363,6 +363,7 @@
 
 	desc->name = "gss";
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
 
 	if (pas_supported(PAS_GSS) > 0) {
 		desc->ops = &pil_gss_ops_trusted;
@@ -374,17 +375,19 @@
 
 	INIT_DELAYED_WORK(&drv->work, remove_gss_proxy_votes);
 
-	ret = msm_pil_register(desc);
-	if (ret) {
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
 		flush_delayed_work_sync(&drv->work);
 		clk_put(drv->xo);
+		return PTR_ERR(drv->pil);
 	}
-	return ret;
+	return 0;
 }
 
 static int __devexit pil_gss_remove(struct platform_device *pdev)
 {
 	struct gss_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
 	flush_delayed_work_sync(&drv->work);
 	clk_put(drv->xo);
 	return 0;
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index 1d13508..a85d13c 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -53,6 +53,7 @@
 struct modem_data {
 	void __iomem *base;
 	unsigned long start_addr;
+	struct pil_device *pil;
 	struct clk *xo;
 	struct delayed_work work;
 };
@@ -277,7 +278,6 @@
 	struct modem_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
-	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -303,6 +303,7 @@
 	desc->name = "modem";
 	desc->depends_on = "q6";
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
 
 	if (pas_supported(PAS_MODEM) > 0) {
 		desc->ops = &pil_modem_ops_trusted;
@@ -313,17 +314,19 @@
 	}
 	INIT_DELAYED_WORK(&drv->work, remove_modem_proxy_votes);
 
-	ret = msm_pil_register(desc);
-	if (ret) {
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
 		flush_delayed_work_sync(&drv->work);
 		clk_put(drv->xo);
+		return PTR_ERR(drv->pil);
 	}
-	return ret;
+	return 0;
 }
 
 static int __devexit pil_modem_driver_exit(struct platform_device *pdev)
 {
 	struct modem_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
 	flush_delayed_work_sync(&drv->work);
 	clk_put(drv->xo);
 	return 0;
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index 06b98e5..54356b8 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -66,6 +66,7 @@
 struct q6v3_data {
 	void __iomem *base;
 	unsigned long start_addr;
+	struct pil_device *pil;
 	struct clk *pll;
 	struct delayed_work work;
 };
@@ -260,6 +261,7 @@
 
 	desc->name = "q6";
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
 
 	if (pas_supported(PAS_Q6) > 0) {
 		desc->ops = &pil_q6v3_ops_trusted;
@@ -271,9 +273,10 @@
 
 	INIT_DELAYED_WORK(&drv->work, q6v3_remove_proxy_votes);
 
-	if (msm_pil_register(desc)) {
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
 		flush_delayed_work_sync(&drv->work);
-		return -EINVAL;
+		return PTR_ERR(drv->pil);
 	}
 	return 0;
 }
@@ -281,6 +284,7 @@
 static int __devexit pil_q6v3_driver_exit(struct platform_device *pdev)
 {
 	struct q6v3_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
 	flush_delayed_work_sync(&drv->work);
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index b0bce02..17f5a41 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -71,6 +71,7 @@
 	bool vreg_enabled;
 	struct clk *xo;
 	struct delayed_work work;
+	struct pil_device *pil;
 };
 
 static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -421,6 +422,7 @@
 	desc->name = pdata->name;
 	desc->depends_on = pdata->depends;
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
 
 	if (pas_supported(pdata->pas_id) > 0) {
 		desc->ops = &pil_q6v4_ops_trusted;
@@ -443,9 +445,11 @@
 	}
 	INIT_DELAYED_WORK(&drv->work, pil_q6v4_remove_proxy_votes);
 
-	ret = msm_pil_register(desc);
-	if (ret)
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
+		ret = PTR_ERR(drv->pil);
 		goto err_pil;
+	}
 	return 0;
 err_pil:
 	flush_delayed_work_sync(&drv->work);
@@ -464,6 +468,7 @@
 	clk_put(drv->xo);
 	regulator_put(drv->vreg);
 	regulator_put(drv->pll_supply);
+	msm_pil_unregister(drv->pil);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index bd49fc0..198572c 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -86,6 +86,7 @@
 	bool use_cxo;
 	struct delayed_work work;
 	struct regulator *pll_supply;
+	struct pil_device *pil;
 };
 
 static int pil_riva_make_proxy_votes(struct device *dev)
@@ -390,6 +391,7 @@
 
 	desc->name = "wcnss";
 	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
 
 	if (pas_supported(PAS_RIVA) > 0) {
 		desc->ops = &pil_riva_ops_trusted;
@@ -406,9 +408,11 @@
 	}
 	INIT_DELAYED_WORK(&drv->work, pil_riva_remove_proxy_votes);
 
-	ret = msm_pil_register(desc);
-	if (ret)
+	drv->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->pil)) {
+		ret = PTR_ERR(drv->pil);
 		goto err_register;
+	}
 	return 0;
 err_register:
 	flush_delayed_work_sync(&drv->work);
@@ -421,6 +425,7 @@
 static int __devexit pil_riva_remove(struct platform_device *pdev)
 {
 	struct riva_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
 	flush_delayed_work_sync(&drv->work);
 	clk_put(drv->xo);
 	regulator_put(drv->pll_supply);
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
index 90ac1d9..b6e5343e 100644
--- a/arch/arm/mach-msm/pil-tzapps.c
+++ b/arch/arm/mach-msm/pil-tzapps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -50,6 +50,7 @@
 static int __devinit pil_tzapps_driver_probe(struct platform_device *pdev)
 {
 	struct pil_desc *desc;
+	struct pil_device *pil;
 
 	if (pas_supported(PAS_TZAPPS) < 0)
 		return -ENOSYS;
@@ -61,13 +62,18 @@
 	desc->name = "tzapps";
 	desc->dev = &pdev->dev;
 	desc->ops = &pil_tzapps_ops;
-	if (msm_pil_register(desc))
-		return -EINVAL;
+	desc->owner = THIS_MODULE;
+	pil = msm_pil_register(desc);
+	if (IS_ERR(pil))
+		return PTR_ERR(pil);
+	platform_set_drvdata(pdev, pil);
 	return 0;
 }
 
 static int __devexit pil_tzapps_driver_exit(struct platform_device *pdev)
 {
+	struct pil_device *pil = platform_get_drvdata(pdev);
+	msm_pil_unregister(pil);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 8081b45..3c46d0f 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -62,6 +62,10 @@
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
+	pr_debug("CPU%u: Booted secondary processor\n", cpu);
+
+	WARN_ON(msm_platform_secondary_init(cpu));
+
 	/*
 	 * if any interrupts are already enabled for the primary
 	 * core (e.g. timer irq), then they will not have been enabled
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index ce09f9f..f4536f7 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -101,6 +101,7 @@
 int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
 {
 	int ret = 0;
+	unsigned long entry;
 
 	switch (pdata->mode) {
 	case MSM_PM_BOOT_CONFIG_TZ:
@@ -130,15 +131,44 @@
 		if (!pdata->p_addr || !pdata->v_addr)
 			return -ENODEV;
 
-		__raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
-				pdata->v_addr);
-
 		ret = msm_pm_boot_reset_vector_init(__va(pdata->p_addr));
 
-		msm_pm_boot_before_pc
-			= msm_pm_config_rst_vector_before_pc;
-		msm_pm_boot_after_pc
-			= msm_pm_config_rst_vector_after_pc;
+		if (!cpu_is_msm8625()) {
+			__raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
+					pdata->v_addr);
+
+			msm_pm_boot_before_pc
+				= msm_pm_config_rst_vector_before_pc;
+			msm_pm_boot_after_pc
+				= msm_pm_config_rst_vector_after_pc;
+		} else {
+			entry = virt_to_phys(msm_pm_boot_entry);
+
+			msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
+			msm_pm_reset_vector[1] = entry;
+
+			/* Here upper 16bits[16:31] used by CORE1
+			 * lower 16bits[0:15] used by CORE0
+			 */
+			entry = (pdata->p_addr) |
+					((pdata->p_addr & 0xFFFF0000) >> 16);
+
+			/* write 'entry' to boot remapper register */
+			__raw_writel(entry, (pdata->v_addr +
+						MPA5_BOOT_REMAP_ADDR));
+
+			/* Enable boot remapper for C0 [bit:25th] */
+			__raw_writel(readl_relaxed(pdata->v_addr +
+					MPA5_CFG_CTL_REG) | BIT(25),
+					pdata->v_addr + MPA5_CFG_CTL_REG);
+
+			/* Enable boot remapper for C1 [bit:26th] */
+			__raw_writel(readl_relaxed(pdata->v_addr +
+					MPA5_CFG_CTL_REG) | BIT(26),
+					pdata->v_addr + MPA5_CFG_CTL_REG);
+
+			msm_pm_boot_before_pc = msm_pm_write_boot_vector;
+		}
 		break;
 	default:
 		__WARN();
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 185d542..30b67c21 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -13,6 +13,11 @@
 #ifndef _ARCH_ARM_MACH_MSM_PM_BOOT_H
 #define _ARCH_ARM_MACH_MSM_PM_BOOT_H
 
+/* 8x25 specific macros */
+#define MPA5_CFG_CTL_REG	0x30
+#define MPA5_BOOT_REMAP_ADDR	0x34
+/* end */
+
 enum {
 	MSM_PM_BOOT_CONFIG_TZ		     = 0,
 	MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 7977d22..4d63b6d 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -48,6 +48,7 @@
 #ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN
 #include <mach/msm_migrate_pages.h>
 #endif
+#include <mach/socinfo.h>
 
 #include "smd_private.h"
 #include "smd_rpcrouter.h"
@@ -68,13 +69,14 @@
  *****************************************************************************/
 
 enum {
-	MSM_PM_DEBUG_SUSPEND = 1U << 0,
-	MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1,
-	MSM_PM_DEBUG_STATE = 1U << 2,
-	MSM_PM_DEBUG_CLOCK = 1U << 3,
-	MSM_PM_DEBUG_RESET_VECTOR = 1U << 4,
-	MSM_PM_DEBUG_SMSM_STATE = 1U << 5,
-	MSM_PM_DEBUG_IDLE = 1U << 6,
+	MSM_PM_DEBUG_SUSPEND = BIT(0),
+	MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
+	MSM_PM_DEBUG_STATE = BIT(2),
+	MSM_PM_DEBUG_CLOCK = BIT(3),
+	MSM_PM_DEBUG_RESET_VECTOR = BIT(4),
+	MSM_PM_DEBUG_SMSM_STATE = BIT(5),
+	MSM_PM_DEBUG_IDLE = BIT(6),
+	MSM_PM_DEBUG_HOTPLUG = BIT(7),
 };
 
 static int msm_pm_debug_mask;
@@ -142,7 +144,6 @@
 static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
 	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND] = " ",
 	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
-	[MSM_PM_SLEEP_MODE_APPS_SLEEP] = "apps_sleep",
 	[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
 		"ramp_down_and_wfi",
 	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
@@ -682,8 +683,6 @@
 	MSM_PM_STAT_IDLE_WFI,
 	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
 	MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_SLEEP,
-	MSM_PM_STAT_IDLE_FAILED_SLEEP,
 	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
 	MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
 	MSM_PM_STAT_SUSPEND,
@@ -1008,6 +1007,13 @@
 
 	memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
 
+	if (cpu_is_msm8625()) {
+		/* Program the SPM */
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE,
+									false);
+		WARN_ON(ret);
+	}
+
 	msm_irq_enter_sleep1(true, from_idle, &msm_pm_smem_data->irq_mask);
 	msm_sirc_enter_sleep();
 	msm_gpio_enter_sleep(from_idle);
@@ -1210,6 +1216,13 @@
 	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
 
 	smd_sleep_exit();
+
+	if (cpu_is_msm8625()) {
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
+									false);
+		WARN_ON(ret);
+	}
+
 	return 0;
 
 power_collapse_early_exit:
@@ -1263,6 +1276,12 @@
 		smd_sleep_exit();
 
 power_collapse_bail:
+	if (cpu_is_msm8625()) {
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
+									false);
+		WARN_ON(ret);
+	}
+
 	return ret;
 }
 
@@ -1272,10 +1291,11 @@
  * Return value:
  *      0: success
  */
-static int msm_pm_power_collapse_standalone(void)
+static int msm_pm_power_collapse_standalone(bool from_idle)
 {
 	int collapsed = 0;
 	int ret;
+	void *entry;
 
 	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
 		KERN_INFO, "%s()\n", __func__);
@@ -1283,21 +1303,26 @@
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE, false);
 	WARN_ON(ret);
 
+	entry = (!smp_processor_id() || from_idle) ?
+			msm_pm_collapse_exit : msm_secondary_startup;
+
 	msm_pm_boot_config_before_pc(smp_processor_id(),
-			virt_to_phys(msm_pm_collapse_exit));
+						virt_to_phys(entry));
 
 #ifdef CONFIG_VFP
 	vfp_flush_context();
 #endif
 
 #ifdef CONFIG_CACHE_L2X0
-	l2x0_suspend();
+	if (!cpu_is_msm8625())
+		l2x0_suspend();
 #endif
 
 	collapsed = msm_pm_collapse();
 
 #ifdef CONFIG_CACHE_L2X0
-	l2x0_resume(collapsed);
+	if (!cpu_is_msm8625())
+		l2x0_resume(collapsed);
 #endif
 
 	msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1321,18 +1346,6 @@
 }
 
 /*
- * Apps-sleep the Apps processor.  This function execute the handshake
- * protocol with Modem.
- *
- * Return value:
- *      -ENOSYS: function not implemented yet
- */
-static int msm_pm_apps_sleep(uint32_t sleep_delay, uint32_t sleep_limit)
-{
-	return -ENOSYS;
-}
-
-/*
  * Bring the Apps processor to SWFI.
  *
  * Return value:
@@ -1353,7 +1366,9 @@
 			return -EIO;
 	}
 
-	msm_pm_config_hw_before_swfi();
+	if (!cpu_is_msm8625())
+		msm_pm_config_hw_before_swfi();
+
 	msm_arch_idle();
 
 	if (ramp_acpu) {
@@ -1395,7 +1410,7 @@
 	int64_t t1;
 	static int64_t t2;
 	int exit_stat;
- #endif /* CONFIG_MSM_IDLE_STATS */
+ #endif
 
 	if (!atomic_read(&msm_pm_init_done))
 		return;
@@ -1412,19 +1427,19 @@
 
 	exit_stat = MSM_PM_STAT_IDLE_SPIN;
 	low_power = 0;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 
 	for (i = 0; i < ARRAY_SIZE(allow); i++)
 		allow[i] = true;
 
-	if ((timer_expiration < msm_pm_idle_sleep_min_time) ||
+	if (num_online_cpus() > 1 ||
+		(timer_expiration < msm_pm_idle_sleep_min_time) ||
 #ifdef CONFIG_HAS_WAKELOCK
 		has_wake_lock(WAKE_LOCK_IDLE) ||
 #endif
 		!msm_irq_idle_sleep_allowed()) {
 		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
 		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
-		allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(allow); i++) {
@@ -1493,32 +1508,15 @@
 			exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
 			msm_pm_sleep_limit = sleep_limit;
 		}
-#endif /* CONFIG_MSM_IDLE_STATS */
-	} else if (allow[MSM_PM_SLEEP_MODE_APPS_SLEEP]) {
-		uint32_t sleep_delay;
-
-		sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
-			timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
-		if (sleep_delay == 0) /* 0 would mean infinite time */
-			sleep_delay = 1;
-
-		ret = msm_pm_apps_sleep(sleep_delay, sleep_limit);
-		low_power = 0;
-
-#ifdef CONFIG_MSM_IDLE_STATS
-		if (ret)
-			exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
-		else
-			exit_stat = MSM_PM_STAT_IDLE_SLEEP;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
-		ret = msm_pm_power_collapse_standalone();
+		ret = msm_pm_power_collapse_standalone(true);
 		low_power = 0;
 #ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = ret ?
 			MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
 			MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
 		ret = msm_pm_swfi(true);
 		if (ret)
@@ -1527,20 +1525,20 @@
 		low_power = 0;
 #ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
 		msm_pm_swfi(false);
 		low_power = 0;
 #ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	} else {
 		while (!msm_irq_pending())
 			udelay(1);
 		low_power = 0;
 #ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	}
 
 	msm_timer_exit_idle(low_power);
@@ -1548,13 +1546,14 @@
 #ifdef CONFIG_MSM_IDLE_STATS
 	t2 = ktime_to_ns(ktime_get());
 	msm_pm_add_stat(exit_stat, t2 - t1);
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 }
 
 /*
  * Suspend the Apps processor.
  *
  * Return value:
+ *	-EPERM: Suspend happened by a not permitted core
  *      -EAGAIN: modem reset occurred or early exit from suspend
  *      -EBUSY: modem not ready for our suspend
  *      -EINVAL: invalid sleep mode
@@ -1566,13 +1565,20 @@
 {
 	bool allow[MSM_PM_SLEEP_MODE_NR];
 	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
-	int ret;
+	int ret = -EPERM;
 	int i;
-
 #ifdef CONFIG_MSM_IDLE_STATS
 	int64_t period = 0;
 	int64_t time = 0;
+#endif
 
+	/* Must executed by CORE0 */
+	if (smp_processor_id()) {
+		__WARN();
+		goto suspend_exit;
+	}
+
+#ifdef CONFIG_MSM_IDLE_STATS
 	time = msm_timer_get_sclk_time(&period);
 #endif
 
@@ -1589,8 +1595,6 @@
 			allow[i] = false;
 	}
 
-	ret = 0;
-
 	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
 		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
 #ifdef CONFIG_MSM_IDLE_STATS
@@ -1647,7 +1651,7 @@
 		msm_pm_add_stat(id, time);
 #endif
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
-		ret = msm_pm_power_collapse_standalone();
+		ret = msm_pm_power_collapse_standalone(false);
 	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
 		ret = msm_pm_swfi(true);
 		if (ret)
@@ -1657,6 +1661,7 @@
 		msm_pm_swfi(false);
 	}
 
+suspend_exit:
 	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
 		"%s(): return %d\n", __func__, ret);
 
@@ -1673,7 +1678,27 @@
  */
 void msm_pm_cpu_enter_lowpower(unsigned int cpu)
 {
-	return;
+	bool allow[MSM_PM_SLEEP_MODE_NR];
+	int i;
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct msm_pm_platform_data *mode;
+
+		mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
+		allow[i] = mode->suspend_supported && mode->suspend_enabled;
+	}
+
+	MSM_PM_DPRINTK(MSM_PM_DEBUG_HOTPLUG, KERN_INFO,
+		"CPU%u: %s: shutting down cpu\n", cpu, __func__);
+
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
+		msm_pm_power_collapse_standalone(false);
+	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+		msm_pm_swfi(false);
+	} else {
+		MSM_PM_DPRINTK(MSM_PM_DEBUG_HOTPLUG, KERN_INFO,
+			"CPU%u: %s: shutting down failed!!!\n", cpu, __func__);
+	}
 }
 
 /******************************************************************************
@@ -1725,10 +1750,6 @@
 };
 
 
-/******************************************************************************
- *
- *****************************************************************************/
-
 /*
  * Initialize the power management subsystem.
  *
@@ -1748,6 +1769,8 @@
 	pmd_t *pmd;
 	unsigned long pmdval;
 
+	if (cpu_is_msm8625())
+		return 0;
 	/* Page table for cores to come back up safely. */
 	pc_pgd = pgd_alloc(&init_mm);
 	if (!pc_pgd)
@@ -1837,15 +1860,6 @@
 			first_bucket_time =
 			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
 
-		stats[MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep";
-		stats[MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_FAILED_SLEEP].name =
-			"idle-failed-sleep";
-		stats[MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
 		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
 			"idle-power-collapse";
 		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index 7a962b2..2011c42 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5/audio_mp3.c
  *
@@ -836,6 +836,7 @@
 
 	file->private_data = audio;
 	audio->opened = 1;
+	audio->stopped = 0;
 	rc = 0;
 done:
 	mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp.c b/arch/arm/mach-msm/qdsp5v2/adsp.c
index b7b56c8..acd9c4c 100644
--- a/arch/arm/mach-msm/qdsp5v2/adsp.c
+++ b/arch/arm/mach-msm/qdsp5v2/adsp.c
@@ -2,7 +2,7 @@
  * Register/Interrupt access for userspace aDSP library.
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2009,2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009,2011-2012 Code Aurora Forum. All rights reserved.
  * Author: Iliyan Malchev <ibm@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -46,8 +46,6 @@
 static int wdump, rdump;
 #endif /* CONFIG_DEBUG_FS */
 
-#define INT_ADSP INT_ADSP_A9_A11
-
 static struct adsp_info adsp_info;
 static struct msm_adsp_module *adsp_modules;
 static int adsp_open_count;
@@ -889,7 +887,7 @@
 
 		mutex_lock(&adsp_open_lock);
 		if (adsp_open_count++ == 0)
-			enable_irq(INT_ADSP);
+			enable_irq(adsp_info.int_adsp);
 		mutex_unlock(&adsp_open_lock);
 		break;
 	case ADSP_STATE_ENABLING:
@@ -944,7 +942,7 @@
 		mutex_unlock(&module->lock);
 		mutex_lock(&adsp_open_lock);
 		if (--adsp_open_count == 0) {
-			disable_irq(INT_ADSP);
+			disable_irq(adsp_info.int_adsp);
 			MM_INFO("disable interrupt\n");
 		}
 		mutex_unlock(&adsp_open_lock);
@@ -959,6 +957,12 @@
 	unsigned count;
 	int rc, i;
 
+	adsp_info.int_adsp = platform_get_irq(pdev, 0);
+	if (adsp_info.int_adsp < 0) {
+		MM_ERR("no irq resource?\n");
+		return -ENODEV;
+	}
+
 	adsp_info.init_info_ptr = kzalloc(
 		(sizeof(struct adsp_rtos_mp_mtoa_init_info_type)), GFP_KERNEL);
 	if (!adsp_info.init_info_ptr)
@@ -996,11 +1000,11 @@
 	spin_lock_init(&adsp_cmd_lock);
 	spin_lock_init(&adsp_write_lock);
 
-	rc = request_irq(INT_ADSP, adsp_irq_handler,
+	rc = request_irq(adsp_info.int_adsp, adsp_irq_handler,
 			IRQF_TRIGGER_RISING, "adsp", 0);
 	if (rc < 0)
 		goto fail_request_irq;
-	disable_irq(INT_ADSP);
+	disable_irq(adsp_info.int_adsp);
 
 	for (i = 0; i < count; i++) {
 		struct msm_adsp_module *mod = adsp_modules + i;
@@ -1056,8 +1060,8 @@
 	daldevice_detach(adsp_info.handle);
 	adsp_info.handle = NULL;
 fail_dal_attach:
-	enable_irq(INT_ADSP);
-	free_irq(INT_ADSP, 0);
+	enable_irq(adsp_info.int_adsp);
+	free_irq(adsp_info.int_adsp, 0);
 fail_request_irq:
 	kfree(adsp_modules);
 	kfree(adsp_info.init_info_ptr);
@@ -1187,11 +1191,6 @@
 	},
 };
 
-struct platform_device msm_adsp_device = {
-	.name = "msm_adsp",
-	.id = -1,
-};
-
 static char msm_adsp_driver_name[] = "msm_adsp";
 
 #ifdef CONFIG_DEBUG_FS
@@ -1218,7 +1217,6 @@
 #endif /* CONFIG_DEBUG_FS */
 
 	msm_adsp_driver.driver.name = msm_adsp_driver_name;
-	rc = platform_device_register(&msm_adsp_device);
 	rc = platform_driver_register(&msm_adsp_driver);
 	MM_INFO("%s -- %d\n", msm_adsp_driver_name, rc);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp.h b/arch/arm/mach-msm/qdsp5v2/adsp.h
index 18f4046..5aceff9 100644
--- a/arch/arm/mach-msm/qdsp5v2/adsp.h
+++ b/arch/arm/mach-msm/qdsp5v2/adsp.h
@@ -229,6 +229,9 @@
 
 	void *handle;
 	void *cb_handle;
+
+	/* Interrupt value */
+	int int_adsp;
 };
 
 #define ADSP_STATE_DISABLED   0
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index ce5d084..9b03985 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -15,7 +15,7 @@
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
-#include <linux/android_pmem.h>
+#include <linux/ion.h>
 #include <linux/mm.h>
 #include <mach/qdsp6v2/audio_acdb.h>
 
@@ -62,13 +62,13 @@
 	/* Sidetone Cal */
 	struct sidetone_atomic_cal	sidetone_cal;
 
-	/* PMEM information */
-	atomic_t			pmem_fd;
+	/* Allocation information */
+	struct ion_client		*ion_client;
+	struct ion_handle		*ion_handle;
+	atomic_t			map_handle;
 	atomic64_t			paddr;
 	atomic64_t			kvaddr;
-	atomic64_t			pmem_len;
-	struct file			*file;
-
+	atomic64_t			mem_len;
 };
 
 static struct acdb_data		acdb_data;
@@ -200,10 +200,10 @@
 {
 	pr_debug("%s,\n", __func__);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
-		pr_err("%s: offset %d is > pmem_len %ld\n",
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
 			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.pmem_len));
+			(long)atomic64_read(&acdb_data.mem_len));
 		goto done;
 	}
 
@@ -221,10 +221,10 @@
 {
 	pr_debug("%s, path = %d\n", __func__, path);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
-		pr_err("%s: offset %d is > pmem_len %ld\n",
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
 			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.pmem_len));
+			(long)atomic64_read(&acdb_data.mem_len));
 		goto done;
 	}
 	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
@@ -271,10 +271,10 @@
 {
 	pr_debug("%s, path = %d\n", __func__, path);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
-		pr_err("%s: offset %d is > pmem_len %ld\n",
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
 			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.pmem_len));
+			(long)atomic64_read(&acdb_data.mem_len));
 		goto done;
 	}
 	if (path >= MAX_AUDPROC_TYPES) {
@@ -321,10 +321,10 @@
 {
 	pr_debug("%s, path = %d\n", __func__, path);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
-		pr_err("%s: offset %d is > pmem_len %ld\n",
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
 			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.pmem_len));
+			(long)atomic64_read(&acdb_data.mem_len));
 		goto done;
 	}
 	if (path >= MAX_AUDPROC_TYPES) {
@@ -371,10 +371,10 @@
 {
 	pr_debug("%s, path = %d\n", __func__, path);
 
-	if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
-		pr_err("%s: offset %d is > pmem_len %ld\n",
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
 			__func__, cal_block->cal_offset,
-			(long)atomic64_read(&acdb_data.pmem_len));
+			(long)atomic64_read(&acdb_data.mem_len));
 		goto done;
 	}
 	if (path >= MAX_AUDPROC_TYPES) {
@@ -432,10 +432,10 @@
 	atomic_set(&acdb_data.vocproc_total_cal_size, 0);
 	for (i = 0; i < len; i++) {
 		if (cal_blocks[i].cal_offset >
-					atomic64_read(&acdb_data.pmem_len)) {
-			pr_err("%s: offset %d is > pmem_len %ld\n",
+					atomic64_read(&acdb_data.mem_len)) {
+			pr_err("%s: offset %d is > mem_len %ld\n",
 				__func__, cal_blocks[i].cal_offset,
-				(long)atomic64_read(&acdb_data.pmem_len));
+				(long)atomic64_read(&acdb_data.mem_len));
 			atomic_set(&acdb_data.vocproc_cal[i].cal_size, 0);
 		} else {
 			atomic_add(cal_blocks[i].cal_size,
@@ -484,10 +484,10 @@
 	atomic_set(&acdb_data.vocstrm_total_cal_size, 0);
 	for (i = 0; i < len; i++) {
 		if (cal_blocks[i].cal_offset >
-					atomic64_read(&acdb_data.pmem_len)) {
-			pr_err("%s: offset %d is > pmem_len %ld\n",
+					atomic64_read(&acdb_data.mem_len)) {
+			pr_err("%s: offset %d is > mem_len %ld\n",
 				__func__, cal_blocks[i].cal_offset,
-				(long)atomic64_read(&acdb_data.pmem_len));
+				(long)atomic64_read(&acdb_data.mem_len));
 			atomic_set(&acdb_data.vocstrm_cal[i].cal_size, 0);
 		} else {
 			atomic_add(cal_blocks[i].cal_size,
@@ -536,10 +536,10 @@
 	atomic_set(&acdb_data.vocvol_total_cal_size, 0);
 	for (i = 0; i < len; i++) {
 		if (cal_blocks[i].cal_offset >
-					atomic64_read(&acdb_data.pmem_len)) {
-			pr_err("%s: offset %d is > pmem_len %ld\n",
+					atomic64_read(&acdb_data.mem_len)) {
+			pr_err("%s: offset %d is > mem_len %ld\n",
 				__func__, cal_blocks[i].cal_offset,
-				(long)atomic64_read(&acdb_data.pmem_len));
+				(long)atomic64_read(&acdb_data.mem_len));
 			atomic_set(&acdb_data.vocvol_cal[i].cal_size, 0);
 		} else {
 			atomic_add(cal_blocks[i].cal_size,
@@ -603,8 +603,9 @@
 	s32 result = 0;
 	pr_debug("%s\n", __func__);
 
-	if (atomic_read(&acdb_data.pmem_fd)) {
-		pr_debug("%s: ACDB opened but PMEM allocated, using existing PMEM!\n",
+	if (atomic64_read(&acdb_data.mem_len)) {
+		pr_debug("%s: ACDB opened but memory allocated, "
+			"using existing allocation!\n",
 			__func__);
 	}
 
@@ -612,46 +613,74 @@
 	return result;
 }
 
-static int deregister_pmem(void)
+static int deregister_memory(void)
 {
-	if (atomic_read(&acdb_data.pmem_fd)) {
+	if (atomic64_read(&acdb_data.mem_len)) {
 		mutex_lock(&acdb_data.acdb_mutex);
-		put_pmem_file(acdb_data.file);
+		ion_unmap_kernel(acdb_data.ion_client, acdb_data.ion_handle);
+		ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+		ion_client_destroy(acdb_data.ion_client);
 		mutex_unlock(&acdb_data.acdb_mutex);
-		atomic_set(&acdb_data.pmem_fd, 0);
+		atomic64_set(&acdb_data.mem_len, 0);
 	}
 	return 0;
 }
 
-static int register_pmem(void)
+static int register_memory(void)
 {
-	int result;
-	unsigned long paddr;
-	unsigned long kvaddr;
-	unsigned long pmem_len;
+	int			result;
+	unsigned long		paddr;
+	unsigned long		kvaddr;
+	unsigned long		mem_len;
 
 	mutex_lock(&acdb_data.acdb_mutex);
-	result = get_pmem_file(atomic_read(&acdb_data.pmem_fd),
-				&paddr, &kvaddr, &pmem_len,
-				&acdb_data.file);
-	mutex_unlock(&acdb_data.acdb_mutex);
-	if (result != 0) {
-		atomic_set(&acdb_data.pmem_fd, 0);
-		atomic64_set(&acdb_data.pmem_len, 0);
-		pr_err("%s: Could not register PMEM!!!\n", __func__);
-		goto done;
+	acdb_data.ion_client =
+		msm_ion_client_create(UINT_MAX, "audio_acdb_client");
+	if (IS_ERR_OR_NULL(acdb_data.ion_client)) {
+		pr_err("%s: Could not register ION client!!!\n", __func__);
+		goto err;
 	}
 
+	acdb_data.ion_handle = ion_import_fd(acdb_data.ion_client,
+		atomic_read(&acdb_data.map_handle));
+	if (IS_ERR_OR_NULL(acdb_data.ion_handle)) {
+		pr_err("%s: Could not import map handle!!!\n", __func__);
+		goto err_ion_client;
+	}
+
+	result = ion_phys(acdb_data.ion_client, acdb_data.ion_handle,
+				&paddr, (size_t *)&mem_len);
+	if (result != 0) {
+		pr_err("%s: Could not get phys addr!!!\n", __func__);
+		goto err_ion_handle;
+	}
+
+	kvaddr = (unsigned long)ion_map_kernel(acdb_data.ion_client,
+		acdb_data.ion_handle, 0);
+	if (IS_ERR_OR_NULL(&kvaddr)) {
+		pr_err("%s: Could not get kernel virt addr!!!\n", __func__);
+		goto err_ion_handle;
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+
 	atomic64_set(&acdb_data.paddr, paddr);
 	atomic64_set(&acdb_data.kvaddr, kvaddr);
-	atomic64_set(&acdb_data.pmem_len, pmem_len);
-	pr_debug("AUDIO_REGISTER_PMEM done! paddr = 0x%lx, "
+	atomic64_set(&acdb_data.mem_len, mem_len);
+	pr_debug("%s done! paddr = 0x%lx, "
 		"kvaddr = 0x%lx, len = x%lx\n",
+		 __func__,
 		(long)atomic64_read(&acdb_data.paddr),
 		(long)atomic64_read(&acdb_data.kvaddr),
-		(long)atomic64_read(&acdb_data.pmem_len));
+		(long)atomic64_read(&acdb_data.mem_len));
 
-done:
+	return result;
+err_ion_handle:
+	ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+err_ion_client:
+	ion_client_destroy(acdb_data.ion_client);
+err:
+	atomic64_set(&acdb_data.mem_len, 0);
+	mutex_unlock(&acdb_data.acdb_mutex);
 	return result;
 }
 static long acdb_ioctl(struct file *f,
@@ -659,7 +688,7 @@
 {
 	int32_t			result = 0;
 	int32_t			size;
-	int32_t			pmem_fd;
+	int32_t			map_fd;
 	uint32_t		topology;
 	struct cal_block	data[MAX_NETWORKS];
 	pr_debug("%s\n", __func__);
@@ -667,23 +696,23 @@
 	switch (cmd) {
 	case AUDIO_REGISTER_PMEM:
 		pr_debug("AUDIO_REGISTER_PMEM\n");
-		if (atomic_read(&acdb_data.pmem_fd)) {
-			deregister_pmem();
-			pr_debug("Remove the existing PMEM\n");
+		if (atomic_read(&acdb_data.mem_len)) {
+			deregister_memory();
+			pr_debug("Remove the existing memory\n");
 		}
 
-		if (copy_from_user(&pmem_fd, (void *)arg, sizeof(pmem_fd))) {
-			pr_err("%s: fail to copy pmem handle!\n", __func__);
+		if (copy_from_user(&map_fd, (void *)arg, sizeof(map_fd))) {
+			pr_err("%s: fail to copy memory handle!\n", __func__);
 			result = -EFAULT;
 		} else {
-			atomic_set(&acdb_data.pmem_fd, pmem_fd);
-			result = register_pmem();
+			atomic_set(&acdb_data.map_handle, map_fd);
+			result = register_memory();
 		}
 		goto done;
 
 	case AUDIO_DEREGISTER_PMEM:
 		pr_debug("AUDIO_DEREGISTER_PMEM\n");
-		deregister_pmem();
+		deregister_memory();
 		goto done;
 	case AUDIO_SET_VOICE_RX_TOPOLOGY:
 		if (copy_from_user(&topology, (void *)arg,
@@ -835,8 +864,8 @@
 
 	pr_debug("%s\n", __func__);
 
-	if (atomic_read(&acdb_data.pmem_fd)) {
-		if (size <= atomic64_read(&acdb_data.pmem_len)) {
+	if (atomic64_read(&acdb_data.mem_len)) {
+		if (size <= atomic64_read(&acdb_data.mem_len)) {
 			vma->vm_page_prot = pgprot_noncached(
 						vma->vm_page_prot);
 			result = remap_pfn_range(vma,
@@ -845,11 +874,11 @@
 				size,
 				vma->vm_page_prot);
 		} else {
-			pr_err("%s: Not enough PMEM memory!\n", __func__);
+			pr_err("%s: Not enough memory!\n", __func__);
 			result = -ENOMEM;
 		}
 	} else {
-		pr_err("%s: PMEM is not allocated, yet!\n", __func__);
+		pr_err("%s: memory is not allocated, yet!\n", __func__);
 		result = -ENODEV;
 	}
 
@@ -869,7 +898,7 @@
 	if (atomic_read(&usage_count) >= 1)
 		result = -EBUSY;
 	else
-		result = deregister_pmem();
+		result = deregister_memory();
 
 	return result;
 }
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
index 0a5acce..aaae776 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
+#include <linux/workqueue.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
 #include <mach/qdsp6v2/audio_dev_ctl.h>
@@ -31,6 +32,9 @@
 
 
 static DEFINE_MUTEX(session_lock);
+static struct workqueue_struct *msm_reset_device_work_queue;
+static void reset_device_work(struct work_struct *work);
+static DECLARE_WORK(msm_reset_device_work, reset_device_work);
 
 struct audio_dev_ctrl_state {
 	struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
@@ -119,6 +123,18 @@
 }
 EXPORT_SYMBOL(msm_reset_all_device);
 
+static void reset_device_work(struct work_struct *work)
+{
+	msm_reset_all_device();
+}
+
+int reset_device(void)
+{
+	queue_work(msm_reset_device_work_queue, &msm_reset_device_work);
+	return 0;
+}
+EXPORT_SYMBOL(reset_device);
+
 int msm_set_copp_id(int session_id, int copp_id)
 {
 	int rc = 0;
@@ -1686,7 +1702,9 @@
 	init_waitqueue_head(&audio_dev_ctrl.wait);
 
 	event.cb = NULL;
-
+	msm_reset_device_work_queue = create_workqueue("reset_device");
+	if (msm_reset_device_work_queue == NULL)
+		return -ENOMEM;
 	atomic_set(&audio_dev_ctrl.opened, 0);
 	audio_dev_ctrl.num_dev = 0;
 	audio_dev_ctrl.voice_tx_dev = NULL;
@@ -1704,6 +1722,7 @@
 
 static void __exit audio_dev_ctrl_exit(void)
 {
+	destroy_workqueue(msm_reset_device_work_queue);
 }
 module_init(audio_dev_ctrl_init);
 module_exit(audio_dev_ctrl_exit);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
index 599198e..41a7387 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -28,8 +28,8 @@
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/earlysuspend.h>
+#include <linux/ion.h>
 #include <linux/list.h>
-#include <linux/android_pmem.h>
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
@@ -88,10 +88,10 @@
 	int event_type;
 	union msm_audio_event_payload payload;
 };
-
-struct audlpa_pmem_region {
+struct audlpa_ion_region {
 	struct list_head list;
-	struct file *file;
+	struct ion_handle *handle;
+	struct ion_client *client;
 	int fd;
 	void *vaddr;
 	unsigned long paddr;
@@ -115,12 +115,13 @@
 
 static void audlpa_post_event(struct audio *audio, int type,
 	union msm_audio_event_payload payload);
-static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
 				unsigned long len, int ref_up);
+static void audlpa_unmap_ion_region(struct audio *audio);
 static void audlpa_async_send_data(struct audio *audio, unsigned needed,
 				uint32_t token);
 static int audlpa_pause(struct audio *audio);
-static void audlpa_unmap_pmem_region(struct audio *audio);
 static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 static int audlpa_set_pcm_params(void *data);
 
@@ -422,7 +423,7 @@
 	    drv_evt->event_type == AUDIO_EVENT_READ_DONE)) {
 		pr_debug("%s: AUDIO_EVENT_WRITE_DONE completing\n", __func__);
 		mutex_lock(&audio->lock);
-		audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+		audlpa_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
 				  drv_evt->payload.aio_buf.buf_len, 0);
 		mutex_unlock(&audio->lock);
 	}
@@ -432,38 +433,41 @@
 	return rc;
 }
 
-static int audlpa_pmem_check(struct audio *audio,
-		void *vaddr, unsigned long len)
+static int audlpa_ion_check(struct audio *audio,
+			void *vaddr, unsigned long len)
 {
-	struct audlpa_pmem_region *region_elt;
-	struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+	struct audlpa_ion_region *region_elt;
+	struct audlpa_ion_region t = {.vaddr = vaddr, .len = len };
 
-	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
 		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
 		    OVERLAPS(region_elt, &t)) {
-			pr_err("%s: region (vaddr %p len %ld)"
-				" clashes with registered region"
-				" (vaddr %p paddr %p len %ld)\n",
-				__func__, vaddr, len,
-				region_elt->vaddr,
-				(void *)region_elt->paddr,
-				region_elt->len);
+			pr_err("%s[%p]:region (vaddr %p len %ld)"
+			" clashes with registered region"
+			" (vaddr %p paddr %p len %ld)\n",
+			__func__, audio, vaddr, len,
+			region_elt->vaddr,
+			(void *)region_elt->paddr, region_elt->len);
 			return -EINVAL;
 		}
 	}
 
 	return 0;
 }
-
-static int audlpa_pmem_add(struct audio *audio,
-	struct msm_audio_pmem_info *info)
+static int audlpa_ion_add(struct audio *audio,
+			struct msm_audio_ion_info *info)
 {
-	unsigned long paddr, kvaddr, len;
-	struct file *file;
-	struct audlpa_pmem_region *region;
+	ion_phys_addr_t paddr;
+	size_t len;
+	unsigned long kvaddr;
+	struct audlpa_ion_region *region;
 	int rc = -EINVAL;
+	struct ion_handle *handle;
+	struct ion_client *client;
+	unsigned long ionflag;
+	void *temp_ptr;
 
-	pr_debug("%s:\n", __func__);
+	pr_debug("%s[%p]:\n", __func__, audio);
 	region = kmalloc(sizeof(*region), GFP_KERNEL);
 
 	if (!region) {
@@ -471,61 +475,105 @@
 		goto end;
 	}
 
-	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
-		kfree(region);
-		goto end;
+	client = msm_ion_client_create(UINT_MAX, "Audio_LPA_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
+		goto client_error;
 	}
 
-	rc = audlpa_pmem_check(audio, info->vaddr, len);
+	handle = ion_import_fd(client, info->fd);
+	if (IS_ERR_OR_NULL(handle)) {
+		pr_err("%s: could not get handle of the given fd\n", __func__);
+		goto import_error;
+	}
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		pr_err("%s: could not get flags for the handle\n", __func__);
+		goto flag_error;
+	}
+
+	temp_ptr = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR_OR_NULL(temp_ptr)) {
+		pr_err("%s: could not get virtual address\n", __func__);
+		goto map_error;
+	}
+	kvaddr = (unsigned long) temp_ptr;
+
+	rc = ion_phys(client, handle, &paddr, &len);
+	if (rc) {
+		pr_err("%s: could not get physical address\n", __func__);
+		goto ion_error;
+	}
+
+	rc = audlpa_ion_check(audio, info->vaddr, len);
 	if (rc < 0) {
-		put_pmem_file(file);
-		kfree(region);
-		goto end;
+		pr_err("%s: audlpa_ion_check failed\n", __func__);
+		goto ion_error;
 	}
 
+	region->client = client;
+	region->handle = handle;
 	region->vaddr = info->vaddr;
 	region->fd = info->fd;
 	region->paddr = paddr;
 	region->kvaddr = kvaddr;
 	region->len = len;
-	region->file = file;
 	region->ref_cnt = 0;
-	pr_debug("%s: add region paddr %lx vaddr %p, len %lu\n", __func__,
-			 region->paddr, region->vaddr,
-			 region->len);
-	list_add_tail(&region->list, &audio->pmem_region_queue);
+	pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		__func__, audio,
+		region->paddr, region->vaddr, region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->ion_region_queue);
+
 	rc = q6asm_memory_map(audio->ac, (uint32_t)paddr, IN, (uint32_t)len, 1);
-	if (rc < 0)
-		pr_err("%s: memory map failed\n", __func__);
+	if (rc < 0) {
+		pr_err("%s[%p]: memory map failed\n", __func__, audio);
+		goto ion_error;
+	} else {
+		goto end;
+	}
+
+ion_error:
+	ion_unmap_kernel(client, handle);
+map_error:
+	ion_free(client, handle);
+flag_error:
+import_error:
+	ion_client_destroy(client);
+client_error:
+	kfree(region);
 end:
 	return rc;
 }
 
-static int audlpa_pmem_remove(struct audio *audio,
-	struct msm_audio_pmem_info *info)
+static int audlpa_ion_remove(struct audio *audio,
+			struct msm_audio_ion_info *info)
 {
-	struct audlpa_pmem_region *region;
+	struct audlpa_ion_region *region;
 	struct list_head *ptr, *next;
 	int rc = -EINVAL;
 
-	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
-		region = list_entry(ptr, struct audlpa_pmem_region, list);
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audlpa_ion_region, list);
 
-		if ((region != NULL) && (region->fd == info->fd) &&
-		    (region->vaddr == info->vaddr)) {
+		if (region != NULL && (region->fd == info->fd) &&
+			(region->vaddr == info->vaddr)) {
 			if (region->ref_cnt) {
-				pr_debug("%s: region %p in use ref_cnt %d\n",
-					__func__, region, region->ref_cnt);
+				pr_debug("%s[%p]:region %p in use ref_cnt %d\n",
+					__func__, audio, region,
+					region->ref_cnt);
 				break;
 			}
 			rc = q6asm_memory_unmap(audio->ac,
-						(uint32_t)region->paddr,
-						IN);
+				(uint32_t) region->paddr, IN);
 			if (rc < 0)
-				pr_err("%s: memory unmap failed\n", __func__);
+				pr_err("%s[%p]: memory unmap failed\n",
+					__func__, audio);
 
 			list_del(&region->list);
-			put_pmem_file(region->file);
+			ion_unmap_kernel(region->client, region->handle);
+			ion_free(region->client, region->handle);
+			ion_client_destroy(region->client);
 			kfree(region);
 			rc = 0;
 			break;
@@ -535,24 +583,21 @@
 	return rc;
 }
 
-static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
-		     unsigned long len, struct audlpa_pmem_region **region)
+static int audlpa_ion_lookup_vaddr(struct audio *audio, void *addr,
+			unsigned long len, struct audlpa_ion_region **region)
 {
-	struct audlpa_pmem_region *region_elt;
-
+	struct audlpa_ion_region *region_elt;
 	int match_count = 0;
-
 	*region = NULL;
 
 	/* returns physical address or zero */
-	list_for_each_entry(region_elt, &audio->pmem_region_queue,
-		list) {
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
 		if (addr >= region_elt->vaddr &&
-		    addr < region_elt->vaddr + region_elt->len &&
-		    addr + len <= region_elt->vaddr + region_elt->len) {
+			addr < region_elt->vaddr + region_elt->len &&
+			addr + len <= region_elt->vaddr + region_elt->len) {
 			/* offset since we could pass vaddr inside a registerd
-			 * pmem buffer
-			 */
+			* ion buffer
+			*/
 
 			match_count++;
 			if (!*region)
@@ -561,32 +606,33 @@
 	}
 
 	if (match_count > 1) {
-		pr_err("%s: multiple hits for vaddr %p, len %ld\n", __func__,
-			   addr, len);
-		list_for_each_entry(region_elt,
-		  &audio->pmem_region_queue, list) {
-			if (addr >= region_elt->vaddr &&
-			    addr < region_elt->vaddr + region_elt->len &&
-			    addr + len <= region_elt->vaddr + region_elt->len)
-				pr_err("%s: \t%p, %ld --> %p\n", __func__,
-					   region_elt->vaddr, region_elt->len,
-					   (void *)region_elt->paddr);
+		pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+			 __func__, audio, addr, len);
+		list_for_each_entry(region_elt, &audio->ion_region_queue,
+					list) {
+		if (addr >= region_elt->vaddr &&
+			addr < region_elt->vaddr + region_elt->len &&
+			addr + len <= region_elt->vaddr + region_elt->len)
+			pr_err("\t%s[%p]:%p, %ld --> %p\n",
+				__func__, audio,
+					region_elt->vaddr,
+					region_elt->len,
+					(void *)region_elt->paddr);
 		}
 	}
-
 	return *region ? 0 : -1;
 }
-
-unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
-		    unsigned long len, int ref_up)
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
+			unsigned long len, int ref_up)
 {
-	struct audlpa_pmem_region *region;
+	struct audlpa_ion_region *region;
 	unsigned long paddr;
 	int ret;
 
-	ret = audlpa_pmem_lookup_vaddr(audio, addr, len, &region);
+	ret = audlpa_ion_lookup_vaddr(audio, addr, len, &region);
 	if (ret) {
-		pr_err("%s: lookup (%p, %ld) failed\n", __func__, addr, len);
+		pr_err("%s[%p]:lookup (%p, %ld) failed\n",
+			__func__, audio, addr, len);
 		return 0;
 	}
 	if (ref_up)
@@ -613,7 +659,7 @@
 		return -EFAULT;
 	}
 
-	buf_node->paddr = audlpa_pmem_fixup(
+	buf_node->paddr = audlpa_ion_fixup(
 		audio, buf_node->buf.buf_addr,
 		buf_node->buf.buf_len, 1);
 	if (dir) {
@@ -669,6 +715,9 @@
 		break;
 	case ASM_SESSION_CMDRSP_GET_SESSION_TIME:
 		break;
+	case RESET_EVENTS:
+		reset_device();
+		break;
 	default:
 		break;
 	}
@@ -918,25 +967,26 @@
 		}
 		break;
 
-	case AUDIO_REGISTER_PMEM: {
-			struct msm_audio_pmem_info info;
-			pr_debug("%s: AUDIO_REGISTER_PMEM\n", __func__);
-			if (copy_from_user(&info, (void *) arg, sizeof(info)))
-				rc = -EFAULT;
-			else
-				rc = audlpa_pmem_add(audio, &info);
-			break;
-		}
+	case AUDIO_REGISTER_ION: {
+		struct msm_audio_ion_info info;
+		pr_debug("%s: AUDIO_REGISTER_ION\n", __func__);
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audlpa_ion_add(audio, &info);
+		break;
+	}
 
-	case AUDIO_DEREGISTER_PMEM: {
-			struct msm_audio_pmem_info info;
-			pr_debug("%s: AUDIO_DEREGISTER_PMEM\n", __func__);
-			if (copy_from_user(&info, (void *) arg, sizeof(info)))
-				rc = -EFAULT;
-			else
-				rc = audlpa_pmem_remove(audio, &info);
-			break;
-		}
+	case AUDIO_DEREGISTER_ION: {
+		struct msm_audio_ion_info info;
+		pr_debug("%s: AUDIO_DEREGISTER_ION\n", __func__);
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audlpa_ion_remove(audio, &info);
+		break;
+	}
+
 	case AUDIO_ASYNC_WRITE:
 		pr_debug("%s: AUDIO_ASYNC_WRITE\n", __func__);
 		if (audio->drv_status & ADRV_STATUS_FSYNC)
@@ -1035,34 +1085,37 @@
 	return audlpa_async_fsync(audio);
 }
 
-static void audlpa_reset_pmem_region(struct audio *audio)
+void audlpa_reset_ion_region(struct audio *audio)
 {
-	struct audlpa_pmem_region *region;
+	struct audlpa_ion_region *region;
 	struct list_head *ptr, *next;
 
-	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
-		region = list_entry(ptr, struct audlpa_pmem_region, list);
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audlpa_ion_region, list);
 		list_del(&region->list);
-		put_pmem_file(region->file);
+		ion_unmap_kernel(region->client, region->handle);
+		ion_free(region->client, region->handle);
+		ion_client_destroy(region->client);
 		kfree(region);
 	}
 
 	return;
 }
 
-static void audlpa_unmap_pmem_region(struct audio *audio)
+static void audlpa_unmap_ion_region(struct audio *audio)
 {
-	struct audlpa_pmem_region *region;
+	struct audlpa_ion_region *region;
 	struct list_head *ptr, *next;
 	int rc = -EINVAL;
 
-	pr_debug("%s:\n", __func__);
-	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
-		region = list_entry(ptr, struct audlpa_pmem_region, list);
-		pr_debug("%s: phy_address = 0x%lx\n", __func__, region->paddr);
+	pr_debug("%s[%p]:\n", __func__, audio);
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audlpa_ion_region, list);
+		pr_debug("%s[%p]: phy_address = 0x%lx\n",
+			__func__, audio, region->paddr);
 		if (region != NULL) {
 			rc = q6asm_memory_unmap(audio->ac,
-						(uint32_t)region->paddr, IN);
+					(uint32_t)region->paddr, IN);
 			if (rc < 0)
 				pr_err("%s: memory unmap failed\n", __func__);
 		}
@@ -1081,12 +1134,12 @@
 	if (audio->out_enabled)
 		audlpa_async_flush(audio);
 	audio->wflush = 0;
-	audlpa_unmap_pmem_region(audio);
+	audlpa_unmap_ion_region(audio);
 	audio_disable(audio);
 	msm_clear_session_id(audio->ac->session);
 	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
 	q6asm_audio_client_free(audio->ac);
-	audlpa_reset_pmem_region(audio);
+	audlpa_reset_ion_region(audio);
 #ifdef CONFIG_HAS_EARLYSUSPEND
 	unregister_early_suspend(&audio->suspend_ctl.node);
 #endif
@@ -1096,7 +1149,6 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audlpa_reset_event_queue(audio);
-	pmem_kfree(audio->phys);
 	if (audio->stopped == 0)
 		audlpa_allow_sleep(audio);
 	wake_lock_destroy(&audio->wakelock);
@@ -1274,7 +1326,7 @@
 	spin_lock_init(&audio->dsp_lock);
 	init_waitqueue_head(&audio->write_wait);
 	INIT_LIST_HEAD(&audio->out_queue);
-	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->ion_region_queue);
 	INIT_LIST_HEAD(&audio->free_event_queue);
 	INIT_LIST_HEAD(&audio->event_queue);
 	init_waitqueue_head(&audio->wait);
@@ -1339,7 +1391,6 @@
 	return rc;
 err:
 	q6asm_audio_client_free(audio->ac);
-	pmem_kfree(audio->phys);
 	kfree(audio);
 	return rc;
 }
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.h b/arch/arm/mach-msm/qdsp6v2/audio_lpa.h
index ffc27ade..34b53f2 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -88,7 +88,7 @@
 
 	uint32_t device_events;
 
-	struct list_head pmem_region_queue; /* protected by lock */
+	struct list_head ion_region_queue; /* protected by lock */
 
 	int eq_enable;
 	int eq_needs_commit;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index c1b5e8b..d2557ca 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1,6 +1,6 @@
 /* Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -129,23 +129,23 @@
 	}
 }
 
-static int audio_aio_pmem_lookup_vaddr(struct q6audio_aio *audio, void *addr,
+static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
 					unsigned long len,
-					struct audio_aio_pmem_region **region)
+					struct audio_aio_ion_region **region)
 {
-	struct audio_aio_pmem_region *region_elt;
+	struct audio_aio_ion_region *region_elt;
 
 	int match_count = 0;
 
 	*region = NULL;
 
 	/* returns physical address or zero */
-	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
 		if (addr >= region_elt->vaddr &&
 			addr < region_elt->vaddr + region_elt->len &&
 			addr + len <= region_elt->vaddr + region_elt->len) {
 			/* offset since we could pass vaddr inside a registerd
-			* pmem buffer
+			* ion buffer
 			*/
 
 			match_count++;
@@ -157,7 +157,7 @@
 	if (match_count > 1) {
 		pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
 			__func__, audio, addr, len);
-		list_for_each_entry(region_elt, &audio->pmem_region_queue,
+		list_for_each_entry(region_elt, &audio->ion_region_queue,
 					list) {
 			if (addr >= region_elt->vaddr &&
 			addr < region_elt->vaddr + region_elt->len &&
@@ -173,14 +173,14 @@
 	return *region ? 0 : -1;
 }
 
-static unsigned long audio_aio_pmem_fixup(struct q6audio_aio *audio, void *addr,
+static unsigned long audio_aio_ion_fixup(struct q6audio_aio *audio, void *addr,
 				unsigned long len, int ref_up, void **kvaddr)
 {
-	struct audio_aio_pmem_region *region;
+	struct audio_aio_ion_region *region;
 	unsigned long paddr;
 	int ret;
 
-	ret = audio_aio_pmem_lookup_vaddr(audio, addr, len, &region);
+	ret = audio_aio_ion_lookup_vaddr(audio, addr, len, &region);
 	if (ret) {
 		pr_err("%s[%p]:lookup (%p, %ld) failed\n",
 				__func__, audio, addr, len);
@@ -519,15 +519,17 @@
 	return rc;
 }
 
-void audio_aio_reset_pmem_region(struct q6audio_aio *audio)
+void audio_aio_reset_ion_region(struct q6audio_aio *audio)
 {
-	struct audio_aio_pmem_region *region;
+	struct audio_aio_ion_region *region;
 	struct list_head *ptr, *next;
 
-	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
-		region = list_entry(ptr, struct audio_aio_pmem_region, list);
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audio_aio_ion_region, list);
 		list_del(&region->list);
-		put_pmem_file(region->file);
+		ion_unmap_kernel(region->client, region->handle);
+		ion_free(region->client, region->handle);
+		ion_client_destroy(region->client);
 		kfree(region);
 	}
 
@@ -558,15 +560,15 @@
 	return;
 }
 
-static void audio_aio_unmap_pmem_region(struct q6audio_aio *audio)
+static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
 {
-	struct audio_aio_pmem_region *region;
+	struct audio_aio_ion_region *region;
 	struct list_head *ptr, *next;
 	int rc = -EINVAL;
 
 	pr_debug("%s[%p]:\n", __func__, audio);
-	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
-		region = list_entry(ptr, struct audio_aio_pmem_region, list);
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audio_aio_ion_region, list);
 		pr_debug("%s[%p]: phy_address = 0x%lx\n",
 				__func__, audio, region->paddr);
 		if (region != NULL) {
@@ -590,9 +592,9 @@
 	audio->wflush = 0;
 	audio->drv_ops.out_flush(audio);
 	audio->drv_ops.in_flush(audio);
-	audio_aio_unmap_pmem_region(audio);
+	audio_aio_unmap_ion_region(audio);
 	audio_aio_disable(audio);
-	audio_aio_reset_pmem_region(audio);
+	audio_aio_reset_ion_region(audio);
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audio_aio_reset_event_queue(audio);
@@ -746,14 +748,14 @@
 		pr_debug("%s[%p]:posted AUDIO_EVENT_WRITE_DONE to user\n",
 			__func__, audio);
 		mutex_lock(&audio->write_lock);
-		audio_aio_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+		audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
 		drv_evt->payload.aio_buf.buf_len, 0, 0);
 		mutex_unlock(&audio->write_lock);
 	} else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
 		pr_debug("%s[%p]:posted AUDIO_EVENT_READ_DONE to user\n",
 			__func__, audio);
 		mutex_lock(&audio->read_lock);
-		audio_aio_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+		audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
 		drv_evt->payload.aio_buf.buf_len, 0, 0);
 		mutex_unlock(&audio->read_lock);
 	}
@@ -773,13 +775,13 @@
 	return rc;
 }
 
-static int audio_aio_pmem_check(struct q6audio_aio *audio,
+static int audio_aio_ion_check(struct q6audio_aio *audio,
 				void *vaddr, unsigned long len)
 {
-	struct audio_aio_pmem_region *region_elt;
-	struct audio_aio_pmem_region t = {.vaddr = vaddr, .len = len };
+	struct audio_aio_ion_region *region_elt;
+	struct audio_aio_ion_region t = {.vaddr = vaddr, .len = len };
 
-	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
 		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
 			OVERLAPS(region_elt, &t)) {
 			pr_err("%s[%p]:region (vaddr %p len %ld)"
@@ -795,13 +797,18 @@
 	return 0;
 }
 
-static int audio_aio_pmem_add(struct q6audio_aio *audio,
-				struct msm_audio_pmem_info *info)
+static int audio_aio_ion_add(struct q6audio_aio *audio,
+				struct msm_audio_ion_info *info)
 {
-	unsigned long paddr, kvaddr, len;
-	struct file *file;
-	struct audio_aio_pmem_region *region;
+	ion_phys_addr_t paddr;
+	size_t len;
+	unsigned long kvaddr;
+	struct audio_aio_ion_region *region;
 	int rc = -EINVAL;
+	struct ion_handle *handle;
+	struct ion_client *client;
+	unsigned long ionflag;
+	void *temp_ptr;
 
 	pr_debug("%s[%p]:\n", __func__, audio);
 	region = kmalloc(sizeof(*region), GFP_KERNEL);
@@ -811,50 +818,89 @@
 		goto end;
 	}
 
-	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
-		kfree(region);
-		goto end;
+	client = msm_ion_client_create(UINT_MAX, "Audio_Dec_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
+		goto client_error;
 	}
 
-	rc = audio_aio_pmem_check(audio, info->vaddr, len);
+	handle = ion_import_fd(client, info->fd);
+	if (IS_ERR_OR_NULL(handle)) {
+		pr_err("%s: could not get handle of the given fd\n", __func__);
+		goto import_error;
+	}
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		pr_err("%s: could not get flags for the handle\n", __func__);
+		goto flag_error;
+	}
+
+	temp_ptr = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR_OR_NULL(temp_ptr)) {
+		pr_err("%s: could not get virtual address\n", __func__);
+		goto map_error;
+	}
+	kvaddr = (unsigned long)temp_ptr;
+
+	rc = ion_phys(client, handle, &paddr, &len);
+	if (rc) {
+		pr_err("%s: could not get physical address\n", __func__);
+		goto ion_error;
+	}
+
+	rc = audio_aio_ion_check(audio, info->vaddr, len);
 	if (rc < 0) {
-		put_pmem_file(file);
-		kfree(region);
-		goto end;
+		pr_err("%s: audio_aio_ion_check failed\n", __func__);
+		goto ion_error;
 	}
 
+	region->client = client;
+	region->handle = handle;
 	region->vaddr = info->vaddr;
 	region->fd = info->fd;
 	region->paddr = paddr;
 	region->kvaddr = kvaddr;
 	region->len = len;
-	region->file = file;
 	region->ref_cnt = 0;
 	pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
 		__func__, audio,
 		region->paddr, region->vaddr, region->len, region->kvaddr);
-	list_add_tail(&region->list, &audio->pmem_region_queue);
-
+	list_add_tail(&region->list, &audio->ion_region_queue);
 	rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
 				1);
-	if (rc < 0)
+	if (rc < 0) {
 		pr_err("%s[%p]: memory map failed\n", __func__, audio);
+		goto ion_error;
+	} else {
+		goto end;
+	}
+
+ion_error:
+	ion_unmap_kernel(client, handle);
+map_error:
+	ion_free(client, handle);
+flag_error:
+import_error:
+	ion_client_destroy(client);
+client_error:
+	kfree(region);
 end:
 	return rc;
 }
 
-static int audio_aio_pmem_remove(struct q6audio_aio *audio,
-				struct msm_audio_pmem_info *info)
+static int audio_aio_ion_remove(struct q6audio_aio *audio,
+				struct msm_audio_ion_info *info)
 {
-	struct audio_aio_pmem_region *region;
+	struct audio_aio_ion_region *region;
 	struct list_head *ptr, *next;
 	int rc = -EINVAL;
 
 	pr_debug("%s[%p]:info fd %d vaddr %p\n",
 		__func__, audio, info->fd, info->vaddr);
 
-	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
-		region = list_entry(ptr, struct audio_aio_pmem_region, list);
+	list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audio_aio_ion_region, list);
 
 		if ((region->fd == info->fd) &&
 			(region->vaddr == info->vaddr)) {
@@ -873,7 +919,9 @@
 					__func__, audio);
 
 			list_del(&region->list);
-			put_pmem_file(region->file);
+			ion_unmap_kernel(region->client, region->handle);
+			ion_free(region->client, region->handle);
+			ion_client_destroy(region->client);
 			kfree(region);
 			rc = 0;
 			break;
@@ -989,8 +1037,7 @@
 	pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len \
 		%d\n", __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
 		buf_node->buf.buf_len, buf_node->buf.data_len);
-
-	buf_node->paddr = audio_aio_pmem_fixup(audio, buf_node->buf.buf_addr,
+	buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
 						buf_node->buf.buf_len, 1,
 						&buf_node->kvaddr);
 	if (dir) {
@@ -1125,7 +1172,7 @@
 	init_waitqueue_head(&audio->event_wait);
 	INIT_LIST_HEAD(&audio->out_queue);
 	INIT_LIST_HEAD(&audio->in_queue);
-	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->ion_region_queue);
 	INIT_LIST_HEAD(&audio->free_event_queue);
 	INIT_LIST_HEAD(&audio->event_queue);
 
@@ -1281,25 +1328,25 @@
 		mutex_unlock(&audio->lock);
 		break;
 	}
-	case AUDIO_REGISTER_PMEM: {
-		struct msm_audio_pmem_info info;
-		pr_debug("%s[%p]:AUDIO_REGISTER_PMEM\n", __func__, audio);
+	case AUDIO_REGISTER_ION: {
+		struct msm_audio_ion_info info;
+		pr_debug("%s[%p]:AUDIO_REGISTER_ION\n", __func__, audio);
 		mutex_lock(&audio->lock);
 		if (copy_from_user(&info, (void *)arg, sizeof(info)))
 			rc = -EFAULT;
 		else
-			rc = audio_aio_pmem_add(audio, &info);
+			rc = audio_aio_ion_add(audio, &info);
 		mutex_unlock(&audio->lock);
 		break;
 	}
-	case AUDIO_DEREGISTER_PMEM: {
-		struct msm_audio_pmem_info info;
+	case AUDIO_DEREGISTER_ION: {
+		struct msm_audio_ion_info info;
 		mutex_lock(&audio->lock);
-		pr_debug("%s[%p]:AUDIO_DEREGISTER_PMEM\n", __func__, audio);
+		pr_debug("%s[%p]:AUDIO_DEREGISTER_ION\n", __func__, audio);
 		if (copy_from_user(&info, (void *)arg, sizeof(info)))
 			rc = -EFAULT;
 		else
-			rc = audio_aio_pmem_remove(audio, &info);
+			rc = audio_aio_ion_remove(audio, &info);
 		mutex_unlock(&audio->lock);
 		break;
 	}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index ebf3668..a25ca4d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -1,6 +1,6 @@
 /* Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -23,15 +23,13 @@
 #include <linux/msm_audio.h>
 #include <linux/debugfs.h>
 #include <linux/list.h>
-#include <linux/android_pmem.h>
 #include <linux/slab.h>
+#include <linux/ion.h>
 #include <asm/ioctls.h>
 #include <asm/atomic.h>
 #include <sound/q6asm.h>
 #include <sound/apr_audio.h>
 
-
-
 #define TUNNEL_MODE     0x0000
 #define NON_TUNNEL_MODE 0x0001
 
@@ -114,9 +112,10 @@
 #define FRAME_NUM               (2)
 #define FRAME_SIZE	((4*1536) + sizeof(struct dec_meta_in))
 
-struct audio_aio_pmem_region {
+struct audio_aio_ion_region {
 	struct list_head list;
-	struct file *file;
+	struct ion_handle *handle;
+	struct ion_client *client;
 	int fd;
 	void *vaddr;
 	unsigned long paddr;
@@ -174,7 +173,7 @@
 	struct list_head in_queue;      /* queue to retain input buffers */
 	struct list_head free_event_queue;
 	struct list_head event_queue;
-	struct list_head pmem_region_queue;     /* protected by lock */
+	struct list_head ion_region_queue;     /* protected by lock */
 	struct audio_aio_drv_operations drv_ops;
 	union msm_audio_event_payload eos_write_payload;
 
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in.c b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
index 1f20aa7..667628c 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2009 Google, Inc.
  * Copyright (C) 2009 HTC Corporation
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -72,6 +72,9 @@
 	case ASM_DATA_EVENT_READ_DONE:
 		pcm_in_get_dsp_buffers(pcm, token, payload);
 		break;
+	case RESET_EVENTS:
+		reset_device();
+		break;
 	default:
 		break;
 	}
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_out.c b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
index a4a6b728..733d5e3 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_out.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 Google, Inc.
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -66,6 +66,9 @@
 		atomic_inc(&pcm->out_count);
 		wake_up(&pcm->write_wait);
 		break;
+	case RESET_EVENTS:
+		reset_device();
+		break;
 	default:
 		break;
 	}
diff --git a/arch/arm/mach-msm/qdss-ptm.c b/arch/arm/mach-msm/qdss-etm.c
similarity index 100%
rename from arch/arm/mach-msm/qdss-ptm.c
rename to arch/arm/mach-msm/qdss-etm.c
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index 6794a88..cdb0cbe 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -333,6 +333,38 @@
 }
 EXPORT_SYMBOL(scm_call_atomic2);
 
+s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2,
+		u32 arg3, u32 arg4, u32 *ret1, u32 *ret2)
+{
+	int ret;
+	int context_id;
+	register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 4);
+	register u32 r1 asm("r1") = (u32)&context_id;
+	register u32 r2 asm("r2") = arg1;
+	register u32 r3 asm("r3") = arg2;
+	register u32 r4 asm("r4") = arg3;
+	register u32 r5 asm("r5") = arg4;
+
+	asm volatile(
+		__asmeq("%0", "r0")
+		__asmeq("%1", "r1")
+		__asmeq("%2", "r2")
+		__asmeq("%3", "r0")
+		__asmeq("%4", "r1")
+		__asmeq("%5", "r2")
+		__asmeq("%6", "r3")
+		"smc	#0	@ switch to secure world\n"
+		: "=r" (r0), "=r" (r1), "=r" (r2)
+		: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5));
+	ret = r0;
+	if (ret1)
+		*ret1 = r1;
+	if (ret2)
+		*ret2 = r2;
+	return r0;
+}
+EXPORT_SYMBOL(scm_call_atomic4_3);
+
 u32 scm_get_version(void)
 {
 	int context_id;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index bca1e0c..9321b40 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -72,6 +72,7 @@
 	MSM_SMSM_DEBUG = 1U << 1,
 	MSM_SMD_INFO = 1U << 2,
 	MSM_SMSM_INFO = 1U << 3,
+	MSM_SMx_POWER_INFO = 1U << 4,
 };
 
 struct smsm_shared_info {
@@ -117,29 +118,34 @@
 };
 
 static irqreturn_t smd_modem_irq_handler(int irq, void *data);
+static irqreturn_t smsm_modem_irq_handler(int irq, void *data);
 static irqreturn_t smd_dsp_irq_handler(int irq, void *data);
+static irqreturn_t smsm_dsp_irq_handler(int irq, void *data);
 static irqreturn_t smd_dsps_irq_handler(int irq, void *data);
+static irqreturn_t smsm_dsps_irq_handler(int irq, void *data);
 static irqreturn_t smd_wcnss_irq_handler(int irq, void *data);
+static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data);
 static irqreturn_t smsm_irq_handler(int irq, void *data);
 
 static struct interrupt_config private_intr_config[NUM_SMD_SUBSYSTEMS] = {
 	[SMD_MODEM] = {
 		.smd.irq_handler = smd_modem_irq_handler,
-		.smsm.irq_handler = smsm_irq_handler,
+		.smsm.irq_handler = smsm_modem_irq_handler,
 	},
 	[SMD_Q6] = {
 		.smd.irq_handler = smd_dsp_irq_handler,
-		.smsm.irq_handler = smsm_irq_handler,
+		.smsm.irq_handler = smsm_dsp_irq_handler,
 	},
 	[SMD_DSPS] = {
 		.smd.irq_handler = smd_dsps_irq_handler,
-		.smsm.irq_handler = smsm_irq_handler,
+		.smsm.irq_handler = smsm_dsps_irq_handler,
 	},
 	[SMD_WCNSS] = {
 		.smd.irq_handler = smd_wcnss_irq_handler,
-		.smsm.irq_handler = smsm_irq_handler,
+		.smsm.irq_handler = smsm_wcnss_irq_handler,
 	},
 };
+struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
 
 #define SMSM_STATE_ADDR(entry)           (smsm_info.state + entry)
 #define SMSM_INTR_MASK_ADDR(entry, host) (smsm_info.intr_mask + \
@@ -175,11 +181,16 @@
 		if (msm_smd_debug_mask & MSM_SMSM_INFO) \
 			printk(KERN_INFO x);		\
 	} while (0)
+#define SMx_POWER_INFO(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMx_POWER_INFO) \
+			printk(KERN_INFO x);		\
+	} while (0)
 #else
 #define SMD_DBG(x...) do { } while (0)
 #define SMSM_DBG(x...) do { } while (0)
 #define SMD_INFO(x...) do { } while (0)
 #define SMSM_INFO(x...) do { } while (0)
+#define SMx_POWER_INFO(x...) do { } while (0)
 #endif
 
 static unsigned last_heap_free = 0xffffffff;
@@ -214,24 +225,6 @@
 #define MSM_TRIG_A2DSPS_SMSM_INT
 #define MSM_TRIG_A2WCNSS_SMD_INT
 #define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_MSM8930) || \
-	defined(CONFIG_ARCH_APQ8064)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1 << 3, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMD_INT    \
-			(smd_write_intr(1 << 15, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1 << 4, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT   \
-			(smd_write_intr(1 << 14, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT  \
-			(smd_write_intr(1, MSM_SIC_NON_SECURE_BASE + 0x4080))
-#define MSM_TRIG_A2DSPS_SMSM_INT \
-			(smd_write_intr(1, MSM_SIC_NON_SECURE_BASE + 0x4094))
-#define MSM_TRIG_A2WCNSS_SMD_INT  \
-			(smd_write_intr(1 << 25, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2WCNSS_SMSM_INT  \
-			(smd_write_intr(1 << 23, MSM_APCS_GCC_BASE + 0x8))
 #elif defined(CONFIG_ARCH_MSM9615)
 #define MSM_TRIG_A2M_SMD_INT     \
 			(smd_write_intr(1 << 3, MSM_APCS_GCC_BASE + 0x8))
@@ -258,15 +251,33 @@
 #define MSM_TRIG_A2DSPS_SMSM_INT
 #define MSM_TRIG_A2WCNSS_SMD_INT
 #define MSM_TRIG_A2WCNSS_SMSM_INT
-#else
+#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7x25)
 #define MSM_TRIG_A2M_SMD_INT     \
 			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
-#define MSM_TRIG_A2Q6_SMD_INT    \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (8) * 4))
+#define MSM_TRIG_A2Q6_SMD_INT
 #define MSM_TRIG_A2M_SMSM_INT    \
 			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
-#define MSM_TRIG_A2Q6_SMSM_INT   \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (8) * 4))
+#define MSM_TRIG_A2Q6_SMSM_INT
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM7X27A)
+#define MSM_TRIG_A2M_SMD_INT     \
+			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
+#define MSM_TRIG_A2Q6_SMD_INT
+#define MSM_TRIG_A2M_SMSM_INT    \
+			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
+#define MSM_TRIG_A2Q6_SMSM_INT
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#else /* use platform device / device tree configuration */
+#define MSM_TRIG_A2M_SMD_INT
+#define MSM_TRIG_A2Q6_SMD_INT
+#define MSM_TRIG_A2M_SMSM_INT
+#define MSM_TRIG_A2Q6_SMSM_INT
 #define MSM_TRIG_A2DSPS_SMD_INT
 #define MSM_TRIG_A2DSPS_SMSM_INT
 #define MSM_TRIG_A2WCNSS_SMD_INT
@@ -349,33 +360,42 @@
 {
 	static const struct interrupt_config_item *intr
 	   = &private_intr_config[SMD_MODEM].smd;
-	if (intr->out_base)
+	if (intr->out_base) {
+		++interrupt_stats[SMD_MODEM].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	else
+	} else {
+		++interrupt_stats[SMD_MODEM].smd_out_hardcode_count;
 		MSM_TRIG_A2M_SMD_INT;
+	}
 }
 
 static inline void notify_dsp_smd(void)
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_Q6].smd;
-	if (intr->out_base)
+	if (intr->out_base) {
+		++interrupt_stats[SMD_Q6].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	else
+	} else {
+		++interrupt_stats[SMD_Q6].smd_out_hardcode_count;
 		MSM_TRIG_A2Q6_SMD_INT;
+	}
 }
 
 static inline void notify_dsps_smd(void)
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_DSPS].smd;
-	if (intr->out_base)
+	if (intr->out_base) {
+		++interrupt_stats[SMD_DSPS].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	else
+	} else {
+		++interrupt_stats[SMD_DSPS].smd_out_hardcode_count;
 		MSM_TRIG_A2DSPS_SMD_INT;
+	}
 }
 
 static inline void notify_wcnss_smd(void)
@@ -384,44 +404,56 @@
 		= &private_intr_config[SMD_WCNSS].smd;
 	wakeup_v1_riva();
 
-	if (intr->out_base)
+	if (intr->out_base) {
+		++interrupt_stats[SMD_WCNSS].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	else
+	} else {
+		++interrupt_stats[SMD_WCNSS].smd_out_hardcode_count;
 		MSM_TRIG_A2WCNSS_SMD_INT;
+	}
 }
 
 static inline void notify_modem_smsm(void)
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_MODEM].smsm;
-	if (intr->out_base)
+	if (intr->out_base) {
+		++interrupt_stats[SMD_MODEM].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	else
+	} else {
+		++interrupt_stats[SMD_MODEM].smsm_out_hardcode_count;
 		MSM_TRIG_A2M_SMSM_INT;
+	}
 }
 
 static inline void notify_dsp_smsm(void)
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_Q6].smsm;
-	if (intr->out_base)
+	if (intr->out_base) {
+		++interrupt_stats[SMD_Q6].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	else
+	} else {
+		++interrupt_stats[SMD_Q6].smsm_out_hardcode_count;
 		MSM_TRIG_A2Q6_SMSM_INT;
+	}
 }
 
 static inline void notify_dsps_smsm(void)
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_DSPS].smsm;
-	if (intr->out_base)
+	if (intr->out_base) {
+		++interrupt_stats[SMD_DSPS].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	else
+	} else {
+		++interrupt_stats[SMD_DSPS].smsm_out_hardcode_count;
 		MSM_TRIG_A2DSPS_SMSM_INT;
+	}
 }
 
 static inline void notify_wcnss_smsm(void)
@@ -430,11 +462,14 @@
 		= &private_intr_config[SMD_WCNSS].smsm;
 	wakeup_v1_riva();
 
-	if (intr->out_base)
+	if (intr->out_base) {
+		++interrupt_stats[SMD_WCNSS].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	else
+	} else {
+		++interrupt_stats[SMD_WCNSS].smsm_out_hardcode_count;
 		MSM_TRIG_A2WCNSS_SMSM_INT;
+	}
 }
 
 static void notify_other_smsm(uint32_t smsm_entry, uint32_t notify_mask)
@@ -589,27 +624,28 @@
 struct edge_to_pid {
 	uint32_t	local_pid;
 	uint32_t	remote_pid;
+	char		subsys_name[SMD_MAX_CH_NAME_LEN];
 };
 
 /**
  * Maps edge type to local and remote processor ID's.
  */
 static struct edge_to_pid edge_to_pids[] = {
-	[SMD_APPS_MODEM] = {SMSM_APPS, SMSM_MODEM},
-	[SMD_APPS_QDSP] = {SMSM_APPS, SMSM_Q6},
-	[SMD_MODEM_QDSP] = {SMSM_MODEM, SMSM_Q6},
-	[SMD_APPS_DSPS] = {SMSM_APPS, SMSM_DSPS},
-	[SMD_MODEM_DSPS] = {SMSM_MODEM, SMSM_DSPS},
-	[SMD_QDSP_DSPS] = {SMSM_Q6, SMSM_DSPS},
-	[SMD_APPS_WCNSS] = {SMSM_APPS, SMSM_WCNSS},
-	[SMD_MODEM_WCNSS] = {SMSM_MODEM, SMSM_WCNSS},
-	[SMD_QDSP_WCNSS] = {SMSM_Q6, SMSM_WCNSS},
-	[SMD_DSPS_WCNSS] = {SMSM_DSPS, SMSM_WCNSS},
-	[SMD_APPS_Q6FW] = {SMSM_APPS, SMD_MODEM_Q6_FW},
-	[SMD_MODEM_Q6FW] = {SMSM_MODEM, SMD_MODEM_Q6_FW},
-	[SMD_QDSP_Q6FW] = {SMSM_Q6, SMD_MODEM_Q6_FW},
-	[SMD_DSPS_Q6FW] = {SMSM_DSPS, SMD_MODEM_Q6_FW},
-	[SMD_WCNSS_Q6FW] = {SMSM_WCNSS, SMD_MODEM_Q6_FW},
+	[SMD_APPS_MODEM] = {SMD_APPS, SMD_MODEM, "modem"},
+	[SMD_APPS_QDSP] = {SMD_APPS, SMD_Q6, "q6"},
+	[SMD_MODEM_QDSP] = {SMD_MODEM, SMD_Q6},
+	[SMD_APPS_DSPS] = {SMD_APPS, SMD_DSPS, "dsps"},
+	[SMD_MODEM_DSPS] = {SMD_MODEM, SMD_DSPS},
+	[SMD_QDSP_DSPS] = {SMD_Q6, SMD_DSPS},
+	[SMD_APPS_WCNSS] = {SMD_APPS, SMD_WCNSS, "wcnss"},
+	[SMD_MODEM_WCNSS] = {SMD_MODEM, SMD_WCNSS},
+	[SMD_QDSP_WCNSS] = {SMD_Q6, SMD_WCNSS},
+	[SMD_DSPS_WCNSS] = {SMD_DSPS, SMD_WCNSS},
+	[SMD_APPS_Q6FW] = {SMD_APPS, SMD_MODEM_Q6_FW},
+	[SMD_MODEM_Q6FW] = {SMD_MODEM, SMD_MODEM_Q6_FW},
+	[SMD_QDSP_Q6FW] = {SMD_Q6, SMD_MODEM_Q6_FW},
+	[SMD_DSPS_Q6FW] = {SMD_DSPS, SMD_MODEM_Q6_FW},
+	[SMD_WCNSS_Q6FW] = {SMD_WCNSS, SMD_MODEM_Q6_FW},
 };
 
 struct restart_notifier_block {
@@ -721,6 +757,50 @@
 	return ret;
 }
 
+/*
+ * Returns a pointer to the subsystem name or NULL if no
+ * subsystem name is available.
+ *
+ * @type - Edge definition
+ */
+const char *smd_edge_to_subsystem(uint32_t type)
+{
+	const char *subsys = NULL;
+
+	if (type < ARRAY_SIZE(edge_to_pids)) {
+		subsys = edge_to_pids[type].subsys_name;
+		if (subsys[0] == 0x0)
+			subsys = NULL;
+	}
+	return subsys;
+}
+EXPORT_SYMBOL(smd_edge_to_subsystem);
+
+/*
+ * Returns a pointer to the subsystem name given the
+ * remote processor ID.
+ *
+ * @pid     Remote processor ID
+ * @returns Pointer to subsystem name or NULL if not found
+ */
+const char *smd_pid_to_subsystem(uint32_t pid)
+{
+	const char *subsys = NULL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(edge_to_pids); ++i) {
+		if (pid == edge_to_pids[i].remote_pid &&
+			edge_to_pids[i].subsys_name[0] != 0x0
+			) {
+			subsys = edge_to_pids[i].subsys_name;
+			break;
+		}
+	}
+
+	return subsys;
+}
+EXPORT_SYMBOL(smd_pid_to_subsystem);
+
 static void smd_reset_edge(struct smd_half_channel *ch, unsigned new_state)
 {
 	if (ch->state != SMD_SS_CLOSED) {
@@ -796,9 +876,10 @@
 
 		/* notify SMSM processors */
 		smsm_irq_handler(0, 0);
-		MSM_TRIG_A2M_SMSM_INT;
-		MSM_TRIG_A2Q6_SMSM_INT;
-		MSM_TRIG_A2DSPS_SMSM_INT;
+		notify_modem_smsm();
+		notify_dsp_smsm();
+		notify_dsps_smsm();
+		notify_wcnss_smsm();
 	}
 
 	/* change all remote states to CLOSING */
@@ -1110,15 +1191,24 @@
 		}
 		tmp = ch->recv->state;
 		if (tmp != ch->last_state) {
+			SMx_POWER_INFO("SMD ch%d '%s' State change %d->%d\n",
+					ch->n, ch->name, ch->last_state, tmp);
 			smd_state_change(ch, ch->last_state, tmp);
 			state_change = 1;
 		}
-		if (ch_flags) {
+		if (ch_flags & 0x3) {
 			ch->update_state(ch);
+			SMx_POWER_INFO("SMD ch%d '%s' Data event r%d/w%d\n",
+					ch->n, ch->name,
+					ch->read_avail(ch),
+					ch->fifo_size - ch->write_avail(ch));
 			ch->notify(ch->priv, SMD_EVENT_DATA);
 		}
-		if (ch_flags & 0x4 && !state_change)
+		if (ch_flags & 0x4 && !state_change) {
+			SMx_POWER_INFO("SMD ch%d '%s' State update\n",
+					ch->n, ch->name);
 			ch->notify(ch->priv, SMD_EVENT_STATUS);
+		}
 	}
 	spin_unlock_irqrestore(&smd_lock, flags);
 	do_smd_probe();
@@ -1126,6 +1216,8 @@
 
 static irqreturn_t smd_modem_irq_handler(int irq, void *data)
 {
+	SMx_POWER_INFO("SMD Int Modem->Apps\n");
+	++interrupt_stats[SMD_MODEM].smd_in_count;
 	handle_smd_irq(&smd_ch_list_modem, notify_modem_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
@@ -1133,6 +1225,8 @@
 
 static irqreturn_t smd_dsp_irq_handler(int irq, void *data)
 {
+	SMx_POWER_INFO("SMD Int LPASS->Apps\n");
+	++interrupt_stats[SMD_Q6].smd_in_count;
 	handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
@@ -1140,6 +1234,8 @@
 
 static irqreturn_t smd_dsps_irq_handler(int irq, void *data)
 {
+	SMx_POWER_INFO("SMD Int DSPS->Apps\n");
+	++interrupt_stats[SMD_DSPS].smd_in_count;
 	handle_smd_irq(&smd_ch_list_dsps, notify_dsps_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
@@ -1147,6 +1243,8 @@
 
 static irqreturn_t smd_wcnss_irq_handler(int irq, void *data)
 {
+	SMx_POWER_INFO("SMD Int WCNSS->Apps\n");
+	++interrupt_stats[SMD_WCNSS].smd_in_count;
 	handle_smd_irq(&smd_ch_list_wcnss, notify_wcnss_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
@@ -2286,6 +2384,34 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t smsm_modem_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMSM Int Modem->Apps\n");
+	++interrupt_stats[SMD_MODEM].smsm_in_count;
+	return smsm_irq_handler(irq, data);
+}
+
+static irqreturn_t smsm_dsp_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMSM Int LPASS->Apps\n");
+	++interrupt_stats[SMD_Q6].smsm_in_count;
+	return smsm_irq_handler(irq, data);
+}
+
+static irqreturn_t smsm_dsps_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMSM Int DSPS->Apps\n");
+	++interrupt_stats[SMD_DSPS].smsm_in_count;
+	return smsm_irq_handler(irq, data);
+}
+
+static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data)
+{
+	SMx_POWER_INFO("SMSM Int WCNSS->Apps\n");
+	++interrupt_stats[SMD_WCNSS].smsm_in_count;
+	return smsm_irq_handler(irq, data);
+}
+
 int smsm_change_intr_mask(uint32_t smsm_entry,
 			  uint32_t clear_mask, uint32_t set_mask)
 {
@@ -2417,6 +2543,9 @@
 
 			state_changes = state_info->last_value ^ new_state;
 			if (state_changes) {
+				SMx_POWER_INFO("SMSM Change %d: %08x->%08x\n",
+						n, state_info->last_value,
+						new_state);
 				list_for_each_entry(cb_info,
 					&state_info->callbacks, cb_list) {
 
@@ -2567,7 +2696,7 @@
 		pr_err("smd_core_init: "
 		       "enable_irq_wake failed for INT_A9_M2A_0\n");
 
-	r = request_irq(INT_A9_M2A_5, smsm_irq_handler,
+	r = request_irq(INT_A9_M2A_5, smsm_modem_irq_handler,
 			flags, "smsm_dev", 0);
 	if (r < 0) {
 		free_irq(INT_A9_M2A_0, 0);
@@ -2590,8 +2719,8 @@
 		return r;
 	}
 
-	r = request_irq(INT_ADSP_A11_SMSM, smsm_irq_handler,
-			flags, "smsm_dev", smsm_irq_handler);
+	r = request_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler,
+			flags, "smsm_dev", smsm_dsp_irq_handler);
 	if (r < 0) {
 		free_irq(INT_A9_M2A_0, 0);
 		free_irq(INT_A9_M2A_5, 0);
@@ -2620,7 +2749,7 @@
 		free_irq(INT_A9_M2A_0, 0);
 		free_irq(INT_A9_M2A_5, 0);
 		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
 		return r;
 	}
 
@@ -2637,7 +2766,7 @@
 		free_irq(INT_A9_M2A_0, 0);
 		free_irq(INT_A9_M2A_5, 0);
 		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
 		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
 		return r;
 	}
@@ -2647,13 +2776,13 @@
 		pr_err("smd_core_init: "
 		       "enable_irq_wake failed for INT_WCNSS_A11\n");
 
-	r = request_irq(INT_WCNSS_A11_SMSM, smsm_irq_handler,
-			flags, "smsm_dev", smsm_irq_handler);
+	r = request_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler,
+			flags, "smsm_dev", smsm_wcnss_irq_handler);
 	if (r < 0) {
 		free_irq(INT_A9_M2A_0, 0);
 		free_irq(INT_A9_M2A_5, 0);
 		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
 		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
 		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
 		return r;
@@ -2666,16 +2795,16 @@
 #endif
 
 #if defined(CONFIG_DSPS_SMSM)
-	r = request_irq(INT_DSPS_A11_SMSM, smsm_irq_handler,
-			flags, "smsm_dev", smsm_irq_handler);
+	r = request_irq(INT_DSPS_A11_SMSM, smsm_dsps_irq_handler,
+			flags, "smsm_dev", smsm_dsps_irq_handler);
 	if (r < 0) {
 		free_irq(INT_A9_M2A_0, 0);
 		free_irq(INT_A9_M2A_5, 0);
 		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
 		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
 		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
-		free_irq(INT_WCNSS_A11_SMSM, smsm_irq_handler);
+		free_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler);
 		return r;
 	}
 
@@ -2770,6 +2899,9 @@
 				cfg->smsm_int.irq_name);
 			break;
 		}
+
+		strncpy(edge_to_pids[cfg->edge].subsys_name,
+				cfg->subsys_name, SMD_MAX_CH_NAME_LEN);
 	}
 
 	if (err_ret < 0) {
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index b95a35c..764102d 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -95,6 +95,61 @@
 	return max;
 }
 
+static int debug_int_stats(char *buf, int max)
+{
+	int i = 0;
+	int subsys;
+	struct interrupt_stat *stats = interrupt_stats;
+	const char *subsys_name;
+
+	i += scnprintf(buf + i, max - i,
+		"   Subsystem    |     In    | Out (Hardcoded) |"
+		" Out (Configured) |\n");
+
+	for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
+		subsys_name = smd_pid_to_subsystem(subsys);
+		if (subsys_name) {
+			i += scnprintf(buf + i, max - i,
+				"%-10s %4s | %9u |       %9u |        %9u |\n",
+				smd_pid_to_subsystem(subsys), "smd",
+				stats->smd_in_count,
+				stats->smd_out_hardcode_count,
+				stats->smd_out_config_count);
+
+			i += scnprintf(buf + i, max - i,
+				"%-10s %4s | %9u |       %9u |        %9u |\n",
+				smd_pid_to_subsystem(subsys), "smsm",
+				stats->smsm_in_count,
+				stats->smsm_out_hardcode_count,
+				stats->smsm_out_config_count);
+		}
+		++stats;
+	}
+
+	return i;
+}
+
+static int debug_int_stats_reset(char *buf, int max)
+{
+	int i = 0;
+	int subsys;
+	struct interrupt_stat *stats = interrupt_stats;
+
+	i += scnprintf(buf + i, max - i, "Resetting interrupt stats.\n");
+
+	for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
+		stats->smd_in_count = 0;
+		stats->smd_out_hardcode_count = 0;
+		stats->smd_out_config_count = 0;
+		stats->smsm_in_count = 0;
+		stats->smsm_out_hardcode_count = 0;
+		stats->smsm_out_config_count = 0;
+		++stats;
+	}
+
+	return i;
+}
+
 static int debug_diag(char *buf, int max)
 {
 	int i = 0;
@@ -694,6 +749,8 @@
 	debug_create("modem_err_f3", 0444, dent, debug_modem_err_f3);
 	debug_create("print_diag", 0444, dent, debug_diag);
 	debug_create("print_f3", 0444, dent, debug_f3);
+	debug_create("int_stats", 0444, dent, debug_int_stats);
+	debug_create("int_stats_reset", 0444, dent, debug_int_stats_reset);
 
 	/* NNV: this is google only stuff */
 	debug_create("build", 0444, dent, debug_read_build_id);
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index aeffbfd..542d224 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -607,7 +607,7 @@
 {
 	int r = 0;
 	struct smd_pkt_dev *smd_pkt_devp;
-	char *peripheral = NULL;
+	const char *peripheral = NULL;
 
 	smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev);
 
@@ -622,17 +622,25 @@
 
 	mutex_lock(&smd_pkt_devp->ch_lock);
 	if (smd_pkt_devp->ch == 0) {
+		init_completion(&smd_pkt_devp->ch_allocated);
+		smd_pkt_devp->driver.probe = smd_pkt_dummy_probe;
+		smd_pkt_devp->driver.driver.name =
+			smd_ch_name[smd_pkt_devp->i];
+		smd_pkt_devp->driver.driver.owner = THIS_MODULE;
+		r = platform_driver_register(&smd_pkt_devp->driver);
+		if (r) {
+			pr_err("%s: %s Platform driver reg. failed\n",
+				__func__, smd_ch_name[smd_pkt_devp->i]);
+			goto out;
+		}
 
-		if (smd_ch_edge[smd_pkt_devp->i] == SMD_APPS_MODEM)
-			peripheral = "modem";
-		else if (smd_ch_edge[smd_pkt_devp->i] == SMD_APPS_QDSP)
-			peripheral = "q6";
-
+		peripheral = smd_edge_to_subsystem(
+				smd_ch_edge[smd_pkt_devp->i]);
 		if (peripheral) {
 			smd_pkt_devp->pil = pil_get(peripheral);
 			if (IS_ERR(smd_pkt_devp->pil)) {
 				r = PTR_ERR(smd_pkt_devp->pil);
-				goto out;
+				goto release_pd;
 			}
 
 			/* Wait for the modem SMSM to be inited for the SMD
@@ -701,6 +709,10 @@
 release_pil:
 	if (peripheral && (r < 0))
 		pil_put(smd_pkt_devp->pil);
+
+release_pd:
+	if (r < 0)
+		platform_driver_unregister(&smd_pkt_devp->driver);
 out:
 	mutex_unlock(&smd_pkt_devp->ch_lock);
 
@@ -726,6 +738,7 @@
 		smd_pkt_devp->ch = 0;
 		smd_pkt_devp->blocking_write = 0;
 		smd_pkt_devp->poll_mode = 0;
+		platform_driver_unregister(&smd_pkt_devp->driver);
 		if (smd_pkt_devp->pil)
 			pil_put(smd_pkt_devp->pil);
 	}
@@ -802,7 +815,6 @@
 		mutex_init(&smd_pkt_devp[i]->ch_lock);
 		mutex_init(&smd_pkt_devp[i]->rx_lock);
 		mutex_init(&smd_pkt_devp[i]->tx_lock);
-		init_completion(&smd_pkt_devp[i]->ch_allocated);
 
 		cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops);
 		smd_pkt_devp[i]->cdev.owner = THIS_MODULE;
@@ -843,13 +855,6 @@
 					&dev_attr_open_timeout))
 			pr_err("%s: unable to create device attr on #%d\n",
 				__func__, i);
-
-		smd_pkt_devp[i]->driver.probe = smd_pkt_dummy_probe;
-		smd_pkt_devp[i]->driver.driver.name = smd_ch_name[i];
-		smd_pkt_devp[i]->driver.driver.owner = THIS_MODULE;
-		r = platform_driver_register(&smd_pkt_devp[i]->driver);
-		if (r)
-			goto error2;
 	}
 
 	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
@@ -860,7 +865,6 @@
  error2:
 	if (i > 0) {
 		while (--i >= 0) {
-			platform_driver_unregister(&smd_pkt_devp[i]->driver);
 			cdev_del(&smd_pkt_devp[i]->cdev);
 			kfree(smd_pkt_devp[i]);
 			device_destroy(smd_pkt_classp,
@@ -880,7 +884,6 @@
 	int i;
 
 	for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
-		platform_driver_unregister(&smd_pkt_devp[i]->driver);
 		cdev_del(&smd_pkt_devp[i]->cdev);
 		kfree(smd_pkt_devp[i]);
 		device_destroy(smd_pkt_classp,
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index a4c60e8..e39c57b 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/smd_private.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <mach/msm_smsm.h>
+#include <mach/msm_smd.h>
 
 #define PC_APPS  0
 #define PC_MODEM 1
@@ -208,4 +209,15 @@
 
 void smd_diag(void);
 
+struct interrupt_stat {
+	uint32_t smd_in_count;
+	uint32_t smd_out_hardcode_count;
+	uint32_t smd_out_config_count;
+
+	uint32_t smsm_in_count;
+	uint32_t smsm_out_hardcode_count;
+	uint32_t smsm_out_config_count;
+};
+extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
+
 #endif
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 4248be4..d856024 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -235,7 +235,7 @@
 	int res = 0;
 	unsigned int n = tty->index;
 	struct smd_tty_info *info;
-	char *peripheral = NULL;
+	const char *peripheral = NULL;
 
 
 	if (n >= MAX_SMD_TTYS || !smd_tty[n].smd)
@@ -247,9 +247,7 @@
 	tty->driver_data = info;
 
 	if (info->open_count++ == 0) {
-		if (smd_tty[n].smd->edge == SMD_APPS_MODEM)
-			peripheral = "modem";
-
+		peripheral = smd_edge_to_subsystem(smd_tty[n].smd->edge);
 		if (peripheral) {
 			info->pil = pil_get(peripheral);
 			if (IS_ERR(info->pil)) {
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 883dec1..1f85194 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -169,11 +169,7 @@
 
 	reg = saw_bases[cpu];
 
-	if (cpu_is_msm8960() || cpu_is_msm8930()) {
-		val = 0xB0;
-		reg += 0x14;
-		timeout = 512;
-	} else if (cpu_is_apq8064()) {
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064()) {
 		val = 0xA4;
 		reg += 0x14;
 		timeout = 512;
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 0bc080c..2dfde6f 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1123,11 +1123,8 @@
 	}
 	msm_sched_clock_init();
 
-	if (is_smp()) {
-		__raw_writel(1,
-			msm_clocks[MSM_CLOCK_DGT].regbase + TIMER_ENABLE);
-		set_delay_fn(read_current_timer_delay_loop);
-	}
+	__raw_writel(1, msm_clocks[MSM_CLOCK_DGT].regbase + TIMER_ENABLE);
+	set_delay_fn(read_current_timer_delay_loop);
 }
 
 #ifdef CONFIG_SMP
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 9970c90..1bdec12 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,7 @@
 static void riva_fatal_fn(struct work_struct *);
 static DECLARE_WORK(riva_fatal_work, riva_fatal_fn);
 
+static struct delayed_work cancel_vote_work;
 static void *riva_ramdump_dev;
 static int riva_crash;
 static int ss_restart_inprogress;
@@ -51,6 +52,9 @@
 static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
 					uint32_t new_state)
 {
+	if (!(new_state & SMSM_RESET))
+		return;
+
 	riva_crash = true;
 	pr_err("%s: smsm state changed to smsm reset\n", MODULE_NAME);
 
@@ -59,10 +63,8 @@
 						MODULE_NAME);
 		return;
 	}
-	if (new_state & SMSM_RESET) {
-		ss_restart_inprogress = true;
-		schedule_work(&riva_smsm_cb_work);
-	}
+	ss_restart_inprogress = true;
+	schedule_work(&riva_smsm_cb_work);
 }
 
 static void riva_fatal_fn(struct work_struct *work)
@@ -97,20 +99,24 @@
 	smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
 }
 
-/* Subsystem handlers */
-static int riva_shutdown(const struct subsys_data *subsys)
+static void riva_post_bootup(struct work_struct *work)
 {
 	struct platform_device *pdev = wcnss_get_platform_device();
 	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
-	int    ret = -1;
 
+	pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Riva\n");
+
+	wcnss_wlan_power(&pdev->dev, pwlanconfig,
+		WCNSS_WLAN_SWITCH_OFF);
+}
+
+/* Subsystem handlers */
+static int riva_shutdown(const struct subsys_data *subsys)
+{
 	pil_force_shutdown("wcnss");
+	flush_delayed_work(&cancel_vote_work);
 
-	/* proxy vote on behalf of Riva */
-	if (pdev && pwlanconfig)
-		ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
-					WCNSS_WLAN_SWITCH_OFF);
-	return ret;
+	return 0;
 }
 
 static int riva_powerup(const struct subsys_data *subsys)
@@ -131,6 +137,7 @@
 	}
 	ss_restart_inprogress = false;
 	enable_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
+	schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
 
 	return ret;
 }
@@ -222,6 +229,8 @@
 		ret = -ENOMEM;
 		goto out;
 	}
+	INIT_DELAYED_WORK(&cancel_vote_work, riva_post_bootup);
+
 	pr_info("%s: module initialized\n", MODULE_NAME);
 out:
 	return ret;
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 3bce534..f748109 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -55,7 +55,7 @@
 	cmp	r1, #2				@ see what cache we have at this level
 	blt	skip				@ skip if no cache, or just i-cache
 #ifdef CONFIG_PREEMPT
-	save_and_disable_irqs r9		@ make cssr&csidr read atomic
+	save_and_disable_irqs_notrace r9	@ make cssr&csidr read atomic
 #endif
 	mcr	p15, 2, r10, c0, c0, 0		@ select current cache level in cssr
 	isb					@ isb to sych the new cssr&csidr
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 321abe8..edede47 100755
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1140,3 +1140,4 @@
 mpq8064_dtv		MACH_MPQ8064_DTV	MPQ8064_DTV		3995
 msm7627a_qrd3		MACH_MSM7627A_QRD3	MSM7627A_QRD3		4005
 msm8625_surf		MACH_MSM8625_SURF	MSM8625_SURF		4037
+msm8625_evb		MACH_MSM8625_EVB	MSM8625_EVB		4042
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 371d319..228c77fb 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -23,6 +23,7 @@
 #include <asm/mach-types.h>
 /* Size of the USB buffers used for read and write*/
 #define USB_MAX_OUT_BUF 4096
+#define APPS_BUF_SIZE	2000
 #define IN_BUF_SIZE		16384
 #define MAX_IN_BUF_SIZE	32768
 #define MAX_SYNC_OBJ_NAME_SIZE	32
@@ -50,6 +51,9 @@
 #define USER_SPACE_DATA 8000
 #define PKT_SIZE 4096
 #define MAX_EQUIP_ID 12
+#define DIAG_CTRL_MSG_LOG_MASK	9
+#define DIAG_CTRL_MSG_EVENT_MASK	10
+#define DIAG_CTRL_MSG_F3_MASK	11
 
 /* Maximum number of pkt reg supported at initialization*/
 extern unsigned int diag_max_reg;
@@ -130,6 +134,7 @@
 	int num_clients;
 	int polling_reg_flag;
 	struct diag_write_device *buf_tbl;
+	int use_device_tree;
 
 	/* Memory pool parameters */
 	unsigned int itemsize;
@@ -148,7 +153,10 @@
 	int count_hdlc_pool;
 	int count_write_struct_pool;
 	int used;
-
+	/* Buffers for masks */
+	struct diag_ctrl_event_mask *event_mask;
+	struct diag_ctrl_log_mask *log_mask;
+	struct diag_ctrl_msg_mask *msg_mask;
 	/* State for diag forwarding */
 	unsigned char *buf_in_1;
 	unsigned char *buf_in_2;
@@ -161,6 +169,10 @@
 	unsigned char *usb_buf_out;
 	unsigned char *apps_rsp_buf;
 	unsigned char *user_space_data;
+	/* buffer for updating mask to peripherals */
+	unsigned char *buf_msg_mask_update;
+	unsigned char *buf_log_mask_update;
+	unsigned char *buf_event_mask_update;
 	smd_channel_t *ch;
 	smd_channel_t *ch_cntl;
 	smd_channel_t *chqdsp;
@@ -190,6 +202,13 @@
 	struct work_struct diag_read_smd_qdsp_cntl_work;
 	struct work_struct diag_read_smd_wcnss_work;
 	struct work_struct diag_read_smd_wcnss_cntl_work;
+	struct workqueue_struct *diag_cntl_wq;
+	struct work_struct diag_msg_mask_update_work;
+	struct work_struct diag_log_mask_update_work;
+	struct work_struct diag_event_mask_update_work;
+	struct work_struct diag_modem_mask_update_work;
+	struct work_struct diag_qdsp_mask_update_work;
+	struct work_struct diag_wcnss_mask_update_work;
 	uint8_t *msg_masks;
 	uint8_t *log_masks;
 	int log_masks_length;
@@ -228,6 +247,7 @@
 	int hsic_ch;
 	int hsic_device_enabled;
 	int hsic_device_opened;
+	int hsic_suspend;
 	int read_len_mdm;
 	int in_busy_hsic_read_on_mdm;
 	int in_busy_hsic_write_on_mdm;
@@ -238,6 +258,8 @@
 	struct workqueue_struct *diag_hsic_wq;
 	struct work_struct diag_read_mdm_work;
 	struct work_struct diag_read_hsic_work;
+	struct work_struct diag_disconnect_work;
+	struct work_struct diag_usb_read_complete_work;
 	struct diag_request *usb_read_mdm_ptr;
 	struct diag_request *write_ptr_mdm;
 #endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index efba92b..d9f12ac 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -48,7 +48,7 @@
 };
 /* The following variables can be specified by module options */
  /* for copy buffer */
-static unsigned int itemsize = 2048; /*Size of item in the mempool */
+static unsigned int itemsize = 4096; /*Size of item in the mempool */
 static unsigned int poolsize = 10; /*Number of items in the mempool */
 /* for hdlc buffer */
 static unsigned int itemsize_hdlc = 8192; /*Size of item in the mempool */
@@ -768,6 +768,14 @@
 		return 0;
 	}
 
+	if (payload_size > itemsize) {
+		pr_err("diag: Dropping packet, packet payload size crosses"
+				"4KB limit. Current payload size %d\n",
+				payload_size);
+		driver->dropped_count++;
+		return -EBADMSG;
+	}
+
 	buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
 	if (!buf_copy) {
 		driver->dropped_count++;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 7f268563..f16aa0c 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -21,6 +21,7 @@
 #include <linux/diagchar.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
+#include <linux/of.h>
 #ifdef CONFIG_DIAG_OVER_USB
 #include <mach/usbdiag.h>
 #endif
@@ -43,8 +44,15 @@
 static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
 struct diag_master_table entry;
 smd_channel_t *ch_temp, *chqdsp_temp, *ch_wcnss_temp;
+int diag_event_num_bytes;
+int diag_event_config;
 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
+struct mask_info {
+	int equip_id;
+	int num_items;
+	int index;
+};
 
 #define ENCODE_RSP_AND_SEND(buf_length)				\
 do {									\
@@ -54,7 +62,7 @@
 	send.terminate = 1;						\
 	if (!driver->in_busy_1) {					\
 		enc.dest = driver->buf_in_1;				\
-		enc.dest_last = (void *)(driver->buf_in_1 + 499);	\
+		enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);\
 		diag_hdlc_encode(&send, &enc);				\
 		driver->write_ptr_1->buf = driver->buf_in_1;		\
 		driver->write_ptr_1->length = (int)(enc.dest - \
@@ -62,55 +70,80 @@
 		driver->in_busy_1 = 1;					\
 		diag_device_write(driver->buf_in_1, MODEM_DATA, \
 						 driver->write_ptr_1); \
-		memset(driver->apps_rsp_buf, '\0', 500);		\
+		memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);	\
 	}								\
 } while (0)
 
 #define CHK_OVERFLOW(bufStart, start, end, length) \
 ((bufStart <= start) && (end - start >= length)) ? 1 : 0
 
+/* Determine if this device uses a device tree */
+#ifdef CONFIG_OF
+static int has_device_tree(void)
+{
+	struct device_node *node;
+
+	node = of_find_node_by_path("/");
+	if (node) {
+		of_node_put(node);
+		return 1;
+	}
+	return 0;
+}
+#else
+static int has_device_tree(void)
+{
+	return 0;
+}
+#endif
+
 int chk_config_get_id(void)
 {
 	/* For all Fusion targets, Modem will always be present */
 	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
 		return 0;
 
-	switch (socinfo_get_id()) {
-	case APQ8060_MACHINE_ID:
-	case MSM8660_MACHINE_ID:
-		return APQ8060_TOOLS_ID;
-	case AO8960_MACHINE_ID:
-	case MSM8260A_MACHINE_ID:
-		return AO8960_TOOLS_ID;
-	case APQ8064_MACHINE_ID:
-		return APQ8064_TOOLS_ID;
-	case MSM8930_MACHINE_ID:
-		return MSM8930_TOOLS_ID;
-	case MSM8974_MACHINE_ID:
-		return MSM8974_TOOLS_ID;
-	default:
-		return 0;
+	if (driver->use_device_tree) {
+		if (machine_is_copper())
+			return MSM8974_TOOLS_ID;
+		else
+			return 0;
+	} else {
+		switch (socinfo_get_msm_cpu()) {
+		case MSM_CPU_8X60:
+			return APQ8060_TOOLS_ID;
+		case MSM_CPU_8960:
+			return AO8960_TOOLS_ID;
+		case MSM_CPU_8064:
+			return APQ8064_TOOLS_ID;
+		case MSM_CPU_8930:
+			return MSM8930_TOOLS_ID;
+		case MSM_CPU_COPPER:
+			return MSM8974_TOOLS_ID;
+		case MSM_CPU_8625:
+			return MSM8625_TOOLS_ID;
+		default:
+			return 0;
+		}
 	}
 }
 
 /*
- * This will return TRUE for targets which support apps only mode.
+ * This will return TRUE for targets which support apps only mode and hence SSR.
  * This applies to 8960 and newer targets.
  */
 int chk_apps_only(void)
 {
-	switch (socinfo_get_id()) {
-	case AO8960_MACHINE_ID:
-	case APQ8064_MACHINE_ID:
-	case MSM8930_MACHINE_ID:
-	case MSM8630_MACHINE_ID:
-	case MSM8230_MACHINE_ID:
-	case APQ8030_MACHINE_ID:
-	case MSM8627_MACHINE_ID:
-	case MSM8227_MACHINE_ID:
-	case MSM8974_MACHINE_ID:
-	case MDM9615_MACHINE_ID:
-	case MSM8260A_MACHINE_ID:
+	if (driver->use_device_tree)
+		return 1;
+
+	switch (socinfo_get_msm_cpu()) {
+	case MSM_CPU_8960:
+	case MSM_CPU_8064:
+	case MSM_CPU_8930:
+	case MSM_CPU_8627:
+	case MSM_CPU_9615:
+	case MSM_CPU_COPPER:
 		return 1;
 	default:
 		return 0;
@@ -124,8 +157,28 @@
  */
 int chk_apps_master(void)
 {
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
-		 cpu_is_apq8064() || cpu_is_msm8627())
+	if (driver->use_device_tree)
+		return 1;
+	else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
+		cpu_is_apq8064() || cpu_is_msm8627())
+		return 1;
+	else
+		return 0;
+}
+
+inline int chk_polling_response(void)
+{
+	if (!(driver->polling_reg_flag) && chk_apps_master())
+		/*
+		 * If the apps processor is master and no other processor
+		 * has registered to respond for polling
+		 */
+		return 1;
+	else if (!(driver->ch) && !(chk_apps_master()))
+		/*
+		 * If the apps processor is not the master and the modem
+		 * is not up
+		 */
 		return 1;
 	else
 		return 0;
@@ -400,8 +453,8 @@
 	uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
 
 	mutex_lock(&driver->diagchar_mutex);
-	/* First SSID can be zero : So check that last is non-zero */
 
+	/* First SSID can be zero : So check that last is non-zero */
 	while (*(uint32_t *)(ptr + 4)) {
 		first = *(uint32_t *)ptr;
 		ptr += 4;
@@ -446,7 +499,7 @@
 
 }
 
-static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bits)
+static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
 {
 	uint8_t *ptr = driver->event_masks;
 	uint8_t *temp = buf + 2;
@@ -456,9 +509,8 @@
 		memset(ptr, 0 , EVENT_MASK_SIZE);
 	else
 		if (CHK_OVERFLOW(ptr, ptr,
-				 ptr+EVENT_MASK_SIZE,
-				  num_bits/8 + 1))
-			memcpy(ptr, temp , num_bits/8 + 1);
+				 ptr+EVENT_MASK_SIZE, num_bytes))
+			memcpy(ptr, temp , num_bytes);
 		else
 			printk(KERN_CRIT "Not enough buffer space "
 					 "for EVENT_MASK\n");
@@ -468,10 +520,6 @@
 static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
 {
 	uint8_t *temp = buf;
-	struct mask_info {
-		int equip_id;
-		int index;
-	};
 	int i = 0;
 	unsigned char *ptr_data;
 	int offset = 8*MAX_EQUIP_ID;
@@ -485,8 +533,9 @@
 			break;
 		}
 		if ((ptr->equip_id == 0) && (ptr->index == 0)) {
-			/*Reached a null entry */
+			/* Reached a null entry */
 			ptr->equip_id = equip_id;
+			ptr->num_items = num_items;
 			ptr->index = driver->log_masks_length;
 			offset = driver->log_masks_length;
 			driver->log_masks_length += ((num_items+7)/8);
@@ -571,6 +620,123 @@
 	}
 }
 
+void diag_modem_mask_update_fn(struct work_struct *work)
+{
+	diag_send_msg_mask_update(driver->ch_cntl);
+	diag_send_log_mask_update(driver->ch_cntl);
+	diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
+}
+
+void diag_qdsp_mask_update_fn(struct work_struct *work)
+{
+	diag_send_msg_mask_update(driver->chqdsp_cntl);
+	diag_send_log_mask_update(driver->chqdsp_cntl);
+	diag_send_event_mask_update(driver->chqdsp_cntl, diag_event_num_bytes);
+}
+
+void diag_wcnss_mask_update_fn(struct work_struct *work)
+{
+	diag_send_msg_mask_update(driver->ch_wcnss_cntl);
+	diag_send_log_mask_update(driver->ch_wcnss_cntl);
+	diag_send_event_mask_update(driver->ch_wcnss_cntl,
+						 diag_event_num_bytes);
+}
+
+void diag_msg_mask_update_fn(struct work_struct *work)
+{
+	diag_send_msg_mask_update(driver->ch_cntl);
+	diag_send_msg_mask_update(driver->chqdsp_cntl);
+	diag_send_msg_mask_update(driver->ch_wcnss_cntl);
+}
+
+void diag_log_mask_update_fn(struct work_struct *work)
+{
+	diag_send_log_mask_update(driver->ch_cntl);
+	diag_send_log_mask_update(driver->chqdsp_cntl);
+	diag_send_log_mask_update(driver->ch_wcnss_cntl);
+}
+
+void diag_send_log_mask_update(smd_channel_t *ch)
+{
+	void *buf = driver->buf_log_mask_update;
+	int header_size = sizeof(struct diag_ctrl_log_mask);
+	struct mask_info *ptr = (struct mask_info *)driver->log_masks;
+	int i, size = (driver->log_mask->num_items+7)/8;
+
+	for (i = 0; i < MAX_EQUIP_ID; i++) {
+		/* reached null entry */
+		if ((ptr->equip_id == 0) && (ptr->index == 0))
+			break;
+		driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
+		driver->log_mask->num_items = ptr->num_items;
+		driver->log_mask->data_len  = 11 + size;
+		driver->log_mask->stream_id = 1; /* 2, if dual stream */
+		driver->log_mask->status = 3; /* status for valid mask */
+		driver->log_mask->equip_id = ptr->equip_id;
+		driver->log_mask->log_mask_size = size;
+		memcpy(buf, driver->log_mask, header_size);
+		memcpy(buf+header_size, driver->log_masks+ptr->index, size);
+		msleep(100);
+		if (ch)
+			smd_write(ch, buf, header_size + size);
+		ptr++;
+	}
+}
+
+void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
+{
+	void *buf = driver->buf_event_mask_update;
+	int header_size = sizeof(struct diag_ctrl_event_mask);
+
+	/* send event mask update */
+	driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
+	driver->event_mask->data_len = 7 + num_bytes;
+	driver->event_mask->stream_id = 1; /* 2, if dual stream */
+	driver->event_mask->status = 3; /* status for valid mask */
+	driver->event_mask->event_config = diag_event_config; /* event config */
+	driver->event_mask->event_mask_size = num_bytes;
+	memcpy(buf, driver->event_mask, header_size);
+	memcpy(buf+header_size, driver->event_masks, num_bytes);
+	msleep(100);
+	if (ch)
+		smd_write(ch, buf, header_size + num_bytes);
+}
+
+void diag_send_msg_mask_update(smd_channel_t *ch)
+{
+	void *buf = driver->buf_msg_mask_update;
+	int first, last;
+	int header_size = sizeof(struct diag_ctrl_msg_mask);
+	uint8_t *ptr = driver->msg_masks;
+
+	while (*(uint32_t *)(ptr + 4)) {
+		first = *(uint32_t *)ptr;
+		ptr += 4;
+		last = *(uint32_t *)ptr;
+		ptr += 4;
+		/* send event mask update */
+		driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
+		driver->msg_mask->msg_mask_size = last - first + 1;
+		driver->msg_mask->data_len = 11 +
+				 4 * (driver->msg_mask->msg_mask_size);
+		driver->msg_mask->stream_id = 1; /* 2, if dual stream */
+		driver->msg_mask->status = 3; /* status for valid mask */
+		driver->msg_mask->msg_mode = 0; /* Legcay mode */
+		driver->msg_mask->ssid_first = first;
+		driver->msg_mask->ssid_last = last;
+		memcpy(buf, driver->msg_mask, header_size);
+		memcpy(buf+header_size, ptr,
+			 4 * (driver->msg_mask->msg_mask_size));
+		/* since mask updates are slow, so sleep needed as to
+		   prevent modem running out of DSM items */
+		msleep(100);
+		if (ch)
+			smd_write(ch, buf,
+			 header_size + 4*(driver->msg_mask->msg_mask_size));
+		ptr += ((last - first) + 1)*4;
+	}
+}
+
 static int diag_process_apps_pkt(unsigned char *buf, int len)
 {
 	uint16_t subsys_cmd_code;
@@ -583,6 +749,93 @@
 	unsigned char *ptr;
 #endif
 
+	/* Set log masks */
+	if (*buf == 0x73 && *(int *)(buf+4) == 3) {
+		buf += 8;
+		/* Read Equip ID and pass as first param below*/
+		diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
+		diag_update_userspace_clients(LOG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x73;
+			*(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
+			*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
+			payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
+			for (i = 0; i < payload_length; i++)
+				*(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
+			queue_work(driver->diag_cntl_wq,
+				 &(driver->diag_log_mask_update_work));
+			ENCODE_RSP_AND_SEND(12 + payload_length - 1);
+			return 0;
+		} else
+			buf = temp;
+#endif
+	} /* Check for set message mask  */
+	else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
+		ssid_first = *(uint16_t *)(buf + 2);
+		ssid_last = *(uint16_t *)(buf + 4);
+		ssid_range = 4 * (ssid_last - ssid_first + 1);
+		diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
+		diag_update_userspace_clients(MSG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			for (i = 0; i < 8 + ssid_range; i++)
+				*(driver->apps_rsp_buf + i) = *(buf+i);
+			*(driver->apps_rsp_buf + 6) = 0x1;
+			queue_work(driver->diag_cntl_wq,
+				 &(driver->diag_msg_mask_update_work));
+			ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
+			return 0;
+		} else
+			buf = temp;
+#endif
+	} else if (*buf == 0x82) {	/* event mask change */
+		buf += 4;
+		diag_event_num_bytes =  (*(uint16_t *)buf)/8+1;
+		diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
+		diag_update_userspace_clients(EVENT_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x82;
+			driver->apps_rsp_buf[1] = 0x0;
+			*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
+			*(uint16_t *)(driver->apps_rsp_buf + 4) =
+							EVENT_LAST_ID + 1;
+			for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
+				*(unsigned char *)(driver->apps_rsp_buf + 6 + i)
+									 = 0x0;
+			/* cannot do this on work queue, as each event update
+			needs a num_bytes variable. Each queue_work call will
+			overwrite the previous input, as its the same struct */
+			diag_send_event_mask_update(driver->ch_cntl,
+							 diag_event_num_bytes);
+			diag_send_event_mask_update(driver->chqdsp_cntl,
+							 diag_event_num_bytes);
+			diag_send_event_mask_update(driver->ch_wcnss_cntl,
+							 diag_event_num_bytes);
+			ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
+			return 0;
+		} else
+			buf = temp;
+#endif
+	} else if (*buf == 0x60) {
+		diag_event_config = *(buf+1);
+#if defined(CONFIG_DIAG_OVER_USB)
+		if (chk_apps_only()) {
+			driver->apps_rsp_buf[0] = 0x60;
+			driver->apps_rsp_buf[1] = 0x0;
+			driver->apps_rsp_buf[2] = 0x0;
+			diag_send_event_mask_update(driver->ch_cntl,
+							 diag_event_num_bytes);
+			diag_send_event_mask_update(driver->chqdsp_cntl,
+							 diag_event_num_bytes);
+			diag_send_event_mask_update(driver->ch_wcnss_cntl,
+							 diag_event_num_bytes);
+			ENCODE_RSP_AND_SEND(2);
+			return 0;
+		}
+#endif
+	}
 	/* Check for registered clients and forward packet to apropriate proc */
 	cmd_code = (int)(*(char *)buf);
 	temp++;
@@ -632,70 +885,9 @@
 			}
 		}
 	}
-	/* set event mask */
-	if (*buf == 0x82) {
-		buf += 4;
-		diag_update_event_mask(buf, 1, *(uint16_t *)buf);
-		diag_update_userspace_clients(EVENT_MASKS_TYPE);
-	}
-	/* event mask change */
-	else if ((*buf == 0x60) && (*(buf+1) == 0x0)) {
-		diag_update_event_mask(buf+1, 0, 0);
-		diag_update_userspace_clients(EVENT_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
-		/* Check for Apps Only */
-		if (!(driver->ch) && chk_apps_only()) {
-			/* echo response back for apps only DIAG */
-			driver->apps_rsp_buf[0] = 0x60;
-			driver->apps_rsp_buf[1] = 0x0;
-			driver->apps_rsp_buf[2] = 0x0;
-			ENCODE_RSP_AND_SEND(2);
-			return 0;
-		}
-#endif
-	}
-	/* Set log masks */
-	else if (*buf == 0x73 && *(int *)(buf+4) == 3) {
-		buf += 8;
-		/* Read Equip ID and pass as first param below*/
-		diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
-		diag_update_userspace_clients(LOG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
-		/* Check for Apps Only */
-		if (!(driver->ch) && chk_apps_only()) {
-			/* echo response back for Apps only DIAG */
-			driver->apps_rsp_buf[0] = 0x73;
-			*(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
-			*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
-			payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
-			for (i = 0; i < payload_length; i++)
-				*(int *)(driver->apps_rsp_buf+12+i) =
-								 *(buf+8+i);
-			ENCODE_RSP_AND_SEND(12 + payload_length - 1);
-			return 0;
-		}
-#endif
-	}
-	/* Check for set message mask  */
-	else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
-		ssid_first = *(uint16_t *)(buf + 2);
-		ssid_last = *(uint16_t *)(buf + 4);
-		ssid_range = 4 * (ssid_last - ssid_first + 1);
-		diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
-		diag_update_userspace_clients(MSG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
-		if (!(driver->ch) && chk_apps_only()) {
-			/* echo response back for apps only DIAG */
-			for (i = 0; i < 8 + ssid_range; i++)
-				*(driver->apps_rsp_buf + i) = *(buf+i);
-			ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
-			return 0;
-		}
-#endif
-	}
 #if defined(CONFIG_DIAG_OVER_USB)
 	/* Check for Apps Only & get event mask request */
-	else if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
+	if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
 		driver->apps_rsp_buf[0] = 0x81;
 		driver->apps_rsp_buf[1] = 0x0;
 		*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
@@ -776,7 +968,15 @@
 		*(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
 		*(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
 		*(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
-		ENCODE_RSP_AND_SEND(83);
+		*(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
+		*(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
+		*(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
+		*(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
+		*(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
+		*(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
+		*(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
+		*(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
+		ENCODE_RSP_AND_SEND(99);
 		return 0;
 	}
 	/* Check for Apps Only Respond to Get Subsys Build mask */
@@ -871,6 +1071,22 @@
 			for (i = 0; i < ssid_range; i += 4)
 				*(int *)(ptr + i) = msg_bld_masks_18[i/4];
 			break;
+		case MSG_SSID_19:
+			for (i = 0; i < ssid_range; i += 4)
+				*(int *)(ptr + i) = msg_bld_masks_19[i/4];
+			break;
+		case MSG_SSID_20:
+			for (i = 0; i < ssid_range; i += 4)
+				*(int *)(ptr + i) = msg_bld_masks_20[i/4];
+			break;
+		case MSG_SSID_21:
+			for (i = 0; i < ssid_range; i += 4)
+				*(int *)(ptr + i) = msg_bld_masks_21[i/4];
+			break;
+		case MSG_SSID_22:
+			for (i = 0; i < ssid_range; i += 4)
+				*(int *)(ptr + i) = msg_bld_masks_22[i/4];
+			break;
 		}
 		ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
 		return 0;
@@ -892,7 +1108,7 @@
 	else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
 		(*(buf+2) == 0x03)) {
 		/* If no one has registered for polling */
-		if (!(driver->polling_reg_flag)) {
+		if (chk_polling_response()) {
 			/* Respond to polling for Apps only DIAG */
 			for (i = 0; i < 3; i++)
 				driver->apps_rsp_buf[i] = *(buf+i);
@@ -904,7 +1120,7 @@
 		}
 	}
 	 /* Check for ID for NO MODEM present */
-	else if (!(driver->polling_reg_flag)) {
+	else if (chk_polling_response()) {
 		/* respond to 0x0 command */
 		if (*buf == 0x00) {
 			for (i = 0; i < 55; i++)
@@ -1311,6 +1527,26 @@
 {
 	diag_debug_buf_idx = 0;
 	driver->read_len_legacy = 0;
+	driver->use_device_tree = has_device_tree();
+
+	if (driver->event_mask == NULL) {
+		driver->event_mask = kzalloc(sizeof(
+			struct diag_ctrl_event_mask), GFP_KERNEL);
+		if (driver->event_mask == NULL)
+			goto err;
+	}
+	if (driver->msg_mask == NULL) {
+		driver->msg_mask = kzalloc(sizeof(
+			struct diag_ctrl_msg_mask), GFP_KERNEL);
+		if (driver->msg_mask == NULL)
+			goto err;
+	}
+	if (driver->log_mask == NULL) {
+		driver->log_mask = kzalloc(sizeof(
+			struct diag_ctrl_log_mask), GFP_KERNEL);
+		if (driver->log_mask == NULL)
+			goto err;
+	}
 	if (driver->buf_in_1 == NULL) {
 		driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_1 == NULL)
@@ -1336,6 +1572,24 @@
 		if (driver->buf_in_wcnss == NULL)
 			goto err;
 	}
+	if (driver->buf_msg_mask_update == NULL) {
+		driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
+								 GFP_KERNEL);
+		if (driver->buf_msg_mask_update == NULL)
+			goto err;
+	}
+	if (driver->buf_log_mask_update == NULL) {
+		driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
+								 GFP_KERNEL);
+		if (driver->buf_log_mask_update == NULL)
+			goto err;
+	}
+	if (driver->buf_event_mask_update == NULL) {
+		driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
+								 GFP_KERNEL);
+		if (driver->buf_event_mask_update == NULL)
+			goto err;
+	}
 	if (driver->usb_buf_out  == NULL &&
 	     (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
 					 GFP_KERNEL)) == NULL)
@@ -1419,7 +1673,7 @@
 			 GFP_KERNEL)) == NULL)
 		goto err;
 	if (driver->apps_rsp_buf == NULL) {
-			driver->apps_rsp_buf = kzalloc(500, GFP_KERNEL);
+		driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
 		if (driver->apps_rsp_buf == NULL)
 			goto err;
 	}
@@ -1427,6 +1681,16 @@
 #ifdef CONFIG_DIAG_OVER_USB
 	INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
 	INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
+	INIT_WORK(&(driver->diag_msg_mask_update_work),
+						 diag_msg_mask_update_fn);
+	INIT_WORK(&(driver->diag_log_mask_update_work),
+						 diag_log_mask_update_fn);
+	INIT_WORK(&(driver->diag_modem_mask_update_work),
+						 diag_modem_mask_update_fn);
+	INIT_WORK(&(driver->diag_qdsp_mask_update_work),
+						 diag_qdsp_mask_update_fn);
+	INIT_WORK(&(driver->diag_wcnss_mask_update_work),
+						 diag_wcnss_mask_update_fn);
 	driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
 			diag_usb_legacy_notifier);
 	if (IS_ERR(driver->legacy_ch)) {
@@ -1440,11 +1704,17 @@
 	return;
 err:
 		pr_err("diag: Could not initialize diag buffers");
+		kfree(driver->event_mask);
+		kfree(driver->log_mask);
+		kfree(driver->msg_mask);
 		kfree(driver->buf_in_1);
 		kfree(driver->buf_in_2);
 		kfree(driver->buf_in_qdsp_1);
 		kfree(driver->buf_in_qdsp_2);
 		kfree(driver->buf_in_wcnss);
+		kfree(driver->buf_msg_mask_update);
+		kfree(driver->buf_log_mask_update);
+		kfree(driver->buf_event_mask_update);
 		kfree(driver->usb_buf_out);
 		kfree(driver->hdlc_buf);
 		kfree(driver->msg_masks);
@@ -1482,11 +1752,17 @@
 #endif
 	platform_driver_unregister(&msm_smd_ch1_driver);
 	platform_driver_unregister(&diag_smd_lite_driver);
+	kfree(driver->event_mask);
+	kfree(driver->log_mask);
+	kfree(driver->msg_mask);
 	kfree(driver->buf_in_1);
 	kfree(driver->buf_in_2);
 	kfree(driver->buf_in_qdsp_1);
 	kfree(driver->buf_in_qdsp_2);
 	kfree(driver->buf_in_wcnss);
+	kfree(driver->buf_msg_mask_update);
+	kfree(driver->buf_log_mask_update);
+	kfree(driver->buf_event_mask_update);
 	kfree(driver->usb_buf_out);
 	kfree(driver->hdlc_buf);
 	kfree(driver->msg_masks);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 6dacab7..9ef0199 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,9 @@
 int mask_request_validate(unsigned char mask_buf[]);
 void diag_clear_reg(int);
 int chk_apps_only(void);
+void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
+void diag_send_msg_mask_update(smd_channel_t *);
+void diag_send_log_mask_update(smd_channel_t *);
 /* State for diag forwarding */
 #ifdef CONFIG_DIAG_OVER_USB
 int diagfwd_connect(void);
@@ -35,5 +38,5 @@
 #endif
 extern int diag_debug_buf_idx;
 extern unsigned char diag_debug_buf[1024];
-
+extern int diag_event_num_bytes;
 #endif
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 2c3dc54..01ed28d 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -36,6 +36,10 @@
 		else
 			pr_debug("diag: incomplete pkt on Modem CNTL ch\n");
 		break;
+	case SMD_EVENT_OPEN:
+		queue_work(driver->diag_cntl_wq,
+			 &(driver->diag_modem_mask_update_work));
+		break;
 	}
 }
 
@@ -56,6 +60,10 @@
 		else
 			pr_debug("diag: incomplete pkt on LPASS CNTL ch\n");
 		break;
+	case SMD_EVENT_OPEN:
+		queue_work(driver->diag_cntl_wq,
+			 &(driver->diag_qdsp_mask_update_work));
+		break;
 	}
 }
 
@@ -76,6 +84,10 @@
 		else
 			pr_debug("diag: incomplete pkt on WCNSS CNTL ch\n");
 		break;
+	case SMD_EVENT_OPEN:
+		queue_work(driver->diag_cntl_wq,
+			 &(driver->diag_wcnss_mask_update_work));
+		break;
 	}
 }
 
@@ -259,6 +271,7 @@
 void diagfwd_cntl_init(void)
 {
 	driver->polling_reg_flag = 0;
+	driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
 	if (driver->buf_in_cntl == NULL) {
 		driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_cntl == NULL)
@@ -283,6 +296,8 @@
 		kfree(driver->buf_in_cntl);
 		kfree(driver->buf_in_qdsp_cntl);
 		kfree(driver->buf_in_wcnss_cntl);
+		if (driver->diag_cntl_wq)
+			destroy_workqueue(driver->diag_cntl_wq);
 }
 
 void diagfwd_cntl_exit(void)
@@ -293,6 +308,7 @@
 	driver->ch_cntl = 0;
 	driver->chqdsp_cntl = 0;
 	driver->ch_wcnss_cntl = 0;
+	destroy_workqueue(driver->diag_cntl_wq);
 	platform_driver_unregister(&msm_smd_ch1_cntl_driver);
 	platform_driver_unregister(&diag_smd_lite_cntl_driver);
 
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index a76d36d..ad1fec9 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -21,10 +21,6 @@
 #define DIAG_CTRL_MSG_DIAGMODE		3
 /* Diag data based on "light" diag mask */
 #define DIAG_CTRL_MSG_DIAGDATA		4
-/* Deprecated */
-#define DIAG_CTRL_MSG_LOG_MASK		5
-#define DIAG_CTRL_MSG_EVENT_MASK	6
-#define DIAG_CTRL_MSG_F3_MASK		7
 /* Send diag internal feature mask 'diag_int_feature_mask' */
 #define DIAG_CTRL_MSG_FEATURE		8
 /* Send Diag log mask for a particular equip id */
@@ -48,6 +44,39 @@
 	uint16_t port;
 };
 
+struct diag_ctrl_event_mask {
+	uint32_t cmd_type;
+	uint32_t data_len;
+	uint8_t stream_id;
+	uint8_t status;
+	uint8_t event_config;
+	uint32_t event_mask_size;
+	/* Copy event mask here */
+} __packed;
+
+struct diag_ctrl_log_mask {
+	uint32_t cmd_type;
+	uint32_t data_len;
+	uint8_t stream_id;
+	uint8_t status;
+	uint8_t equip_id;
+	uint32_t num_items; /* Last log code for this equip_id */
+	uint32_t log_mask_size; /* Size of log mask stored in log_mask[] */
+	/* Copy log mask here */
+} __packed;
+
+struct diag_ctrl_msg_mask {
+	uint32_t cmd_type;
+	uint32_t data_len;
+	uint8_t stream_id;
+	uint8_t status;
+	uint8_t msg_mode;
+	uint16_t ssid_first; /* Start of range of supported SSIDs */
+	uint16_t ssid_last; /* Last SSID in range */
+	uint32_t msg_mask_size; /* ssid_last - ssid_first + 1 */
+	/* Copy msg mask here */
+} __packed;
+
 void diagfwd_cntl_init(void);
 void diagfwd_cntl_exit(void);
 void diag_read_smd_cntl_work_fn(struct work_struct *);
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index ac5722f..b2080b3 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -102,14 +102,16 @@
 						driver->write_ptr_mdm);
 		}
 	} else {
-		pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
+		pr_debug("%s: actual_size: %d\n", __func__, actual_size);
 	}
 
 	/*
 	 * If for some reason there was no hsic data to write to the
 	 * mdm channel, set up another read
 	 */
-	if (!driver->in_busy_hsic_write_on_mdm)
+	if (!driver->in_busy_hsic_write_on_mdm &&
+			driver->usb_mdm_connected &&
+			!driver->hsic_suspend)
 		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
 }
 
@@ -127,13 +129,34 @@
 	if (actual_size < 0)
 		pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
 
-	queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+	if (driver->usb_mdm_connected)
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+}
+
+static int diag_hsic_suspend(void *ctxt)
+{
+	if (driver->in_busy_hsic_write)
+		return -EBUSY;
+
+	driver->hsic_suspend = 1;
+
+	return 0;
+}
+
+static void diag_hsic_resume(void *ctxt)
+{
+	driver->hsic_suspend = 0;
+
+	if (!driver->in_busy_hsic_write_on_mdm && driver->usb_mdm_connected)
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
 }
 
 static struct diag_bridge_ops hsic_diag_bridge_ops = {
 	.ctxt = NULL,
 	.read_complete_cb = diag_hsic_read_complete_callback,
 	.write_complete_cb = diag_hsic_write_complete_callback,
+	.suspend = diag_hsic_suspend,
+	.resume = diag_hsic_resume,
 };
 
 static int diag_hsic_close(void)
@@ -177,11 +200,11 @@
 				pr_err("DIAG: HSIC channel open error: %d\n",
 					err);
 			} else {
-				pr_info("DIAG: opened HSIC channel\n");
+				pr_debug("DIAG: opened HSIC channel\n");
 				driver->hsic_device_opened = 1;
 			}
 		} else {
-			pr_info("DIAG: HSIC channel already open\n");
+			pr_debug("DIAG: HSIC channel already open\n");
 		}
 
 		/*
@@ -220,9 +243,7 @@
 	driver->in_busy_hsic_read = 1;
 
 	/* Turn off communication over usb mdm and hsic */
-	driver->hsic_ch = 0;
-
-	return 0;
+	return diag_hsic_close();
 }
 
 /*
@@ -311,10 +332,11 @@
 		diagfwd_connect_hsic();
 		break;
 	case USB_DIAG_DISCONNECT:
-		diagfwd_disconnect_hsic();
+		queue_work(driver->diag_hsic_wq, &driver->diag_disconnect_work);
 		break;
 	case USB_DIAG_READ_DONE:
-		diagfwd_read_complete_hsic(d_req);
+		queue_work(driver->diag_hsic_wq,
+				&driver->diag_usb_read_complete_work);
 		break;
 	case USB_DIAG_WRITE_DONE:
 		diagfwd_write_complete_hsic();
@@ -326,6 +348,16 @@
 	}
 }
 
+static void diag_usb_read_complete_fn(struct work_struct *w)
+{
+	diagfwd_read_complete_hsic(driver->usb_read_mdm_ptr);
+}
+
+static void diag_disconnect_work_fn(struct work_struct *w)
+{
+	diagfwd_disconnect_hsic();
+}
+
 static void diag_read_mdm_work_fn(struct work_struct *work)
 {
 	if (!driver->hsic_ch) {
@@ -380,7 +412,6 @@
 		sizeof(struct diag_request), GFP_KERNEL);
 	if (driver->usb_read_mdm_ptr == NULL)
 		goto err;
-	driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
 #ifdef CONFIG_DIAG_OVER_USB
 	INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
 #endif
@@ -413,23 +444,22 @@
 		}
 	}
 
-	/* The hsic (diag_bridge) platform device driver is enabled */
-	err = diag_bridge_open(&hsic_diag_bridge_ops);
-	if (err) {
-		pr_err("DIAG could not open HSIC channel, err: %d\n", err);
-		driver->hsic_device_opened = 0;
-		return err;
-	}
-
-	pr_info("DIAG opened HSIC channel\n");
-	driver->hsic_device_opened = 1;
-
 	/*
 	 * The probe function was called after the usb was connected
 	 * on the legacy channel. Communication over usb mdm and hsic
 	 * needs to be turned on.
 	 */
-	if (driver->usb_connected) {
+	if (driver->usb_mdm_connected) {
+		/* The hsic (diag_bridge) platform device driver is enabled */
+		err = diag_bridge_open(&hsic_diag_bridge_ops);
+		if (err) {
+			pr_err("DIAG could not open HSIC, err: %d\n", err);
+			driver->hsic_device_opened = 0;
+			return err;
+		}
+
+		pr_debug("DIAG opened HSIC channel\n");
+		driver->hsic_device_opened = 1;
 		driver->hsic_ch = 1;
 		driver->in_busy_hsic_write_on_mdm = 0;
 		driver->in_busy_hsic_read_on_mdm = 0;
@@ -448,7 +478,7 @@
 
 static int diag_hsic_remove(struct platform_device *pdev)
 {
-	pr_info("DIAG: %s called\n", __func__);
+	pr_debug("DIAG: %s called\n", __func__);
 	diag_hsic_close();
 	return 0;
 }
@@ -487,6 +517,11 @@
 
 	pr_debug("DIAG in %s\n", __func__);
 
+	driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
+	INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
+	INIT_WORK(&(driver->diag_usb_read_complete_work),
+			diag_usb_read_complete_fn);
+
 #ifdef CONFIG_DIAG_OVER_USB
 	driver->mdm_ch = usb_diag_open(DIAG_MDM, driver, diagfwd_hsic_notifier);
 	if (IS_ERR(driver->mdm_ch)) {
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index bd48925..3d9c9d1 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -749,7 +749,8 @@
 }
 
 static int get_img(struct msmfb_data *fbd, unsigned long *start,
-	unsigned long *len, struct file **p_file, struct ion_handle **p_ihdl)
+	unsigned long *len, struct file **p_file, int *p_need,
+	struct ion_handle **p_ihdl)
 {
 	int ret = 0;
 #ifdef CONFIG_FB
@@ -760,6 +761,8 @@
 	unsigned long vstart;
 #endif
 
+	*p_need = 0;
+
 #ifdef CONFIG_FB
 	if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
 		file = fget_light(fbd->memory_id, &put_needed);
@@ -770,8 +773,10 @@
 			fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
 			if (get_fb_phys_info(start, len, fb_num))
 				ret = -1;
-			else
+			else {
 				*p_file = file;
+				*p_need = put_needed;
+			}
 		} else
 			ret = -1;
 		if (ret)
@@ -822,6 +827,7 @@
 	struct file *srcp1_file = NULL, *dstp1_file = NULL;
 	struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
 	struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
+	int ps0_need, p_need;
 	unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
 	unsigned int in_chroma2_paddr = 0;
 	struct msm_rotator_img_info *img_info;
@@ -872,8 +878,9 @@
 		goto do_rotate_unlock_mutex;
 	}
 
+
 	rc = get_img(&info.src, (unsigned long *)&in_paddr,
-			(unsigned long *)&src_len, &srcp0_file, &srcp0_ihdl);
+		(unsigned long *)&src_len, &srcp0_file, &ps0_need, &srcp0_ihdl);
 	if (rc) {
 		pr_err("%s: in get_img() failed id=0x%08x\n",
 			DRIVER_NAME, info.src.memory_id);
@@ -881,7 +888,7 @@
 	}
 
 	rc = get_img(&info.dst, (unsigned long *)&out_paddr,
-			(unsigned long *)&dst_len, &dstp0_file, &dstp0_ihdl);
+		(unsigned long *)&dst_len, &dstp0_file, &p_need, &dstp0_ihdl);
 	if (rc) {
 		pr_err("%s: out get_img() failed id=0x%08x\n",
 		       DRIVER_NAME, info.dst.memory_id);
@@ -911,7 +918,7 @@
 
 		rc = get_img(&info.src_chroma,
 				(unsigned long *)&in_chroma_paddr,
-				(unsigned long *)&src_len, &srcp1_file,
+				(unsigned long *)&src_len, &srcp1_file, &p_need,
 				&srcp1_ihdl);
 		if (rc) {
 			pr_err("%s: in chroma get_img() failed id=0x%08x\n",
@@ -921,7 +928,7 @@
 
 		rc = get_img(&info.dst_chroma,
 				(unsigned long *)&out_chroma_paddr,
-				(unsigned long *)&dst_len, &dstp1_file,
+				(unsigned long *)&dst_len, &dstp1_file, &p_need,
 				&dstp1_ihdl);
 		if (rc) {
 			pr_err("%s: out chroma get_img() failed id=0x%08x\n",
@@ -1089,7 +1096,12 @@
 	put_img(dstp1_file, dstp1_ihdl);
 	put_img(srcp1_file, srcp1_ihdl);
 	put_img(dstp0_file, dstp0_ihdl);
-	put_img(srcp0_file, srcp0_ihdl);
+
+	/* only source may use frame buffer */
+	if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
+		fput_light(srcp0_file, ps0_need);
+	else
+		put_img(srcp0_file, srcp0_ihdl);
 	mutex_unlock(&msm_rotator_dev->rotator_lock);
 	dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
 		__func__, rc);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index ff15497..36375c05 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -273,8 +273,10 @@
 		trace_cpu_frequency(freqs->new, freqs->cpu);
 		srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
 				CPUFREQ_POSTCHANGE, freqs);
-		if (likely(policy) && likely(policy->cpu == freqs->cpu))
+		if (likely(policy) && likely(policy->cpu == freqs->cpu)) {
 			policy->cur = freqs->new;
+			sysfs_notify(&policy->kobj, NULL, "scaling_cur_freq");
+		}
 		break;
 	}
 }
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 5276bcc..0d3c4c39 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -155,10 +155,14 @@
 
 		ret = readl_relaxed(pce_dev->iobase + CRYPTO_CONFIG_REG);
 		if (ret) {
-			val = (CRYPTO_REQ_SIZE_ENUM_64_BYTES <<
-					CRYPTO_REQ_SIZE) |
-				(CRYPTO_FIFO_ENUM_64_BYTES <<
-					CRYPTO_FIFO_THRESHOLD);
+			val = BIT(CRYPTO_MASK_DOUT_INTR) |
+					BIT(CRYPTO_MASK_DIN_INTR) |
+					BIT(CRYPTO_MASK_OP_DONE_INTR) |
+					BIT(CRYPTO_MASK_ERR_INTR) |
+					(CRYPTO_REQ_SIZE_ENUM_64_BYTES <<
+						CRYPTO_REQ_SIZE) |
+					(CRYPTO_FIFO_ENUM_64_BYTES <<
+						CRYPTO_FIFO_THRESHOLD);
 
 			writel_relaxed(val, pce_dev->iobase +
 					CRYPTO_CONFIG_REG);
@@ -183,24 +187,6 @@
 	return 0;
 };
 
-static void config_ce_engine(struct qce_device *pce_dev)
-{
-	unsigned int val = 0;
-	unsigned int ret = 0;
-
-	/* Crypto config register returns a 0 when it is XPU protected. */
-	ret = readl_relaxed(pce_dev->iobase + CRYPTO_CONFIG_REG);
-
-	/* Configure the crypto register if it is not XPU protected. */
-	if (ret) {
-		val = BIT(CRYPTO_MASK_DOUT_INTR) |
-			BIT(CRYPTO_MASK_DIN_INTR) |
-			BIT(CRYPTO_MASK_OP_DONE_INTR) |
-			BIT(CRYPTO_MASK_ERR_INTR);
-
-		writel_relaxed(val, pce_dev->iobase + CRYPTO_CONFIG_REG);
-	}
-}
 
 static void _check_probe_done_call_back(struct msm_dmov_cmd *cmd_ptr,
 		unsigned int result, struct msm_dmov_errdata *err)
@@ -234,9 +220,6 @@
 	*/
 	mb();
 
-	/* Configure the CE Engine */
-	config_ce_engine(pce_dev);
-
 	/*
 	 * Clear ACCESS_VIOL bit in CRYPTO_STATUS REGISTER
 	*/
@@ -2622,4 +2605,4 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Crypto Engine driver");
-MODULE_VERSION("2.15");
+MODULE_VERSION("2.16");
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index c1a65fc..fff494c 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1,6 +1,6 @@
 /* Qualcomm CE device driver.
  *
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -172,7 +172,7 @@
 #endif
 }
 
-static int qcedev_ce_high_bw_req(struct qcedev_control *podev,
+static void qcedev_ce_high_bw_req(struct qcedev_control *podev,
 							bool high_bw_req)
 {
 	int ret = 0;
@@ -180,18 +180,22 @@
 	mutex_lock(&sent_bw_req);
 	if (high_bw_req) {
 		if (podev->high_bw_req_count == 0)
-			msm_bus_scale_client_update_request(
+			ret = msm_bus_scale_client_update_request(
 					podev->bus_scale_handle, 1);
+		if (ret)
+			pr_err("%s Unable to set to high bandwidth\n",
+							__func__);
 		podev->high_bw_req_count++;
 	} else {
 		if (podev->high_bw_req_count == 1)
-			msm_bus_scale_client_update_request(
+			ret = msm_bus_scale_client_update_request(
 					podev->bus_scale_handle, 0);
+		if (ret)
+			pr_err("%s Unable to set to low bandwidth\n",
+							__func__);
 		podev->high_bw_req_count--;
 	}
 	mutex_unlock(&sent_bw_req);
-
-	return ret;
 }
 
 
@@ -331,7 +335,7 @@
 	handle->cntl = podev;
 	file->private_data = handle;
 	if (podev->platform_support.bus_scale_table != NULL)
-		return qcedev_ce_high_bw_req(podev, true);
+		qcedev_ce_high_bw_req(podev, true);
 	return 0;
 }
 
@@ -349,7 +353,7 @@
 	kzfree(handle);
 	file->private_data = NULL;
 	if (podev->platform_support.bus_scale_table != NULL)
-		return qcedev_ce_high_bw_req(podev, false);
+		qcedev_ce_high_bw_req(podev, false);
 	return 0;
 }
 
@@ -2218,7 +2222,7 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Qualcomm DEV Crypto driver");
-MODULE_VERSION("1.25");
+MODULE_VERSION("1.26");
 
 module_init(qcedev_init);
 module_exit(qcedev_exit);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 3fff05c..21c3aff 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -1,6 +1,6 @@
 /* Qualcomm Crypto driver
  *
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -329,7 +329,7 @@
 	}
 }
 
-static int qcrypto_ce_high_bw_req(struct crypto_priv *cp, bool high_bw_req)
+static void qcrypto_ce_high_bw_req(struct crypto_priv *cp, bool high_bw_req)
 {
 	int ret = 0;
 
@@ -338,16 +338,20 @@
 		if (cp->high_bw_req_count == 0)
 			ret = msm_bus_scale_client_update_request(
 				cp->bus_scale_handle, 1);
+		if (ret)
+			pr_err("%s Unable to set to high bandwidth\n",
+							__func__);
 		cp->high_bw_req_count++;
 	} else {
 		if (cp->high_bw_req_count == 1)
 			ret = msm_bus_scale_client_update_request(
 				cp->bus_scale_handle, 0);
+		if (ret)
+			pr_err("%s Unable to set to low bandwidth\n",
+							__func__);
 		cp->high_bw_req_count--;
 	}
 	mutex_unlock(&sent_bw_req);
-
-	return ret;
 }
 
 static void _start_qcrypto_process(struct crypto_priv *cp);
@@ -403,7 +407,7 @@
 	/* random first IV */
 	get_random_bytes(ctx->iv, QCRYPTO_MAX_IV_LENGTH);
 	if (ctx->cp->platform_support.bus_scale_table != NULL)
-		return  qcrypto_ce_high_bw_req(ctx->cp, true);
+		qcrypto_ce_high_bw_req(ctx->cp, true);
 
 	return 0;
 };
@@ -440,7 +444,7 @@
 
 	sha_ctx->ahash_req = NULL;
 	if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
-		return qcrypto_ce_high_bw_req(sha_ctx->cp, true);
+		qcrypto_ce_high_bw_req(sha_ctx->cp, true);
 
 	return 0;
 };
@@ -3359,4 +3363,4 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Qualcomm Crypto driver");
-MODULE_VERSION("1.20");
+MODULE_VERSION("1.21");
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index a6c36c8..9b1e548 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -613,6 +613,11 @@
 	struct ion_iommu_map *iommu_map;
 	int ret = 0;
 
+	if (ION_IS_CACHED(flags)) {
+		pr_err("%s: Cannot map iommu as cached.\n", __func__);
+		return -EINVAL;
+	}
+
 	mutex_lock(&client->lock);
 	if (!ion_handle_validate(client, handle)) {
 		pr_err("%s: invalid handle passed to map_kernel.\n",
@@ -631,11 +636,6 @@
 		goto out;
 	}
 
-	if (ion_validate_buffer_flags(buffer, flags)) {
-		ret = -EEXIST;
-		goto out;
-	}
-
 	/*
 	 * If clients don't want a custom iova length, just use whatever
 	 * the buffer size is
@@ -882,7 +882,7 @@
 	return ret;
 }
 
-static int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
 			void *uaddr, unsigned long offset, unsigned long len,
 			unsigned int cmd)
 {
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 1d40aef..36758fa 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -271,4 +271,23 @@
 void *ion_map_fmem_buffer(struct ion_buffer *buffer, unsigned long phys_base,
 				void *virt_base, unsigned long flags);
 
+/**
+ * ion_do_cache_op - do cache operations.
+ *
+ * @client - pointer to ION client.
+ * @handle - pointer to buffer handle.
+ * @uaddr -  virtual address to operate on.
+ * @offset - offset from physical address.
+ * @len - Length of data to do cache operation on.
+ * @cmd - Cache operation to perform:
+ *		ION_IOC_CLEAN_CACHES
+ *		ION_IOC_INV_CACHES
+ *		ION_IOC_CLEAN_INV_CACHES
+ *
+ * Returns 0 on success
+ */
+int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+			void *uaddr, unsigned long offset, unsigned long len,
+			unsigned int cmd);
+
 #endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index a81dbd3..203b41a 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -43,6 +43,13 @@
 }
 EXPORT_SYMBOL(msm_ion_unsecure_heap);
 
+int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+			void *vaddr, unsigned long len, unsigned int cmd)
+{
+	return ion_do_cache_op(client, handle, vaddr, 0, len, cmd);
+}
+EXPORT_SYMBOL(msm_ion_do_cache_op);
+
 static unsigned long msm_ion_get_base(unsigned long size, int memory_type,
 				    unsigned int align)
 {
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 73d00b3..0cadc33 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -136,6 +136,9 @@
 	{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
 		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
 		512, 384, 3},
+	{ ADRENO_REV_A203, 0, 1, 1, ANY_ID,
+		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
+		512, 384, 3},
 	{ ADRENO_REV_A205, 0, 1, 0, ANY_ID,
 		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
 		512, 384, 3},
@@ -400,11 +403,14 @@
 
 	/* 8x50 returns 0 for patch release, but it should be 1 */
 	/* 8960v3 returns 5 for patch release, but it should be 6 */
+	/* 8x25 returns 0 for minor id, but it should be 1 */
 	if (cpu_is_qsd8x50())
 		patchid = 1;
 	else if (cpu_is_msm8960() &&
 			SOCINFO_VERSION_MAJOR(soc_platform_version) == 3)
 		patchid = 6;
+	else if (cpu_is_msm8625() && minorid == 0)
+		minorid = 1;
 
 	chipid |= (minorid << 8) | patchid;
 
@@ -604,6 +610,8 @@
 	unsigned int soptimestamp;
 	unsigned int eoptimestamp;
 	struct adreno_context *drawctxt;
+	struct kgsl_context *context;
+	int next = 0;
 
 	KGSL_DRV_ERR(device, "Starting recovery from 3D GPU hang....\n");
 	rb_buffer = vmalloc(rb->buffer_desc.size);
@@ -672,6 +680,24 @@
 
 	drawctxt->flags |= CTXT_FLAGS_GPU_HANG;
 
+	/*
+	 * Set the reset status of all contexts to
+	 * INNOCENT_CONTEXT_RESET_EXT except for the bad context
+	 * since thats the guilty party
+	 */
+	while ((context = idr_get_next(&device->context_idr, &next))) {
+		if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
+			context->reset_status) {
+			if (context->devctxt != drawctxt)
+				context->reset_status =
+				KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
+			else
+				context->reset_status =
+				KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+		}
+		next = next + 1;
+	}
+
 	/* Restore valid commands in ringbuffer */
 	adreno_ringbuffer_restore(rb, rb_buffer, num_rb_contents);
 	rb->timestamp = timestamp;
@@ -967,8 +993,7 @@
 		if (!kgsl_mmu_pt_equal(priv->pagetable, pt_base))
 			continue;
 		spin_lock(&priv->mem_lock);
-		entry = kgsl_sharedmem_find_region(priv, gpuaddr,
-						sizeof(unsigned int));
+		entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
 		if (entry) {
 			result = &entry->memdesc;
 			spin_unlock(&priv->mem_lock);
@@ -1248,7 +1273,7 @@
 	default:
 		KGSL_DRV_INFO(dev_priv->device,
 			"invalid ioctl code %08x\n", cmd);
-		result = -EINVAL;
+		result = -ENOIOCTLCMD;
 		break;
 	}
 	return result;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 9498b80..74f36c3 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -44,6 +44,7 @@
 enum adreno_gpurev {
 	ADRENO_REV_UNKNOWN = 0,
 	ADRENO_REV_A200 = 200,
+	ADRENO_REV_A203 = 203,
 	ADRENO_REV_A205 = 205,
 	ADRENO_REV_A220 = 220,
 	ADRENO_REV_A225 = 225,
@@ -129,15 +130,19 @@
 	return (adreno_dev->gpurev == ADRENO_REV_A200);
 }
 
+static inline int adreno_is_a203(struct adreno_device *adreno_dev)
+{
+	return (adreno_dev->gpurev == ADRENO_REV_A203);
+}
+
 static inline int adreno_is_a205(struct adreno_device *adreno_dev)
 {
-	return (adreno_dev->gpurev == ADRENO_REV_A200);
+	return (adreno_dev->gpurev == ADRENO_REV_A205);
 }
 
 static inline int adreno_is_a20x(struct adreno_device *adreno_dev)
 {
-	return (adreno_dev->gpurev  == ADRENO_REV_A200 ||
-		adreno_dev->gpurev == ADRENO_REV_A205);
+	return (adreno_dev->gpurev <= 209);
 }
 
 static inline int adreno_is_a220(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index b53ca8f..68299cf 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,7 +23,8 @@
 #include "a2xx_reg.h"
 
 unsigned int kgsl_cff_dump_enable;
-int kgsl_pm_regs_enabled;
+int adreno_pm_regs_enabled;
+int adreno_pm_ib_enabled;
 
 static struct dentry *pm_d_debugfs;
 
@@ -46,20 +47,37 @@
 
 static int pm_regs_enabled_set(void *data, u64 val)
 {
-	kgsl_pm_regs_enabled = val ? 1 : 0;
+	adreno_pm_regs_enabled = val ? 1 : 0;
 	return 0;
 }
 
 static int pm_regs_enabled_get(void *data, u64 *val)
 {
-	*val = kgsl_pm_regs_enabled;
+	*val = adreno_pm_regs_enabled;
 	return 0;
 }
 
+static int pm_ib_enabled_set(void *data, u64 val)
+{
+	adreno_pm_ib_enabled = val ? 1 : 0;
+	return 0;
+}
+
+static int pm_ib_enabled_get(void *data, u64 *val)
+{
+	*val = adreno_pm_ib_enabled;
+	return 0;
+}
+
+
 DEFINE_SIMPLE_ATTRIBUTE(pm_regs_enabled_fops,
 			pm_regs_enabled_get,
 			pm_regs_enabled_set, "%llu\n");
 
+DEFINE_SIMPLE_ATTRIBUTE(pm_ib_enabled_fops,
+			pm_ib_enabled_get,
+			pm_ib_enabled_set, "%llu\n");
+
 
 static int kgsl_cff_dump_enable_set(void *data, u64 val)
 {
@@ -358,4 +376,6 @@
 			    &pm_dump_fops);
 	debugfs_create_file("regs_enabled", 0644, pm_d_debugfs, device,
 			    &pm_regs_enabled_fops);
+	debugfs_create_file("ib_enabled", 0644, pm_d_debugfs, device,
+				    &pm_ib_enabled_fops);
 }
diff --git a/drivers/gpu/msm/adreno_debugfs.h b/drivers/gpu/msm/adreno_debugfs.h
index 0356ac6e..5f8d89a 100644
--- a/drivers/gpu/msm/adreno_debugfs.h
+++ b/drivers/gpu/msm/adreno_debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,11 +17,17 @@
 
 int adreno_debugfs_init(struct kgsl_device *device);
 
-extern int kgsl_pm_regs_enabled;
+extern int adreno_pm_regs_enabled;
+extern int adreno_pm_ib_enabled;
 
-static inline int kgsl_pmregs_enabled(void)
+static inline int is_adreno_pm_regs_enabled(void)
 {
-	return kgsl_pm_regs_enabled;
+	return adreno_pm_regs_enabled;
+}
+
+static inline int is_adreno_pm_ib_enabled(void)
+{
+	return adreno_pm_ib_enabled;
 }
 
 #else
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index f99462e..75512d0 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -209,4 +209,14 @@
 /* gmem command buffer length */
 #define CP_REG(reg) ((0x4 << 16) | (SUBBLOCK_OFFSET(reg)))
 
+
+/* Return 1 if the command is an indirect buffer of any kind */
+static inline int adreno_cmd_is_ib(unsigned int cmd)
+{
+	return (cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2) ||
+		cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2) ||
+		cmd == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFE, 2) ||
+		cmd == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFD, 2));
+}
+
 #endif	/* __ADRENO_PM4TYPES_H */
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 7902f305..e4bc470 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -201,7 +201,7 @@
 
 	for (i = 0; i+3 < ib1_size; ) {
 		value = ib1_addr[i++];
-		if (value == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
+		if (adreno_cmd_is_ib(value)) {
 			uint32_t ib2_base = ib1_addr[i++];
 			uint32_t ib2_size = ib1_addr[i++];
 
@@ -294,15 +294,6 @@
 	}
 }
 
-static bool adreno_ib_dump_enabled(void)
-{
-#ifdef CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP
-	return 0;
-#else
-	return 1;
-#endif
-}
-
 struct log_field {
 	bool show;
 	const char *display;
@@ -778,7 +769,7 @@
 	i = 0;
 	for (read_idx = 0; read_idx < num_item; ) {
 		uint32_t this_cmd = rb_copy[read_idx++];
-		if (this_cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
+		if (adreno_cmd_is_ib(this_cmd)) {
 			uint32_t ib_addr = rb_copy[read_idx++];
 			uint32_t ib_size = rb_copy[read_idx++];
 			dump_ib1(device, cur_pt_base, (read_idx-3)<<2, ib_addr,
@@ -817,12 +808,11 @@
 		cp_rb_base, cp_rb_rptr, cp_rb_wptr, read_idx);
 	adreno_dump_rb(device, rb_copy, num_item<<2, read_idx, rb_count);
 
-	if (adreno_ib_dump_enabled()) {
+	if (is_adreno_pm_ib_enabled()) {
 		for (read_idx = NUM_DWORDS_OF_RINGBUFFER_HISTORY;
 			read_idx >= 0; --read_idx) {
 			uint32_t this_cmd = rb_copy[read_idx];
-			if (this_cmd == cp_type3_packet(
-				CP_INDIRECT_BUFFER_PFD, 2)) {
+			if (adreno_cmd_is_ib(this_cmd)) {
 				uint32_t ib_addr = rb_copy[read_idx+1];
 				uint32_t ib_size = rb_copy[read_idx+2];
 				if (ib_size && cp_ib1_base == ib_addr) {
@@ -849,16 +839,17 @@
 	}
 
 	/* Dump the registers if the user asked for it */
-
-	if (adreno_is_a20x(adreno_dev))
-		adreno_dump_regs(device, a200_registers,
-			a200_registers_count);
-	else if (adreno_is_a22x(adreno_dev))
-		adreno_dump_regs(device, a220_registers,
-			a220_registers_count);
-	else if (adreno_is_a3xx(adreno_dev))
-		adreno_dump_regs(device, a3xx_registers,
-			a3xx_registers_count);
+	if (is_adreno_pm_regs_enabled()) {
+		if (adreno_is_a20x(adreno_dev))
+			adreno_dump_regs(device, a200_registers,
+					a200_registers_count);
+		else if (adreno_is_a22x(adreno_dev))
+			adreno_dump_regs(device, a220_registers,
+					a220_registers_count);
+		else if (adreno_is_a3xx(adreno_dev))
+			adreno_dump_regs(device, a3xx_registers,
+					a3xx_registers_count);
+	}
 
 error_vfree:
 	vfree(rb_copy);
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index a4899a2..9836043 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -104,15 +104,6 @@
 	return 0;
 }
 
-/* Return 1 if the packet starting at ptr is an indirect buffer of any kind */
-static inline int packet_is_buffer(unsigned int *ptr)
-{
-	return (*ptr == cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2) ||
-		*ptr == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2) ||
-		*ptr == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFE, 2) ||
-		*ptr == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFD, 2));
-}
-
 /* Snapshot the istore memory */
 static int snapshot_istore(struct kgsl_device *device, void *snapshot,
 	int remain, void *priv)
@@ -258,7 +249,7 @@
 		if (index == rptr)
 			parse_ibs = 0;
 
-		if (parse_ibs && packet_is_buffer(&rbptr[index]))
+		if (parse_ibs && adreno_cmd_is_ib(rbptr[index]))
 			push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
 				rbptr[index + 1], rbptr[index + 2]);
 
@@ -312,7 +303,7 @@
 		*dst = *src;
 		/* If another IB is discovered, then push it on the list too */
 
-		if (packet_is_buffer(src))
+		if (adreno_cmd_is_ib(*src))
 			push_object(device, SNAPSHOT_OBJ_TYPE_IB, obj->ptbase,
 				*(src + 1), *(src + 2));
 
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 9333dca..b7356ac 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -789,6 +789,40 @@
 
 		break;
 	}
+	case KGSL_PROP_GPU_RESET_STAT:
+	{
+		/* Return reset status of given context and clear it */
+		uint32_t id;
+		struct kgsl_context *context;
+
+		if (param->sizebytes != sizeof(unsigned int)) {
+			result = -EINVAL;
+			break;
+		}
+		/* We expect the value passed in to contain the context id */
+		if (copy_from_user(&id, param->value,
+			sizeof(unsigned int))) {
+			result = -EFAULT;
+			break;
+		}
+		context = kgsl_find_context(dev_priv, id);
+		if (!context) {
+			result = -EINVAL;
+			break;
+		}
+		/*
+		 * Copy the reset status to value which also serves as
+		 * the out parameter
+		 */
+		if (copy_to_user(param->value, &(context->reset_status),
+			sizeof(unsigned int))) {
+			result = -EFAULT;
+			break;
+		}
+		/* Clear reset status once its been queried */
+		context->reset_status = KGSL_CTX_STAT_NO_ERROR;
+		break;
+	}
 	default:
 		result = dev_priv->device->ftbl->getproperty(
 					dev_priv->device, param->type,
@@ -990,6 +1024,7 @@
 	spin_lock(&entry->priv->mem_lock);
 	list_del(&entry->list);
 	spin_unlock(&entry->priv->mem_lock);
+	trace_kgsl_mem_timestamp_free(entry, timestamp);
 	kgsl_mem_entry_put(entry);
 }
 
@@ -1000,12 +1035,18 @@
 	int result = 0;
 	struct kgsl_cmdstream_freememontimestamp *param = data;
 	struct kgsl_mem_entry *entry = NULL;
+	struct kgsl_device *device = dev_priv->device;
+	unsigned int cur;
 
 	spin_lock(&dev_priv->process_priv->mem_lock);
 	entry = kgsl_sharedmem_find(dev_priv->process_priv, param->gpuaddr);
 	spin_unlock(&dev_priv->process_priv->mem_lock);
 
 	if (entry) {
+		cur = device->ftbl->readtimestamp(device,
+						KGSL_TIMESTAMP_RETIRED);
+
+		trace_kgsl_mem_timestamp_queue(entry, cur);
 		result = kgsl_add_event(dev_priv->device, param->timestamp,
 					kgsl_freemem_event_cb, entry, dev_priv);
 	} else {
@@ -1084,6 +1125,7 @@
 	spin_unlock(&private->mem_lock);
 
 	if (entry) {
+		trace_kgsl_mem_free(entry);
 		kgsl_mem_entry_put(entry);
 	} else {
 		KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
@@ -1184,6 +1226,7 @@
 
 	kgsl_mem_entry_attach_process(entry, private);
 
+	trace_kgsl_mem_alloc(entry);
 	/* Process specific statistics */
 	kgsl_process_add_stats(private, entry->memtype, len);
 
@@ -1618,6 +1661,7 @@
 	kgsl_process_add_stats(private, entry->memtype, param->len);
 
 	kgsl_mem_entry_attach_process(entry, private);
+	trace_kgsl_mem_map(entry, param->fd);
 
 	kgsl_check_idle(dev_priv->device);
 	return result;
@@ -1684,6 +1728,7 @@
 		param->gpuaddr = entry->memdesc.gpuaddr;
 
 		kgsl_process_add_stats(private, entry->memtype, param->size);
+		trace_kgsl_mem_alloc(entry);
 	} else
 		kfree(entry);
 
@@ -1930,7 +1975,7 @@
 		if (!func) {
 			KGSL_DRV_INFO(dev_priv->device,
 				      "invalid ioctl code %08x\n", cmd);
-			ret = -EINVAL;
+			ret = -ENOIOCTLCMD;
 			goto done;
 		}
 		lock = 1;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2fb1e43..06432f9 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -197,6 +197,11 @@
 
 	/* Pointer to the device specific context information */
 	void *devctxt;
+	/*
+	 * Status indicating whether a gpu reset occurred and whether this
+	 * context was responsible for causing it
+	 */
+	unsigned int reset_status;
 };
 
 struct kgsl_process_private {
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 389ed6d..7264c25 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -150,7 +150,7 @@
 #endif
 	MEM_ENTRY_STAT(KGSL_MEM_ENTRY_USER, user),
 #ifdef CONFIG_ION
-	MEM_ENTRY_STAT(KGSL_MEM_ENTRY_USER, ion),
+	MEM_ENTRY_STAT(KGSL_MEM_ENTRY_ION, ion),
 #endif
 };
 
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index de39ee4..93fdc087 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/vmalloc.h>
 #include <linux/time.h>
 #include <linux/sysfs.h>
 #include <linux/utsname.h>
@@ -299,6 +298,10 @@
 	/* Freeze the snapshot on a hang until it gets read */
 	device->snapshot_frozen = (hang) ? 1 : 0;
 
+	/* log buffer info to aid in ramdump recovery */
+	KGSL_DRV_ERR(device, "snapshot created at va %p pa %lx size %d\n",
+			device->snapshot, __pa(device->snapshot),
+			device->snapshot_size);
 	return 0;
 }
 EXPORT_SYMBOL(kgsl_device_snapshot);
@@ -448,7 +451,7 @@
 	int ret;
 
 	if (device->snapshot == NULL)
-		device->snapshot = vmalloc(KGSL_SNAPSHOT_MEMSIZE);
+		device->snapshot = kzalloc(KGSL_SNAPSHOT_MEMSIZE, GFP_KERNEL);
 
 	if (device->snapshot == NULL)
 		return -ENOMEM;
@@ -491,7 +494,7 @@
 
 	kobject_put(&device->snapshot_kobj);
 
-	vfree(device->snapshot);
+	kfree(device->snapshot);
 
 	device->snapshot = NULL;
 	device->snapshot_maxsize = 0;
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 86a9adc..22bc576 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -257,6 +257,122 @@
 	TP_ARGS(device, state)
 );
 
+TRACE_EVENT(kgsl_mem_alloc,
+
+	TP_PROTO(struct kgsl_mem_entry *mem_entry),
+
+	TP_ARGS(mem_entry),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, gpuaddr)
+		__field(unsigned int, size)
+	),
+
+	TP_fast_assign(
+		__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+		__entry->size = mem_entry->memdesc.size;
+	),
+
+	TP_printk(
+		"gpuaddr=0x%08x size=%d",
+		__entry->gpuaddr, __entry->size
+	)
+);
+
+TRACE_EVENT(kgsl_mem_map,
+
+	TP_PROTO(struct kgsl_mem_entry *mem_entry, int fd),
+
+	TP_ARGS(mem_entry, fd),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, gpuaddr)
+		__field(unsigned int, size)
+		__field(int, fd)
+		__field(int, type)
+	),
+
+	TP_fast_assign(
+		__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+		__entry->size = mem_entry->memdesc.size;
+		__entry->fd = fd;
+		__entry->type = mem_entry->memtype;
+	),
+
+	TP_printk(
+		"gpuaddr=0x%08x size=%d type=%d fd=%d",
+		__entry->gpuaddr, __entry->size,
+		__entry->type, __entry->fd
+	)
+);
+
+TRACE_EVENT(kgsl_mem_free,
+
+	TP_PROTO(struct kgsl_mem_entry *mem_entry),
+
+	TP_ARGS(mem_entry),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, gpuaddr)
+		__field(unsigned int, size)
+		__field(int, type)
+		__field(int, fd)
+	),
+
+	TP_fast_assign(
+		__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+		__entry->size = mem_entry->memdesc.size;
+		__entry->type = mem_entry->memtype;
+	),
+
+	TP_printk(
+		"gpuaddr=0x%08x size=%d type=%d",
+		__entry->gpuaddr, __entry->size, __entry->type
+	)
+);
+
+DECLARE_EVENT_CLASS(kgsl_mem_timestamp_template,
+
+	TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned int curr_ts),
+
+	TP_ARGS(mem_entry, curr_ts),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, gpuaddr)
+		__field(unsigned int, size)
+		__field(int, type)
+		__field(unsigned int, drawctxt_id)
+		__field(unsigned int, curr_ts)
+		__field(unsigned int, free_ts)
+	),
+
+	TP_fast_assign(
+		__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+		__entry->size = mem_entry->memdesc.size;
+		__entry->drawctxt_id = 1337;
+		__entry->type = mem_entry->memtype;
+		__entry->curr_ts = curr_ts;
+		__entry->free_ts = mem_entry->free_timestamp;
+	),
+
+	TP_printk(
+		"gpuaddr=0x%08x size=%d type=%d ctx=%u curr_ts=0x%08x free_ts=0x%08x",
+		__entry->gpuaddr, __entry->size, __entry->type,
+		__entry->drawctxt_id, __entry->curr_ts, __entry->free_ts
+	)
+);
+
+DEFINE_EVENT(kgsl_mem_timestamp_template, kgsl_mem_timestamp_queue,
+	TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned int curr_ts),
+	TP_ARGS(mem_entry, curr_ts)
+);
+
+DEFINE_EVENT(kgsl_mem_timestamp_template, kgsl_mem_timestamp_free,
+	TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned int curr_ts),
+	TP_ARGS(mem_entry, curr_ts)
+);
+
+
 #endif /* _KGSL_TRACE_H */
 
 /* This part must be outside protection */
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index cb3da90..6c43a75 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -339,13 +339,15 @@
 	*p++ = ADDR_VGV3_LAST << 24;
 }
 
-static void z180_cmdstream_start(struct kgsl_device *device)
+static void z180_cmdstream_start(struct kgsl_device *device, int init_ram)
 {
 	struct z180_device *z180_dev = Z180_DEVICE(device);
 	unsigned int cmd = VGV3_NEXTCMD_JUMP << VGV3_NEXTCMD_NEXTCMD_FSHIFT;
 
-	z180_dev->timestamp = 0;
-	z180_dev->current_timestamp = 0;
+	if (init_ram) {
+		z180_dev->timestamp = 0;
+		z180_dev->current_timestamp = 0;
+	}
 
 	addmarker(&z180_dev->ringbuffer, 0);
 
@@ -566,7 +568,7 @@
 	if (status)
 		goto error_clk_off;
 
-	z180_cmdstream_start(device);
+	z180_cmdstream_start(device, init_ram);
 
 	mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 40aae69..f5bfc7b 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -25,6 +25,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/regulator/consumer.h>
+#include <linux/string.h>
 
 #if defined(CONFIG_HAS_EARLYSUSPEND)
 #include <linux/earlysuspend.h>
@@ -42,15 +43,32 @@
 #define MXT_VER_21		21
 #define MXT_VER_22		22
 
-/* Slave addresses */
-#define MXT_APP_LOW		0x4a
-#define MXT_APP_HIGH		0x4b
-#define MXT_BOOT_LOW		0x24
-#define MXT_BOOT_HIGH		0x25
+/* I2C slave address pairs */
+struct mxt_address_pair {
+	int bootloader;
+	int application;
+};
+
+static const struct mxt_address_pair mxt_slave_addresses[] = {
+	{ 0x24, 0x4a },
+	{ 0x25, 0x4b },
+	{ 0x25, 0x4b },
+	{ 0x26, 0x4c },
+	{ 0x27, 0x4d },
+	{ 0x34, 0x5a },
+	{ 0x35, 0x5b },
+	{ 0 },
+};
+
+enum mxt_device_state { INIT, APPMODE, BOOTLOADER };
 
 /* Firmware */
 #define MXT_FW_NAME		"maxtouch.fw"
 
+/* Firmware frame size including frame data and CRC */
+#define MXT_SINGLE_FW_MAX_FRAME_SIZE	278
+#define MXT_CHIPSET_FW_MAX_FRAME_SIZE	534
+
 /* Registers */
 #define MXT_FAMILY_ID		0x00
 #define MXT_VARIANT_ID		0x01
@@ -215,7 +233,7 @@
 #define MXT_RESET_TIME		250	/* msec */
 #define MXT_RESET_NOCHGREAD	400	/* msec */
 
-#define MXT_FWRESET_TIME	175	/* msec */
+#define MXT_FWRESET_TIME	1000	/* msec */
 
 #define MXT_WAKE_TIME		25
 
@@ -231,6 +249,8 @@
 #define MXT_FRAME_CRC_PASS	0x04
 #define MXT_APP_CRC_FAIL	0x40	/* valid 7 8 bit only */
 #define MXT_BOOT_STATUS_MASK	0x3f
+#define MXT_BOOT_EXTENDED_ID	(1 << 5)
+#define MXT_BOOT_ID_MASK	0x1f
 
 /* Touch status */
 #define MXT_SUPPRESS		(1 << 1)
@@ -299,6 +319,7 @@
 	struct input_dev *input_dev;
 	const struct mxt_platform_data *pdata;
 	const struct mxt_config_info *config_info;
+	enum mxt_device_state state;
 	struct mxt_object *object_table;
 	struct mxt_info info;
 	struct mxt_finger finger[MXT_MAX_FINGER];
@@ -323,6 +344,7 @@
 	u8 t15_min_reportid;
 	u8 curr_cfg_version;
 	int cfg_version_idx;
+	const char *fw_name;
 };
 
 static struct dentry *debug_base;
@@ -409,8 +431,116 @@
 	dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
 }
 
+static int mxt_switch_to_bootloader_address(struct mxt_data *data)
+{
+	int i;
+	struct i2c_client *client = data->client;
+
+	if (data->state == BOOTLOADER) {
+		dev_err(&client->dev, "Already in BOOTLOADER state\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; mxt_slave_addresses[i].application != 0;  i++) {
+		if (mxt_slave_addresses[i].application == client->addr) {
+			dev_info(&client->dev, "Changing to bootloader address: "
+				"%02x -> %02x",
+				client->addr,
+				mxt_slave_addresses[i].bootloader);
+
+			client->addr = mxt_slave_addresses[i].bootloader;
+			data->state = BOOTLOADER;
+			return 0;
+		}
+	}
+
+	dev_err(&client->dev, "Address 0x%02x not found in address table",
+								client->addr);
+	return -EINVAL;
+}
+
+static int mxt_switch_to_appmode_address(struct mxt_data *data)
+{
+	int i;
+	struct i2c_client *client = data->client;
+
+	if (data->state == APPMODE) {
+		dev_err(&client->dev, "Already in APPMODE state\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; mxt_slave_addresses[i].application != 0;  i++) {
+		if (mxt_slave_addresses[i].bootloader == client->addr) {
+			dev_info(&client->dev,
+				"Changing to application mode address: "
+							"0x%02x -> 0x%02x",
+				client->addr,
+				mxt_slave_addresses[i].application);
+
+			client->addr = mxt_slave_addresses[i].application;
+			data->state = APPMODE;
+			return 0;
+		}
+	}
+
+	dev_err(&client->dev, "Address 0x%02x not found in address table",
+								client->addr);
+	return -EINVAL;
+}
+
+static int mxt_get_bootloader_version(struct i2c_client *client, u8 val)
+{
+	u8 buf[3];
+
+	if (val | MXT_BOOT_EXTENDED_ID)	{
+		dev_dbg(&client->dev,
+				"Retrieving extended mode ID information");
+
+		if (i2c_master_recv(client, &buf[0], 3) != 3) {
+			dev_err(&client->dev, "%s: i2c recv failed\n",
+								__func__);
+			return -EIO;
+		}
+
+		dev_info(&client->dev, "Bootloader ID:%d Version:%d",
+			buf[1], buf[2]);
+
+		return buf[0];
+	} else {
+		dev_info(&client->dev, "Bootloader ID:%d",
+			val & MXT_BOOT_ID_MASK);
+
+		return val;
+	}
+}
+
+static int mxt_get_bootloader_id(struct i2c_client *client)
+{
+	u8 val;
+	u8 buf[3];
+
+	if (i2c_master_recv(client, &val, 1) != 1) {
+		dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
+		return -EIO;
+	}
+
+	if (val | MXT_BOOT_EXTENDED_ID)	{
+		if (i2c_master_recv(client, &buf[0], 3) != 3) {
+			dev_err(&client->dev, "%s: i2c recv failed\n",
+								__func__);
+			return -EIO;
+		}
+		return buf[1];
+	} else {
+		dev_info(&client->dev, "Bootloader ID:%d",
+			val & MXT_BOOT_ID_MASK);
+
+		return val & MXT_BOOT_ID_MASK;
+	}
+}
+
 static int mxt_check_bootloader(struct i2c_client *client,
-				     unsigned int state)
+				unsigned int state)
 {
 	u8 val;
 
@@ -422,19 +552,28 @@
 
 	switch (state) {
 	case MXT_WAITING_BOOTLOAD_CMD:
+		val = mxt_get_bootloader_version(client, val);
+		val &= ~MXT_BOOT_STATUS_MASK;
+		break;
 	case MXT_WAITING_FRAME_DATA:
+	case MXT_APP_CRC_FAIL:
 		val &= ~MXT_BOOT_STATUS_MASK;
 		break;
 	case MXT_FRAME_CRC_PASS:
 		if (val == MXT_FRAME_CRC_CHECK)
 			goto recheck;
+		if (val == MXT_FRAME_CRC_FAIL) {
+			dev_err(&client->dev, "Bootloader CRC fail\n");
+			return -EINVAL;
+		}
 		break;
 	default:
 		return -EINVAL;
 	}
 
 	if (val != state) {
-		dev_err(&client->dev, "Unvalid bootloader mode state\n");
+		dev_err(&client->dev, "Invalid bootloader mode state %X\n",
+			val);
 		return -EINVAL;
 	}
 
@@ -457,7 +596,7 @@
 }
 
 static int mxt_fw_write(struct i2c_client *client,
-			     const u8 *data, unsigned int frame_size)
+			const u8 *data, unsigned int frame_size)
 {
 	if (i2c_master_send(client, data, frame_size) != frame_size) {
 		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
@@ -735,6 +874,11 @@
 	int id;
 	u8 reportid;
 
+	if (data->state != APPMODE) {
+		dev_err(dev, "Ignoring IRQ - not in APPMODE state\n");
+		return IRQ_HANDLED;
+	}
+
 	do {
 		if (mxt_read_message(data, &message)) {
 			dev_err(dev, "Failed to read message\n");
@@ -921,11 +1065,13 @@
 			if (data->curr_cfg_version == cfg_version ||
 				!version_match) {
 				data->config_info = cfg_info;
+				data->fw_name = pdata->config_array[i].fw_name;
 				return 0;
 			}
 		}
 	}
 
+	data->fw_name = NULL;
 	dev_info(&data->client->dev,
 		"Config not found: F: %d, V: %d, FW: %d.%d.%d, CFG: %d\n",
 		info->family_id, info->variant_id,
@@ -1003,8 +1149,30 @@
 	struct mxt_object *t15_object;
 
 	error = mxt_get_info(data);
-	if (error)
-		return error;
+	if (error) {
+		/* Try bootloader mode */
+		error = mxt_switch_to_bootloader_address(data);
+		if (error)
+			return error;
+
+		error = mxt_check_bootloader(client, MXT_APP_CRC_FAIL);
+		if (error)
+			return error;
+
+		dev_err(&client->dev, "Application CRC failure\n");
+		data->state = BOOTLOADER;
+
+		return 0;
+	}
+
+	dev_info(&client->dev,
+			"Family ID: %d Variant ID: %d Version: %d.%d "
+			"Build: 0x%02X Object Num: %d\n",
+			info->family_id, info->variant_id,
+			info->version >> 4, info->version & 0xf,
+			info->build, info->object_num);
+
+	data->state = APPMODE;
 
 	data->object_table = kcalloc(info->object_num,
 				     sizeof(struct mxt_object),
@@ -1112,14 +1280,8 @@
 	info->matrix_ysize = val;
 
 	dev_info(&client->dev,
-			"Family ID: %d Variant ID: %d Version: %d Build: %d\n",
-			info->family_id, info->variant_id, info->version,
-			info->build);
-
-	dev_info(&client->dev,
-			"Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n",
-			info->matrix_xsize, info->matrix_ysize,
-			info->object_num);
+			"Matrix X Size: %d Matrix Y Size: %d\n",
+			info->matrix_xsize, info->matrix_ysize);
 
 	return 0;
 
@@ -1175,108 +1337,230 @@
 	return count;
 }
 
+static int strtobyte(const char *data, u8 *value)
+{
+	char str[3];
+
+	str[0] = data[0];
+	str[1] = data[1];
+	str[2] = '\0';
+
+	return kstrtou8(str, 16, value);
+}
+
 static int mxt_load_fw(struct device *dev, const char *fn)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
 	struct i2c_client *client = data->client;
 	const struct firmware *fw = NULL;
 	unsigned int frame_size;
+	unsigned int retry = 0;
 	unsigned int pos = 0;
-	int ret;
+	int ret, i, max_frame_size;
+	u8 *frame;
 
-	ret = request_firmware(&fw, fn, dev);
-	if (ret) {
-		dev_err(dev, "Unable to open firmware %s\n", fn);
-		return ret;
+	switch (data->info.family_id) {
+	case MXT224_ID:
+		max_frame_size = MXT_SINGLE_FW_MAX_FRAME_SIZE;
+		break;
+	case MXT1386_ID:
+		max_frame_size = MXT_CHIPSET_FW_MAX_FRAME_SIZE;
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	/* Change to the bootloader mode */
-	mxt_write_object(data, MXT_GEN_COMMAND_T6,
-			MXT_COMMAND_RESET, MXT_BOOT_VALUE);
+	frame = kmalloc(max_frame_size, GFP_KERNEL);
+	if (!frame) {
+		dev_err(dev, "Unable to allocate memory for frame data\n");
+		return -ENOMEM;
+	}
 
-	mxt_reset_delay(data);
+	ret = request_firmware(&fw, fn, dev);
+	if (ret < 0) {
+		dev_err(dev, "Unable to open firmware %s\n", fn);
+		goto free_frame;
+	}
 
-	/* Change to slave address of bootloader */
-	if (client->addr == MXT_APP_LOW)
-		client->addr = MXT_BOOT_LOW;
-	else
-		client->addr = MXT_BOOT_HIGH;
+	if (data->state != BOOTLOADER) {
+		/* Change to the bootloader mode */
+		mxt_write_object(data, MXT_GEN_COMMAND_T6,
+				MXT_COMMAND_RESET, MXT_BOOT_VALUE);
+		mxt_reset_delay(data);
+
+		ret = mxt_switch_to_bootloader_address(data);
+		if (ret)
+			goto release_firmware;
+	}
 
 	ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
-	if (ret)
-		goto out;
+	if (ret) {
+		/* Bootloader may still be unlocked from previous update
+		 * attempt */
+		ret = mxt_check_bootloader(client,
+			MXT_WAITING_FRAME_DATA);
 
-	/* Unlock bootloader */
-	mxt_unlock_bootloader(client);
+		if (ret)
+			goto return_to_app_mode;
+	} else {
+		dev_info(dev, "Unlocking bootloader\n");
+		/* Unlock bootloader */
+		mxt_unlock_bootloader(client);
+	}
 
 	while (pos < fw->size) {
 		ret = mxt_check_bootloader(client,
 						MXT_WAITING_FRAME_DATA);
 		if (ret)
-			goto out;
+			goto release_firmware;
 
-		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
+		/* Get frame length MSB */
+		ret = strtobyte(fw->data + pos, frame);
+		if (ret)
+			goto release_firmware;
+
+		/* Get frame length LSB */
+		ret = strtobyte(fw->data + pos + 2, frame + 1);
+		if (ret)
+			goto release_firmware;
+
+		frame_size = ((*frame << 8) | *(frame + 1));
 
 		/* We should add 2 at frame size as the the firmware data is not
 		 * included the CRC bytes.
 		 */
 		frame_size += 2;
 
+		if (frame_size > max_frame_size) {
+			dev_err(dev, "Invalid frame size - %d\n", frame_size);
+			ret = -EINVAL;
+			goto release_firmware;
+		}
+
+		/* Convert frame data and CRC from hex to binary */
+		for (i = 2; i < frame_size; i++) {
+			ret = strtobyte(fw->data + pos + i * 2, frame + i);
+			if (ret)
+				goto release_firmware;
+		}
+
 		/* Write one frame to device */
-		mxt_fw_write(client, fw->data + pos, frame_size);
+		mxt_fw_write(client, frame, frame_size);
 
 		ret = mxt_check_bootloader(client,
 						MXT_FRAME_CRC_PASS);
-		if (ret)
-			goto out;
+		if (ret) {
+			retry++;
 
-		pos += frame_size;
+			/* Back off by 20ms per retry */
+			msleep(retry * 20);
 
-		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
+			if (retry > 20)
+				goto release_firmware;
+		} else {
+			retry = 0;
+			pos += frame_size * 2;
+			dev_dbg(dev, "Updated %d/%zd bytes\n", pos, fw->size);
+		}
 	}
 
-out:
+return_to_app_mode:
+	mxt_switch_to_appmode_address(data);
+release_firmware:
 	release_firmware(fw);
-
-	/* Change to slave address of application */
-	if (client->addr == MXT_BOOT_LOW)
-		client->addr = MXT_APP_LOW;
-	else
-		client->addr = MXT_APP_HIGH;
+free_frame:
+	kfree(frame);
 
 	return ret;
 }
 
+static const char *
+mxt_search_fw_name(struct mxt_data *data, u8 bootldr_id)
+{
+	const struct mxt_platform_data *pdata = data->pdata;
+	const struct mxt_config_info *cfg_info;
+	const char *fw_name = NULL;
+	int i;
+
+	for (i = 0; i < pdata->config_array_size; i++) {
+		cfg_info = &pdata->config_array[i];
+		if (bootldr_id == cfg_info->bootldr_id && cfg_info->fw_name) {
+			data->config_info = cfg_info;
+			data->info.family_id = cfg_info->family_id;
+			fw_name = cfg_info->fw_name;
+		}
+	}
+
+	return fw_name;
+}
+
 static ssize_t mxt_update_fw_store(struct device *dev,
 					struct device_attribute *attr,
 					const char *buf, size_t count)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
 	int error;
+	const char *fw_name;
+	u8 bootldr_id;
+
+	/* If fw_name is set, then the existing firmware has an upgrade */
+	if (!data->fw_name) {
+		/*
+		 * If the device boots up in the bootloader mode, check if
+		 * there is a firmware to upgrade.
+		 */
+		if (data->state == BOOTLOADER) {
+			bootldr_id = mxt_get_bootloader_id(data->client);
+			if (bootldr_id <= 0) {
+				dev_err(dev,
+					"Unable to retrieve bootloader id\n");
+				return -EINVAL;
+			}
+			fw_name = mxt_search_fw_name(data, bootldr_id);
+			if (fw_name == NULL) {
+				dev_err(dev,
+				"Unable to find fw from bootloader id\n");
+				return -EINVAL;
+			}
+		} else {
+			/* In APPMODE, if the f/w name does not exist, quit */
+			dev_err(dev,
+			"Firmware name not specified in platform data\n");
+			return -EINVAL;
+		}
+	} else {
+		fw_name = data->fw_name;
+	}
+
+	dev_info(dev, "Upgrading the firmware file to %s\n", fw_name);
 
 	disable_irq(data->irq);
 
-	error = mxt_load_fw(dev, MXT_FW_NAME);
+	error = mxt_load_fw(dev, fw_name);
 	if (error) {
 		dev_err(dev, "The firmware update failed(%d)\n", error);
 		count = error;
 	} else {
-		dev_dbg(dev, "The firmware update succeeded\n");
+		dev_info(dev, "The firmware update succeeded\n");
 
 		/* Wait for reset */
 		msleep(MXT_FWRESET_TIME);
 
+		data->state = INIT;
 		kfree(data->object_table);
 		data->object_table = NULL;
+		data->cfg_version_idx = 0;
 
 		mxt_initialize(data);
 	}
 
-	enable_irq(data->irq);
+	if (data->state == APPMODE) {
+		enable_irq(data->irq);
 
-	error = mxt_make_highchg(data);
-	if (error)
-		return error;
+		error = mxt_make_highchg(data);
+		if (error)
+			return error;
+	}
 
 	return count;
 }
@@ -1345,10 +1629,12 @@
 	struct mxt_data *data = input_get_drvdata(dev);
 	int error;
 
-	error = mxt_start(data);
-	if (error < 0) {
-		dev_err(&data->client->dev, "mxt_start failed in input_open\n");
-		return error;
+	if (data->state == APPMODE) {
+		error = mxt_start(data);
+		if (error < 0) {
+			dev_err(&data->client->dev, "mxt_start failed in input_open\n");
+			return error;
+		}
 	}
 
 	return 0;
@@ -1359,10 +1645,11 @@
 	struct mxt_data *data = input_get_drvdata(dev);
 	int error;
 
-	error = mxt_stop(data);
-	if (error < 0)
-		dev_err(&data->client->dev, "mxt_stop failed in input_close\n");
-
+	if (data->state == APPMODE) {
+		error = mxt_stop(data);
+		if (error < 0)
+			dev_err(&data->client->dev, "mxt_stop failed in input_close\n");
+	}
 }
 
 static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
@@ -1818,6 +2105,7 @@
 		goto err_free_mem;
 	}
 
+	data->state = INIT;
 	input_dev->name = "atmel_mxt_ts";
 	input_dev->id.bustype = BUS_I2C;
 	input_dev->dev.parent = &client->dev;
@@ -1941,9 +2229,13 @@
 		goto err_free_object;
 	}
 
-	error = mxt_make_highchg(data);
-	if (error)
-		goto err_free_irq;
+	if (data->state == APPMODE) {
+		error = mxt_make_highchg(data);
+		if (error) {
+			dev_err(&client->dev, "Failed to make high CHG\n");
+			goto err_free_irq;
+		}
+	}
 
 	error = input_register_device(input_dev);
 	if (error)
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 84d441d..78c474e 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -163,6 +163,10 @@
 		if (!rc)
 			rc = -ETIMEDOUT;
 		if (rc < 0) {
+			rcmd = msm_dequeue(queue, list_control);
+			if (!rcmd)
+				free_qcmd(rcmd);
+			kfree(isp_event);
 			pr_err("%s: wait_event error %d\n", __func__, rc);
 			return rc;
 		}
@@ -518,6 +522,7 @@
 	ctrlcmd.value = (void *)ctrl_data;
 	memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
 	ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.vnode_id = pcam->vnode_id;
 	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
 
 	/* send command to config thread in usersspace, and get return value */
@@ -543,6 +548,7 @@
 	ctrlcmd.value = (void *)ctrl_data;
 	memcpy(ctrlcmd.value, queryctrl, ctrlcmd.length);
 	ctrlcmd.timeout_ms = 1000;
+	ctrlcmd.vnode_id = pcam->vnode_id;
 	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
 
 	/* send command to config thread in userspace, and get return value */
@@ -943,7 +949,8 @@
 		not in use when we free the buffers */
 	mutex_lock(&pcam->vid_lock);
 	pcam_inst->streamon = 0;
-	rc = msm_server_streamoff(pcam, pcam_inst->my_index);
+	if (g_server_dev.use_count > 0)
+		rc = msm_server_streamoff(pcam, pcam_inst->my_index);
 	mutex_unlock(&pcam->vid_lock);
 	if (rc < 0)
 		pr_err("%s: hw failed to stop streaming\n", __func__);
@@ -1448,6 +1455,7 @@
 		}
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 		pcam->mctl.client = msm_ion_client_create(-1, "camera");
+		kref_init(&pcam->mctl.refcount);
 #endif
 		/* Should be set to sensor ops if any but right now its OK!! */
 		if (!pcam->mctl.mctl_open) {
@@ -1502,6 +1510,7 @@
 
 
 	if (pcam->use_count == 1) {
+		msm_queue_init(&g_server_dev.ctrl_q, "control");
 		rc = msm_send_open_server(pcam->vnode_id);
 		if (rc < 0) {
 			mutex_unlock(&pcam->vid_lock);
@@ -1573,6 +1582,14 @@
 	return rc;
 }
 
+void msm_release_ion_client(struct kref *ref)
+{
+	struct msm_cam_media_controller *mctl = container_of(ref,
+			struct msm_cam_media_controller, refcount);
+	pr_err("%s Calling ion_client_destroy ", __func__);
+	ion_client_destroy(mctl->client);
+}
+
 static int msm_close(struct file *f)
 {
 	int rc = 0;
@@ -1581,13 +1598,11 @@
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
 	pcam = pcam_inst->pcam;
-	D("%s\n", __func__);
 	if (!pcam) {
 		pr_err("%s NULL pointer of camera device!\n", __func__);
 		return -EINVAL;
 	}
 
-
 	mutex_lock(&pcam->vid_lock);
 	pcam_inst->streamon = 0;
 	pcam->use_count--;
@@ -1610,17 +1625,21 @@
 		if (rc < 0)
 			pr_err("msm_cam_server_close_session fails %d\n", rc);
 
-		rc = msm_send_close_server(pcam->vnode_id);
-		if (rc < 0)
-			pr_err("msm_send_close_server failed %d\n", rc);
+		if (g_server_dev.use_count > 0) {
+			rc = msm_send_close_server(pcam->vnode_id);
+			if (rc < 0)
+				pr_err("msm_send_close_server failed %d\n", rc);
+		}
 		if (pcam->mctl.mctl_release) {
 			rc = pcam->mctl.mctl_release(&(pcam->mctl));
 			if (rc < 0)
 				pr_err("mctl_release fails %d\n", rc);
 		}
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-		ion_client_destroy(pcam->mctl.client);
+		kref_put(&pcam->mctl.refcount, msm_release_ion_client);
 #endif
+		if (g_server_dev.use_count == 0)
+			mutex_unlock(&g_server_dev.server_lock);
 	}
 	mutex_unlock(&pcam->vid_lock);
 	return rc;
@@ -1879,16 +1898,17 @@
 {
 	int rc;
 	D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
-
+	mutex_lock(&g_server_dev.server_lock);
 	rc = nonseekable_open(inode, fp);
 	if (rc < 0) {
 		pr_err("%s: nonseekable_open error %d\n", __func__, rc);
+		mutex_unlock(&g_server_dev.server_lock);
 		return rc;
 	}
 	g_server_dev.use_count++;
 	if (g_server_dev.use_count == 1)
 		msm_queue_init(&g_server_dev.ctrl_q, "control");
-
+	mutex_unlock(&g_server_dev.server_lock);
 	return rc;
 }
 
@@ -1909,6 +1929,29 @@
 	return rc;
 }
 
+static int msm_close_server(struct inode *inode, struct file *fp)
+{
+	mutex_lock(&g_server_dev.server_lock);
+	if (g_server_dev.use_count > 0)
+		g_server_dev.use_count--;
+	mutex_unlock(&g_server_dev.server_lock);
+	if (g_server_dev.use_count == 0) {
+		if (g_server_dev.pcam_active) {
+			struct v4l2_event v4l2_ev;
+			mutex_lock(&g_server_dev.server_lock);
+
+			v4l2_ev.type = V4L2_EVENT_PRIVATE_START
+				+ MSM_CAM_APP_NOTIFY_ERROR_EVENT;
+			ktime_get_ts(&v4l2_ev.timestamp);
+			v4l2_event_queue(
+				g_server_dev.pcam_active->pvdev, &v4l2_ev);
+		}
+		msm_queue_drain(&g_server_dev.ctrl_q, list_control);
+	}
+	return 0;
+}
+
+
 static long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
 		unsigned int cmd, unsigned long evt)
 {
@@ -2147,10 +2190,19 @@
 	spin_lock_init(&config_cam->p_mctl->sync.pmem_stats_spinlock);
 
 	config_cam->p_mctl->config_device = config_cam;
+	kref_get(&config_cam->p_mctl->refcount);
 	fp->private_data = config_cam;
 	return rc;
 }
 
+static int msm_close_config(struct inode *node, struct file *f)
+{
+	struct msm_cam_config_dev *config_cam = f->private_data;
+	D("%s Decrementing ref count of config node ", __func__);
+	kref_put(&config_cam->p_mctl->refcount, msm_release_ion_client);
+	return 0;
+}
+
 static struct v4l2_file_operations g_msm_fops = {
 	.owner   = THIS_MODULE,
 	.open	= msm_open,
@@ -2169,6 +2221,7 @@
 	.open  = msm_open_server,
 	.poll  = msm_poll_server,
 	.unlocked_ioctl = msm_ioctl_server,
+	.release = msm_close_server,
 };
 
 static const struct file_operations msm_fops_config = {
@@ -2177,6 +2230,7 @@
 	.poll  = msm_poll_config,
 	.unlocked_ioctl = msm_ioctl_config,
 	.mmap	= msm_mmap_config,
+	.release = msm_close_config,
 };
 
 int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
@@ -2294,6 +2348,7 @@
 		return rc;
 	}
 
+	mutex_init(&g_server_dev.server_lock);
 	g_server_dev.pcam_active = NULL;
 	g_server_dev.camera_info.num_cameras = 0;
 	atomic_set(&g_server_dev.number_pcam_active, 0);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 55c0da1..c90ab44 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -239,6 +239,7 @@
 	struct pm_qos_request_list pm_qos_req_list;
 	struct msm_mctl_pp_info pp_info;
 	struct ion_client *client;
+	struct kref refcount;
 	/* VFE output mode.
 	* Used to interpret the Primary/Secondary messages
 	* to preview/video/main/thumbnail image types*/
@@ -409,6 +410,7 @@
 	struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];
 	/* info of MCTL nodes successfully probed*/
 	struct msm_mctl_node_info mctl_node_info;
+	struct mutex server_lock;
 };
 
 /* camera server related functions */
@@ -525,6 +527,7 @@
 			int image_mode, struct msm_frame_buffer *buf);
 int msm_mctl_pp_mctl_divert_done(struct msm_cam_media_controller *p_mctl,
 					void __user *arg);
+void msm_release_ion_client(struct kref *ref);
 #endif /* __KERNEL__ */
 
 #endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 54458d1..492bcce 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -890,7 +890,7 @@
 		return rc;
 	}
 	pcam_inst->vbqueue_initialized = 0;
-
+	kref_get(&pcam->mctl.refcount);
 	f->private_data = &pcam_inst->eventHandle;
 
 	D("f->private_data = 0x%x, pcam = 0x%x\n",
@@ -961,6 +961,7 @@
 	v4l2_fh_exit(&pcam_inst->eventHandle);
 
 	kfree(pcam_inst);
+	kref_put(&pcam->mctl.refcount, msm_release_ion_client);
 	f->private_data = NULL;
 	mutex_unlock(&pcam->mctl_node.dev_lock);
 	D("%s : X ", __func__);
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index 6c52e21..31b8239 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -334,16 +334,26 @@
 	struct vcd_buffer_requirement buf_req;
 	struct venc_inst *inst = sd->dev_priv;
 	struct video_client_ctx *client_ctx = &inst->venc_client;
+	int aligned_width, aligned_height;
 	if (!client_ctx) {
 		WFD_MSG_ERR("Invalid client context");
 		rc = -EINVAL;
 		goto err;
 	}
+	aligned_width = ALIGN(b->width, 16);
+	aligned_height = ALIGN(b->height, 16);
+
+	if (aligned_width != b->width) {
+		WFD_MSG_ERR("Width not 16 byte aligned\n");
+		rc = -EINVAL;
+		goto err;
+	}
+
 	buf_req.actual_count = b->count;
 	buf_req.min_count = b->count;
 	buf_req.max_count = b->count;
-	buf_req.sz = (((b->height * b->width) + 2047) & (~2047))
-		+ (((b->height * b->width * 1/2) + 2047) & (~2047));
+	buf_req.sz = ALIGN(aligned_height * aligned_width, SZ_2K)
+		+ ALIGN(aligned_height * aligned_width * 1/2, SZ_2K);
 	buf_req.align = 0;
 	inst->width = b->width;
 	inst->height = b->height;
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.c b/drivers/media/video/msm/wfd/vsg-subdev.c
index 96a48f26..8e385a4 100644
--- a/drivers/media/video/msm/wfd/vsg-subdev.c
+++ b/drivers/media/video/msm/wfd/vsg-subdev.c
@@ -76,10 +76,29 @@
 	}
 }
 
+static void vsg_encode_helper_func(struct work_struct *task)
+{
+	struct vsg_encode_work *work =
+		container_of(task, struct vsg_encode_work, work);
+
+	/*
+	 * Note: don't need to lock for context below as we only
+	 * access fields that are "static".
+	 */
+	int rc = vsg_encode_frame(work->context, work->buf);
+	if (rc < 0) {
+		mutex_lock(&work->context->mutex);
+		work->context->state = VSG_STATE_ERROR;
+		mutex_unlock(&work->context->mutex);
+	}
+	kfree(work);
+}
+
 static void vsg_work_func(struct work_struct *task)
 {
 	struct vsg_work *work =
 		container_of(task, struct vsg_work, work);
+	struct vsg_encode_work *encode_work;
 	struct vsg_context *context = work->context;
 	struct vsg_buf_info *buf_info = NULL, *temp = NULL;
 	int rc = 0;
@@ -88,8 +107,9 @@
 	if (list_empty(&context->free_queue.node)) {
 		WFD_MSG_DBG("%s: queue empty doing nothing\n", __func__);
 		goto err_skip_encode;
-	} else if (context->stopped) {
-		WFD_MSG_DBG("%s: vsg is stopped doing nothing\n", __func__);
+	} else if (context->state != VSG_STATE_STARTED) {
+		WFD_MSG_DBG("%s: vsg is stopped or in error state "
+				"doing nothing\n", __func__);
 		goto err_skip_encode;
 	}
 
@@ -114,15 +134,19 @@
 		}
 	}
 
-	buf_info->flags |= VSG_BUF_BEING_ENCODED;
-	mutex_unlock(&context->mutex);
-	rc = vsg_encode_frame(context, buf_info);
-	if (rc < 0) {
-		WFD_MSG_ERR("frame encode failed");
-		goto err_encode_fail;
+	encode_work = kmalloc(sizeof(*encode_work), GFP_KERNEL);
+	encode_work->buf = buf_info;
+	encode_work->context = context;
+	INIT_WORK(&encode_work->work, vsg_encode_helper_func);
+	rc = queue_work(context->work_queue, &encode_work->work);
+	if (!rc) {
+		WFD_MSG_ERR("Queueing buffer for encode failed\n");
+		kfree(encode_work);
+		encode_work = NULL;
+		goto err_queue_encode_fail;
 	}
-	mutex_lock(&context->mutex);
 
+	buf_info->flags |= VSG_BUF_BEING_ENCODED;
 	if (!(buf_info->flags & VSG_NEVER_SET_LAST_BUFFER)) {
 		bool is_same_buffer = context->last_buffer &&
 			mdp_buf_info_equals(
@@ -149,7 +173,7 @@
 	list_add_tail(&buf_info->node, &context->busy_queue.node);
 err_skip_encode:
 	mutex_unlock(&context->mutex);
-err_encode_fail:
+err_queue_encode_fail:
 	kfree(work);
 }
 
@@ -163,7 +187,7 @@
 
 	mutex_lock(&context->mutex);
 
-	if (context->stopped)
+	if (context->state != VSG_STATE_STARTED)
 		goto err_locked;
 
 	if (list_empty(&context->free_queue.node)
@@ -280,7 +304,7 @@
 	context->last_buffer = context->regen_buffer = NULL;
 	context->send_regen_buffer = false;
 	context->mode = DEFAULT_MODE;
-	context->stopped = false;
+	context->state = VSG_STATE_NONE;
 	mutex_init(&context->mutex);
 
 	sd->dev_priv = context;
@@ -311,6 +335,16 @@
 	}
 
 	context = (struct vsg_context *)sd->dev_priv;
+
+	if (context->state == VSG_STATE_STARTED) {
+		WFD_MSG_ERR("VSG not stopped, start not allowed\n");
+		return -EINPROGRESS;
+	} else if (context->state == VSG_STATE_ERROR) {
+		WFD_MSG_ERR("VSG in error state, not allowed to restart\n");
+		return -ENOTRECOVERABLE;
+	}
+
+	context->state = VSG_STATE_STARTED;
 	mod_timer(&context->threshold_timer, jiffies +
 			nsecs_to_jiffies(context->max_frame_interval));
 	return 0;
@@ -328,7 +362,7 @@
 	context = (struct vsg_context *)sd->dev_priv;
 
 	mutex_lock(&context->mutex);
-	context->stopped = true;
+	context->state = VSG_STATE_STOPPED;
 	{ /*delete pending buffers as we're not going to encode them*/
 		struct list_head *pos, *next;
 		list_for_each_safe(pos, next, &context->free_queue.node) {
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.h b/drivers/media/video/msm/wfd/vsg-subdev.h
index e6c731f..826105c 100644
--- a/drivers/media/video/msm/wfd/vsg-subdev.h
+++ b/drivers/media/video/msm/wfd/vsg-subdev.h
@@ -34,6 +34,13 @@
 	VSG_MODE_VFR,
 };
 
+enum vsg_states {
+	VSG_STATE_NONE,
+	VSG_STATE_STARTED,
+	VSG_STATE_STOPPED,
+	VSG_STATE_ERROR
+};
+
 struct vsg_buf_info {
 	struct mdp_buf_info mdp_buf_info;
 	struct timespec time;
@@ -59,7 +66,7 @@
 	struct vsg_buf_info *last_buffer, *regen_buffer;
 	bool send_regen_buffer;
 	int mode;
-	bool stopped;
+	int state;
 };
 
 struct vsg_work {
@@ -67,6 +74,12 @@
 	struct work_struct work;
 };
 
+struct vsg_encode_work {
+	struct vsg_buf_info *buf;
+	struct vsg_context *context;
+	struct work_struct work;
+};
+
 #define VSG_OPEN  _IO(VSG_MAGIC_IOCTL, 1)
 #define VSG_CLOSE  _IO(VSG_MAGIC_IOCTL, 2)
 #define VSG_START  _IO(VSG_MAGIC_IOCTL, 3)
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index ce81746..e38bb80 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -561,6 +561,11 @@
 				"V4L2_PIX_FMT_H264 are supported\n");
 		return -EINVAL;
 	}
+
+	if (fmt->fmt.pix.width % 16) {
+		WFD_MSG_ERR("Only 16 byte aligned widths are supported\n");
+		return -ENOTSUPP;
+	}
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, SET_FORMAT,
 				(void *)fmt);
 	if (rc) {
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
index 17b518e..ac39e80 100644
--- a/drivers/mfd/pm8xxx-irq.c
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -449,7 +449,7 @@
 	return chip;
 }
 
-int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
+int pm8xxx_irq_exit(struct pm_irq_chip *chip)
 {
 	irq_set_chained_handler(chip->devirq, NULL);
 	kfree(chip);
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index 191e079..022cfb6 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -1364,7 +1364,7 @@
 {
 	const struct pm8xxx_pwm_platform_data *pdata = pdev->dev.platform_data;
 	struct pm8xxx_pwm_chip	*chip;
-	int	i;
+	int	i, dtest_channel;
 	enum pm8xxx_version version;
 
 	chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -1373,6 +1373,11 @@
 		return -ENOMEM;
 	}
 
+	if (pdata != NULL)
+		dtest_channel = pdata->dtest_channel;
+	else
+		dtest_channel = -1;
+
 	mutex_init(&chip->pwm_mutex);
 
 	chip->dev = &pdev->dev;
@@ -1413,7 +1418,7 @@
 	for (i = 0; i < chip->pwm_channels; i++) {
 		chip->pwm_dev[i].pwm_id = i;
 		chip->pwm_dev[i].chip = chip;
-		if (i == pdata->dtest_channel)
+		if (i == dtest_channel)
 			chip->pwm_dev[i].dtest_mode_supported = 1;
 	}
 
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index e4c3152..a8f9f35 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -199,7 +199,7 @@
 };
 
 static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
-		struct qseecom_register_listener_req svc)
+		struct qseecom_register_listener_req *svc)
 {
 	struct qseecom_registered_listener_list *ptr;
 	int unique = 1;
@@ -207,7 +207,7 @@
 
 	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
 	list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
-		if (ptr->svc.listener_id == svc.listener_id) {
+		if (ptr->svc.listener_id == svc->listener_id) {
 			pr_err("Service id: %u is already registered\n",
 					ptr->svc.listener_id);
 			unique = 0;
@@ -333,16 +333,12 @@
 		pr_err("copy_from_user failed\n");
 		return ret;
 	}
-
-	if (!__qseecom_is_svc_unique(data, rcvd_lstnr)) {
+	data->listener.id = 0;
+	data->service = true;
+	if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
 		pr_err("Service is not unique and is already registered\n");
-		return ret;
-	}
-
-	ret = copy_to_user(argp, &rcvd_lstnr, sizeof(rcvd_lstnr));
-	if (ret) {
-		pr_err("copy_to_user failed\n");
-		return ret;
+		data->released = true;
+		return -EBUSY;
 	}
 
 	new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
@@ -360,13 +356,14 @@
 		kzfree(new_entry);
 		return -ENOMEM;
 	}
+
 	data->listener.id = rcvd_lstnr.listener_id;
-	data->service = true;
 	init_waitqueue_head(&new_entry->rcv_req_wq);
 
 	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
 	list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
 	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
 	return ret;
 }
 
@@ -743,6 +740,7 @@
 					break;
 				} else {
 					ptr_app->ref_cnt--;
+					data->released = true;
 					break;
 				}
 			}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 03be6d0..122ffb5 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -299,10 +299,11 @@
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			type);
 	} else {
-		printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
+		pr_info("%s: new %s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_sd_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			type, card->rca);
 	}
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 998797e..c1b0405 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -113,6 +113,9 @@
 	case MMC_TIMING_SD_HS:
 		str = "sd high-speed";
 		break;
+	case MMC_TIMING_MMC_HS200:
+		str = "mmc high-speed SDR200";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0c70d4a..b7b899e6 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -283,6 +283,27 @@
 	}
 	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
 	switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+	case EXT_CSD_CARD_TYPE_SDR_ALL:
+	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
+	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
+	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
+		card->ext_csd.hs_max_dtr = 200000000;
+		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
+		break;
+	case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
+	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
+	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
+	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
+		card->ext_csd.hs_max_dtr = 200000000;
+		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
+		break;
+	case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
+	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
+	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
+	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
+		card->ext_csd.hs_max_dtr = 200000000;
+		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
+		break;
 	case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
 	     EXT_CSD_CARD_TYPE_26:
 		card->ext_csd.hs_max_dtr = 52000000;
@@ -645,6 +666,79 @@
 }
 
 /*
+ * Selects the desired buswidth and switch to the HS200 mode
+ * if bus width set without error
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	int idx, err = 0;
+	struct mmc_host *host;
+	static unsigned ext_csd_bits[] = {
+		EXT_CSD_BUS_WIDTH_4,
+		EXT_CSD_BUS_WIDTH_8,
+	};
+	static unsigned bus_widths[] = {
+		MMC_BUS_WIDTH_4,
+		MMC_BUS_WIDTH_8,
+	};
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
+	    host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+		if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
+			err = mmc_set_signal_voltage(host,
+						     MMC_SIGNAL_VOLTAGE_180, 0);
+
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto err;
+
+	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+
+	/*
+	 * Unlike SD, MMC cards dont have a configuration register to notify
+	 * supported bus width. So bus test command should be run to identify
+	 * the supported bus width or compare the ext csd values of current
+	 * bus width and ext csd values of 1 bit mode read earlier.
+	 */
+	for (; idx >= 0; idx--) {
+
+		/*
+		 * Host is capable of 8bit transfer, then switch
+		 * the device to work in 8bit transfer mode. If the
+		 * mmc switch command returns error then switch to
+		 * 4bit transfer mode. On success set the corresponding
+		 * bus width on the host.
+		 */
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_BUS_WIDTH,
+				 ext_csd_bits[idx],
+				 card->ext_csd.generic_cmd6_time);
+		if (err)
+			continue;
+
+		mmc_set_bus_width(card->host, bus_widths[idx]);
+
+		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
+			err = mmc_compare_ext_csds(card, bus_widths[idx]);
+		else
+			err = mmc_bus_test(card, bus_widths[idx]);
+		if (!err)
+			break;
+	}
+
+	/* switch to HS200 mode if bus width set successfully */
+	if (!err)
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_HS_TIMING, 2, 0);
+err:
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -848,11 +942,16 @@
 	/*
 	 * Activate high speed (if supported)
 	 */
-	if ((card->ext_csd.hs_max_dtr != 0) &&
-		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 1,
-				 card->ext_csd.generic_cmd6_time);
+	if (card->ext_csd.hs_max_dtr != 0) {
+		err = 0;
+		if (card->ext_csd.hs_max_dtr > 52000000 &&
+		    host->caps2 & MMC_CAP2_HS200)
+			err = mmc_select_hs200(card);
+		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					 EXT_CSD_HS_TIMING, 1,
+					 card->ext_csd.generic_cmd6_time);
+
 		if (err && err != -EBADMSG)
 			goto free_card;
 
@@ -861,33 +960,24 @@
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			mmc_card_set_highspeed(card);
-			mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+			if (card->ext_csd.hs_max_dtr > 52000000 &&
+			    host->caps2 & MMC_CAP2_HS200) {
+				mmc_card_set_hs200(card);
+				mmc_set_timing(card->host,
+					       MMC_TIMING_MMC_HS200);
+			} else {
+				mmc_card_set_highspeed(card);
+				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+			}
 		}
 	}
 
 	/*
-	 * Enable HPI feature (if supported)
-	 */
-	if (card->ext_csd.hpi) {
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-			EXT_CSD_HPI_MGMT, 1, 0);
-		if (err && err != -EBADMSG)
-			goto free_card;
-		if (err) {
-			pr_warning("%s: Enabling HPI failed\n",
-				   mmc_hostname(card->host));
-			err = 0;
-		} else
-			card->ext_csd.hpi_en = 1;
-	}
-
-	/*
 	 * Compute bus speed.
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -913,9 +1003,51 @@
 	}
 
 	/*
+	 * Indicate HS200 SDR mode (if supported).
+	 */
+	if (mmc_card_hs200(card)) {
+		u32 ext_csd_bits;
+		u32 bus_width = card->host->ios.bus_width;
+
+		/*
+		 * For devices supporting HS200 mode, the bus width has
+		 * to be set before executing the tuning function. If
+		 * set before tuning, then device will respond with CRC
+		 * errors for responses on CMD line. So for HS200 the
+		 * sequence will be
+		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
+		 * 2. switch to HS200 mode
+		 * 3. set the clock to > 52Mhz <=200MHz and
+		 * 4. execute tuning for HS200
+		 */
+		if ((host->caps2 & MMC_CAP2_HS200) &&
+		    card->host->ops->execute_tuning) {
+			mmc_host_clk_hold(card->host);
+			err = card->host->ops->execute_tuning(card->host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+			mmc_host_clk_release(card->host);
+		}
+		if (err) {
+			pr_warning("%s: tuning execution failed\n",
+				   mmc_hostname(card->host));
+			goto err;
+		}
+
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
+		err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+		if (err) {
+			pr_err("%s: power class selection to bus width %d failed\n",
+				mmc_hostname(card->host), 1 << bus_width);
+			goto err;
+		}
+	}
+
+	/*
 	 * Activate wide bus and DDR (if supported).
 	 */
-	if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
+	if (!mmc_card_hs200(card) &&
+	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
 	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
 		static unsigned ext_csd_bits[][2] = {
 			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
@@ -1014,6 +1146,23 @@
 	}
 
 	/*
+	 * Enable HPI feature (if supported)
+	 */
+	if (card->ext_csd.hpi) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_HPI_MGMT, 1,
+				card->ext_csd.generic_cmd6_time);
+		if (err && err != -EBADMSG)
+			goto free_card;
+		if (err) {
+			pr_warning("%s: Enabling HPI failed\n",
+				   mmc_hostname(card->host));
+			err = 0;
+		} else
+			card->ext_csd.hpi_en = 1;
+	}
+
+	/*
 	 * If cache size is higher than 0, this indicates
 	 * the existence of cache and it can be turned on.
 	 */
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 6522efb..cd0eb4e 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -651,7 +651,8 @@
 	/* SPI mode doesn't define CMD19 */
 	if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
 		mmc_host_clk_hold(card->host);
-		err = card->host->ops->execute_tuning(card->host);
+		err = card->host->ops->execute_tuning(card->host,
+						      MMC_SEND_TUNING_BLOCK);
 		mmc_host_clk_release(card->host);
 	}
 
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 8ac2e59..1d6cf1d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -14,6 +14,7 @@
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e364eac..a1ad63e 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -134,6 +134,7 @@
 		      u32 c);
 static inline void msmsdcc_delay(struct msmsdcc_host *host);
 static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
+static void msmsdcc_sg_start(struct msmsdcc_host *host);
 
 static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
 {
@@ -1076,21 +1077,15 @@
 
 	/* Is data transfer in PIO mode required? */
 	if (!(datactrl & MCI_DPSM_DMAENABLE)) {
-		unsigned int sg_miter_flags = SG_MITER_ATOMIC;
-
 		if (data->flags & MMC_DATA_READ) {
-			sg_miter_flags |= SG_MITER_TO_SG;
 			pio_irqmask = MCI_RXFIFOHALFFULLMASK;
 			if (host->curr.xfer_remain < MCI_FIFOSIZE)
 				pio_irqmask |= MCI_RXDATAAVLBLMASK;
-		} else {
-			sg_miter_flags |= SG_MITER_FROM_SG;
+		} else
 			pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
 					MCI_TXFIFOEMPTYMASK;
-		}
 
-		sg_miter_start(&host->sg_miter, data->sg, data->sg_len,
-				sg_miter_flags);
+		msmsdcc_sg_start(host);
 	}
 
 	if (data->flags & MMC_DATA_READ)
@@ -1250,6 +1245,144 @@
 	return ptr - buffer;
 }
 
+/*
+ * Copy up to a word (4 bytes) between a scatterlist
+ * and a temporary bounce buffer when the word lies across
+ * two pages. The temporary buffer can then be read to/
+ * written from the FIFO once.
+ */
+static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
+{
+	struct msmsdcc_pio_data *pio = &host->pio;
+	unsigned int bytes_avail;
+
+	if (host->curr.data->flags & MMC_DATA_READ)
+		memcpy(pio->sg_miter.addr, pio->bounce_buf,
+		       pio->bounce_buf_len);
+	else
+		memcpy(pio->bounce_buf, pio->sg_miter.addr,
+		       pio->bounce_buf_len);
+
+	while (pio->bounce_buf_len != 4) {
+		if (!sg_miter_next(&pio->sg_miter))
+			break;
+		bytes_avail = min_t(unsigned int, pio->sg_miter.length,
+			4 - pio->bounce_buf_len);
+		if (host->curr.data->flags & MMC_DATA_READ)
+			memcpy(pio->sg_miter.addr,
+			       &pio->bounce_buf[pio->bounce_buf_len],
+			       bytes_avail);
+		else
+			memcpy(&pio->bounce_buf[pio->bounce_buf_len],
+			       pio->sg_miter.addr, bytes_avail);
+
+		pio->sg_miter.consumed = bytes_avail;
+		pio->bounce_buf_len += bytes_avail;
+	}
+}
+
+/*
+ * Use sg_miter_next to return as many 4-byte aligned
+ * chunks as possible, using a temporary 4 byte buffer
+ * for alignment if necessary
+ */
+static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
+{
+	struct msmsdcc_pio_data *pio = &host->pio;
+	unsigned int length, rlength;
+	char *buffer;
+
+	if (!sg_miter_next(&pio->sg_miter))
+		return 0;
+
+	buffer = pio->sg_miter.addr;
+	length = pio->sg_miter.length;
+
+	if (length < host->curr.xfer_remain) {
+		rlength = round_down(length, 4);
+		if (rlength) {
+			/*
+			 * We have a 4-byte aligned chunk.
+			 * The rounding will be reflected by
+			 * a call to msmsdcc_sg_consumed
+			 */
+			length = rlength;
+			goto sg_next_end;
+		}
+		/*
+		 * We have a length less than 4 bytes. Check to
+		 * see if more buffer is available, and combine
+		 * to make 4 bytes if possible.
+		 */
+		pio->bounce_buf_len = length;
+		memset(pio->bounce_buf, 0, 4);
+
+		/*
+		 * On a read, get 4 bytes from FIFO, and distribute
+		 * (4-bouce_buf_len) bytes into consecutive
+		 * sgl buffers when msmsdcc_sg_consumed is called
+		 */
+		if (host->curr.data->flags & MMC_DATA_READ) {
+			buffer = pio->bounce_buf;
+			length = 4;
+			goto sg_next_end;
+		} else {
+			_msmsdcc_sg_consume_word(host);
+			buffer = pio->bounce_buf;
+			length = pio->bounce_buf_len;
+		}
+	}
+
+sg_next_end:
+	*buf = buffer;
+	*len = length;
+	return 1;
+}
+
+/*
+ * Update sg_miter.consumed based on how many bytes were
+ * consumed. If the bounce buffer was used to read from FIFO,
+ * redistribute into sgls.
+ */
+static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
+				unsigned int length)
+{
+	struct msmsdcc_pio_data *pio = &host->pio;
+
+	if (host->curr.data->flags & MMC_DATA_READ) {
+		if (length > pio->sg_miter.consumed)
+			/*
+			 * consumed 4 bytes, but sgl
+			 * describes < 4 bytes
+			 */
+			_msmsdcc_sg_consume_word(host);
+		else
+			pio->sg_miter.consumed = length;
+	} else
+		if (length < pio->sg_miter.consumed)
+			pio->sg_miter.consumed = length;
+}
+
+static void msmsdcc_sg_start(struct msmsdcc_host *host)
+{
+	unsigned int sg_miter_flags = SG_MITER_ATOMIC;
+
+	host->pio.bounce_buf_len = 0;
+
+	if (host->curr.data->flags & MMC_DATA_READ)
+		sg_miter_flags |= SG_MITER_TO_SG;
+	else
+		sg_miter_flags |= SG_MITER_FROM_SG;
+
+	sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
+		       host->curr.data->sg_len, sg_miter_flags);
+}
+
+static void msmsdcc_sg_stop(struct msmsdcc_host *host)
+{
+	sg_miter_stop(&host->pio.sg_miter);
+}
+
 static irqreturn_t
 msmsdcc_pio_irq(int irq, void *dev_id)
 {
@@ -1257,6 +1390,8 @@
 	void __iomem		*base = host->base;
 	uint32_t		status;
 	unsigned long flags;
+	unsigned int remain;
+	char *buffer;
 
 	spin_lock(&host->lock);
 
@@ -1267,45 +1402,43 @@
 		spin_unlock(&host->lock);
 		return IRQ_NONE;
 	}
-
 #if IRQ_DEBUG
 	msmsdcc_print_status(host, "irq1-r", status);
 #endif
 	local_irq_save(flags);
 
-	while (sg_miter_next(&host->sg_miter)) {
-
-		unsigned int remain, len;
-		char *buffer;
+	do {
+		unsigned int len;
 
 		if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
 				| MCI_RXDATAAVLBL)))
 			break;
 
-		buffer = host->sg_miter.addr;
-		remain = host->sg_miter.length;
+		if (!msmsdcc_sg_next(host, &buffer, &remain))
+			break;
 
 		len = 0;
 		if (status & MCI_RXACTIVE)
 			len = msmsdcc_pio_read(host, buffer, remain);
 		if (status & MCI_TXACTIVE)
 			len = msmsdcc_pio_write(host, buffer, remain);
+
 		/* len might have aligned to 32bits above */
 		if (len > remain)
 			len = remain;
 
-		host->sg_miter.consumed = len;
 		host->curr.xfer_remain -= len;
 		host->curr.data_xfered += len;
 		remain -= len;
+		msmsdcc_sg_consumed(host, len);
 
 		if (remain) /* Done with this page? */
 			break; /* Nope */
 
 		status = readl_relaxed(base + MMCISTATUS);
-	}
+	} while (1);
 
-	sg_miter_stop(&host->sg_miter);
+	msmsdcc_sg_stop(host);
 	local_irq_restore(flags);
 
 	if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
@@ -2877,15 +3010,22 @@
  * Select the 3/4 of the range and configure the DLL with the
  * selected DLL clock output phase.
 */
-static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
+static int find_most_appropriate_phase(struct msmsdcc_host *host,
 				u8 *phase_table, u8 total_phases)
 {
-	u8 ret, ranges[16][16] = { {0}, {0} };
+	int ret;
+	u8 ranges[16][16] = { {0}, {0} };
 	u8 phases_per_row[16] = {0};
 	int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
 	int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
 	bool phase_0_found = false, phase_15_found = false;
 
+	if (total_phases > 16) {
+		pr_err("%s: %s: invalid argument: total_phases=%d\n",
+			mmc_hostname(host->mmc), __func__, total_phases);
+		return -EINVAL;
+	}
+
 	for (cnt = 0; cnt < total_phases; cnt++) {
 		ranges[row_index][col_index] = phase_table[cnt];
 		phases_per_row[row_index] += 1;
@@ -2943,12 +3083,12 @@
 	}
 
 	i = ((curr_max * 3) / 4) - 1;
-	ret = ranges[selected_row_index][i];
+	ret = (int)ranges[selected_row_index][i];
 
 	return ret;
 }
 
-static int msmsdcc_execute_tuning(struct mmc_host *mmc)
+static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	int rc = 0;
 	struct msmsdcc_host *host = mmc_priv(mmc);
@@ -3022,8 +3162,13 @@
 	} while (++phase < 16);
 
 	if (tuned_phase_cnt) {
-		phase = find_most_appropriate_phase(host, tuned_phases,
+		rc = find_most_appropriate_phase(host, tuned_phases,
 							tuned_phase_cnt);
+		if (rc < 0)
+			goto kfree;
+		else
+			phase = (u8)rc;
+
 		/*
 		 * Finally set the selected phase in delay
 		 * line hw block.
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 319d721..8a728f2 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -281,9 +281,10 @@
 };
 
 struct msmsdcc_pio_data {
-	struct scatterlist	*sg;
-	unsigned int		sg_len;
-	unsigned int		sg_off;
+	struct sg_mapping_iter		sg_miter;
+	char				bounce_buf[4];
+	/* valid bytes in bounce_buf */
+	int				bounce_buf_len;
 };
 
 struct msmsdcc_curr_req {
@@ -361,7 +362,7 @@
 	struct msmsdcc_sps_data sps;
 	bool			is_dma_mode;
 	bool			is_sps_mode;
-	struct sg_mapping_iter sg_miter;
+	struct msmsdcc_pio_data	pio;
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 	struct early_suspend early_suspend;
diff --git a/drivers/mtd/devices/msm_nand.c b/drivers/mtd/devices/msm_nand.c
index 5ced423..2479a11 100644
--- a/drivers/mtd/devices/msm_nand.c
+++ b/drivers/mtd/devices/msm_nand.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -6718,7 +6718,7 @@
 			supported_flash.pagesize = 1024 << (devcfg & 0x3);
 			supported_flash.blksize = (64 * 1024) <<
 							((devcfg >> 4) & 0x3);
-			supported_flash.oobsize = (8 << ((devcfg >> 2) & 1)) *
+			supported_flash.oobsize = (8 << ((devcfg >> 2) & 0x3)) *
 				(supported_flash.pagesize >> 9);
 		} else {
 			supported_flash.flash_id = flash_id;
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index b693b18..5a016bb 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -264,19 +264,10 @@
 {
 	int	retval = 0;
 
-	retval = usb_autopm_get_interface(dev->intf);
-	if (retval < 0) {
-		dev_err(dev->devicep, "%s Resumption fail\n", __func__);
-		goto done_nopm;
-	}
-
 	retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
 	if (retval < 0)
 		dev_err(dev->devicep, "%s Intr submit %d\n", __func__, retval);
 
-	usb_autopm_put_interface(dev->intf);
-
-done_nopm:
 	return retval;
 }
 
@@ -342,35 +333,19 @@
 }
 static int rmnet_usb_ctrl_write_cmd(struct rmnet_ctrl_dev *dev)
 {
-	int			retval = 0;
 	struct usb_device	*udev;
 
 	if (!is_dev_connected(dev))
 		return -ENODEV;
 
 	udev = interface_to_usbdev(dev->intf);
-	retval = usb_autopm_get_interface(dev->intf);
-	if (retval < 0) {
-		dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
-			__func__, retval);
-
-		/*
-		* Revisit if (retval == -EPERM)
-		*		rmnet_usb_suspend(dev->intf, PMSG_SUSPEND);
-		*/
-
-		return retval;
-	}
 	dev->set_ctrl_line_state_cnt++;
-	retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+	return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 		USB_CDC_REQ_SET_CONTROL_LINE_STATE,
 		(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
 		dev->cbits_tomdm,
 		dev->intf->cur_altsetting->desc.bInterfaceNumber,
 		NULL, 0, USB_CTRL_SET_TIMEOUT);
-	usb_autopm_put_interface(dev->intf);
-
-	return retval;
 }
 
 static void ctrl_write_callback(struct urb *urb)
@@ -428,7 +403,7 @@
 			     (unsigned char *)out_ctlreq, (void *)buf, size,
 			     ctrl_write_callback, dev);
 
-	result = usb_autopm_get_interface_async(dev->intf);
+	result = usb_autopm_get_interface(dev->intf);
 	if (result < 0) {
 		dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
 			__func__, result);
@@ -450,7 +425,7 @@
 		dev_err(dev->devicep, "%s: Submit URB error %d\n",
 			__func__, result);
 		dev->snd_encap_cmd_cnt--;
-		usb_autopm_put_interface_async(dev->intf);
+		usb_autopm_put_interface(dev->intf);
 		usb_unanchor_urb(sndurb);
 		usb_free_urb(sndurb);
 		kfree(out_ctlreq);
@@ -573,7 +548,7 @@
 
 ctrl_read:
 	if (!is_dev_connected(dev)) {
-		dev_err(dev->devicep, "%s: Device not connected\n",
+		dev_dbg(dev->devicep, "%s: Device not connected\n",
 			__func__);
 		return -ENETRESET;
 	}
@@ -662,6 +637,8 @@
 static int rmnet_ctrl_tiocmset(struct rmnet_ctrl_dev *dev, unsigned int set,
 		unsigned int clear)
 {
+	int retval;
+
 	mutex_lock(&dev->dev_lock);
 	if (set & TIOCM_DTR)
 		dev->cbits_tomdm |= ACM_CTRL_DTR;
@@ -681,7 +658,17 @@
 
 	mutex_unlock(&dev->dev_lock);
 
-	return rmnet_usb_ctrl_write_cmd(dev);
+	retval = usb_autopm_get_interface(dev->intf);
+	if (retval < 0) {
+		dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+			__func__, retval);
+		return retval;
+	}
+
+	retval = rmnet_usb_ctrl_write_cmd(dev);
+
+	usb_autopm_put_interface(dev->intf);
+	return retval;
 }
 
 static int rmnet_ctrl_tiocmget(struct rmnet_ctrl_dev *dev)
@@ -774,6 +761,10 @@
 	dev->tx_ctrl_err_cnt = 0;
 	dev->set_ctrl_line_state_cnt = 0;
 
+	ret = rmnet_usb_ctrl_write_cmd(dev);
+	if (ret < 0)
+		return ret;
+
 	dev->inturb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!dev->inturb) {
 		dev_err(dev->devicep, "Error allocating int urb\n");
@@ -799,19 +790,15 @@
 		dev->intf->cur_altsetting->desc.bInterfaceNumber;
 	dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH);
 
-	interval =
-		max((int)int_in->desc.bInterval,
-		(udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL : FS_LS_INTERVAL);
+	interval = max((int)int_in->desc.bInterval,
+			(udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL
+							: FS_LS_INTERVAL);
 
 	usb_fill_int_urb(dev->inturb, udev,
 			 dev->int_pipe,
 			 dev->intbuf, wMaxPacketSize,
 			 notification_available_cb, dev, interval);
 
-	ret = rmnet_usb_ctrl_write_cmd(dev);
-	if (ret < 0)
-		return ret;
-
 	return rmnet_usb_ctrl_start_rx(dev);
 }
 
@@ -828,6 +815,8 @@
 	dev->intf = NULL;
 	mutex_unlock(&dev->dev_lock);
 
+	wake_up(&dev->read_wait_queue);
+
 	usb_free_urb(dev->inturb);
 	dev->inturb = NULL;
 
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 658b393..1eb6845 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -148,7 +148,6 @@
 
 	retval = usbnet_resume(iface);
 	if (!retval) {
-
 		if (oldstate & PM_EVENT_SUSPEND)
 			retval = rmnet_usb_ctrl_start(dev);
 	}
@@ -260,6 +259,12 @@
 	return 1;
 }
 
+static int rmnet_usb_manage_power(struct usbnet *dev, int on)
+{
+	dev->intf->needs_remote_wakeup = on;
+	return 0;
+}
+
 static int rmnet_change_mtu(struct net_device *dev, int new_mtu)
 {
 	if (0 > new_mtu || RMNET_DATA_LEN < new_mtu)
@@ -501,6 +506,7 @@
 	.bind          = rmnet_usb_bind,
 	.tx_fixup      = rmnet_usb_tx_fixup,
 	.rx_fixup      = rmnet_usb_rx_fixup,
+	.manage_power  = rmnet_usb_manage_power,
 	.data          = PID9034_IFACE_MASK,
 };
 
@@ -509,6 +515,7 @@
 	.bind          = rmnet_usb_bind,
 	.tx_fixup      = rmnet_usb_tx_fixup,
 	.rx_fixup      = rmnet_usb_rx_fixup,
+	.manage_power  = rmnet_usb_manage_power,
 	.data          = PID9048_IFACE_MASK,
 };
 
@@ -517,6 +524,7 @@
 	.bind          = rmnet_usb_bind,
 	.tx_fixup      = rmnet_usb_tx_fixup,
 	.rx_fixup      = rmnet_usb_rx_fixup,
+	.manage_power  = rmnet_usb_manage_power,
 	.data          = PID904C_IFACE_MASK,
 };
 
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index c3a756d..2620108e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -35,6 +35,7 @@
 
 #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>
@@ -332,7 +333,9 @@
 		usb_free_urb (urb);
 		return -ENOMEM;
 	}
-	skb_reserve (skb, NET_IP_ALIGN);
+
+	if (dev->net->type != ARPHRD_RAWIP)
+		skb_reserve(skb, NET_IP_ALIGN);
 
 	entry = (struct skb_data *) skb->cb;
 	entry->urb = urb;
diff --git a/drivers/net/wireless/libra/libra_sdioif.c b/drivers/net/wireless/libra/libra_sdioif.c
index 3955642..3421f84 100644
--- a/drivers/net/wireless/libra/libra_sdioif.c
+++ b/drivers/net/wireless/libra/libra_sdioif.c
@@ -29,6 +29,37 @@
 static suspend_handler_t *libra_suspend_hldr;
 static resume_handler_t *libra_resume_hldr;
 
+int libra_enable_sdio_irq_in_chip(struct sdio_func *func, u8 enable)
+{
+	unsigned char reg = 0;
+	int err = 0;
+
+	sdio_claim_host(func);
+
+	/* Read the value into reg */
+	libra_sdiocmd52(func, SDIO_CCCR_IENx, &reg, 0, &err);
+	if (err)
+		printk(KERN_ERR "%s: Could not read  SDIO_CCCR_IENx register "
+				"err=%d\n", __func__, err);
+
+	if (libra_mmc_host) {
+		if (enable) {
+			reg |= 1 << func->num;
+			reg |= 1;
+		} else {
+			reg &= ~(1 << func->num);
+		}
+		libra_sdiocmd52(func, SDIO_CCCR_IENx, &reg, 1, &err);
+		if (err)
+			printk(KERN_ERR "%s: Could not enable/disable irq "
+					 "err=%d\n", __func__, err);
+	 }
+	sdio_release_host(func);
+
+	return err;
+}
+EXPORT_SYMBOL(libra_enable_sdio_irq_in_chip);
+
 /**
  * libra_sdio_configure() - Function to configure the SDIO device param
  * @libra_sdio_rxhandler    Rx handler
@@ -89,6 +120,8 @@
 		goto cfg_error;
 	}
 
+	libra_enable_sdio_irq_in_chip(func, 0);
+
 	sdio_release_host(func);
 
 	return 0;
diff --git a/drivers/net/wireless/libra/qcomwlan_pwrif.c b/drivers/net/wireless/libra/qcomwlan_pwrif.c
index 6a0c78f..94ea0b3 100644
--- a/drivers/net/wireless/libra/qcomwlan_pwrif.c
+++ b/drivers/net/wireless/libra/qcomwlan_pwrif.c
@@ -154,7 +154,7 @@
 
 	/* WLAN VREG settings */
 	for (i = 0; i < ARRAY_SIZE(vregs_qwlan_name); i++) {
-		if (vregs_qwlan[i] == NULL) {
+		if (on && !wlan_on)	{
 			vregs_qwlan[i] = regulator_get(NULL,
 					vregs_qwlan_name[i]);
 			if (IS_ERR(vregs_qwlan[i])) {
@@ -187,8 +187,7 @@
 					goto vreg_fail;
 				}
 			}
-		}
-		if (on && !wlan_on) {
+
 			if (vregs_qwlan_peek_current[i]) {
 				rc = regulator_set_optimum_mode(vregs_qwlan[i],
 						vregs_qwlan_peek_current[i]);
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
index 0939dd8..23365ff 100644
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ b/drivers/net/wireless/wcnss/wcnss_riva.c
@@ -61,7 +61,6 @@
 };
 
 static struct vregs_info iris_vregs[] = {
-	{"iris_vddio",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 4000,   NULL},
 	{"iris_vddxo",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000,  NULL},
 	{"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
 	{"iris_vddpa",  VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
diff --git a/drivers/of/of_spmi.c b/drivers/of/of_spmi.c
index 9f2a396..2032b46 100644
--- a/drivers/of/of_spmi.c
+++ b/drivers/of/of_spmi.c
@@ -19,62 +19,93 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 
-/**
- * Allocate resources for a child of a spmi-container node.
- */
-static int of_spmi_allocate_resources(struct spmi_controller *ctrl,
-				      struct spmi_boardinfo *info,
-				      struct device_node *node,
-				      uint32_t num_reg)
+struct of_spmi_dev_info {
+	struct spmi_controller *ctrl;
+	struct spmi_boardinfo b_info;
+};
+
+struct of_spmi_res_info {
+	struct device_node *node;
+	uint32_t num_reg;
+	uint32_t num_irq;
+};
+
+static void of_spmi_sum_resources(struct of_spmi_res_info *r_info, bool has_reg)
 {
-	int i, num_irq = 0;
+	struct of_irq oirq;
 	uint64_t size;
 	uint32_t flags;
+
+	while (of_irq_map_one(r_info->node, r_info->num_irq, &oirq) == 0)
+		r_info->num_irq++;
+
+	if (!has_reg)
+		return;
+
+	/*
+	 * We can't use of_address_to_resource here since it includes
+	 * address translation; and address translation assumes that no
+	 * parent buses have a size-cell of 0. But SPMI does have a
+	 * size-cell of 0.
+	 */
+	while (of_get_address(r_info->node, r_info->num_reg,
+						&size, &flags) != NULL)
+		r_info->num_reg++;
+}
+
+/**
+ * Allocate resources for a child of a spmi-slave node.
+ */
+static int of_spmi_allocate_resources(struct of_spmi_dev_info *d_info,
+				      struct of_spmi_res_info *r_info)
+
+{
+	uint32_t num_irq = r_info->num_irq, num_reg = r_info->num_reg;
+	int i;
 	struct resource *res;
 	const  __be32 *addrp;
-	struct of_irq oirq;
-
-	while (of_irq_map_one(node, num_irq, &oirq) == 0)
-		num_irq++;
+	uint64_t size;
+	uint32_t flags;
 
 	if (num_irq || num_reg) {
 		res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
 		if (!res)
 			return -ENOMEM;
 
-		info->num_resources = num_reg + num_irq;
-		info->resource = res;
+		d_info->b_info.num_resources = num_reg + num_irq;
+		d_info->b_info.resource = res;
 		for (i = 0; i < num_reg; i++, res++) {
 			/* Addresses are always 16 bits */
-			addrp = of_get_address(node, i, &size, &flags);
+			addrp = of_get_address(r_info->node, i, &size, &flags);
 			BUG_ON(!addrp);
 			res->start = be32_to_cpup(addrp);
 			res->end = res->start + size - 1;
 			res->flags = flags;
 		}
-		WARN_ON(of_irq_to_resource_table(node, res, num_irq) !=
+		WARN_ON(of_irq_to_resource_table(r_info->node, res, num_irq) !=
 								num_irq);
 	}
 
 	return 0;
 }
 
-static int of_spmi_create_device(struct spmi_controller *ctrl,
-				 struct spmi_boardinfo *info,
-			  struct device_node *node)
+static int of_spmi_create_device(struct of_spmi_dev_info *d_info,
+				 struct device_node *node)
 {
+	struct spmi_controller *ctrl = d_info->ctrl;
+	struct spmi_boardinfo *b_info = &d_info->b_info;
 	void *result;
 	int rc;
 
-	rc = of_modalias_node(node, info->name, sizeof(info->name));
+	rc = of_modalias_node(node, b_info->name, sizeof(b_info->name));
 	if (rc < 0) {
 		dev_err(&ctrl->dev, "of_spmi modalias failure on %s\n",
 				node->full_name);
 		return rc;
 	}
 
-	info->of_node = of_node_get(node);
-	result = spmi_new_device(ctrl, info);
+	b_info->of_node = of_node_get(node);
+	result = spmi_new_device(ctrl, b_info);
 
 	if (result == NULL) {
 		dev_err(&ctrl->dev, "of_spmi: Failure registering %s\n",
@@ -86,32 +117,26 @@
 	return 0;
 }
 
-static void of_spmi_walk_container_children(struct spmi_controller *ctrl,
-				     struct spmi_boardinfo *info,
-				     struct device_node *container)
+static void of_spmi_walk_slave_container(struct of_spmi_dev_info *d_info,
+					struct device_node *container)
 {
+	struct spmi_controller *ctrl = d_info->ctrl;
 	struct device_node *node;
-	uint64_t size;
-	uint32_t flags, num_reg = 0;
 	int rc;
 
 	for_each_child_of_node(container, node) {
-		/*
-		 * We can't use of_address_to_resource here since it includes
-		 * address translation; and address translation assumes that no
-		 * parent buses have a size-cell of 0. But SPMI does have a
-		 * size-cell of 0.
-		 */
-		while (of_get_address(node, num_reg, &size, &flags) != NULL)
-			num_reg++;
+		struct of_spmi_res_info r_info;
 
-		rc = of_spmi_allocate_resources(ctrl, info, node, num_reg);
+		r_info.node = node;
+		of_spmi_sum_resources(&r_info, 1);
+
+		rc = of_spmi_allocate_resources(d_info, &r_info);
 		if (rc) {
 			dev_err(&ctrl->dev, "%s: unable to allocate"
 						" resources\n", __func__);
 			return;
 		}
-		rc = of_spmi_create_device(ctrl, info, node);
+		rc = of_spmi_create_device(d_info, node);
 		if (rc) {
 			dev_err(&ctrl->dev, "%s: unable to create device for"
 				     " node %s\n", __func__, node->full_name);
@@ -129,7 +154,7 @@
 		return -ENODEV;
 
 	for_each_child_of_node(ctrl->dev.of_node, node) {
-		struct spmi_boardinfo info = {};
+		struct of_spmi_dev_info d_info = {};
 		const __be32 *slave_id;
 		int len, rc;
 
@@ -140,16 +165,21 @@
 			continue;
 		}
 
-		info.slave_id = be32_to_cpup(slave_id);
+		d_info.b_info.slave_id = be32_to_cpup(slave_id);
+		d_info.ctrl = ctrl;
 
-		if (of_get_property(node, "spmi-dev-container", NULL)) {
-			of_spmi_walk_container_children(ctrl, &info, node);
+		if (of_get_property(node, "spmi-slave-container", NULL)) {
+			of_spmi_walk_slave_container(&d_info, node);
 			continue;
 		} else {
-			rc = of_spmi_allocate_resources(ctrl, &info, node, 0);
+			struct of_spmi_res_info r_info;
+
+			r_info.node = node;
+			of_spmi_sum_resources(&r_info, 0);
+			rc = of_spmi_allocate_resources(&d_info, &r_info);
 			if (rc)
 				continue;
-			of_spmi_create_device(ctrl, &info, node);
+			of_spmi_create_device(&d_info, node);
 		}
 	}
 
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 4279603..edef402 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
 
 #include "bam.h"
 #include "sps_bam.h"
+#include "spsi.h"
 
 /**
  *  Valid BAM Hardware version.
@@ -740,8 +741,11 @@
 		return -ENODEV;
 	}
 
-	if (num_pipes > BAM_MAX_PIPES)
+	if (num_pipes > BAM_MAX_PIPES) {
+		SPS_ERR("sps:bam 0x%x(va) the number of pipes is more than "
+			"the maximum number allowed.", (u32) base);
 		return -ENODEV;
+	}
 
 	for (pipe = 0, mask = 1; pipe < num_pipes; pipe++, mask <<= 1)
 		if ((mask & pipe_mask) != 0)
@@ -764,8 +768,11 @@
 {
 	u32 ver = 0;
 
-	if (!bam_read_reg_field(base, CTRL, BAM_EN))
+	if (!bam_read_reg_field(base, CTRL, BAM_EN)) {
+		SPS_ERR("sps:%s:bam 0x%x(va) is not enabled.\n",
+				__func__, (u32) base);
 		return -ENODEV;
+	}
 
 	ver = bam_read_reg(base, REVISION) & BAM_REVISION;
 
@@ -778,8 +785,8 @@
 
 	/* Check BAM version */
 	if ((ver < BAM_MIN_VERSION) || (ver > BAM_MAX_VERSION)) {
-		SPS_ERR("sps:bam 0x%x(va) Invalid BAM version 0x%x.\n",
-				(u32) base, ver);
+		SPS_ERR("sps:%s:bam 0x%x(va) Invalid BAM version 0x%x.\n",
+				__func__, (u32) base, ver);
 		return -ENODEV;
 	}
 
@@ -866,7 +873,7 @@
 
 		bam_write_reg(base, P_EVNT_DEST_ADDR(pipe), peer_dest_addr);
 
-		SPS_DBG("sps:bam=0x%x(va).pipe=%d.peer_bam=0x%x."
+		SPS_DBG2("sps:bam=0x%x(va).pipe=%d.peer_bam=0x%x."
 			"peer_pipe=%d.\n",
 			(u32) base, pipe,
 			(u32) param->peer_phys_addr,
@@ -1051,3 +1058,206 @@
 {
 	return bam_read_reg(base, P_TIMER(pipe));
 }
+
+#ifdef CONFIG_DEBUG_FS
+/* output the content of BAM-level registers */
+void print_bam_reg(void *virt_addr)
+{
+	int i, n;
+	u32 *bam = (u32 *) virt_addr;
+	u32 ctrl;
+	u32 ver;
+	u32 pipes;
+
+	if (bam == NULL)
+		return;
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	ctrl = bam[0x0 / 4];
+	ver = bam[0x4 / 4];
+	pipes = bam[0x3c / 4];
+#else
+	ctrl = bam[0xf80 / 4];
+	ver = bam[0xf84 / 4];
+	pipes = bam[0xfbc / 4];
+#endif
+
+	SPS_INFO("\nsps:----- Content of BAM-level registers <begin> -----\n");
+
+	SPS_INFO("BAM_CTRL: 0x%x.\n", ctrl);
+	SPS_INFO("BAM_REVISION: 0x%x.\n", ver);
+	SPS_INFO("NUM_PIPES: 0x%x.\n", pipes);
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	for (i = 0x0; i < 0x80; i += 0x10)
+#else
+	for (i = 0xf80; i < 0x1000; i += 0x10)
+#endif
+		SPS_INFO("bam addr 0x%x: 0x%x,0x%x,0x%x,0x%x.\n", i,
+			bam[i / 4], bam[(i / 4) + 1],
+			bam[(i / 4) + 2], bam[(i / 4) + 3]);
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	for (i = 0x800, n = 0; n++ < 8; i += 0x80)
+#else
+	for (i = 0x1800, n = 0; n++ < 4; i += 0x80)
+#endif
+		SPS_INFO("bam addr 0x%x: 0x%x,0x%x,0x%x,0x%x.\n", i,
+			bam[i / 4], bam[(i / 4) + 1],
+			bam[(i / 4) + 2], bam[(i / 4) + 3]);
+
+	SPS_INFO("\nsps:----- Content of BAM-level registers <end> -----\n");
+}
+
+/* output the content of BAM pipe registers */
+void print_bam_pipe_reg(void *virt_addr, u32 pipe_index)
+{
+	int i;
+	u32 *bam = (u32 *) virt_addr;
+	u32 pipe = pipe_index;
+
+	if (bam == NULL)
+		return;
+
+	SPS_INFO("\nsps:----- Content of Pipe %d registers <begin> -----\n",
+			pipe);
+
+	SPS_INFO("-- Pipe Management Registers --\n");
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	for (i = 0x1000 + 0x1000 * pipe; i < 0x1000 + 0x1000 * pipe + 0x80;
+	    i += 0x10)
+#else
+	for (i = 0x0000 + 0x80 * pipe; i < 0x0000 + 0x80 * (pipe + 1);
+	    i += 0x10)
+#endif
+		SPS_INFO("bam addr 0x%x: 0x%x,0x%x,0x%x,0x%x.\n", i,
+			bam[i / 4], bam[(i / 4) + 1],
+			bam[(i / 4) + 2], bam[(i / 4) + 3]);
+
+	SPS_INFO("-- Pipe Configuration and Internal State Registers --\n");
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+	for (i = 0x1800 + 0x1000 * pipe; i < 0x1800 + 0x1000 * pipe + 0x40;
+	    i += 0x10)
+#else
+	for (i = 0x1000 + 0x40 * pipe; i < 0x1000 + 0x40 * (pipe + 1);
+	    i += 0x10)
+#endif
+		SPS_INFO("bam addr 0x%x: 0x%x,0x%x,0x%x,0x%x.\n", i,
+			bam[i / 4], bam[(i / 4) + 1],
+			bam[(i / 4) + 2], bam[(i / 4) + 3]);
+
+	SPS_INFO("\nsps:----- Content of Pipe %d registers <end> -----\n",
+			pipe);
+}
+
+/* output the content of selected BAM-level registers */
+void print_bam_selected_reg(void *virt_addr)
+{
+	void *base = virt_addr;
+
+	if (base == NULL)
+		return;
+
+	SPS_INFO("\nsps:----- Content of BAM-level registers <begin> -----\n");
+
+	SPS_INFO("BAM_CTRL: 0x%x\n"
+		"BAM_REVISION: 0x%x\n"
+		"BAM_NUM_EES: %d\n"
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+		"BAM_CMD_DESC_EN: 0x%x\n"
+#endif
+		"BAM_NUM_PIPES: %d\n"
+		"BAM_DESC_CNT_TRSHLD: 0x%x (%d)\n"
+		"BAM_IRQ_SRCS: 0x%x\n"
+		"BAM_IRQ_SRCS_MSK: 0x%x\n"
+		"BAM_EE: %d\n"
+		"BAM_CNFG_BITS: 0x%x\n",
+		bam_read_reg(base, CTRL),
+		bam_read_reg_field(base, REVISION, BAM_REVISION),
+		bam_read_reg_field(base, REVISION, BAM_NUM_EES),
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+		bam_read_reg_field(base, REVISION, BAM_CMD_DESC_EN),
+#endif
+		bam_read_reg_field(base, NUM_PIPES, BAM_NUM_PIPES),
+		bam_read_reg_field(base, DESC_CNT_TRSHLD, BAM_DESC_CNT_TRSHLD),
+		bam_read_reg_field(base, DESC_CNT_TRSHLD, BAM_DESC_CNT_TRSHLD),
+		bam_read_reg(base, IRQ_SRCS),
+		bam_read_reg(base, IRQ_SRCS_MSK),
+		bam_read_reg_field(base, TRUST_REG, BAM_EE),
+		bam_read_reg(base, CNFG_BITS));
+
+	SPS_INFO("\nsps:----- Content of BAM-level registers <end> -----\n");
+}
+
+/* output the content of selected BAM pipe registers */
+void print_bam_pipe_selected_reg(void *virt_addr, u32 pipe_index)
+{
+	void *base = virt_addr;
+	u32 pipe = pipe_index;
+
+	if (base == NULL)
+		return;
+
+	SPS_INFO("\nsps:----- Registers of Pipe %d -----\n", pipe);
+
+	SPS_INFO("BAM_P_CTRL: 0x%x\n"
+		"BAM_P_SYS_MODE: %d\n"
+		"BAM_P_DIRECTION: %d\n"
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+		"BAM_P_LOCK_GROUP: 0x%x (%d)\n"
+#endif
+		"BAM_P_EE: %d\n"
+		"BAM_P_IRQ_STTS: 0x%x\n"
+		"BAM_P_IRQ_STTS_P_TRNSFR_END_IRQ: 0x%x\n"
+		"BAM_P_IRQ_STTS_P_PRCSD_DESC_IRQ: 0x%x\n"
+		"BAM_P_IRQ_EN: %d\n"
+		"BAM_P_PRDCR_SDBNDn_BAM_P_BYTES_FREE: 0x%x (%d)\n"
+		"BAM_P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL: 0x%x (%d)\n"
+		"BAM_P_SW_DESC_OFST: 0x%x\n"
+		"BAM_P_DESC_FIFO_PEER_OFST: 0x%x\n"
+		"BAM_P_EVNT_DEST_ADDR: 0x%x\n"
+		"BAM_P_DESC_FIFO_ADDR: 0x%x\n"
+		"BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n"
+		"BAM_P_DATA_FIFO_ADDR: 0x%x\n"
+		"BAM_P_DATA_FIFO_SIZE: 0x%x (%d)\n"
+		"BAM_P_EVNT_GEN_TRSHLD: 0x%x (%d)\n",
+		bam_read_reg(base, P_CTRL(pipe)),
+		bam_read_reg_field(base, P_CTRL(pipe), P_SYS_MODE),
+		bam_read_reg_field(base, P_CTRL(pipe), P_DIRECTION),
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+		bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP),
+		bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP),
+#endif
+		bam_read_reg_field(base, P_TRUST_REG(pipe), BAM_P_EE),
+		bam_read_reg(base, P_IRQ_STTS(pipe)),
+		bam_read_reg_field(base, P_IRQ_STTS(pipe),
+					P_IRQ_STTS_P_TRNSFR_END_IRQ),
+		bam_read_reg_field(base, P_IRQ_STTS(pipe),
+					P_IRQ_STTS_P_PRCSD_DESC_IRQ),
+		bam_read_reg(base, P_IRQ_EN(pipe)),
+		bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+					P_PRDCR_SDBNDn_BAM_P_BYTES_FREE),
+		bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+					P_PRDCR_SDBNDn_BAM_P_BYTES_FREE),
+		bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+					P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL),
+		bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+					P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL),
+		bam_read_reg_field(base, P_SW_OFSTS(pipe), SW_DESC_OFST),
+		bam_read_reg_field(base, P_EVNT_REG(pipe),
+					P_DESC_FIFO_PEER_OFST),
+		bam_read_reg(base, P_EVNT_DEST_ADDR(pipe)),
+		bam_read_reg(base, P_DESC_FIFO_ADDR(pipe)),
+		bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DESC_FIFO_SIZE),
+		bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DESC_FIFO_SIZE),
+		bam_read_reg(base, P_DATA_FIFO_ADDR(pipe)),
+		bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DATA_FIFO_SIZE),
+		bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DATA_FIFO_SIZE),
+		bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
+					P_EVNT_GEN_TRSHLD_P_TRSHLD),
+		bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
+					P_EVNT_GEN_TRSHLD_P_TRSHLD));
+}
+#endif
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index c17da9b..b876d2d 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -82,18 +82,31 @@
 static void sps_device_de_init(void);
 
 #ifdef CONFIG_DEBUG_FS
-#define MAX_OUTPUT_MAGIC_NUM 777
-u32 sps_debugfs_enabled;
-u32 detailed_debug_on;
+u8 debugfs_record_enabled;
+u8 logging_option;
+u8 debug_level_option;
+u8 print_limit_option;
+u8 reg_dump_option;
+
 static char *debugfs_buf;
-static int debugfs_buf_size;
-static int debugfs_buf_used;
+static u32 debugfs_buf_size;
+static u32 debugfs_buf_used;
 static int wraparound;
 
+struct dentry *dent;
+struct dentry *dfile_info;
+struct dentry *dfile_logging_option;
+struct dentry *dfile_debug_level_option;
+struct dentry *dfile_print_limit_option;
+struct dentry *dfile_reg_dump_option;
+struct dentry *dfile_bam_addr;
+
+static struct sps_bam *phy2bam(u32 phys_addr);
+
 /* record debug info for debugfs */
 void sps_debugfs_record(const char *msg)
 {
-	if (sps_debugfs_enabled) {
+	if (debugfs_record_enabled) {
 		if (debugfs_buf_used + MAX_MSG_LEN >= debugfs_buf_size) {
 			debugfs_buf_used = 0;
 			wraparound = true;
@@ -112,30 +125,33 @@
 static ssize_t sps_read_info(struct file *file, char __user *ubuf,
 		size_t count, loff_t *ppos)
 {
-	int ret;
+	int ret = 0;
 	int size;
 
-	if (wraparound)
-		size = debugfs_buf_size - MAX_MSG_LEN;
-	else
-		size = debugfs_buf_used;
+	if (debugfs_record_enabled) {
+		if (wraparound)
+			size = debugfs_buf_size - MAX_MSG_LEN;
+		else
+			size = debugfs_buf_used;
 
-	ret = simple_read_from_buffer(ubuf, count, ppos,
-			debugfs_buf, size);
+		ret = simple_read_from_buffer(ubuf, count, ppos,
+				debugfs_buf, size);
+	}
 
 	return ret;
 }
 
 /*
  * set the buffer size (in KB) for debug info
- * if input is 0, then stop recording debug info into buffer
  */
 static ssize_t sps_set_info(struct file *file, const char __user *buf,
 				 size_t count, loff_t *ppos)
 {
 	unsigned long missing;
-	static char str[5];
-	int i, buf_size_kb = 0;
+	char str[MAX_MSG_LEN];
+	int i;
+	u32 buf_size_kb = 0;
+	u32 new_buf_size;
 
 	memset(str, 0, sizeof(str));
 	missing = copy_from_user(str, buf, sizeof(str));
@@ -145,37 +161,53 @@
 	for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
 		buf_size_kb = (buf_size_kb * 10) + (str[i] - '0');
 
-	pr_info("sps:debugfs buffer size is %dKB\n", buf_size_kb);
+	pr_info("sps:debugfs: input buffer size is %dKB\n", buf_size_kb);
 
-	if (sps_debugfs_enabled && (buf_size_kb == 0)) {
-		sps_debugfs_enabled = false;
-		detailed_debug_on = false;
-		kfree(debugfs_buf);
-		debugfs_buf = NULL;
-		debugfs_buf_used = 0;
-		debugfs_buf_size = 0;
-		wraparound = false;
-	} else if (!sps_debugfs_enabled && (buf_size_kb > 0)) {
-		debugfs_buf_size = buf_size_kb * SZ_1K;
+	if ((logging_option == 0) || (logging_option == 2)) {
+		pr_info("sps:debugfs: need to first turn on recording.\n");
+		return -EFAULT;
+	}
 
-		debugfs_buf = kzalloc(sizeof(char) * debugfs_buf_size,
-				GFP_KERNEL);
-		if (!debugfs_buf) {
-			debugfs_buf_size = 0;
-			pr_err("sps:fail to allocate memory for debug_fs.\n");
-			return -ENOMEM;
+	if (buf_size_kb < 1) {
+		pr_info("sps:debugfs: buffer size should be "
+			"no less than 1KB.\n");
+		return -EFAULT;
+	}
+
+	new_buf_size = buf_size_kb * SZ_1K;
+
+	if (debugfs_record_enabled) {
+		if (debugfs_buf_size == new_buf_size) {
+			/* need do nothing */
+			pr_info("sps:debugfs: input buffer size "
+				"is the same as before.\n");
+			return count;
+		} else {
+			/* release the current buffer */
+			debugfs_record_enabled = false;
+			debugfs_buf_used = 0;
+			wraparound = false;
+			kfree(debugfs_buf);
+			debugfs_buf = NULL;
 		}
+	}
 
-		if (buf_size_kb == MAX_OUTPUT_MAGIC_NUM)
-			detailed_debug_on = true;
-		sps_debugfs_enabled = true;
-		debugfs_buf_used = 0;
-		wraparound = false;
-	} else if (sps_debugfs_enabled && (buf_size_kb > 0))
-		pr_info("sps:should disable debugfs before change "
-				"buffer size.\n");
+	/* allocate new buffer */
+	debugfs_buf_size = new_buf_size;
 
-	return sps_debugfs_enabled;
+	debugfs_buf = kzalloc(sizeof(char) * debugfs_buf_size,
+			GFP_KERNEL);
+	if (!debugfs_buf) {
+		debugfs_buf_size = 0;
+		pr_err("sps:fail to allocate memory for debug_fs.\n");
+		return -ENOMEM;
+	}
+
+	debugfs_buf_used = 0;
+	wraparound = false;
+	debugfs_record_enabled = true;
+
+	return count;
 }
 
 const struct file_operations sps_info_ops = {
@@ -183,12 +215,136 @@
 	.write = sps_set_info,
 };
 
-struct dentry *dent;
-struct dentry *dfile;
+/* return the current logging option to userspace */
+static ssize_t sps_read_logging_option(struct file *file, char __user *ubuf,
+		size_t count, loff_t *ppos)
+{
+	char value[MAX_MSG_LEN];
+	int nbytes;
+
+	nbytes = snprintf(value, MAX_MSG_LEN, "%d\n", logging_option);
+
+	return simple_read_from_buffer(ubuf, count, ppos, value, nbytes);
+}
+
+/*
+ * set the logging option
+ */
+static ssize_t sps_set_logging_option(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	unsigned long missing;
+	char str[MAX_MSG_LEN];
+	int i;
+	u8 option = 0;
+
+	memset(str, 0, sizeof(str));
+	missing = copy_from_user(str, buf, sizeof(str));
+	if (missing)
+		return -EFAULT;
+
+	for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
+		option = (option * 10) + (str[i] - '0');
+
+	pr_info("sps:debugfs: try to change logging option to %d\n", option);
+
+	if (option > 3) {
+		pr_err("sps:debugfs: invalid logging option:%d\n", option);
+		return count;
+	}
+
+	if (((option == 0) || (option == 2)) &&
+		((logging_option == 1) || (logging_option == 3))) {
+		debugfs_record_enabled = false;
+		kfree(debugfs_buf);
+		debugfs_buf = NULL;
+		debugfs_buf_used = 0;
+		debugfs_buf_size = 0;
+		wraparound = false;
+	}
+
+	logging_option = option;
+
+	return count;
+}
+
+const struct file_operations sps_logging_option_ops = {
+	.read = sps_read_logging_option,
+	.write = sps_set_logging_option,
+};
+
+/*
+ * input the bam physical address
+ */
+static ssize_t sps_set_bam_addr(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	unsigned long missing;
+	char str[MAX_MSG_LEN];
+	u32 i;
+	u32 bam_addr = 0;
+	struct sps_bam *bam;
+	u32 num_pipes = 0;
+	void *vir_addr;
+
+	memset(str, 0, sizeof(str));
+	missing = copy_from_user(str, buf, sizeof(str));
+	if (missing)
+		return -EFAULT;
+
+	for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
+		bam_addr = (bam_addr * 10) + (str[i] - '0');
+
+	pr_info("sps:debugfs:input BAM physical address:0x%x\n", bam_addr);
+
+	bam = phy2bam(bam_addr);
+
+	if (bam == NULL) {
+		pr_err("sps:debugfs:BAM 0x%x is not registered.", bam_addr);
+		return count;
+	} else {
+		vir_addr = bam->base;
+		num_pipes = bam->props.num_pipes;
+	}
+
+	switch (reg_dump_option) {
+	case 1: /* output all registers of this BAM */
+		print_bam_reg(vir_addr);
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_reg(vir_addr, i);
+		break;
+	case 2: /* output BAM-level registers */
+		print_bam_reg(vir_addr);
+		break;
+	case 3: /* output selected BAM-level registers */
+		print_bam_selected_reg(vir_addr);
+		break;
+	case 4: /* output selected registers of all pipes */
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_selected_reg(vir_addr, i);
+		break;
+	case 5: /* output selected registers of some pipes */
+		print_bam_pipe_selected_reg(vir_addr, 4);
+		print_bam_pipe_selected_reg(vir_addr, 5);
+		break;
+	default:
+		pr_info("sps:no dump option is chosen yet.");
+	}
+
+	return count;
+}
+
+const struct file_operations sps_bam_addr_ops = {
+	.write = sps_set_bam_addr,
+};
+
 static void sps_debugfs_init(void)
 {
-	sps_debugfs_enabled = false;
-	detailed_debug_on = false;
+	debugfs_record_enabled = false;
+	logging_option = 0;
+	debug_level_option = 0;
+	print_limit_option = 0;
+	reg_dump_option = 0;
 	debugfs_buf_size = 0;
 	debugfs_buf_used = 0;
 	wraparound = false;
@@ -199,19 +355,83 @@
 		return;
 	}
 
-	dfile = debugfs_create_file("info", 0444, dent, 0,
+	dfile_info = debugfs_create_file("info", 0666, dent, 0,
 			&sps_info_ops);
-	if (!dfile || IS_ERR(dfile)) {
-		pr_err("sps:fail to create the file for debug_fs.\n");
-		debugfs_remove(dent);
-		return;
+	if (!dfile_info || IS_ERR(dfile_info)) {
+		pr_err("sps:fail to create the file for debug_fs info.\n");
+		goto info_err;
 	}
+
+	dfile_logging_option = debugfs_create_file("logging_option", 0666,
+			dent, 0, &sps_logging_option_ops);
+	if (!dfile_logging_option || IS_ERR(dfile_logging_option)) {
+		pr_err("sps:fail to create the file for debug_fs "
+			"logging_option.\n");
+		goto logging_option_err;
+	}
+
+	dfile_debug_level_option = debugfs_create_u8("debug_level_option",
+					0666, dent, &debug_level_option);
+	if (!dfile_debug_level_option || IS_ERR(dfile_debug_level_option)) {
+		pr_err("sps:fail to create the file for debug_fs "
+			"debug_level_option.\n");
+		goto debug_level_option_err;
+	}
+
+	dfile_print_limit_option = debugfs_create_u8("print_limit_option",
+					0666, dent, &print_limit_option);
+	if (!dfile_print_limit_option || IS_ERR(dfile_print_limit_option)) {
+		pr_err("sps:fail to create the file for debug_fs "
+			"print_limit_option.\n");
+		goto print_limit_option_err;
+	}
+
+	dfile_reg_dump_option = debugfs_create_u8("reg_dump_option", 0666,
+						dent, &reg_dump_option);
+	if (!dfile_reg_dump_option || IS_ERR(dfile_reg_dump_option)) {
+		pr_err("sps:fail to create the file for debug_fs "
+			"reg_dump_option.\n");
+		goto reg_dump_option_err;
+	}
+
+	dfile_bam_addr = debugfs_create_file("bam_addr", 0666,
+			dent, 0, &sps_bam_addr_ops);
+	if (!dfile_bam_addr || IS_ERR(dfile_bam_addr)) {
+		pr_err("sps:fail to create the file for debug_fs "
+			"bam_addr.\n");
+		goto bam_addr_err;
+	}
+
+	return;
+
+bam_addr_err:
+	debugfs_remove(dfile_reg_dump_option);
+reg_dump_option_err:
+	debugfs_remove(dfile_print_limit_option);
+print_limit_option_err:
+	debugfs_remove(dfile_debug_level_option);
+debug_level_option_err:
+	debugfs_remove(dfile_logging_option);
+logging_option_err:
+	debugfs_remove(dfile_info);
+info_err:
+	debugfs_remove(dent);
 }
 
 static void sps_debugfs_exit(void)
 {
-	if (dfile)
-		debugfs_remove(dfile);
+	if (dfile_info)
+		debugfs_remove(dfile_info);
+	if (dfile_logging_option)
+		debugfs_remove(dfile_logging_option);
+	if (dfile_debug_level_option)
+		debugfs_remove(dfile_debug_level_option);
+	if (dfile_print_limit_option)
+		debugfs_remove(dfile_print_limit_option);
+	if (dfile_reg_dump_option)
+		debugfs_remove(dfile_reg_dump_option);
+	if (dfile_bam_addr)
+		debugfs_remove(dfile_bam_addr);
 	if (dent)
 		debugfs_remove(dent);
 	kfree(debugfs_buf);
@@ -235,13 +455,13 @@
 	struct sps_bam_props bamdma_props = {0};
 #endif
 
-	SPS_DBG("sps_device_init");
+	SPS_DBG("sps:sps_device_init");
 
 	success = false;
 
 	result = sps_mem_init(sps->pipemem_phys_base, sps->pipemem_size);
 	if (result) {
-		SPS_ERR("SPS memory init failed");
+		SPS_ERR("sps:SPS memory init failed");
 		goto exit_err;
 	}
 
@@ -249,13 +469,13 @@
 	mutex_init(&sps->lock);
 
 	if (sps_rm_init(&sps->connection_ctrl, sps->options)) {
-		SPS_ERR("Failed to init SPS resource manager");
+		SPS_ERR("sps:Fail to init SPS resource manager");
 		goto exit_err;
 	}
 
 	result = sps_bam_driver_init(sps->options);
 	if (result) {
-		SPS_ERR("SPS BAM driver init failed");
+		SPS_ERR("sps:SPS BAM driver init failed");
 		goto exit_err;
 	}
 
@@ -266,11 +486,11 @@
 					 sps->bamdma_bam_size);
 
 	if (!bamdma_props.virt_addr) {
-		SPS_ERR("sps:Failed to IO map BAM-DMA BAM registers.\n");
+		SPS_ERR("sps:Fail to IO map BAM-DMA BAM registers.\n");
 		goto exit_err;
 	}
 
-	SPS_DBG("sps:bamdma_bam.phys=0x%x.virt=0x%x.",
+	SPS_DBG2("sps:bamdma_bam.phys=0x%x.virt=0x%x.",
 		bamdma_props.phys_addr,
 		(u32) bamdma_props.virt_addr);
 
@@ -280,11 +500,11 @@
 						sps->bamdma_dma_size);
 
 	if (!bamdma_props.periph_virt_addr) {
-		SPS_ERR("sps:Failed to IO map BAM-DMA peripheral reg.\n");
+		SPS_ERR("sps:Fail to IO map BAM-DMA peripheral reg.\n");
 		goto exit_err;
 	}
 
-	SPS_DBG("sps:bamdma_dma.phys=0x%x.virt=0x%x.",
+	SPS_DBG2("sps:bamdma_dma.phys=0x%x.virt=0x%x.",
 		bamdma_props.periph_phys_addr,
 		(u32) bamdma_props.periph_virt_addr);
 
@@ -298,14 +518,14 @@
 
 	result = sps_dma_init(&bamdma_props);
 	if (result) {
-		SPS_ERR("SPS BAM DMA driver init failed");
+		SPS_ERR("sps:SPS BAM DMA driver init failed");
 		goto exit_err;
 	}
 #endif /* CONFIG_SPS_SUPPORT_BAMDMA */
 
 	result = sps_map_init(NULL, sps->options);
 	if (result) {
-		SPS_ERR("SPS connection mapping init failed");
+		SPS_ERR("sps:SPS connection mapping init failed");
 		goto exit_err;
 	}
 
@@ -331,7 +551,7 @@
  */
 static void sps_device_de_init(void)
 {
-	SPS_DBG("%s.", __func__);
+	SPS_DBG2("sps:%s.", __func__);
 
 	if (sps != NULL) {
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
@@ -339,7 +559,7 @@
 #endif
 		/* Are there any remaining BAM registrations? */
 		if (!list_empty(&sps->bams_q))
-			SPS_ERR("SPS de-init: BAMs are still registered");
+			SPS_ERR("sps:SPS de-init: BAMs are still registered");
 
 		sps_map_de_init();
 
@@ -390,7 +610,7 @@
 static int sps_client_de_init(struct sps_pipe *client)
 {
 	if (client->client_state != SPS_STATE_DISCONNECT) {
-		SPS_ERR("De-init client in connected state: 0x%x",
+		SPS_ERR("sps:De-init client in connected state: 0x%x",
 				   client->client_state);
 		return SPS_ERROR;
 	}
@@ -449,7 +669,7 @@
 		}
 	}
 
-	SPS_INFO("sps: BAM device 0x%x is not registered yet.\n", phys_addr);
+	SPS_ERR("sps: BAM device 0x%x is not registered yet.\n", phys_addr);
 
 	return -ENODEV;
 }
@@ -472,14 +692,16 @@
 int sps_setup_bam2bam_fifo(struct sps_mem_buffer *mem_buffer,
 		  u32 addr, u32 size, int use_offset)
 {
-	if ((mem_buffer == NULL) || (size == 0))
+	if ((mem_buffer == NULL) || (size == 0)) {
+		SPS_ERR("sps:invalid buffer address or size.");
 		return SPS_ERROR;
+	}
 
 	if (use_offset) {
 		if ((addr + size) <= sps->pipemem_size)
 			mem_buffer->phys_base = sps->pipemem_phys_base + addr;
 		else {
-			SPS_ERR("sps: requested mem is out of "
+			SPS_ERR("sps:requested mem is out of "
 					"pipe mem range.\n");
 			return SPS_ERROR;
 		}
@@ -489,7 +711,7 @@
 						+ sps->pipemem_size))
 			mem_buffer->phys_base = addr;
 		else {
-			SPS_ERR("sps: requested mem is out of "
+			SPS_ERR("sps:requested mem is out of "
 					"pipe mem range.\n");
 			return SPS_ERROR;
 		}
@@ -527,7 +749,7 @@
 			return bam;
 	}
 
-	SPS_ERR("Can't find BAM device for handle 0x%x.", h);
+	SPS_ERR("sps:Can't find BAM device for handle 0x%x.", h);
 
 	return NULL;
 }
@@ -549,7 +771,7 @@
 
 	bam = pipe->bam;
 	if (bam == NULL) {
-		SPS_ERR("Connection not in connected state");
+		SPS_ERR("sps:Connection is not in connected state.");
 		return NULL;
 	}
 
@@ -559,7 +781,7 @@
 	pipe_index = pipe->pipe_index;
 	if (pipe_index >= bam->props.num_pipes ||
 	    pipe != bam->pipes[pipe_index]) {
-		SPS_ERR("Client not owner of BAM 0x%x pipe: %d (max %d)",
+		SPS_ERR("sps:Client not owner of BAM 0x%x pipe: %d (max %d)",
 			bam->props.phys_addr, pipe_index,
 			bam->props.num_pipes);
 		spin_unlock_irqrestore(&bam->connection_lock,
@@ -598,7 +820,7 @@
 		return -ENODEV;
 
 	if (!sps->is_ready) {
-		SPS_ERR("sps_connect.sps driver not ready.\n");
+		SPS_ERR("sps:sps_connect:sps driver is not ready.\n");
 		return -EAGAIN;
 	}
 
@@ -614,12 +836,12 @@
 
 	bam = sps_h2bam(dev);
 	if (bam == NULL) {
-		SPS_ERR("Invalid BAM device handle: 0x%x", dev);
+		SPS_ERR("sps:Invalid BAM device handle: 0x%x", dev);
 		result = SPS_ERROR;
 		goto exit_err;
 	}
 
-	SPS_DBG("sps_connect: bam 0x%x src 0x%x dest 0x%x mode %s",
+	SPS_DBG2("sps:sps_connect: bam 0x%x src 0x%x dest 0x%x mode %s",
 			BAM_ID(bam),
 			connect->source,
 			connect->destination,
@@ -674,14 +896,18 @@
 	struct sps_bam *bam;
 	int result;
 
-	if (pipe == NULL)
+	if (pipe == NULL) {
+		SPS_ERR("sps:Invalid pipe.");
 		return SPS_ERROR;
+	}
 
 	bam = pipe->bam;
-	if (bam == NULL)
+	if (bam == NULL) {
+		SPS_ERR("sps:BAM device of this pipe is NULL.");
 		return SPS_ERROR;
+	}
 
-	SPS_DBG("sps_disconnect: bam 0x%x src 0x%x dest 0x%x mode %s",
+	SPS_DBG2("sps:sps_disconnect: bam 0x%x src 0x%x dest 0x%x mode %s",
 			BAM_ID(bam),
 			pipe->connect.source,
 			pipe->connect.destination,
@@ -695,7 +921,7 @@
 		check = pipe->map->client_dest;
 
 	if (check != pipe) {
-		SPS_ERR("Client context is corrupt");
+		SPS_ERR("sps:Client context is corrupt");
 		goto exit_err;
 	}
 
@@ -725,13 +951,13 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG2("sps:%s.", __func__);
 
 	if (sps == NULL)
 		return -ENODEV;
 
 	if (!sps->is_ready) {
-		SPS_ERR("sps_connect.sps driver not ready.\n");
+		SPS_ERR("sps:sps_connect:sps driver not ready.\n");
 		return -EAGAIN;
 	}
 
@@ -742,7 +968,7 @@
 	result = sps_bam_pipe_reg_event(bam, pipe->pipe_index, reg);
 	sps_bam_unlock(bam);
 	if (result)
-		SPS_ERR("Failed to register event for BAM 0x%x pipe %d",
+		SPS_ERR("sps:Fail to register event for BAM 0x%x pipe %d",
 			pipe->bam->props.phys_addr, pipe->pipe_index);
 
 	return result;
@@ -759,7 +985,7 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG2("sps:%s.", __func__);
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -783,7 +1009,7 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG2("sps:%s.", __func__);
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -807,7 +1033,7 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -832,7 +1058,7 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -857,7 +1083,7 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -880,7 +1106,7 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -903,7 +1129,7 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -925,13 +1151,13 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s: dev = 0x%x", __func__, dev);
+	SPS_DBG2("sps:%s: dev = 0x%x", __func__, dev);
 
 	mutex_lock(&sps->lock);
 	/* Search for the target BAM device */
 	bam = sps_h2bam(dev);
 	if (bam == NULL) {
-		SPS_ERR("Invalid BAM device handle: 0x%x", dev);
+		SPS_ERR("sps:Invalid BAM device handle: 0x%x", dev);
 		result = SPS_ERROR;
 		goto exit_err;
 	}
@@ -940,7 +1166,7 @@
 	result = sps_bam_reset(bam);
 	mutex_unlock(&bam->lock);
 	if (result) {
-		SPS_ERR("Failed to reset BAM device: 0x%x", dev);
+		SPS_ERR("sps:Fail to reset BAM device: 0x%x", dev);
 		goto exit_err;
 	}
 
@@ -960,7 +1186,7 @@
 	struct sps_pipe *pipe = h;
 
 	if (config == NULL) {
-		SPS_ERR("Config pointer is NULL");
+		SPS_ERR("sps:Config pointer is NULL");
 		return SPS_ERROR;
 	}
 
@@ -981,7 +1207,7 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -1009,7 +1235,7 @@
 	int result;
 
 	if (owner != SPS_OWNER_REMOTE) {
-		SPS_ERR("Unsupported ownership state: %d", owner);
+		SPS_ERR("sps:Unsupported ownership state: %d", owner);
 		return SPS_ERROR;
 	}
 
@@ -1053,16 +1279,20 @@
 		return -ENODEV;
 
 	if (!sps->is_ready) {
-		SPS_ERR("sps_alloc_mem.sps driver not ready.\n");
+		SPS_ERR("sps:sps_alloc_mem:sps driver is not ready.");
 		return -EAGAIN;
 	}
 
-	if (mem_buffer == NULL || mem_buffer->size == 0)
+	if (mem_buffer == NULL || mem_buffer->size == 0) {
+		SPS_ERR("sps:invalid memory buffer address or size");
 		return SPS_ERROR;
+	}
 
 	mem_buffer->phys_base = sps_mem_alloc_io(mem_buffer->size);
-	if (mem_buffer->phys_base == SPS_ADDR_INVALID)
+	if (mem_buffer->phys_base == SPS_ADDR_INVALID) {
+		SPS_ERR("sps:invalid address of allocated memory");
 		return SPS_ERROR;
+	}
 
 	mem_buffer->base = spsi_get_mem_ptr(mem_buffer->phys_base);
 
@@ -1076,8 +1306,10 @@
  */
 int sps_free_mem(struct sps_pipe *h, struct sps_mem_buffer *mem_buffer)
 {
-	if (mem_buffer == NULL || mem_buffer->phys_base == SPS_ADDR_INVALID)
+	if (mem_buffer == NULL || mem_buffer->phys_base == SPS_ADDR_INVALID) {
+		SPS_ERR("sps:invalid memory to free");
 		return SPS_ERROR;
+	}
 
 	sps_mem_free_io(mem_buffer->phys_base, mem_buffer->size);
 
@@ -1103,7 +1335,7 @@
 
 	/* BAM-DMA is registered internally during power-up */
 	if ((!sps->is_ready) && !(bam_props->options & SPS_BAM_OPT_BAMDMA)) {
-		SPS_ERR("sps_register_bam_device.sps driver not ready.\n");
+		SPS_ERR("sps:sps_register_bam_device:sps driver not ready.\n");
 		return -EAGAIN;
 	}
 
@@ -1114,7 +1346,7 @@
 	manage = bam_props->manage & SPS_BAM_MGR_ACCESS_MASK;
 	if (manage != SPS_BAM_MGR_NONE) {
 		if (bam_props->virt_addr == NULL && bam_props->virt_size == 0) {
-			SPS_ERR("Invalid properties for BAM: %x",
+			SPS_ERR("sps:Invalid properties for BAM: %x",
 					   bam_props->phys_addr);
 			return SPS_ERROR;
 		}
@@ -1122,8 +1354,8 @@
 	if ((bam_props->manage & SPS_BAM_MGR_DEVICE_REMOTE) == 0) {
 		/* BAM global is configured by local processor */
 		if (bam_props->summing_threshold == 0) {
-			SPS_ERR("Invalid device ctrl properties for BAM: %x",
-			 bam_props->phys_addr);
+			SPS_ERR("sps:Invalid device ctrl properties for "
+				"BAM: %x", bam_props->phys_addr);
 			return SPS_ERROR;
 		}
 	}
@@ -1139,7 +1371,8 @@
 	bam = phy2bam(bam_props->phys_addr);
 	if (bam != NULL) {
 		mutex_unlock(&sps->lock);
-		SPS_ERR("BAM already registered: %x", bam->props.phys_addr);
+		SPS_ERR("sps:BAM is already registered: %x",
+				bam->props.phys_addr);
 		result = -EEXIST;
 		bam = NULL;   /* Avoid error clean-up kfree(bam) */
 		goto exit_err;
@@ -1151,7 +1384,7 @@
 		/* Map the memory region */
 		virt_addr = ioremap(bam_props->phys_addr, bam_props->virt_size);
 		if (virt_addr == NULL) {
-			SPS_ERR("Unable to map BAM IO memory: %x %x",
+			SPS_ERR("sps:Unable to map BAM IO mem:0x%x size:0x%x",
 				bam_props->phys_addr, bam_props->virt_size);
 			goto exit_err;
 		}
@@ -1159,7 +1392,7 @@
 
 	bam = kzalloc(sizeof(*bam), GFP_KERNEL);
 	if (bam == NULL) {
-		SPS_ERR("Unable to allocate BAM device state: size 0x%x",
+		SPS_ERR("sps:Unable to allocate BAM device state: size 0x%x",
 			sizeof(*bam));
 		goto exit_err;
 	}
@@ -1181,7 +1414,7 @@
 		 * to a non-zero value to insure EE zero globals are not
 		 * modified.
 		 */
-		SPS_INFO("Setting EE for BAM %x to non-zero",
+		SPS_DBG2("sps:Setting EE for BAM %x to non-zero",
 				  bam_props->phys_addr);
 		bam->props.ee = 1;
 	}
@@ -1189,7 +1422,7 @@
 	ok = sps_bam_device_init(bam);
 	mutex_unlock(&bam->lock);
 	if (ok) {
-		SPS_ERR("Failed to init BAM device: phys 0x%0x",
+		SPS_ERR("sps:Fail to init BAM device: phys 0x%0x",
 			bam->props.phys_addr);
 		goto exit_err;
 	}
@@ -1218,14 +1451,14 @@
 		if (sps_dma_device_init((u32) bam)) {
 			bam->props.options &= ~SPS_BAM_OPT_BAMDMA;
 			sps_deregister_bam_device((u32) bam);
-			SPS_ERR("Failed to init BAM-DMA device: BAM phys 0x%0x",
+			SPS_ERR("sps:Fail to init BAM-DMA BAM: phys 0x%0x",
 				bam->props.phys_addr);
 			return SPS_ERROR;
 		}
 	}
 #endif /* CONFIG_SPS_SUPPORT_BAMDMA */
 
-	SPS_DBG("SPS registered BAM: phys 0x%x.", bam->props.phys_addr);
+	SPS_INFO("sps:BAM 0x%x is registered.", bam->props.phys_addr);
 
 	return 0;
 }
@@ -1240,10 +1473,12 @@
 	struct sps_bam *bam;
 
 	bam = sps_h2bam(dev_handle);
-	if (bam == NULL)
+	if (bam == NULL) {
+		SPS_ERR("sps:did not find a BAM for this handle");
 		return SPS_ERROR;
+	}
 
-	SPS_DBG("SPS deregister BAM: phys 0x%x.", bam->props.phys_addr);
+	SPS_DBG2("sps:SPS deregister BAM: phys 0x%x.", bam->props.phys_addr);
 
 	/* If this BAM is attached to a BAM-DMA, init the BAM-DMA device */
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
@@ -1283,10 +1518,12 @@
 	struct sps_bam *bam;
 	int result;
 
-	if (h == NULL || iovec == NULL)
+	if (h == NULL || iovec == NULL) {
+		SPS_ERR("sps:invalid pipe or iovec");
 		return SPS_ERROR;
+	}
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -1312,10 +1549,12 @@
 	struct sps_bam *bam;
 	int result;
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
-	if (h == NULL || timer_ctrl == NULL)
+	if (h == NULL || timer_ctrl == NULL) {
+		SPS_ERR("sps:invalid pipe or timer ctrl");
 		return SPS_ERROR;
+	}
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
@@ -1340,7 +1579,7 @@
 
 	ctx = kzalloc(sizeof(struct sps_pipe), GFP_KERNEL);
 	if (ctx == NULL) {
-		SPS_ERR("Allocate pipe context fail.");
+		SPS_ERR("sps:Fail to allocate pipe context.");
 		return NULL;
 	}
 
@@ -1439,9 +1678,10 @@
 
 	if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,bam-dma-res-pipes",
-				&sps->bamdma_restricted_pipes))
+				&sps->bamdma_restricted_pipes)) {
+		SPS_ERR("sps:Fail to get restricted bamdma pipes.\n");
 		return -EINVAL;
-	else
+	} else
 		SPS_DBG("sps:bamdma_restricted_pipes=0x%x.",
 			sps->bamdma_restricted_pipes);
 
@@ -1489,17 +1729,19 @@
 	SPS_DBG("sps:msm_sps_probe.");
 
 	if (pdev->dev.of_node) {
-		SPS_DBG("sps:get data from device tree.");
-		ret = get_device_tree_data(pdev);
-
+		if (get_device_tree_data(pdev)) {
+			SPS_ERR("sps:Fail to get data from device tree.");
+			return -ENODEV;
+		} else
+			SPS_DBG("sps:get data from device tree.");
 	} else {
-		SPS_DBG("sps:get platform data.");
-		ret = get_platform_data(pdev);
+		if (get_platform_data(pdev)) {
+			SPS_ERR("sps:Fail to get platform data.");
+			return -ENODEV;
+		} else
+			SPS_DBG("sps:get platform data.");
 	}
 
-	if (ret)
-		return -ENODEV;
-
 	/* Create Device */
 	sps->dev_class = class_create(THIS_MODULE, SPS_DRV_NAME);
 
@@ -1574,7 +1816,7 @@
 #endif
 	sps->is_ready = true;
 
-	SPS_INFO("sps is ready.");
+	SPS_INFO("sps:sps is ready.");
 
 	return 0;
 clk_err:
@@ -1590,7 +1832,7 @@
 
 static int __devexit msm_sps_remove(struct platform_device *pdev)
 {
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	device_destroy(sps->dev_class, sps->dev_num);
 	unregister_chrdev_region(sps->dev_num, 1);
@@ -1631,7 +1873,7 @@
 	sps_debugfs_init();
 #endif
 
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	/* Allocate the SPS driver state struct */
 	sps = kzalloc(sizeof(*sps), GFP_KERNEL);
@@ -1650,7 +1892,7 @@
  */
 static void __exit sps_exit(void)
 {
-	SPS_DBG("%s.", __func__);
+	SPS_DBG("sps:%s.", __func__);
 
 	platform_driver_unregister(&msm_sps_driver);
 
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index cb5a0ee..e48f59b 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -102,7 +102,7 @@
 	for (n = 0; n < ARRAY_SIZE(opt_event_table); n++) {
 		if ((u32)opt_event_table[n].option !=
 			(u32)opt_event_table[n].pipe_irq) {
-			SPS_ERR("SPS_O 0x%x != HAL IRQ 0x%x",
+			SPS_ERR("sps:SPS_O 0x%x != HAL IRQ 0x%x",
 				opt_event_table[n].option,
 				opt_event_table[n].pipe_irq);
 			return SPS_ERROR;
@@ -138,7 +138,7 @@
 							  dev->props.ee,
 							  mask);
 
-		SPS_DBG("sps:bam_isr:bam=0x%x;source=0x%x;mask=0x%x.",
+		SPS_DBG1("sps:bam_isr:bam=0x%x;source=0x%x;mask=0x%x.",
 				BAM_ID(dev), source, mask);
 
 		/* Mask any non-local source */
@@ -146,6 +146,9 @@
 	} else {
 		/* If MTIs are used, must poll each active pipe */
 		source = dev->pipe_active_mask;
+
+		SPS_DBG1("sps:bam_isr for MTI:bam=0x%x;source=0x%x.",
+				BAM_ID(dev), source);
 	}
 
 	/* Process active pipe sources */
@@ -164,7 +167,7 @@
 
 	/* Process any inactive pipe sources */
 	if (source) {
-		SPS_ERR("IRQ from BAM 0x%x inactive pipe(s) 0x%x",
+		SPS_ERR("sps:IRQ from BAM 0x%x inactive pipe(s) 0x%x",
 			BAM_ID(dev), source);
 		dev->irq_from_disabled_pipe++;
 	}
@@ -191,7 +194,7 @@
 
 	/* Is there any access to this BAM? */
 	if ((dev->props.manage & SPS_BAM_MGR_ACCESS_MASK) == SPS_BAM_MGR_NONE) {
-		SPS_ERR("No local access to BAM 0x%x", BAM_ID(dev));
+		SPS_ERR("sps:No local access to BAM 0x%x", BAM_ID(dev));
 		return SPS_ERROR;
 	}
 
@@ -209,7 +212,7 @@
 				    IRQF_TRIGGER_HIGH, "sps", dev);
 
 		if (result) {
-			SPS_ERR("Failed to register BAM 0x%x IRQ %d",
+			SPS_ERR("sps:Failed to register BAM 0x%x IRQ %d",
 				BAM_ID(dev), dev->props.irq);
 			return SPS_ERROR;
 		}
@@ -223,11 +226,14 @@
 			result = enable_irq_wake(dev->props.irq);
 
 			if (result) {
-				SPS_ERR("Failed to enable wakeup irq "
+				SPS_ERR("sps:Fail to enable wakeup irq "
 					"BAM 0x%x IRQ %d",
 					BAM_ID(dev), dev->props.irq);
 				return SPS_ERROR;
-			}
+			} else
+				SPS_DBG2("sps:Enable wakeup irq for "
+					"BAM 0x%x IRQ %d",
+					BAM_ID(dev), dev->props.irq);
 		}
 	}
 
@@ -245,7 +251,7 @@
 		rc = bam_check(dev->base, &dev->version, &num_pipes);
 
 	if (rc) {
-		SPS_ERR("Failed to init BAM 0x%x IRQ %d",
+		SPS_ERR("sps:Fail to init BAM 0x%x IRQ %d",
 			BAM_ID(dev), dev->props.irq);
 		return SPS_ERROR;
 	}
@@ -264,7 +270,7 @@
 		 * must use MTI. Thus, force EE index to a non-zero value to
 		 * insure that EE zero globals can't be modified.
 		 */
-		SPS_ERR("sps: EE for satellite BAM must be set to non-zero");
+		SPS_ERR("sps:EE for satellite BAM must be set to non-zero.");
 		return SPS_ERROR;
 	}
 
@@ -278,7 +284,7 @@
 		MTIenabled) {
 		if (dev->props.irq_gen_addr == 0 ||
 		    dev->props.irq_gen_addr == SPS_ADDR_INVALID) {
-			SPS_ERR("MTI destination address not specified "
+			SPS_ERR("sps:MTI destination address not specified "
 				"for BAM 0x%x",	BAM_ID(dev));
 			return SPS_ERROR;
 		}
@@ -287,13 +293,14 @@
 
 	if (num_pipes) {
 		dev->props.num_pipes = num_pipes;
-		SPS_DBG("BAM 0x%x number of pipes reported by hw: %d",
+		SPS_DBG1("sps:BAM 0x%x number of pipes reported by hw: %d",
 				 BAM_ID(dev), dev->props.num_pipes);
 	}
 
 	/* Check EE index */
 	if (!MTIenabled && dev->props.ee >= SPS_BAM_NUM_EES) {
-		SPS_ERR("Invalid EE BAM 0x%x: %d", BAM_ID(dev), dev->props.ee);
+		SPS_ERR("sps:Invalid EE BAM 0x%x: %d", BAM_ID(dev),
+				dev->props.ee);
 		return SPS_ERROR;
 	}
 
@@ -305,7 +312,7 @@
 		struct sps_bam_sec_config_props *p_sec =
 						dev->props.p_sec_config_props;
 		if (p_sec == NULL) {
-			SPS_ERR("EE config table is not specified for "
+			SPS_ERR("sps:EE config table is not specified for "
 				"BAM 0x%x", BAM_ID(dev));
 			return SPS_ERROR;
 		}
@@ -333,7 +340,7 @@
 				for (i = n + 1; i < SPS_BAM_NUM_EES; i++) {
 					if ((p_sec->ees[n].pipe_mask &
 						p_sec->ees[i].pipe_mask) != 0) {
-						SPS_ERR("Overlapping pipe "
+						SPS_ERR("sps:Overlapping pipe "
 							"assignments for BAM "
 							"0x%x: EEs %d and %d",
 							BAM_ID(dev), n, i);
@@ -385,7 +392,7 @@
 	}
 
 	dev->state |= BAM_STATE_ENABLED;
-	SPS_DBG("BAM 0x%x enabled: ver: %d, number of pipes: %d",
+	SPS_DBG2("sps:BAM 0x%x enabled: ver: %d, number of pipes: %d",
 		BAM_ID(dev), dev->version, dev->props.num_pipes);
 	return 0;
 }
@@ -401,7 +408,7 @@
 
 	/* Is there any access to this BAM? */
 	if ((dev->props.manage & SPS_BAM_MGR_ACCESS_MASK) == SPS_BAM_MGR_NONE) {
-		SPS_ERR("No local access to BAM 0x%x", BAM_ID(dev));
+		SPS_ERR("sps:No local access to BAM 0x%x", BAM_ID(dev));
 		return SPS_ERROR;
 	}
 
@@ -425,7 +432,7 @@
 
 	dev->state &= ~BAM_STATE_ENABLED;
 
-	SPS_DBG("BAM 0x%x disabled", BAM_ID(dev));
+	SPS_DBG2("sps:BAM 0x%x disabled", BAM_ID(dev));
 
 	return 0;
 }
@@ -436,7 +443,7 @@
 int sps_bam_device_init(struct sps_bam *dev)
 {
 	if (dev->props.virt_addr == NULL) {
-		SPS_ERR("NULL BAM virtual address");
+		SPS_ERR("sps:NULL BAM virtual address");
 		return SPS_ERROR;
 	}
 	dev->base = (void *) dev->props.virt_addr;
@@ -444,7 +451,7 @@
 	if (dev->props.num_pipes == 0) {
 		/* Assume max number of pipes until BAM registers can be read */
 		dev->props.num_pipes = BAM_MAX_PIPES;
-		SPS_DBG("BAM 0x%x: assuming max number of pipes: %d",
+		SPS_DBG2("sps:BAM 0x%x: assuming max number of pipes: %d",
 			BAM_ID(dev), dev->props.num_pipes);
 	}
 
@@ -459,10 +466,13 @@
 	spin_lock_init(&dev->connection_lock);
 
 	if ((dev->props.options & SPS_BAM_OPT_ENABLE_AT_BOOT))
-		if (sps_bam_enable(dev))
+		if (sps_bam_enable(dev)) {
+			SPS_ERR("sps:Fail to enable bam device");
 			return SPS_ERROR;
+		}
 
-	SPS_DBG("BAM device: phys 0x%x IRQ %d", BAM_ID(dev), dev->props.irq);
+	SPS_DBG2("sps:BAM device: phys 0x%x IRQ %d",
+			BAM_ID(dev), dev->props.irq);
 
 	return 0;
 }
@@ -475,7 +485,7 @@
 {
 	int result;
 
-	SPS_DBG("BAM device DEINIT: phys 0x%x IRQ %d",
+	SPS_DBG2("sps:BAM device DEINIT: phys 0x%x IRQ %d",
 		BAM_ID(dev), dev->props.irq);
 
 	result = sps_bam_disable(dev);
@@ -493,7 +503,7 @@
 	u32 pipe_index;
 	int result;
 
-	SPS_DBG("BAM device RESET: phys 0x%x IRQ %d",
+	SPS_DBG2("sps:BAM device RESET: phys 0x%x IRQ %d",
 		BAM_ID(dev), dev->props.irq);
 
 	/* If BAM is enabled, then disable */
@@ -504,7 +514,7 @@
 		      pipe_index++) {
 			pipe = dev->pipes[pipe_index];
 			if (BAM_PIPE_IS_ASSIGNED(pipe)) {
-				SPS_ERR("BAM device 0x%x RESET failed: "
+				SPS_ERR("sps:BAM device 0x%x RESET failed: "
 					"pipe %d in use",
 					BAM_ID(dev), pipe_index);
 				result = SPS_ERROR;
@@ -557,8 +567,8 @@
 	if (pipe_index == SPS_BAM_PIPE_INVALID) {
 		/* Allocate a pipe from the BAM */
 		if ((dev->props.manage & SPS_BAM_MGR_PIPE_NO_ALLOC)) {
-			SPS_ERR("Restricted from allocating pipes on BAM 0x%x",
-				BAM_ID(dev));
+			SPS_ERR("sps:Restricted from allocating pipes "
+				"on BAM 0x%x", BAM_ID(dev));
 			return SPS_BAM_PIPE_INVALID;
 		}
 		for (pipe_index = 0, pipe_mask = 1;
@@ -571,24 +581,24 @@
 				break;	/* Found an available pipe */
 		}
 		if (pipe_index >= dev->props.num_pipes) {
-			SPS_ERR("Failed to allocate pipe on BAM 0x%x",
+			SPS_ERR("sps:Fail to allocate pipe on BAM 0x%x",
 				BAM_ID(dev));
 			return SPS_BAM_PIPE_INVALID;
 		}
 	} else {
 		/* Check that client-specified pipe is available */
 		if (pipe_index >= dev->props.num_pipes) {
-			SPS_ERR("Invalid pipe %d for allocate on BAM 0x%x",
+			SPS_ERR("sps:Invalid pipe %d for allocate on BAM 0x%x",
 				pipe_index, BAM_ID(dev));
 			return SPS_BAM_PIPE_INVALID;
 		}
 		if ((dev->props.restricted_pipes & (1UL << pipe_index))) {
-			SPS_ERR("BAM 0x%x pipe %d is not local",
+			SPS_ERR("sps:BAM 0x%x pipe %d is not local",
 				BAM_ID(dev), pipe_index);
 			return SPS_BAM_PIPE_INVALID;
 		}
 		if (dev->pipes[pipe_index] != NULL) {
-			SPS_ERR("Pipe %d already allocated on BAM 0x%x",
+			SPS_ERR("sps:Pipe %d already allocated on BAM 0x%x",
 				pipe_index, BAM_ID(dev));
 			return SPS_BAM_PIPE_INVALID;
 		}
@@ -609,7 +619,8 @@
 	struct sps_pipe *pipe;
 
 	if (pipe_index >= dev->props.num_pipes) {
-		SPS_ERR("Invalid BAM 0x%x pipe: %d", BAM_ID(dev), pipe_index);
+		SPS_ERR("sps:Invalid BAM 0x%x pipe: %d", BAM_ID(dev),
+				pipe_index);
 		return;
 	}
 
@@ -619,8 +630,8 @@
 
 	/* Is the pipe currently allocated? */
 	if (pipe == NULL) {
-		SPS_ERR("Attempt to free unallocated pipe %d on BAM 0x%x",
-			pipe_index, BAM_ID(dev));
+		SPS_ERR("sps:Attempt to free unallocated pipe %d on "
+			"BAM 0x%x", pipe_index, BAM_ID(dev));
 		return;
 	}
 
@@ -631,7 +642,7 @@
 	if (!list_empty(&pipe->sys.events_q)) {
 		struct sps_q_event *sps_event;
 
-		SPS_ERR("Disconnect BAM 0x%x pipe %d with events pending",
+		SPS_ERR("sps:Disconnect BAM 0x%x pipe %d with events pending",
 			BAM_ID(dev), pipe_index);
 
 		sps_event = list_entry((&pipe->sys.events_q)->next,
@@ -695,7 +706,8 @@
 	dev = map_pipe->bam;
 	pipe_index = map_pipe->pipe_index;
 	if (pipe_index >= dev->props.num_pipes) {
-		SPS_ERR("Invalid BAM 0x%x pipe: %d", BAM_ID(dev), pipe_index);
+		SPS_ERR("sps:Invalid BAM 0x%x pipe: %d", BAM_ID(dev),
+				pipe_index);
 		return SPS_ERROR;
 	}
 	hw_params.event_threshold = (u16) map_pipe->event_threshold;
@@ -704,14 +716,14 @@
 	/* Verify that control of this pipe is allowed */
 	if ((dev->props.manage & SPS_BAM_MGR_PIPE_NO_CTRL) ||
 	    (dev->props.restricted_pipes & (1UL << pipe_index))) {
-		SPS_ERR("BAM 0x%x pipe %d is not local",
+		SPS_ERR("sps:BAM 0x%x pipe %d is not local",
 			BAM_ID(dev), pipe_index);
 		return SPS_ERROR;
 	}
 
 	/* Control without configuration permission is not supported yet */
 	if ((dev->props.manage & SPS_BAM_MGR_PIPE_NO_CONFIG)) {
-		SPS_ERR("BAM 0x%x pipe %d remote config is not supported",
+		SPS_ERR("sps:BAM 0x%x pipe %d remote config is not supported",
 			BAM_ID(dev), pipe_index);
 		return SPS_ERROR;
 	}
@@ -729,8 +741,8 @@
 		if (map->desc.phys_base == SPS_ADDR_INVALID ||
 		    map->data.phys_base == SPS_ADDR_INVALID ||
 		    map->desc.size == 0 || map->data.size == 0) {
-			SPS_ERR("FIFO buffers are not allocated for BAM 0x%x "
-				"pipe %d", BAM_ID(dev), pipe_index);
+			SPS_ERR("sps:FIFO buffers are not allocated for BAM "
+				"0x%x pipe %d.", BAM_ID(dev), pipe_index);
 			return SPS_ERROR;
 		}
 		hw_params.data_base = map->data.phys_base;
@@ -754,7 +766,7 @@
 	/* Get virtual address for descriptor FIFO */
 	if (map->desc.phys_base != SPS_ADDR_INVALID) {
 		if (map->desc.size < (2 * sizeof(struct sps_iovec))) {
-			SPS_ERR("Invalid descriptor FIFO size "
+			SPS_ERR("sps:Invalid descriptor FIFO size "
 				"for BAM 0x%x pipe %d: %d",
 				BAM_ID(dev), pipe_index, map->desc.size);
 			return SPS_ERROR;
@@ -788,19 +800,19 @@
 
 	/* Check pipe allocation */
 	if (dev->pipes[pipe_index] != BAM_PIPE_UNASSIGNED) {
-		SPS_ERR("Invalid pipe %d on BAM 0x%x for connect",
+		SPS_ERR("sps:Invalid pipe %d on BAM 0x%x for connect",
 			pipe_index, BAM_ID(dev));
 		goto exit_err;
 	}
 
 	if (bam_pipe_is_enabled(dev->base, pipe_index)) {
-		SPS_ERR("BAM 0x%x pipe %d sharing violation",
+		SPS_ERR("sps:BAM 0x%x pipe %d sharing violation",
 			BAM_ID(dev), pipe_index);
 		goto exit_err;
 	}
 
 	if (bam_pipe_init(dev->base, pipe_index, &hw_params, dev->props.ee)) {
-		SPS_ERR("BAM 0x%x pipe %d init error",
+		SPS_ERR("sps:BAM 0x%x pipe %d init error",
 			BAM_ID(dev), pipe_index);
 		goto exit_err;
 	}
@@ -870,7 +882,8 @@
 	int result;
 
 	if (pipe_index >= dev->props.num_pipes) {
-		SPS_ERR("Invalid BAM 0x%x pipe: %d", BAM_ID(dev), pipe_index);
+		SPS_ERR("sps:Invalid BAM 0x%x pipe: %d", BAM_ID(dev),
+				pipe_index);
 		return SPS_ERROR;
 	}
 
@@ -895,7 +908,7 @@
 	}
 
 	if (result)
-		SPS_ERR("BAM 0x%x pipe %d already disconnected",
+		SPS_ERR("sps:BAM 0x%x pipe %d already disconnected",
 			BAM_ID(dev), pipe_index);
 
 	return result;
@@ -938,7 +951,7 @@
 		irq_enable = BAM_DISABLE;
 		pipe->polled = true;
 		if (poll == 0 && pipe->irq_mask)
-			SPS_INFO("BAM 0x%x pipe %d forced to use polling",
+			SPS_DBG2("sps:BAM 0x%x pipe %d forced to use polling",
 				 BAM_ID(dev), pipe_index);
 	}
 	if ((pipe->state & BAM_STATE_MTI) == 0)
@@ -984,7 +997,7 @@
 	if (pipe->sys.desc_wr_count > 0 &&
 	    (no_queue != pipe->sys.no_queue
 	     || ack_xfers != pipe->sys.ack_xfers)) {
-		SPS_ERR("Queue/ack mode change after transfer: "
+		SPS_ERR("sps:Queue/ack mode change after transfer: "
 			"BAM 0x%x pipe %d opt 0x%x",
 			BAM_ID(dev), pipe_index, options);
 		return SPS_ERROR;
@@ -994,7 +1007,7 @@
 	/* Is client setting invalid options for a BAM-to-BAM connection? */
 	if ((pipe->state & BAM_STATE_BAM2BAM) &&
 	    (options & BAM2BAM_O_INVALID)) {
-		SPS_ERR("Invalid option for BAM-to-BAM: BAM 0x%x pipe %d "
+		SPS_ERR("sps:Invalid option for BAM-to-BAM: BAM 0x%x pipe %d "
 			"opt 0x%x", BAM_ID(dev), pipe_index, options);
 		return SPS_ERROR;
 	}
@@ -1008,7 +1021,7 @@
 		kzalloc(pipe->desc_size + size, GFP_KERNEL);
 		if (pipe->sys.desc_cache == NULL) {
 			/*** MUST BE LAST POINT OF FAILURE (see below) *****/
-			SPS_ERR("Desc cache error: BAM 0x%x pipe %d: %d",
+			SPS_ERR("sps:Desc cache error: BAM 0x%x pipe %d: %d",
 				BAM_ID(dev), pipe_index,
 				pipe->desc_size + size);
 			return SPS_ERROR;
@@ -1079,7 +1092,7 @@
 
 	if (pipe->sys.no_queue && reg->xfer_done != NULL &&
 	    reg->mode != SPS_TRIGGER_CALLBACK) {
-		SPS_ERR("Only callback events support for NO_Q: "
+		SPS_ERR("sps:Only callback events support for NO_Q: "
 			"BAM 0x%x pipe %d mode %d",
 			BAM_ID(dev), pipe_index, reg->mode);
 		return SPS_ERROR;
@@ -1094,7 +1107,7 @@
 
 		index = SPS_EVENT_INDEX(opt_event_table[n].event_id);
 		if (index < 0)
-			SPS_ERR("Negative event index: "
+			SPS_ERR("sps:Negative event index: "
 			"BAM 0x%x pipe %d mode %d",
 			BAM_ID(dev), pipe_index, reg->mode);
 		else {
@@ -1124,7 +1137,7 @@
 
 	/* Is this a BAM-to-BAM or satellite connection? */
 	if ((pipe->state & (BAM_STATE_BAM2BAM | BAM_STATE_REMOTE))) {
-		SPS_ERR("Transfer on BAM-to-BAM: BAM 0x%x pipe %d",
+		SPS_ERR("sps:Transfer on BAM-to-BAM: BAM 0x%x pipe %d",
 			BAM_ID(dev), pipe_index);
 		return SPS_ERROR;
 	}
@@ -1134,7 +1147,7 @@
 	 * SPS_O_NO_Q option.
 	 */
 	if (pipe->sys.no_queue && user != NULL) {
-		SPS_ERR("User pointer arg non-NULL: BAM 0x%x pipe %d",
+		SPS_ERR("sps:User pointer arg non-NULL: BAM 0x%x pipe %d",
 			BAM_ID(dev), pipe_index);
 		return SPS_ERROR;
 	}
@@ -1153,13 +1166,13 @@
 		if (!pipe->sys.ack_xfers && pipe->polled) {
 			pipe_handler_eot(dev, pipe);
 			if (next_write == pipe->sys.acked_offset) {
-				SPS_DBG("Descriptor FIFO is full for "
-					"BAM 0x%x pipe %d",
+				SPS_DBG2("sps:Descriptor FIFO is full for BAM "
+					"0x%x pipe %d after pipe_handler_eot",
 					BAM_ID(dev), pipe_index);
 				return SPS_ERROR;
 			}
 		} else {
-			SPS_DBG("Descriptor FIFO is full for "
+			SPS_DBG2("sps:Descriptor FIFO is full for "
 				"BAM 0x%x pipe %d", BAM_ID(dev), pipe_index);
 			return SPS_ERROR;
 		}
@@ -1236,14 +1249,14 @@
 	int result;
 
 	if (transfer->iovec_count == 0) {
-		SPS_ERR("iovec count zero: BAM 0x%x pipe %d",
+		SPS_ERR("sps:iovec count zero: BAM 0x%x pipe %d",
 			BAM_ID(dev), pipe_index);
 		return SPS_ERROR;
 	}
 
 	sps_bam_get_free_count(dev, pipe_index, &count);
 	if (count < transfer->iovec_count) {
-		SPS_ERR("Insufficient free desc: BAM 0x%x pipe %d: %d",
+		SPS_ERR("sps:Insufficient free desc: BAM 0x%x pipe %d: %d",
 			BAM_ID(dev), pipe_index, count);
 		return SPS_ERROR;
 	}
@@ -1669,7 +1682,7 @@
 	struct sps_q_event *event_queue;
 
 	if (pipe->sys.no_queue) {
-		SPS_ERR("Invalid connection for event: "
+		SPS_ERR("sps:Invalid connection for event: "
 			"BAM 0x%x pipe %d context 0x%x",
 			BAM_ID(dev), pipe_index, (u32) pipe);
 		notify->event_id = SPS_EVENT_INVALID;
@@ -1774,7 +1787,7 @@
 
 	/* Is this a satellite connection? */
 	if ((pipe->state & BAM_STATE_REMOTE)) {
-		SPS_ERR("Is empty on remote: BAM 0x%x pipe %d",
+		SPS_ERR("sps:Is empty on remote: BAM 0x%x pipe %d",
 			BAM_ID(dev), pipe_index);
 		return SPS_ERROR;
 	}
@@ -1813,8 +1826,8 @@
 
 	/* Is this a BAM-to-BAM or satellite connection? */
 	if ((pipe->state & (BAM_STATE_BAM2BAM | BAM_STATE_REMOTE))) {
-		SPS_ERR("Free count on BAM-to-BAM or remote: BAM 0x%x pipe %d",
-			BAM_ID(dev), pipe_index);
+		SPS_ERR("sps:Free count on BAM-to-BAM or remote: BAM "
+			"0x%x pipe %d",	BAM_ID(dev), pipe_index);
 		*count = 0;
 		return SPS_ERROR;
 	}
@@ -1849,14 +1862,14 @@
 	 */
 	if ((dev->props.manage & SPS_BAM_MGR_MULTI_EE) == 0 ||
 	    (dev->props.manage & SPS_BAM_MGR_DEVICE_REMOTE)) {
-		SPS_ERR("Cannot grant satellite control to BAM 0x%x pipe %d",
-			BAM_ID(dev), pipe_index);
+		SPS_ERR("sps:Cannot grant satellite control to BAM 0x%x "
+			"pipe %d", BAM_ID(dev), pipe_index);
 		return SPS_ERROR;
 	}
 
 	/* Is this pipe locally controlled? */
 	if ((dev->pipe_active_mask & (1UL << pipe_index)) == 0) {
-		SPS_ERR("BAM 0x%x pipe %d not local and active",
+		SPS_ERR("sps:BAM 0x%x pipe %d not local and active",
 			BAM_ID(dev), pipe_index);
 		return SPS_ERROR;
 	}
@@ -1904,7 +1917,7 @@
 
 	/* Is this pipe locally controlled? */
 	if ((dev->pipe_active_mask & (1UL << pipe_index)) == 0) {
-		SPS_ERR("BAM 0x%x pipe %d not local and active",
+		SPS_ERR("sps:BAM 0x%x pipe %d not local and active",
 			BAM_ID(dev), pipe_index);
 		return SPS_ERROR;
 	}
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index 3af891e..70e7898 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -26,7 +26,6 @@
 
 #include "spsi.h"
 
-#define BAM_MAX_PIPES              31
 #define BAM_HANDLE_INVALID         0
 
 enum bam_irq {
diff --git a/drivers/platform/msm/sps/sps_dma.c b/drivers/platform/msm/sps/sps_dma.c
index 48c7ffd..bfb5981 100644
--- a/drivers/platform/msm/sps/sps_dma.c
+++ b/drivers/platform/msm/sps/sps_dma.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -65,7 +65,7 @@
 static inline void dma_write_reg(void *base, u32 offset, u32 val)
 {
 	iowrite32(val, base + offset);
-	SPS_DBG("bamdma: write reg 0x%x w_val 0x%x.", offset, val);
+	SPS_DBG("sps:bamdma: write reg 0x%x w_val 0x%x.", offset, val);
 }
 
 /**
@@ -86,7 +86,7 @@
 	tmp &= ~mask;		/* clear written bits */
 	val = tmp | (val << shift);
 	iowrite32(val, base + offset);
-	SPS_DBG("bamdma: write reg 0x%x w_val 0x%x.", offset, val);
+	SPS_DBG("sps:bamdma: write reg 0x%x w_val 0x%x.", offset, val);
 }
 
 /* Round max number of pipes to nearest multiple of 2 */
@@ -210,7 +210,8 @@
 
 	/* Enable BAM device */
 	if (sps_bam_enable(dev->bam)) {
-		SPS_ERR("Failed to enable BAM DMA's BAM: %x", dev->phys_addr);
+		SPS_ERR("sps:Failed to enable BAM DMA's BAM: %x",
+			dev->phys_addr);
 		return SPS_ERROR;
 	}
 
@@ -243,7 +244,7 @@
 	}
 
 	if (pipe_index < dev->num_pipes) {
-		SPS_ERR("Failed to disable BAM-DMA %x: channels are active",
+		SPS_ERR("sps:Fail to disable BAM-DMA %x:channels are active",
 			dev->phys_addr);
 		return SPS_ERROR;
 	}
@@ -252,7 +253,7 @@
 
 	/* Disable BAM device */
 	if (sps_bam_disable(dev->bam)) {
-		SPS_ERR("Failed to disable BAM-DMA %x BAM", dev->phys_addr);
+		SPS_ERR("sps:Fail to disable BAM-DMA BAM:%x", dev->phys_addr);
 		return SPS_ERROR;
 	}
 
@@ -280,7 +281,7 @@
 	/* Find a free BAM-DMA device slot */
 	dev = NULL;
 	if (bam_dma_dev[0].bam != NULL) {
-		SPS_ERR("BAM-DMA BAM device already initialized.");
+		SPS_ERR("sps:BAM-DMA BAM device is already initialized.");
 		goto exit_err;
 	} else {
 		dev = &bam_dma_dev[0];
@@ -292,7 +293,8 @@
 	dev->bam = sps_h2bam(h);
 
 	if (dev->bam == NULL) {
-		SPS_ERR("BAM-DMA BAM device is not found from the handle.");
+		SPS_ERR("sps:BAM-DMA BAM device is not found "
+				"from the handle.");
 		goto exit_err;
 	}
 
@@ -304,7 +306,7 @@
 		dev->virtual_mapped = false;
 	} else {
 		if (props->periph_virt_size == 0) {
-			SPS_ERR("Unable to map BAM DMA IO memory: %x %x",
+			SPS_ERR("sps:Unable to map BAM DMA IO memory: %x %x",
 			 dev->phys_addr, props->periph_virt_size);
 			goto exit_err;
 		}
@@ -312,7 +314,7 @@
 		dev->virt_addr = ioremap(dev->phys_addr,
 					  props->periph_virt_size);
 		if (dev->virt_addr == NULL) {
-			SPS_ERR("Unable to map BAM DMA IO memory: %x %x",
+			SPS_ERR("sps:Unable to map BAM DMA IO memory: %x %x",
 				dev->phys_addr, props->periph_virt_size);
 			goto exit_err;
 		}
@@ -322,11 +324,11 @@
 
 	/* Is the BAM-DMA device locally controlled? */
 	if ((props->manage & SPS_BAM_MGR_DEVICE_REMOTE) == 0) {
-		SPS_DBG("BAM-DMA is controlled locally: %x",
+		SPS_DBG2("sps:BAM-DMA is controlled locally: %x",
 			dev->phys_addr);
 		dev->local = true;
 	} else {
-		SPS_DBG("BAM-DMA is controlled remotely: %x",
+		SPS_DBG2("sps:BAM-DMA is controlled remotely: %x",
 			dev->phys_addr);
 		dev->local = false;
 	}
@@ -379,7 +381,7 @@
 
 	dev = sps_dma_find_device(h);
 	if (dev == NULL) {
-		SPS_ERR("BAM-DMA: not registered: %x", h);
+		SPS_ERR("sps:BAM-DMA: not registered: %x", h);
 		result = SPS_ERROR;
 		goto exit_err;
 	}
@@ -387,14 +389,15 @@
 	/* Check for channel leaks */
 	for (chan = 0; chan < dev->num_pipes / 2; chan++) {
 		if (dev->chans[chan].state != DMA_CHAN_STATE_FREE) {
-			SPS_ERR("BAM-DMA: channel not free: %d", chan);
+			SPS_ERR("sps:BAM-DMA: channel not free: %d", chan);
 			result = SPS_ERROR;
 			dev->chans[chan].state = DMA_CHAN_STATE_FREE;
 		}
 	}
 	for (pipe_index = 0; pipe_index < dev->num_pipes; pipe_index++) {
 		if (dev->pipes[pipe_index] != PIPE_INACTIVE) {
-			SPS_ERR("BAM-DMA: pipe not inactive: %d", pipe_index);
+			SPS_ERR("sps:BAM-DMA: pipe not inactive: %d",
+					pipe_index);
 			result = SPS_ERROR;
 			dev->pipes[pipe_index] = PIPE_INACTIVE;
 		}
@@ -446,7 +449,7 @@
 		bam_reg = bam_props;
 		if ((bam_props->options & SPS_BAM_OPT_BAMDMA) &&
 		    (bam_props->manage & SPS_BAM_MGR_MULTI_EE) == 0) {
-			SPS_DBG("Setting multi-EE options for BAM-DMA: %x",
+			SPS_DBG("sps:Setting multi-EE options for BAM-DMA: %x",
 				bam_props->phys_addr);
 			props = *bam_props;
 			props.manage |= SPS_BAM_MGR_MULTI_EE;
@@ -455,7 +458,7 @@
 
 		/* Register the BAM */
 		if (sps_register_bam_device(bam_reg, &h)) {
-			SPS_ERR("Failed to register BAM-DMA BAM device: "
+			SPS_ERR("sps:Fail to register BAM-DMA BAM device: "
 				"phys 0x%0x", bam_props->phys_addr);
 			return SPS_ERROR;
 		}
@@ -465,11 +468,12 @@
 			bam_handles[num_bams] = h;
 			num_bams++;
 		} else {
-			SPS_ERR("BAM-DMA: BAM limit exceeded: %d", num_bams);
+			SPS_ERR("sps:BAM-DMA: BAM limit exceeded: %d",
+					num_bams);
 			return SPS_ERROR;
 		}
 	} else {
-		SPS_ERR("BAM-DMA phys_addr is zero.");
+		SPS_ERR("sps:BAM-DMA phys_addr is zero.");
 		return SPS_ERROR;
 	}
 
@@ -510,7 +514,7 @@
 	int result = SPS_ERROR;
 
 	if (alloc == NULL || chan_info == NULL) {
-		SPS_ERR("sps_alloc_dma_chan. invalid parameters");
+		SPS_ERR("sps:sps_alloc_dma_chan. invalid parameters");
 		return SPS_ERROR;
 	}
 
@@ -529,7 +533,7 @@
 	weight = alloc->priority;
 
 	if ((u32)alloc->priority > (u32)BAM_DMA_WEIGHT_HIGH) {
-		SPS_ERR("BAM-DMA: invalid priority: %x", alloc->priority);
+		SPS_ERR("sps:BAM-DMA: invalid priority: %x", alloc->priority);
 		return SPS_ERROR;
 	}
 
@@ -537,7 +541,7 @@
 
 	dev = sps_dma_find_device(alloc->dev);
 	if (dev == NULL) {
-		SPS_ERR("BAM-DMA: invalid BAM handle: %x", alloc->dev);
+		SPS_ERR("sps:BAM-DMA: invalid BAM handle: %x", alloc->dev);
 		goto exit_err;
 	}
 
@@ -548,7 +552,8 @@
 			/* Just check pipes for safety */
 			if (dev->pipes[pipe_index] != PIPE_INACTIVE ||
 			    dev->pipes[pipe_index + 1] != PIPE_INACTIVE) {
-				SPS_ERR("BAM-DMA: channel %d state error:%d %d",
+				SPS_ERR("sps:BAM-DMA: channel %d state "
+					"error:%d %d",
 					pipe_index / 2, dev->pipes[pipe_index],
 				 dev->pipes[pipe_index + 1]);
 				goto exit_err;
@@ -558,7 +563,7 @@
 	}
 
 	if (pipe_index >= dev->num_pipes) {
-		SPS_ERR("BAM-DMA: no free channel. num_pipes = %d",
+		SPS_ERR("sps:BAM-DMA: no free channel. num_pipes = %d",
 			dev->num_pipes);
 		goto exit_err;
 	}
@@ -572,7 +577,7 @@
 	chan->priority = alloc->priority;
 	chan->weight = weight;
 
-	SPS_DBG("sps_alloc_dma_chan. pipe %d.\n", pipe_index);
+	SPS_DBG2("sps:sps_alloc_dma_chan. pipe %d.\n", pipe_index);
 
 	/* Report allocated pipes to client */
 	chan_info->dev = dev->h;
@@ -600,7 +605,7 @@
 	int result = 0;
 
 	if (chan == NULL) {
-		SPS_ERR("sps_free_dma_chan. chan is NULL");
+		SPS_ERR("sps:sps_free_dma_chan. chan is NULL");
 		return SPS_ERROR;
 	}
 
@@ -608,7 +613,7 @@
 
 	dev = sps_dma_find_device(chan->dev);
 	if (dev == NULL) {
-		SPS_ERR("BAM-DMA: invalid BAM handle: %x", chan->dev);
+		SPS_ERR("sps:BAM-DMA: invalid BAM handle: %x", chan->dev);
 		result = SPS_ERROR;
 		goto exit_err;
 	}
@@ -617,8 +622,8 @@
 	pipe_index = chan->dest_pipe_index;
 	if (pipe_index >= dev->num_pipes || ((pipe_index & 1)) ||
 	    (pipe_index + 1) != chan->src_pipe_index) {
-		SPS_ERR("sps_free_dma_chan. Invalid pipe indices");
-		SPS_DBG("num_pipes=%d.dest=%d.src=%d.",
+		SPS_ERR("sps:sps_free_dma_chan. Invalid pipe indices."
+			"num_pipes=%d.dest=%d.src=%d.",
 			dev->num_pipes,
 			chan->dest_pipe_index,
 			chan->src_pipe_index);
@@ -630,7 +635,7 @@
 	if (dev->chans[pipe_index / 2].state != DMA_CHAN_STATE_ALLOC_EXT ||
 	    dev->pipes[pipe_index] != PIPE_INACTIVE ||
 	    dev->pipes[pipe_index + 1] != PIPE_INACTIVE) {
-		SPS_ERR("BAM-DMA: attempt to free active chan %d: %d %d",
+		SPS_ERR("sps:BAM-DMA: attempt to free active chan %d: %d %d",
 			pipe_index / 2, dev->pipes[pipe_index],
 			dev->pipes[pipe_index + 1]);
 		result = SPS_ERROR;
@@ -695,14 +700,14 @@
 	int result = SPS_ERROR;
 
 	if (bam == NULL) {
-		SPS_ERR("BAM context is NULL");
+		SPS_ERR("sps:BAM context is NULL");
 		return SPS_ERROR;
 	}
 
 	/* Check pipe direction */
 	if ((DMA_PIPE_IS_DEST(pipe_index) && dir != SPS_MODE_DEST) ||
 	    (DMA_PIPE_IS_SRC(pipe_index) && dir != SPS_MODE_SRC)) {
-		SPS_ERR("BAM-DMA: wrong direction for BAM %x pipe %d",
+		SPS_ERR("sps:BAM-DMA: wrong direction for BAM %x pipe %d",
 			bam->props.phys_addr, pipe_index);
 		return SPS_ERROR;
 	}
@@ -711,17 +716,17 @@
 
 	dev = sps_dma_find_device((u32) bam);
 	if (dev == NULL) {
-		SPS_ERR("BAM-DMA: invalid BAM: %x",
+		SPS_ERR("sps:BAM-DMA: invalid BAM: %x",
 			bam->props.phys_addr);
 		goto exit_err;
 	}
 	if (pipe_index >= dev->num_pipes) {
-		SPS_ERR("BAM-DMA: BAM %x invalid pipe: %d",
+		SPS_ERR("sps:BAM-DMA: BAM %x invalid pipe: %d",
 			bam->props.phys_addr, pipe_index);
 		goto exit_err;
 	}
 	if (dev->pipes[pipe_index] != PIPE_INACTIVE) {
-		SPS_ERR("BAM-DMA: BAM %x pipe %d already active",
+		SPS_ERR("sps:BAM-DMA: BAM %x pipe %d already active",
 			bam->props.phys_addr, pipe_index);
 		goto exit_err;
 	}
@@ -756,22 +761,22 @@
 	u32 channel;
 	int result = SPS_ERROR;
 
-	SPS_DBG("sps_dma_pipe_enable.pipe %d", pipe_index);
+	SPS_DBG2("sps:sps_dma_pipe_enable.pipe %d", pipe_index);
 
 	mutex_lock(&bam_dma_lock);
 
 	dev = sps_dma_find_device((u32) bam);
 	if (dev == NULL) {
-		SPS_ERR("BAM-DMA: invalid BAM");
+		SPS_ERR("sps:BAM-DMA: invalid BAM");
 		goto exit_err;
 	}
 	if (pipe_index >= dev->num_pipes) {
-		SPS_ERR("BAM-DMA: BAM %x invalid pipe: %d",
+		SPS_ERR("sps:BAM-DMA: BAM %x invalid pipe: %d",
 			bam->props.phys_addr, pipe_index);
 		goto exit_err;
 	}
 	if (dev->pipes[pipe_index] != PIPE_ACTIVE) {
-		SPS_ERR("BAM-DMA: BAM %x pipe %d not active",
+		SPS_ERR("sps:BAM-DMA: BAM %x pipe %d not active",
 			bam->props.phys_addr, pipe_index);
 		goto exit_err;
 	}
@@ -836,7 +841,7 @@
 	if (dev->pipes[pipe_index] != PIPE_ACTIVE)
 		return SPS_ERROR;	/* Pipe is not active */
 
-	SPS_DBG("BAM-DMA: deactivate pipe %d", pipe_index);
+	SPS_DBG2("sps:BAM-DMA: deactivate pipe %d", pipe_index);
 
 	/* Mark pipe inactive */
 	dev->pipes[pipe_index] = PIPE_INACTIVE;
@@ -873,7 +878,7 @@
 
 	dev = sps_dma_find_device((u32) bam);
 	if (dev == NULL) {
-		SPS_ERR("BAM-DMA: invalid BAM");
+		SPS_ERR("sps:BAM-DMA: invalid BAM");
 		result = SPS_ERROR;
 		goto exit_err;
 	}
diff --git a/drivers/platform/msm/sps/sps_map.c b/drivers/platform/msm/sps/sps_map.c
index 16d5065..d98a8b1 100644
--- a/drivers/platform/msm/sps/sps_map.c
+++ b/drivers/platform/msm/sps/sps_map.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -50,7 +50,7 @@
 		    maps->src.periph_phy_addr == SPS_ADDR_INVALID)
 			break;
 
-	SPS_DBG("SPS driver: %d mappings", sps_maps.num_maps);
+	SPS_DBG("sps: %d mappings", sps_maps.num_maps);
 
 	return 0;
 }
@@ -96,7 +96,7 @@
 	 */
 	desc = spsi_get_mem_ptr(map->desc_base);
 	if (desc == NULL) {
-		SPS_ERR("Cannot get virt addr for I/O buffer: 0x%x",
+		SPS_ERR("sps:Cannot get virt addr for I/O buffer: 0x%x",
 			map->desc_base);
 		return SPS_ERROR;
 	}
@@ -104,7 +104,7 @@
 	if (map->data_size > 0 && map->data_base != SPS_ADDR_INVALID) {
 		data = spsi_get_mem_ptr(map->data_base);
 		if (data == NULL) {
-			SPS_ERR("Cannot get virt addr for I/O buffer: 0x%x",
+			SPS_ERR("sps:Can't get virt addr for I/O buffer: 0x%x",
 				map->data_base);
 			return SPS_ERROR;
 		}
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index 358dbd3..1b19b12 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -74,7 +74,7 @@
 		return SPS_ADDR_INVALID;
 	}
 
-	SPS_DBG("sps:sps_mem_alloc_io.phys=0x%x.virt=0x%x.size=0x%x.",
+	SPS_DBG2("sps:sps_mem_alloc_io.phys=0x%x.virt=0x%x.size=0x%x.",
 		phys_addr, virt_addr, bytes);
 
 	return phys_addr;
@@ -91,7 +91,7 @@
 	iomem_offset = phys_addr - iomem_phys;
 	virt_addr = (u32) iomem_virt + iomem_offset;
 
-	SPS_DBG("sps:sps_mem_free_io.phys=0x%x.virt=0x%x.size=0x%x.",
+	SPS_DBG2("sps:sps_mem_free_io.phys=0x%x.virt=0x%x.size=0x%x.",
 		phys_addr, virt_addr, bytes);
 
 	gen_pool_free(pool, virt_addr, bytes);
diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c
index ac1f4d1..75194e0 100644
--- a/drivers/platform/msm/sps/sps_rm.c
+++ b/drivers/platform/msm/sps/sps_rm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -70,7 +70,7 @@
 	map->refs--;
 	if (map->refs <= 0) {
 		if (map->client_src != NULL || map->client_dest != NULL)
-			SPS_ERR("Failed to allocate connection struct");
+			SPS_ERR("sps:Failed to allocate connection struct");
 
 		list_del(&map->list);
 		kfree(map);
@@ -179,14 +179,17 @@
 
 	/* Check ownership and BAM */
 	if ((cfg->mode == SPS_MODE_SRC && map->client_src != NULL) ||
-	    (cfg->mode != SPS_MODE_SRC && map->client_dest != NULL))
-		/* The end point is already connected */
+	    (cfg->mode != SPS_MODE_SRC && map->client_dest != NULL)) {
+		SPS_ERR("sps:The end point is already connected.\n");
 		return SPS_ERROR;
+	}
 
 	/* Check whether this end point is a BAM (not memory) */
 	if ((cfg->mode == SPS_MODE_SRC && map->src.bam == NULL) ||
-	    (cfg->mode != SPS_MODE_SRC && map->dest.bam == NULL))
+	    (cfg->mode != SPS_MODE_SRC && map->dest.bam == NULL)) {
+		SPS_ERR("sps:The end point is empty.\n");
 		return SPS_ERROR;
+	}
 
 	/* Record the connection assignment */
 	if (cfg->mode == SPS_MODE_SRC) {
@@ -355,7 +358,7 @@
 	/* Allocate new connection */
 	map = kzalloc(sizeof(*map), GFP_KERNEL);
 	if (map == NULL) {
-		SPS_ERR("Failed to allocate connection struct");
+		SPS_ERR("sps:Failed to allocate connection struct");
 		return NULL;
 	}
 
@@ -369,7 +372,7 @@
 	map->src.bam = sps_h2bam(map->src.dev);
 	if (map->src.bam == NULL) {
 		if (map->src.dev != SPS_DEV_HANDLE_MEM) {
-			SPS_ERR("Invalid BAM handle: 0x%x", map->src.dev);
+			SPS_ERR("sps:Invalid BAM handle: 0x%x", map->src.dev);
 			goto exit_err;
 		}
 		map->src.pipe_index = SPS_BAM_PIPE_INVALID;
@@ -377,7 +380,7 @@
 	map->dest.bam = sps_h2bam(map->dest.dev);
 	if (map->dest.bam == NULL) {
 		if (map->dest.dev != SPS_DEV_HANDLE_MEM) {
-			SPS_ERR("Invalid BAM handle: 0x%x", map->dest.dev);
+			SPS_ERR("sps:Invalid BAM handle: 0x%x", map->dest.dev);
 			goto exit_err;
 		}
 		map->dest.pipe_index = SPS_BAM_PIPE_INVALID;
@@ -386,7 +389,7 @@
 	/* Check the BAM device for the pipe */
 	if ((dir == SPS_MODE_SRC && map->src.bam == NULL) ||
 	    (dir != SPS_MODE_SRC && map->dest.bam == NULL)) {
-		SPS_ERR("Invalid BAM endpt: dir %d src 0x%x dest 0x%x",
+		SPS_ERR("sps:Invalid BAM endpt: dir %d src 0x%x dest 0x%x",
 			dir, map->src.dev, map->dest.dev);
 		goto exit_err;
 	}
@@ -409,7 +412,7 @@
 			rc = sps_dma_pipe_alloc(bam, map->src.pipe_index,
 						 SPS_MODE_SRC);
 			if (rc) {
-				SPS_ERR("Failed to alloc BAM-DMA pipe: %d",
+				SPS_ERR("sps:Failed to alloc BAM-DMA pipe: %d",
 					map->src.pipe_index);
 				goto exit_err;
 			}
@@ -436,7 +439,7 @@
 			rc = sps_dma_pipe_alloc(bam, map->dest.pipe_index,
 					       SPS_MODE_DEST);
 			if (rc) {
-				SPS_ERR("Failed to alloc BAM-DMA pipe: %d",
+				SPS_ERR("sps:Failed to alloc BAM-DMA pipe: %d",
 					map->dest.pipe_index);
 				goto exit_err;
 			}
@@ -474,12 +477,12 @@
 		map->data.size = 0;
 	}
 	if (map->desc.size > SPSRM_MAX_DESC_FIFO_SIZE) {
-		SPS_ERR("Invalid desc FIFO size: 0x%x",	map->desc.size);
+		SPS_ERR("sps:Invalid desc FIFO size: 0x%x", map->desc.size);
 		goto exit_err;
 	}
 	if (map->src.bam != NULL && map->dest.bam != NULL &&
 	    map->data.size > SPSRM_MAX_DATA_FIFO_SIZE) {
-		SPS_ERR("Invalid data FIFO size: 0x%x",	map->data.size);
+		SPS_ERR("sps:Invalid data FIFO size: 0x%x", map->data.size);
 		goto exit_err;
 	}
 
@@ -487,14 +490,14 @@
 	if (map->desc.size && map->desc.phys_base == SPS_ADDR_INVALID) {
 		map->alloc_desc_base = sps_mem_alloc_io(map->desc.size);
 		if (map->alloc_desc_base == SPS_ADDR_INVALID) {
-			SPS_ERR("I/O memory allocation failure: 0x%x",
+			SPS_ERR("sps:I/O memory allocation failure:0x%x",
 				map->desc.size);
 			goto exit_err;
 		}
 		map->desc.phys_base = map->alloc_desc_base;
 		map->desc.base = spsi_get_mem_ptr(map->desc.phys_base);
 		if (map->desc.base == NULL) {
-			SPS_ERR("Cannot get virt addr for I/O buffer: 0x%x",
+			SPS_ERR("sps:Cannot get virt addr for I/O buffer:0x%x",
 				map->desc.phys_base);
 			goto exit_err;
 		}
@@ -504,22 +507,24 @@
 	if (map->data.size && map->data.phys_base == SPS_ADDR_INVALID) {
 		map->alloc_data_base = sps_mem_alloc_io(map->data.size);
 		if (map->alloc_data_base == SPS_ADDR_INVALID) {
-			SPS_ERR("I/O memory allocation failure: 0x%x",
+			SPS_ERR("sps:I/O memory allocation failure:0x%x",
 				map->data.size);
 			goto exit_err;
 		}
 		map->data.phys_base = map->alloc_data_base;
 		map->data.base = spsi_get_mem_ptr(map->data.phys_base);
 		if (map->data.base == NULL) {
-			SPS_ERR("Cannot get virt addr for I/O buffer: 0x%x",
+			SPS_ERR("sps:Cannot get virt addr for I/O buffer:0x%x",
 				map->data.phys_base);
 			goto exit_err;
 		}
 	}
 
 	/* Attempt to assign this connection to the client */
-	if (sps_rm_assign(pipe, map))
+	if (sps_rm_assign(pipe, map)) {
+		SPS_ERR("sps:failed to assign a connection to the client.\n");
 		goto exit_err;
+	}
 
 	/* Initialization was successful */
 	success = true;
@@ -611,7 +616,7 @@
 	 */
 	if (pipe->connect.config != SPS_CONFIG_DEFAULT) {
 		if (sps_map_find(&pipe->connect)) {
-			SPS_ERR("Failed to find connection mapping");
+			SPS_ERR("sps:Failed to find connection mapping");
 			return SPS_ERROR;
 		}
 	}
@@ -619,7 +624,7 @@
 	mutex_lock(&sps_rm->lock);
 	/* Check client state */
 	if (IS_SPS_STATE_OK(pipe)) {
-		SPS_ERR("Client connection already allocated");
+		SPS_ERR("sps:Client connection already allocated");
 		goto exit_err;
 	}
 
@@ -636,7 +641,7 @@
 	if (map == NULL) {
 		map = sps_rm_create(pipe);
 		if (map == NULL) {
-			SPS_ERR("Failed to allocate connection");
+			SPS_ERR("sps:Failed to allocate connection");
 			goto exit_err;
 		}
 		list_add_tail(&map->list, &sps_rm->connections_q);
@@ -692,8 +697,12 @@
 	/* Allocate the pipe */
 	if (pipe->client_state == SPS_STATE_DISCONNECT &&
 	    state == SPS_STATE_ALLOCATE) {
-		if (sps_rm_alloc(pipe))
+		if (sps_rm_alloc(pipe)) {
+			SPS_ERR("sps:Fail to allocate resource for"
+				" BAM 0x%x pipe %d",
+				(u32) pipe->bam, pipe->pipe_index);
 			return SPS_ERROR;
+		}
 	}
 
 	/* Configure the pipe */
@@ -710,7 +719,7 @@
 		}
 		result = sps_bam_pipe_connect(pipe, &params);
 		if (result) {
-			SPS_ERR("Failed to connect BAM 0x%x pipe %d",
+			SPS_ERR("sps:Failed to connect BAM 0x%x pipe %d",
 				(u32) pipe->bam, pipe->pipe_index);
 			return SPS_ERROR;
 		}
@@ -733,7 +742,7 @@
 		|| (pipe->connect.options & SPS_O_AUTO_ENABLE))) {
 		result = sps_bam_pipe_enable(pipe->bam, pipe->pipe_index);
 		if (result) {
-			SPS_ERR("Failed to set BAM 0x%x pipe %d flow on",
+			SPS_ERR("sps:Failed to set BAM 0x%x pipe %d flow on",
 				pipe->bam->props.phys_addr,
 				pipe->pipe_index);
 			return SPS_ERROR;
@@ -746,8 +755,8 @@
 			result = sps_dma_pipe_enable(pipe->bam,
 						     pipe->pipe_index);
 			if (result) {
-				SPS_ERR("Failed to activate BAM-DMA pipe: %d",
-					pipe->pipe_index);
+				SPS_ERR("sps:Failed to activate BAM-DMA"
+					" pipe: %d", pipe->pipe_index);
 				return SPS_ERROR;
 			}
 		}
@@ -760,7 +769,7 @@
 	    (state == SPS_STATE_DISABLE	|| state == SPS_STATE_DISCONNECT)) {
 		result = sps_bam_pipe_disable(pipe->bam, pipe->pipe_index);
 		if (result) {
-			SPS_ERR("Failed to set BAM 0x%x pipe %d flow off",
+			SPS_ERR("sps:Failed to set BAM 0x%x pipe %d flow off",
 				pipe->bam->props.phys_addr,
 				pipe->pipe_index);
 			return SPS_ERROR;
@@ -782,7 +791,7 @@
 
 		result = sps_bam_pipe_disconnect(pipe->bam, pipe_index);
 		if (result) {
-			SPS_ERR("Failed to disconnect BAM 0x%x pipe %d",
+			SPS_ERR("sps:Failed to disconnect BAM 0x%x pipe %d",
 				pipe->bam->props.phys_addr,
 				pipe->pipe_index);
 			return SPS_ERROR;
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 4de70ab..4126999 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,11 +21,14 @@
 #include <linux/list.h>		/* list_head */
 #include <linux/kernel.h>	/* pr_info() */
 #include <linux/compiler.h>
+#include <linux/ratelimit.h>
 
 #include <mach/sps.h>
 
 #include "sps_map.h"
 
+#define BAM_MAX_PIPES              31
+
 /* Adjust for offset of struct sps_q_event */
 #define SPS_EVENT_INDEX(e)    ((e) - 1)
 #define SPS_ERROR -1
@@ -34,33 +37,85 @@
 #define BAM_ID(dev)       ((dev)->props.phys_addr)
 
 #ifdef CONFIG_DEBUG_FS
-extern u32 sps_debugfs_enabled;
-extern u32 detailed_debug_on;
+extern u8 debugfs_record_enabled;
+extern u8 logging_option;
+extern u8 debug_level_option;
+extern u8 print_limit_option;
+
 #define MAX_MSG_LEN 80
 #define SPS_DEBUGFS(msg, args...) do {					\
-			char buf[MAX_MSG_LEN];		\
-			snprintf(buf, MAX_MSG_LEN, msg"\n", ##args);	\
-			sps_debugfs_record(buf);	\
-		} while (0)
+		char buf[MAX_MSG_LEN];		\
+		snprintf(buf, MAX_MSG_LEN, msg"\n", ##args);	\
+		sps_debugfs_record(buf);	\
+	} while (0)
 #define SPS_ERR(msg, args...) do {					\
+		if (unlikely(print_limit_option > 2))	\
+			pr_err_ratelimited(msg, ##args);	\
+		else	\
 			pr_err(msg, ##args);	\
-			if (unlikely(sps_debugfs_enabled))	\
-				SPS_DEBUGFS(msg, ##args);	\
-		} while (0)
+		if (unlikely(debugfs_record_enabled))	\
+			SPS_DEBUGFS(msg, ##args);	\
+	} while (0)
 #define SPS_INFO(msg, args...) do {					\
+		if (unlikely(print_limit_option > 1))	\
+			pr_info_ratelimited(msg, ##args);	\
+		else	\
 			pr_info(msg, ##args);	\
-			if (unlikely(sps_debugfs_enabled))	\
-				SPS_DEBUGFS(msg, ##args);	\
-		} while (0)
+		if (unlikely(debugfs_record_enabled))	\
+			SPS_DEBUGFS(msg, ##args);	\
+	} while (0)
 #define SPS_DBG(msg, args...) do {					\
-			if (unlikely(detailed_debug_on))	\
-				pr_info(msg, ##args);	\
+		if ((unlikely(logging_option > 1))	\
+			&& (unlikely(debug_level_option > 3))) {\
+			if (unlikely(print_limit_option > 0))	\
+				pr_info_ratelimited(msg, ##args);	\
 			else	\
-				pr_debug(msg, ##args);	\
-			if (unlikely(sps_debugfs_enabled))	\
-				SPS_DEBUGFS(msg, ##args);	\
-		} while (0)
+				pr_info(msg, ##args);	\
+		} else	\
+			pr_debug(msg, ##args);	\
+		if (unlikely(debugfs_record_enabled))	\
+			SPS_DEBUGFS(msg, ##args);	\
+	} while (0)
+#define SPS_DBG1(msg, args...) do {					\
+		if ((unlikely(logging_option > 1))	\
+			&& (unlikely(debug_level_option > 2))) {\
+			if (unlikely(print_limit_option > 0))	\
+				pr_info_ratelimited(msg, ##args);	\
+			else	\
+				pr_info(msg, ##args);	\
+		} else	\
+			pr_debug(msg, ##args);	\
+		if (unlikely(debugfs_record_enabled))	\
+			SPS_DEBUGFS(msg, ##args);	\
+	} while (0)
+#define SPS_DBG2(msg, args...) do {					\
+		if ((unlikely(logging_option > 1))	\
+			&& (unlikely(debug_level_option > 1))) {\
+			if (unlikely(print_limit_option > 0))	\
+				pr_info_ratelimited(msg, ##args);	\
+			else	\
+				pr_info(msg, ##args);	\
+		} else	\
+			pr_debug(msg, ##args);	\
+		if (unlikely(debugfs_record_enabled))	\
+			SPS_DEBUGFS(msg, ##args);	\
+	} while (0)
+#define SPS_DBG3(msg, args...) do {					\
+		if ((unlikely(logging_option > 1))	\
+			&& (unlikely(debug_level_option > 0))) {\
+			if (unlikely(print_limit_option > 0))	\
+				pr_info_ratelimited(msg, ##args);	\
+			else	\
+				pr_info(msg, ##args);	\
+		} else	\
+			pr_debug(msg, ##args);	\
+		if (unlikely(debugfs_record_enabled))	\
+			SPS_DEBUGFS(msg, ##args);	\
+	} while (0)
 #else
+#define	SPS_DBG3(x...)		pr_debug(x)
+#define	SPS_DBG2(x...)		pr_debug(x)
+#define	SPS_DBG1(x...)		pr_debug(x)
 #define	SPS_DBG(x...)		pr_debug(x)
 #define	SPS_INFO(x...)		pr_info(x)
 #define	SPS_ERR(x...)		pr_err(x)
@@ -121,6 +176,18 @@
 #ifdef CONFIG_DEBUG_FS
 /* record debug info for debugfs */
 void sps_debugfs_record(const char *);
+
+/* output the content of BAM-level registers */
+void print_bam_reg(void *);
+
+/* output the content of BAM pipe registers */
+void print_bam_pipe_reg(void *, u32);
+
+/* output the content of selected BAM-level registers */
+void print_bam_selected_reg(void *);
+
+/* output the content of selected BAM pipe registers */
+void print_bam_pipe_selected_reg(void *, u32);
 #endif
 
 /**
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 22297be..420c93c 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -821,7 +821,7 @@
 			timeout = wait_for_completion_timeout(&dev->reconf, HZ);
 			dev->reconf_busy = false;
 			if (timeout) {
-				clk_disable(dev->rclk);
+				clk_disable_unprepare(dev->rclk);
 				disable_irq(dev->irq);
 			}
 		}
@@ -880,7 +880,7 @@
 {
 	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
 	enable_irq(dev->irq);
-	clk_enable(dev->rclk);
+	clk_prepare_enable(dev->rclk);
 	writel_relaxed(1, dev->base + FRM_WAKEUP);
 	/* Make sure framer wakeup write goes through before exiting function */
 	mb();
@@ -1913,7 +1913,7 @@
 		goto err_clk_get_failed;
 	}
 	clk_set_rate(dev->rclk, SLIM_ROOT_FREQ);
-	clk_enable(dev->rclk);
+	clk_prepare_enable(dev->rclk);
 
 	/* Component register initialization */
 	writel_relaxed(1, dev->base + COMP_CFG);
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 7768eeda..6d12c7e 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -25,5 +25,13 @@
 	bool "MSM QPNP"
 	help
 	  Say 'y' here to include support for the Qualcomm QPNP
+
+config MSM_QPNP_INT
+	depends on SPARSE_IRQ
+	depends on ARCH_MSMCOPPER
+	depends on OF_SPMI
+	bool "MSM QPNP INT"
+	help
+	  Say 'y' here to include support for the Qualcomm QPNP interrupt
 	  support. QPNP is a SPMI based PMIC implementation.
 endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 659e886..d59a610 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -4,3 +4,4 @@
 obj-$(CONFIG_SPMI)			+= spmi.o
 obj-$(CONFIG_SPMI_MSM_PMIC_ARB)		+= spmi-pmic-arb.o
 obj-$(CONFIG_MSM_QPNP)                  += qpnp.o
+obj-$(CONFIG_MSM_QPNP_INT)		+= qpnp-int.o
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
new file mode 100644
index 0000000..2998c01
--- /dev/null
+++ b/drivers/spmi/qpnp-int.c
@@ -0,0 +1,510 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/spmi.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
+#include <linux/printk.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <mach/qpnp-int.h>
+
+#define QPNPINT_MAX_BUSSES 1
+
+/* 16 slave_ids, 256 per_ids per slave, and 8 ints per per_id */
+#define QPNPINT_NR_IRQS (16 * 256 * 8)
+
+enum qpnpint_regs {
+	QPNPINT_REG_RT_STS		= 0x10,
+	QPNPINT_REG_SET_TYPE		= 0x11,
+	QPNPINT_REG_POLARITY_HIGH	= 0x12,
+	QPNPINT_REG_POLARITY_LOW	= 0x13,
+	QPNPINT_REG_LATCHED_CLR		= 0x14,
+	QPNPINT_REG_EN_SET		= 0x15,
+	QPNPINT_REG_EN_CLR		= 0x16,
+	QPNPINT_REG_LATCHED_STS		= 0x18,
+};
+
+struct q_perip_data {
+	uint8_t type;	    /* bitmap */
+	uint8_t pol_high;   /* bitmap */
+	uint8_t pol_low;    /* bitmap */
+	uint8_t int_en;     /* bitmap */
+	uint8_t use_count;
+};
+
+struct q_irq_data {
+	uint32_t priv_d; /* data to optimize arbiter interactions */
+	struct q_chip_data *chip_d;
+	struct q_perip_data *per_d;
+	uint8_t mask_shift;
+	uint8_t spmi_slave;
+	uint16_t spmi_offset;
+};
+
+struct q_chip_data {
+	int bus_nr;
+	struct irq_domain domain;
+	struct qpnp_local_int cb;
+	struct spmi_controller *spmi_ctrl;
+	struct radix_tree_root per_tree;
+};
+
+static struct q_chip_data chip_data[QPNPINT_MAX_BUSSES] __read_mostly;
+
+/**
+ * qpnpint_encode_hwirq - translate between qpnp_irq_spec and
+ *			  hwirq representation.
+ *
+ * slave_offset = (addr->slave * 256 * 8);
+ * perip_offset = slave_offset + (addr->perip * 8);
+ * return perip_offset + addr->irq;
+ */
+static inline int qpnpint_encode_hwirq(struct qpnp_irq_spec *spec)
+{
+	uint32_t hwirq;
+
+	if (spec->slave > 15 || spec->irq > 7)
+		return -EINVAL;
+
+	hwirq = (spec->slave << 11);
+	hwirq |= (spec->per << 3);
+	hwirq |= spec->irq;
+
+	return hwirq;
+}
+/**
+ * qpnpint_decode_hwirq - translate between hwirq and
+ *			  qpnp_irq_spec representation.
+ */
+static inline int qpnpint_decode_hwirq(unsigned long hwirq,
+					struct qpnp_irq_spec *spec)
+{
+	if (hwirq > 65535)
+		return -EINVAL;
+
+	spec->slave = (hwirq >> 11) & 0xF;
+	spec->per = (hwirq >> 3) & 0xFF;
+	spec->irq = hwirq & 0x7;
+	return 0;
+}
+
+static int qpnpint_spmi_write(struct q_irq_data *irq_d, uint8_t reg,
+			      void *buf, uint32_t len)
+{
+	struct q_chip_data *chip_d = irq_d->chip_d;
+	int rc;
+
+	if (!chip_d->spmi_ctrl)
+		return -ENODEV;
+
+	rc = spmi_ext_register_writel(chip_d->spmi_ctrl, irq_d->spmi_slave,
+				      irq_d->spmi_offset + reg, buf, len);
+	return rc;
+}
+
+static void qpnpint_irq_mask(struct irq_data *d)
+{
+	struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+	struct q_chip_data *chip_d = irq_d->chip_d;
+	struct q_perip_data *per_d = irq_d->per_d;
+	struct qpnp_irq_spec q_spec;
+	int rc;
+
+	pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+	if (chip_d->cb.mask) {
+		rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
+		if (rc)
+			pr_err("%s: decode failed on hwirq %lu\n",
+						 __func__, d->hwirq);
+		else
+			chip_d->cb.mask(chip_d->spmi_ctrl, &q_spec,
+								irq_d->priv_d);
+	}
+
+	per_d->int_en &= ~irq_d->mask_shift;
+
+	rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
+					(u8 *)&irq_d->mask_shift, 1);
+	if (rc)
+		pr_err("%s: spmi failure on irq %d\n",
+						 __func__, d->irq);
+}
+
+static void qpnpint_irq_mask_ack(struct irq_data *d)
+{
+	struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+	struct q_chip_data *chip_d = irq_d->chip_d;
+	struct q_perip_data *per_d = irq_d->per_d;
+	struct qpnp_irq_spec q_spec;
+	int rc;
+
+	pr_debug("hwirq %lu irq: %d mask: 0x%x\n", d->hwirq, d->irq,
+							irq_d->mask_shift);
+
+	if (chip_d->cb.mask) {
+		rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
+		if (rc)
+			pr_err("%s: decode failed on hwirq %lu\n",
+						 __func__, d->hwirq);
+		else
+			chip_d->cb.mask(chip_d->spmi_ctrl, &q_spec,
+								irq_d->priv_d);
+	}
+
+	per_d->int_en &= ~irq_d->mask_shift;
+
+	rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
+							&irq_d->mask_shift, 1);
+	if (rc)
+		pr_err("%s: spmi failure on irq %d\n",
+						 __func__, d->irq);
+
+	rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
+							&irq_d->mask_shift, 1);
+	if (rc)
+		pr_err("%s: spmi failure on irq %d\n",
+						 __func__, d->irq);
+}
+
+static void qpnpint_irq_unmask(struct irq_data *d)
+{
+	struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+	struct q_chip_data *chip_d = irq_d->chip_d;
+	struct q_perip_data *per_d = irq_d->per_d;
+	struct qpnp_irq_spec q_spec;
+	int rc;
+
+	pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+	if (chip_d->cb.unmask) {
+		rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
+		if (rc)
+			pr_err("%s: decode failed on hwirq %lu\n",
+						 __func__, d->hwirq);
+		else
+			chip_d->cb.unmask(chip_d->spmi_ctrl, &q_spec,
+								irq_d->priv_d);
+	}
+
+	per_d->int_en |= irq_d->mask_shift;
+	rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_SET,
+					&irq_d->mask_shift, 1);
+	if (rc)
+		pr_err("%s: spmi failure on irq %d\n",
+						 __func__, d->irq);
+}
+
+static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+	struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+	struct q_perip_data *per_d = irq_d->per_d;
+	int rc;
+	u8 buf[3];
+
+	pr_debug("hwirq %lu irq: %d flow: 0x%x\n", d->hwirq,
+							d->irq, flow_type);
+
+	per_d->pol_high &= ~irq_d->mask_shift;
+	per_d->pol_low &= ~irq_d->mask_shift;
+	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+		per_d->type |= irq_d->mask_shift; /* edge trig */
+		if (flow_type & IRQF_TRIGGER_RISING)
+			per_d->pol_high |= irq_d->mask_shift;
+		if (flow_type & IRQF_TRIGGER_FALLING)
+			per_d->pol_low |= irq_d->mask_shift;
+	} else {
+		if ((flow_type & IRQF_TRIGGER_HIGH) &&
+		    (flow_type & IRQF_TRIGGER_LOW))
+			return -EINVAL;
+		per_d->type &= ~irq_d->mask_shift; /* level trig */
+		if (flow_type & IRQF_TRIGGER_HIGH)
+			per_d->pol_high |= irq_d->mask_shift;
+		else
+			per_d->pol_high &= ~irq_d->mask_shift;
+	}
+
+	buf[0] = per_d->type;
+	buf[1] = per_d->pol_high;
+	buf[2] = per_d->pol_low;
+
+	rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_SET_TYPE, &buf, 3);
+	if (rc)
+		pr_err("%s: spmi failure on irq %d\n",
+						 __func__, d->irq);
+	return rc;
+}
+
+static struct irq_chip qpnpint_chip = {
+	.name		= "qpnp-int",
+	.irq_mask	= qpnpint_irq_mask,
+	.irq_mask_ack	= qpnpint_irq_mask_ack,
+	.irq_unmask	= qpnpint_irq_unmask,
+	.irq_set_type	= qpnpint_irq_set_type,
+};
+
+static int qpnpint_init_irq_data(struct q_chip_data *chip_d,
+				 struct q_irq_data *irq_d,
+				 unsigned long hwirq)
+{
+	struct qpnp_irq_spec q_spec;
+	int rc;
+
+	irq_d->mask_shift = 1 << (hwirq & 0x7);
+	rc = qpnpint_decode_hwirq(hwirq, &q_spec);
+	if (rc < 0)
+		return rc;
+	irq_d->spmi_slave = q_spec.slave;
+	irq_d->spmi_offset = q_spec.per << 8;
+	irq_d->per_d->use_count++;
+	irq_d->chip_d = chip_d;
+
+	if (chip_d->cb.register_priv_data)
+		rc = chip_d->cb.register_priv_data(chip_d->spmi_ctrl, &q_spec,
+							&irq_d->priv_d);
+	return rc;
+}
+
+static struct q_irq_data *qpnpint_alloc_irq_data(
+					struct q_chip_data *chip_d,
+					unsigned long hwirq)
+{
+	struct q_irq_data *irq_d;
+	struct q_perip_data *per_d;
+
+	irq_d = kzalloc(sizeof(struct q_irq_data), GFP_KERNEL);
+	if (!irq_d)
+		return ERR_PTR(-ENOMEM);
+
+	/**
+	 * The Peripheral Tree is keyed from the slave + per_id. We're
+	 * ignoring the irq bits here since this peripheral structure
+	 * should be common for all irqs on the same peripheral.
+	 */
+	per_d = radix_tree_lookup(&chip_d->per_tree, (hwirq & ~0x7));
+	if (!per_d) {
+		per_d = kzalloc(sizeof(struct q_perip_data), GFP_KERNEL);
+		if (!per_d)
+			return ERR_PTR(-ENOMEM);
+		radix_tree_insert(&chip_d->per_tree,
+				  (hwirq & ~0x7), per_d);
+	}
+	irq_d->per_d = per_d;
+
+	return irq_d;
+}
+
+static int qpnpint_register_int(uint32_t busno, unsigned long hwirq)
+{
+	int irq, rc;
+	struct irq_domain *domain;
+	struct q_irq_data *irq_d;
+
+	pr_debug("busno = %u hwirq = %lu\n", busno, hwirq);
+
+	if (hwirq < 0 || hwirq >= 32768) {
+		pr_err("%s: hwirq %lu out of qpnp interrupt bounds\n",
+							__func__, hwirq);
+		return -EINVAL;
+	}
+
+	if (busno < 0 || busno > QPNPINT_MAX_BUSSES) {
+		pr_err("%s: invalid bus number %d\n", __func__, busno);
+		return -EINVAL;
+	}
+
+	domain = &chip_data[busno].domain;
+	irq = irq_domain_to_irq(domain, hwirq);
+
+	rc = irq_alloc_desc_at(irq, numa_node_id());
+	if (rc < 0) {
+		if (rc != -EEXIST)
+			pr_err("%s: failed to alloc irq at %d with "
+					"rc %d\n", __func__, irq, rc);
+		return rc;
+	}
+	irq_d = qpnpint_alloc_irq_data(&chip_data[busno], hwirq);
+	if (IS_ERR(irq_d)) {
+		pr_err("%s: failed to alloc irq data %d with "
+					"rc %d\n", __func__, irq, rc);
+		rc = PTR_ERR(irq_d);
+		goto register_err_cleanup;
+	}
+	rc = qpnpint_init_irq_data(&chip_data[busno], irq_d, hwirq);
+	if (rc) {
+		pr_err("%s: failed to init irq data %d with "
+					"rc %d\n", __func__, irq, rc);
+		goto register_err_cleanup;
+	}
+
+	irq_domain_register_irq(domain, hwirq);
+
+	irq_set_chip_and_handler(irq,
+			&qpnpint_chip,
+			handle_level_irq);
+	irq_set_chip_data(irq, irq_d);
+#ifdef CONFIG_ARM
+	set_irq_flags(irq, IRQF_VALID);
+#else
+	irq_set_noprobe(irq);
+#endif
+	return 0;
+
+register_err_cleanup:
+	irq_free_desc(irq);
+	if (!IS_ERR(irq_d)) {
+		if (irq_d->per_d->use_count == 1)
+			kfree(irq_d->per_d);
+		else
+			irq_d->per_d->use_count--;
+		kfree(irq_d);
+	}
+	return rc;
+}
+
+static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
+				       struct device_node *controller,
+				       const u32 *intspec, unsigned int intsize,
+				       unsigned long *out_hwirq,
+				       unsigned int *out_type)
+{
+	struct qpnp_irq_spec addr;
+	struct q_chip_data *chip_d = d->priv;
+	int ret;
+
+	pr_debug("%s: intspec[0] 0x%x intspec[1] 0x%x intspec[2] 0x%x\n",
+				__func__, intspec[0], intspec[1], intspec[2]);
+
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize != 3)
+		return -EINVAL;
+
+	addr.irq = intspec[2] & 0x7;
+	addr.per = intspec[1] & 0xFF;
+	addr.slave = intspec[0] & 0xF;
+
+	ret = qpnpint_encode_hwirq(&addr);
+	if (ret < 0) {
+		pr_err("%s: invalid intspec\n", __func__);
+		return ret;
+	}
+	*out_hwirq = ret;
+	*out_type = IRQ_TYPE_NONE;
+
+	/**
+	 * Register the interrupt if it's not already registered.
+	 * This implies that mapping a qpnp interrupt allocates
+	 * resources.
+	 */
+	ret = qpnpint_register_int(chip_d->bus_nr, *out_hwirq);
+	if (ret && ret != -EEXIST) {
+		pr_err("%s: Cannot register hwirq %lu\n", __func__, *out_hwirq);
+		return ret;
+	}
+
+	return 0;
+}
+
+const struct irq_domain_ops qpnpint_irq_domain_ops = {
+	.dt_translate = qpnpint_irq_domain_dt_translate,
+};
+
+int qpnpint_register_controller(unsigned int busno,
+				struct qpnp_local_int *li_cb)
+{
+	if (busno >= QPNPINT_MAX_BUSSES)
+		return -EINVAL;
+	chip_data[busno].cb = *li_cb;
+	chip_data[busno].spmi_ctrl = spmi_busnum_to_ctrl(busno);
+	if (!chip_data[busno].spmi_ctrl)
+		return -ENOENT;
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnpint_register_controller);
+
+int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	struct irq_domain *domain;
+	unsigned long hwirq, busno;
+	int irq;
+
+	pr_debug("spec slave = %u per = %u irq = %u\n",
+					spec->slave, spec->per, spec->irq);
+
+	if (!spec || !spmi_ctrl)
+		return -EINVAL;
+
+	busno = spmi_ctrl->nr;
+	if (busno >= QPNPINT_MAX_BUSSES)
+		return -EINVAL;
+
+	hwirq = qpnpint_encode_hwirq(spec);
+	if (hwirq < 0) {
+		pr_err("%s: invalid irq spec passed\n", __func__);
+		return -EINVAL;
+	}
+
+	domain = &chip_data[busno].domain;
+	irq = irq_domain_to_irq(domain, hwirq);
+
+	generic_handle_irq(irq);
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnpint_handle_irq);
+
+/**
+ * This assumes that there's a relationship between the order of the interrupt
+ * controllers specified to of_irq_match() is the SPMI device topology. If
+ * this ever turns out to be a bad assumption, then of_irq_init_cb_t should
+ * be modified to pass a parameter to this function.
+ */
+static int qpnpint_cnt __initdata;
+
+int __init qpnpint_of_init(struct device_node *node, struct device_node *parent)
+{
+	struct q_chip_data *chip_d = &chip_data[qpnpint_cnt];
+	struct irq_domain *domain = &chip_d->domain;
+
+	INIT_RADIX_TREE(&chip_d->per_tree, GFP_ATOMIC);
+
+	domain->irq_base = irq_domain_find_free_range(0, QPNPINT_NR_IRQS);
+	domain->nr_irq = QPNPINT_NR_IRQS;
+	domain->of_node = of_node_get(node);
+	domain->priv = chip_d;
+	domain->ops = &qpnpint_irq_domain_ops;
+	irq_domain_add(domain);
+
+	pr_info("irq_base = %d\n", domain->irq_base);
+
+	qpnpint_cnt++;
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnpint_of_init);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index e5a9d40..632db71 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -78,8 +78,14 @@
 #define PMIC_ARB_MAX_PERIPHS		256
 #define PMIC_ARB_PERIPH_ID_VALID	(1 << 15)
 #define PMIC_ARB_TIMEOUT_US		100
-#define PMIC_ARB_APID_MASK		0xFF
-#define PMIC_ARB_PPID_MASK		0xFFF
+
+#define PMIC_ARB_APID_MASK				0xFF
+#define PMIC_ARB_PPID_MASK				0xFFF
+/* extract PPID and APID from interrupt map in .dts config file format */
+#define PMIC_ARB_DEV_TRE_2_PPID(MAP_COMPRS_VAL)		\
+			((MAP_COMPRS_VAL) >> (20))
+#define PMIC_ARB_DEV_TRE_2_APID(MAP_COMPRS_VAL)		\
+			((MAP_COMPRS_VAL) &  PMIC_ARB_APID_MASK)
 
 /**
  * base - base address of the PMIC Arbiter core registers.
@@ -504,7 +510,7 @@
 	int ret;
 	int map_size;
 	u32 *map_data;
-	const int map_width = 2 * sizeof(*map_data);
+	const int map_width = sizeof(*map_data);
 	const struct device_node *of_node = pdev->dev.of_node;
 
 	/* Get size of the mapping table (in bytes) */
@@ -514,8 +520,7 @@
 	}
 
 	/* Map size can't exceed the maximum number of peripherals */
-	if (map_size == 0 || map_size % map_width ||
-				map_size > map_width * PMIC_ARB_MAX_PERIPHS) {
+	if (map_size == 0 || map_size > map_width * PMIC_ARB_MAX_PERIPHS) {
 		dev_err(&pdev->dev, "map size of %d is not valid\n", map_size);
 		return -ENODEV;
 	}
@@ -538,20 +543,9 @@
 
 	/* Build the mapping table from the data */
 	for (i = 0; i < map_size/sizeof(u32);) {
-		u32 ppid = map_data[i++];
-		u32 apid = map_data[i++];
-
-		if (apid > PMIC_ARB_APID_MASK) {
-			ret = -ENODEV;
-			dev_err(&pdev->dev, "invalid APID: 0x%x\n", apid);
-			goto err;
-		}
-
-		if (ppid > PMIC_ARB_PPID_MASK) {
-			ret = -ENODEV;
-			dev_err(&pdev->dev, "invalid PPID: 0x%x\n", ppid);
-			goto err;
-		}
+		u32 map_compressed_val = map_data[i++];
+		u32 ppid = PMIC_ARB_DEV_TRE_2_PPID(map_compressed_val) ;
+		u32 apid = PMIC_ARB_DEV_TRE_2_APID(map_compressed_val) ;
 
 		if (pmic_arb->periph_id_map[apid] & PMIC_ARB_PERIPH_ID_VALID)
 			dev_warn(&pdev->dev, "duplicate APID 0x%x\n", apid);
diff --git a/drivers/staging/westbridge/astoria/gadget/cyasgadget.c b/drivers/staging/westbridge/astoria/gadget/cyasgadget.c
index be851ca..2ec93d2 100644
--- a/drivers/staging/westbridge/astoria/gadget/cyasgadget.c
+++ b/drivers/staging/westbridge/astoria/gadget/cyasgadget.c
@@ -1595,12 +1595,18 @@
 	return 0;
 }
 
+static int cyasgadget_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int cyasgadget_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops cyasgadget_ops = {
 	.get_frame		 = cyasgadget_get_frame,
 	.wakeup		 = cyasgadget_wakeup,
 	.set_selfpowered = cyasgadget_set_selfpowered,
 	.pullup		 = cyasgadget_pullup,
 	.ioctl	   = cyasgadget_ioctl,
+	.start		= cyasgadget_start,
+	.stop		= cyasgadget_stop,
 };
 
 
@@ -1883,7 +1889,7 @@
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int cyasgadget_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	cyasgadget *dev = cy_as_gadget_controller;
@@ -1938,7 +1944,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 static void cyasgadget_nuke(
 							cyasgadget_ep *an_ep
@@ -2011,7 +2016,7 @@
 	#endif
 }
 
-int usb_gadget_unregister_driver(
+static int cyasgadget_stop(
 				struct usb_gadget_driver *driver
 				)
 {
@@ -2040,7 +2045,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 static void cyas_gadget_release(
 				struct device *_dev
@@ -2071,6 +2075,7 @@
 		#endif
 		return;
 	}
+	usb_del_gadget_udc(&cy_as_dev->gadget);
 
 	if (cy_as_dev->driver) {
 		/* should have been done already by driver model core */
@@ -2131,6 +2136,19 @@
 
 	/* We are done now */
 	cy_as_gadget_controller = cy_as_dev;
+
+	/*
+	 * We actually want to use "cy_as_dev->gadget.dev.parent", but we just
+	 * don't have a parent in this driver implementation. Therefore, in
+	 * order to still allow calling to usb_add_gadget_udc, we send for now
+	 * &cy_as_dev->gadget.dev, so the parent of the udc-core will be
+	 * actually the usb_gadget it holds.
+	 */
+	retval = usb_add_gadget_udc(&cy_as_dev->gadget.dev, &cy_as_dev->gadget);
+	if (retval)
+		goto done;
+
+
 	return 0;
 
 /*
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index f49769d..04dd590 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -639,7 +639,7 @@
 	/* enable TX & RX */
 	msm_hsl_write(port, data, regmap[vid][UARTDM_CR]);
 
-	msm_hsl_write(port, RESET_STALE_INT, UARTDM_CR_ADDR);
+	msm_hsl_write(port, RESET_STALE_INT, regmap[vid][UARTDM_CR]);
 	/* turn on RX and CTS interrupts */
 	msm_hsl_port->imr = UARTDM_ISR_RXSTALE_BMSK
 		| UARTDM_ISR_DELTA_CTS_BMSK | UARTDM_ISR_RXLEV_BMSK;
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 48f1781..288b570 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -110,6 +110,8 @@
 
 source "drivers/usb/core/Kconfig"
 
+source "drivers/usb/dwc3/Kconfig"
+
 source "drivers/usb/mon/Kconfig"
 
 source "drivers/usb/wusbcore/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index ef69048..0fd0bbd 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -6,6 +6,8 @@
 
 obj-$(CONFIG_USB)		+= core/
 
+obj-$(CONFIG_USB_DWC3)		+= dwc3/
+
 obj-$(CONFIG_USB_MON)		+= mon/
 
 obj-$(CONFIG_USB_OTG_UTILS)	+= otg/
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 97c5690..5cd6bb1 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1285,10 +1285,20 @@
 	struct usb_bus *bus =
 		container_of(work, struct usb_bus, hnp_polling.work);
 	struct usb_device *udev = bus->root_hub->children[bus->otg_port - 1];
-	u8 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+	u8 *status = NULL;
 
+	/*
+	 * The OTG-B device must hand back the host role to OTG PET
+	 * within 100 msec irrespective of host_request flag.
+	 */
+	if (bus->quick_hnp) {
+		bus->quick_hnp = 0;
+		goto start_hnp;
+	}
+
+	status = kmalloc(sizeof(*status), GFP_KERNEL);
 	if (!status)
-		return;
+		goto reschedule;
 
 	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE,
@@ -1300,17 +1310,20 @@
 		goto out;
 	}
 
-	/* Spec says host must suspend the bus with in 2 sec. */
-	if (*status & (1 << HOST_REQUEST_FLAG)) {
-		do_unbind_rebind(udev, DO_UNBIND);
-		udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
-		ret = usb_suspend_both(udev, PMSG_USER_SUSPEND);
-		if (ret)
-			dev_info(&udev->dev, "suspend failed\n");
-	} else {
-		schedule_delayed_work(&bus->hnp_polling,
-			msecs_to_jiffies(THOST_REQ_POLL));
-	}
+	if (!(*status & (1 << HOST_REQUEST_FLAG)))
+		goto reschedule;
+
+start_hnp:
+	do_unbind_rebind(udev, DO_UNBIND);
+	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+	ret = usb_suspend_both(udev, PMSG_USER_SUSPEND);
+	if (ret)
+		dev_info(&udev->dev, "suspend failed\n");
+	goto out;
+
+reschedule:
+	schedule_delayed_work(&bus->hnp_polling,
+		msecs_to_jiffies(THOST_REQ_POLL));
 out:
 	kfree(status);
 }
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5442297..7347c3d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1690,7 +1690,7 @@
 
 #ifdef CONFIG_USB_OTG
 	if (udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) {
-		cancel_delayed_work(&udev->bus->hnp_polling);
+		cancel_delayed_work_sync(&udev->bus->hnp_polling);
 		udev->bus->hnp_support = 0;
 	}
 #endif
@@ -1778,6 +1778,7 @@
 	int err = 0;
 
 #ifdef	CONFIG_USB_OTG
+	bool old_otg = false;
 	/*
 	 * OTG-aware devices on OTG-capable root hubs may be able to use SRP,
 	 * to wake us after we've powered off VBUS; and HNP, switching roles
@@ -1811,7 +1812,10 @@
 				 * compliant to revision 2.0 or subsequent
 				 * versions.
 				 */
-				if (le16_to_cpu(desc->bcdOTG) >= 0x0200)
+
+				if ((le16_to_cpu(desc->bLength) ==
+						USB_DT_OTG_SIZE) &&
+					le16_to_cpu(desc->bcdOTG) >= 0x0200)
 					goto out;
 
 				/* Legacy B-device i.e compliant to spec
@@ -1819,6 +1823,7 @@
 				 * a_hnp_support or b_hnp_enable before
 				 * selecting configuration.
 				 */
+				old_otg = true;
 
 				/* enable HNP before suspend, it's simpler */
 				err = usb_control_msg(udev,
@@ -1839,6 +1844,14 @@
 		}
 	}
 out:
+	if ((udev->quirks & USB_QUIRK_OTG_PET)) {
+		if (le16_to_cpu(udev->descriptor.bcdDevice) &
+			OTG_TTST_VBUS_OFF)
+			udev->bus->otg_vbus_off = 1;
+		if (udev->bus->is_b_host || old_otg)
+			udev->bus->quick_hnp = 1;
+	}
+
 	if (!is_targeted(udev)) {
 
 		otg_send_event(OTG_EVENT_DEV_NOT_SUPPORTED);
@@ -1859,8 +1872,12 @@
 		 * re-armed if device returns STALL. B-Host also perform
 		 * HNP polling.
 		 */
-		schedule_delayed_work(&udev->bus->hnp_polling,
-			msecs_to_jiffies(THOST_REQ_POLL));
+		if (udev->bus->quick_hnp)
+			schedule_delayed_work(&udev->bus->hnp_polling,
+				msecs_to_jiffies(OTG_TTST_SUSP));
+		else
+			schedule_delayed_work(&udev->bus->hnp_polling,
+				msecs_to_jiffies(THOST_REQ_POLL));
 	}
 #endif
 	return err;
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
index cec4167..7bb6747 100644
--- a/drivers/usb/core/otg_whitelist.h
+++ b/drivers/usb/core/otg_whitelist.h
@@ -59,6 +59,11 @@
 	     le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
 		return 0;
 
+	/* OTG PET device is always targeted (see OTG 2.0 ECN 6.4.2) */
+	if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+	     le16_to_cpu(dev->descriptor.idProduct) == 0x0200))
+		return 1;
+
 	/* NOTE: can't use usb_match_id() since interface caches
 	 * aren't set up yet. this is cut/paste from that code.
 	 */
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 81ce6a8..d5a29b3 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -96,6 +96,9 @@
 	/* INTEL VALUE SSD */
 	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Protocol and OTG Electrical Test Device */
+	{ USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_OTG_PET },
+
 	{ }  /* terminating entry must be last */
 };
 
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
new file mode 100644
index 0000000..3c1d67d
--- /dev/null
+++ b/drivers/usb/dwc3/Kconfig
@@ -0,0 +1,25 @@
+config USB_DWC3
+	tristate "DesignWare USB3 DRD Core Support"
+	depends on (USB || USB_GADGET)
+	select USB_OTG_UTILS
+	help
+	  Say Y or M here if your system has a Dual Role SuperSpeed
+	  USB controller based on the DesignWare USB3 IP Core.
+
+	  If you choose to build this driver is a dynamically linked
+	  module, the module will be called dwc3.ko.
+
+if USB_DWC3
+
+config USB_DWC3_DEBUG
+	bool "Enable Debugging Messages"
+	help
+	  Say Y here to enable debugging messages on DWC3 Driver.
+
+config USB_DWC3_VERBOSE
+	bool "Enable Verbose Debugging Messages"
+	depends on USB_DWC3_DEBUG
+	help
+	  Say Y here to enable verbose debugging messages on DWC3 Driver.
+
+endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
new file mode 100644
index 0000000..593d1dbc
--- /dev/null
+++ b/drivers/usb/dwc3/Makefile
@@ -0,0 +1,36 @@
+ccflags-$(CONFIG_USB_DWC3_DEBUG)	:= -DDEBUG
+ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG
+
+obj-$(CONFIG_USB_DWC3)			+= dwc3.o
+
+dwc3-y					:= core.o
+
+ifneq ($(CONFIG_USB_GADGET_DWC3),)
+	dwc3-y				+= gadget.o ep0.o
+endif
+
+ifneq ($(CONFIG_DEBUG_FS),)
+	dwc3-y				+= debugfs.o
+endif
+
+##
+# Platform-specific glue layers go here
+#
+# NOTICE: Make sure your glue layer doesn't depend on anything
+# which is arch-specific and that it compiles on all situations.
+#
+# We want to keep this requirement in order to be able to compile
+# the entire driver (with all its glue layers) on several architectures
+# and make sure it compiles fine. This will also help with allmodconfig
+# and allyesconfig builds.
+#
+# The only exception is the PCI glue layer, but that's only because
+# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
+##
+
+obj-$(CONFIG_USB_DWC3)		+= dwc3-omap.o
+
+ifneq ($(CONFIG_PCI),)
+	obj-$(CONFIG_USB_DWC3)		+= dwc3-pci.o
+endif
+
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
new file mode 100644
index 0000000..717ebc9
--- /dev/null
+++ b/drivers/usb/dwc3/core.c
@@ -0,0 +1,484 @@
+/**
+ * core.c - DesignWare USB3 DRD Controller Core file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/module.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#include "debug.h"
+
+/**
+ * dwc3_core_soft_reset - Issues core soft reset and PHY reset
+ * @dwc: pointer to our context structure
+ */
+static void dwc3_core_soft_reset(struct dwc3 *dwc)
+{
+	u32		reg;
+
+	/* Before Resetting PHY, put Core in Reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg |= DWC3_GCTL_CORESOFTRESET;
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	/* Assert USB3 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+	/* Assert USB2 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+	mdelay(100);
+
+	/* Clear USB3 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+	/* Clear USB2 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+	/* After PHYs are stable we can take Core out of reset state */
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~DWC3_GCTL_CORESOFTRESET;
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+/**
+ * dwc3_free_one_event_buffer - Frees one event buffer
+ * @dwc: Pointer to our controller context structure
+ * @evt: Pointer to event buffer to be freed
+ */
+static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
+		struct dwc3_event_buffer *evt)
+{
+	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
+	kfree(evt);
+}
+
+/**
+ * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
+ * @dwc: Pointer to our controller context structure
+ * @length: size of the event buffer
+ *
+ * Returns a pointer to the allocated event buffer structure on succes
+ * otherwise ERR_PTR(errno).
+ */
+static struct dwc3_event_buffer *__devinit
+dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
+{
+	struct dwc3_event_buffer	*evt;
+
+	evt = kzalloc(sizeof(*evt), GFP_KERNEL);
+	if (!evt)
+		return ERR_PTR(-ENOMEM);
+
+	evt->dwc	= dwc;
+	evt->length	= length;
+	evt->buf	= dma_alloc_coherent(dwc->dev, length,
+			&evt->dma, GFP_KERNEL);
+	if (!evt->buf) {
+		kfree(evt);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return evt;
+}
+
+/**
+ * dwc3_free_event_buffers - frees all allocated event buffers
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_free_event_buffers(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	int i;
+
+	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+		evt = dwc->ev_buffs[i];
+		if (evt) {
+			dwc3_free_one_event_buffer(dwc, evt);
+			dwc->ev_buffs[i] = NULL;
+		}
+	}
+}
+
+/**
+ * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
+ * @dwc: Pointer to out controller context structure
+ * @num: number of event buffers to allocate
+ * @length: size of event buffer
+ *
+ * Returns 0 on success otherwise negative errno. In error the case, dwc
+ * may contain some buffers allocated but not all which were requested.
+ */
+static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
+		unsigned length)
+{
+	int			i;
+
+	for (i = 0; i < num; i++) {
+		struct dwc3_event_buffer	*evt;
+
+		evt = dwc3_alloc_one_event_buffer(dwc, length);
+		if (IS_ERR(evt)) {
+			dev_err(dwc->dev, "can't allocate event buffer\n");
+			return PTR_ERR(evt);
+		}
+		dwc->ev_buffs[i] = evt;
+	}
+
+	return 0;
+}
+
+/**
+ * dwc3_event_buffers_setup - setup our allocated event buffers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	int				n;
+
+	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+		evt = dwc->ev_buffs[n];
+		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
+				evt->buf, (unsigned long long) evt->dma,
+				evt->length);
+
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
+				lower_32_bits(evt->dma));
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
+				upper_32_bits(evt->dma));
+		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
+				evt->length & 0xffff);
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+	}
+
+	return 0;
+}
+
+static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	int				n;
+
+	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+		evt = dwc->ev_buffs[n];
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
+		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+	}
+}
+
+static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
+{
+	struct dwc3_hwparams	*parms = &dwc->hwparams;
+
+	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
+	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
+	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
+	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
+	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
+	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
+	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
+	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
+	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
+}
+
+/**
+ * dwc3_core_init - Low-level initialization of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_core_init(struct dwc3 *dwc)
+{
+	unsigned long		timeout;
+	u32			reg;
+	int			ret;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+	/* This should read as U3 followed by revision number */
+	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
+		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+		ret = -ENODEV;
+		goto err0;
+	}
+	dwc->revision = reg & DWC3_GSNPSREV_MASK;
+
+	dwc3_core_soft_reset(dwc);
+
+	/* issue device SoftReset too */
+	timeout = jiffies + msecs_to_jiffies(500);
+	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		if (!(reg & DWC3_DCTL_CSFTRST))
+			break;
+
+		if (time_after(jiffies, timeout)) {
+			dev_err(dwc->dev, "Reset Timed Out\n");
+			ret = -ETIMEDOUT;
+			goto err0;
+		}
+
+		cpu_relax();
+	} while (true);
+
+	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
+			DWC3_EVENT_BUFFERS_SIZE);
+	if (ret) {
+		dev_err(dwc->dev, "failed to allocate event buffers\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	ret = dwc3_event_buffers_setup(dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to setup event buffers\n");
+		goto err1;
+	}
+
+	dwc3_cache_hwparams(dwc);
+
+	return 0;
+
+err1:
+	dwc3_free_event_buffers(dwc);
+
+err0:
+	return ret;
+}
+
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+	dwc3_event_buffers_cleanup(dwc);
+	dwc3_free_event_buffers(dwc);
+}
+
+#define DWC3_ALIGN_MASK		(16 - 1)
+
+static int __devinit dwc3_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	struct resource		*res;
+	struct dwc3		*dwc;
+	void __iomem		*regs;
+	unsigned int		features = id->driver_data;
+	int			ret = -ENOMEM;
+	int			irq;
+	void			*mem;
+
+	mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+	if (!mem) {
+		dev_err(&pdev->dev, "not enough memory\n");
+		goto err0;
+	}
+	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
+	dwc->mem = mem;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "missing resource\n");
+		goto err1;
+	}
+
+	res = request_mem_region(res->start, resource_size(res),
+			dev_name(&pdev->dev));
+	if (!res) {
+		dev_err(&pdev->dev, "can't request mem region\n");
+		goto err1;
+	}
+
+	regs = ioremap(res->start, resource_size(res));
+	if (!regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		goto err2;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "missing IRQ\n");
+		goto err3;
+	}
+
+	spin_lock_init(&dwc->lock);
+	platform_set_drvdata(pdev, dwc);
+
+	dwc->regs	= regs;
+	dwc->regs_size	= resource_size(res);
+	dwc->dev	= &pdev->dev;
+	dwc->irq	= irq;
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	pm_runtime_forbid(&pdev->dev);
+
+	ret = dwc3_core_init(dwc);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize core\n");
+		goto err3;
+	}
+
+	if (features & DWC3_HAS_PERIPHERAL) {
+		ret = dwc3_gadget_init(dwc);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to initialized gadget\n");
+			goto err4;
+		}
+	}
+
+	ret = dwc3_debugfs_init(dwc);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize debugfs\n");
+		goto err5;
+	}
+
+	pm_runtime_allow(&pdev->dev);
+
+	return 0;
+
+err5:
+	if (features & DWC3_HAS_PERIPHERAL)
+		dwc3_gadget_exit(dwc);
+
+err4:
+	dwc3_core_exit(dwc);
+
+err3:
+	iounmap(regs);
+
+err2:
+	release_mem_region(res->start, resource_size(res));
+
+err1:
+	kfree(dwc->mem);
+
+err0:
+	return ret;
+}
+
+static int __devexit dwc3_remove(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	struct dwc3	*dwc = platform_get_drvdata(pdev);
+	struct resource	*res;
+	unsigned int	features = id->driver_data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	dwc3_debugfs_exit(dwc);
+
+	if (features & DWC3_HAS_PERIPHERAL)
+		dwc3_gadget_exit(dwc);
+
+	dwc3_core_exit(dwc);
+	release_mem_region(res->start, resource_size(res));
+	iounmap(dwc->regs);
+	kfree(dwc->mem);
+
+	return 0;
+}
+
+static const struct platform_device_id dwc3_id_table[] __devinitconst = {
+	{
+		.name	= "dwc3-omap",
+		.driver_data = (DWC3_HAS_PERIPHERAL
+			| DWC3_HAS_XHCI
+			| DWC3_HAS_OTG),
+	},
+	{
+		.name	= "dwc3-pci",
+		.driver_data = DWC3_HAS_PERIPHERAL,
+	},
+	{  },	/* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, dwc3_id_table);
+
+static struct platform_driver dwc3_driver = {
+	.probe		= dwc3_probe,
+	.remove		= __devexit_p(dwc3_remove),
+	.driver		= {
+		.name	= "dwc3",
+	},
+	.id_table	= dwc3_id_table,
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
+
+static int __devinit dwc3_init(void)
+{
+	return platform_driver_register(&dwc3_driver);
+}
+module_init(dwc3_init);
+
+static void __exit dwc3_exit(void)
+{
+	platform_driver_unregister(&dwc3_driver);
+}
+module_exit(dwc3_exit);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
new file mode 100644
index 0000000..29a8e16
--- /dev/null
+++ b/drivers/usb/dwc3/core.h
@@ -0,0 +1,768 @@
+/**
+ * core.h - DesignWare USB3 DRD Core Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_CORE_H
+#define __DRIVERS_USB_DWC3_CORE_H
+
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Global constants */
+#define DWC3_ENDPOINTS_NUM	32
+
+#define DWC3_EVENT_BUFFERS_NUM	2
+#define DWC3_EVENT_BUFFERS_SIZE	PAGE_SIZE
+#define DWC3_EVENT_TYPE_MASK	0xfe
+
+#define DWC3_EVENT_TYPE_DEV	0
+#define DWC3_EVENT_TYPE_CARKIT	3
+#define DWC3_EVENT_TYPE_I2C	4
+
+#define DWC3_DEVICE_EVENT_DISCONNECT		0
+#define DWC3_DEVICE_EVENT_RESET			1
+#define DWC3_DEVICE_EVENT_CONNECT_DONE		2
+#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE	3
+#define DWC3_DEVICE_EVENT_WAKEUP		4
+#define DWC3_DEVICE_EVENT_EOPF			6
+#define DWC3_DEVICE_EVENT_SOF			7
+#define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
+#define DWC3_DEVICE_EVENT_CMD_CMPL		10
+#define DWC3_DEVICE_EVENT_OVERFLOW		11
+
+#define DWC3_GEVNTCOUNT_MASK	0xfffc
+#define DWC3_GSNPSID_MASK	0xffff0000
+#define DWC3_GSNPSREV_MASK	0xffff
+
+/* Global Registers */
+#define DWC3_GSBUSCFG0		0xc100
+#define DWC3_GSBUSCFG1		0xc104
+#define DWC3_GTXTHRCFG		0xc108
+#define DWC3_GRXTHRCFG		0xc10c
+#define DWC3_GCTL		0xc110
+#define DWC3_GEVTEN		0xc114
+#define DWC3_GSTS		0xc118
+#define DWC3_GSNPSID		0xc120
+#define DWC3_GGPIO		0xc124
+#define DWC3_GUID		0xc128
+#define DWC3_GUCTL		0xc12c
+#define DWC3_GBUSERRADDR0	0xc130
+#define DWC3_GBUSERRADDR1	0xc134
+#define DWC3_GPRTBIMAP0		0xc138
+#define DWC3_GPRTBIMAP1		0xc13c
+#define DWC3_GHWPARAMS0		0xc140
+#define DWC3_GHWPARAMS1		0xc144
+#define DWC3_GHWPARAMS2		0xc148
+#define DWC3_GHWPARAMS3		0xc14c
+#define DWC3_GHWPARAMS4		0xc150
+#define DWC3_GHWPARAMS5		0xc154
+#define DWC3_GHWPARAMS6		0xc158
+#define DWC3_GHWPARAMS7		0xc15c
+#define DWC3_GDBGFIFOSPACE	0xc160
+#define DWC3_GDBGLTSSM		0xc164
+#define DWC3_GPRTBIMAP_HS0	0xc180
+#define DWC3_GPRTBIMAP_HS1	0xc184
+#define DWC3_GPRTBIMAP_FS0	0xc188
+#define DWC3_GPRTBIMAP_FS1	0xc18c
+
+#define DWC3_GUSB2PHYCFG(n)	(0xc200 + (n * 0x04))
+#define DWC3_GUSB2I2CCTL(n)	(0xc240 + (n * 0x04))
+
+#define DWC3_GUSB2PHYACC(n)	(0xc280 + (n * 0x04))
+
+#define DWC3_GUSB3PIPECTL(n)	(0xc2c0 + (n * 0x04))
+
+#define DWC3_GTXFIFOSIZ(n)	(0xc300 + (n * 0x04))
+#define DWC3_GRXFIFOSIZ(n)	(0xc380 + (n * 0x04))
+
+#define DWC3_GEVNTADRLO(n)	(0xc400 + (n * 0x10))
+#define DWC3_GEVNTADRHI(n)	(0xc404 + (n * 0x10))
+#define DWC3_GEVNTSIZ(n)	(0xc408 + (n * 0x10))
+#define DWC3_GEVNTCOUNT(n)	(0xc40c + (n * 0x10))
+
+#define DWC3_GHWPARAMS8		0xc600
+
+/* Device Registers */
+#define DWC3_DCFG		0xc700
+#define DWC3_DCTL		0xc704
+#define DWC3_DEVTEN		0xc708
+#define DWC3_DSTS		0xc70c
+#define DWC3_DGCMDPAR		0xc710
+#define DWC3_DGCMD		0xc714
+#define DWC3_DALEPENA		0xc720
+#define DWC3_DEPCMDPAR2(n)	(0xc800 + (n * 0x10))
+#define DWC3_DEPCMDPAR1(n)	(0xc804 + (n * 0x10))
+#define DWC3_DEPCMDPAR0(n)	(0xc808 + (n * 0x10))
+#define DWC3_DEPCMD(n)		(0xc80c + (n * 0x10))
+
+/* OTG Registers */
+#define DWC3_OCFG		0xcc00
+#define DWC3_OCTL		0xcc04
+#define DWC3_OEVTEN		0xcc08
+#define DWC3_OSTS		0xcc0C
+
+/* Bit fields */
+
+/* Global Configuration Register */
+#define DWC3_GCTL_PWRDNSCALE(n)	(n << 19)
+#define DWC3_GCTL_U2RSTECN	(1 << 16)
+#define DWC3_GCTL_RAMCLKSEL(x)	((x & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_CLK_BUS	(0)
+#define DWC3_GCTL_CLK_PIPE	(1)
+#define DWC3_GCTL_CLK_PIPEHALF	(2)
+#define DWC3_GCTL_CLK_MASK	(3)
+
+#define DWC3_GCTL_PRTCAPDIR(n)	(n << 12)
+#define DWC3_GCTL_PRTCAP_HOST	1
+#define DWC3_GCTL_PRTCAP_DEVICE	2
+#define DWC3_GCTL_PRTCAP_OTG	3
+
+#define DWC3_GCTL_CORESOFTRESET	(1 << 11)
+#define DWC3_GCTL_SCALEDOWN(n)	(n << 4)
+#define DWC3_GCTL_DISSCRAMBLE	(1 << 3)
+#define DWC3_GCTL_DSBLCLKGTNG	(1 << 0)
+
+/* Global USB2 PHY Configuration Register */
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB2PHYCFG_SUSPHY	(1 << 6)
+
+/* Global USB3 PIPE Control Register */
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+
+/* Global HWPARAMS1 Register */
+#define DWC3_GHWPARAMS1_EN_PWROPT(n)	((n & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
+#define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
+
+/* Device Configuration Register */
+#define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
+#define DWC3_DCFG_DEVADDR_MASK	DWC3_DCFG_DEVADDR(0x7f)
+
+#define DWC3_DCFG_SPEED_MASK	(7 << 0)
+#define DWC3_DCFG_SUPERSPEED	(4 << 0)
+#define DWC3_DCFG_HIGHSPEED	(0 << 0)
+#define DWC3_DCFG_FULLSPEED2	(1 << 0)
+#define DWC3_DCFG_LOWSPEED	(2 << 0)
+#define DWC3_DCFG_FULLSPEED1	(3 << 0)
+
+/* Device Control Register */
+#define DWC3_DCTL_RUN_STOP	(1 << 31)
+#define DWC3_DCTL_CSFTRST	(1 << 30)
+#define DWC3_DCTL_LSFTRST	(1 << 29)
+
+#define DWC3_DCTL_HIRD_THRES_MASK	(0x1f << 24)
+#define DWC3_DCTL_HIRD_THRES(n)	(((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24)
+
+#define DWC3_DCTL_APPL1RES	(1 << 23)
+
+#define DWC3_DCTL_INITU2ENA	(1 << 12)
+#define DWC3_DCTL_ACCEPTU2ENA	(1 << 11)
+#define DWC3_DCTL_INITU1ENA	(1 << 10)
+#define DWC3_DCTL_ACCEPTU1ENA	(1 << 9)
+#define DWC3_DCTL_TSTCTRL_MASK	(0xf << 1)
+
+#define DWC3_DCTL_ULSTCHNGREQ_MASK	(0x0f << 5)
+#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
+
+#define DWC3_DCTL_ULSTCHNG_NO_ACTION	(DWC3_DCTL_ULSTCHNGREQ(0))
+#define DWC3_DCTL_ULSTCHNG_SS_DISABLED	(DWC3_DCTL_ULSTCHNGREQ(4))
+#define DWC3_DCTL_ULSTCHNG_RX_DETECT	(DWC3_DCTL_ULSTCHNGREQ(5))
+#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE	(DWC3_DCTL_ULSTCHNGREQ(6))
+#define DWC3_DCTL_ULSTCHNG_RECOVERY	(DWC3_DCTL_ULSTCHNGREQ(8))
+#define DWC3_DCTL_ULSTCHNG_COMPLIANCE	(DWC3_DCTL_ULSTCHNGREQ(10))
+#define DWC3_DCTL_ULSTCHNG_LOOPBACK	(DWC3_DCTL_ULSTCHNGREQ(11))
+
+/* Device Event Enable Register */
+#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN	(1 << 12)
+#define DWC3_DEVTEN_EVNTOVERFLOWEN	(1 << 11)
+#define DWC3_DEVTEN_CMDCMPLTEN		(1 << 10)
+#define DWC3_DEVTEN_ERRTICERREN		(1 << 9)
+#define DWC3_DEVTEN_SOFEN		(1 << 7)
+#define DWC3_DEVTEN_EOPFEN		(1 << 6)
+#define DWC3_DEVTEN_WKUPEVTEN		(1 << 4)
+#define DWC3_DEVTEN_ULSTCNGEN		(1 << 3)
+#define DWC3_DEVTEN_CONNECTDONEEN	(1 << 2)
+#define DWC3_DEVTEN_USBRSTEN		(1 << 1)
+#define DWC3_DEVTEN_DISCONNEVTEN	(1 << 0)
+
+/* Device Status Register */
+#define DWC3_DSTS_PWRUPREQ		(1 << 24)
+#define DWC3_DSTS_COREIDLE		(1 << 23)
+#define DWC3_DSTS_DEVCTRLHLT		(1 << 22)
+
+#define DWC3_DSTS_USBLNKST_MASK		(0x0f << 18)
+#define DWC3_DSTS_USBLNKST(n)		(((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
+
+#define DWC3_DSTS_RXFIFOEMPTY		(1 << 17)
+
+#define DWC3_DSTS_SOFFN_MASK		(0x3ff << 3)
+#define DWC3_DSTS_SOFFN(n)		(((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
+
+#define DWC3_DSTS_CONNECTSPD		(7 << 0)
+
+#define DWC3_DSTS_SUPERSPEED		(4 << 0)
+#define DWC3_DSTS_HIGHSPEED		(0 << 0)
+#define DWC3_DSTS_FULLSPEED2		(1 << 0)
+#define DWC3_DSTS_LOWSPEED		(2 << 0)
+#define DWC3_DSTS_FULLSPEED1		(3 << 0)
+
+/* Device Generic Command Register */
+#define DWC3_DGCMD_SET_LMP		0x01
+#define DWC3_DGCMD_SET_PERIODIC_PAR	0x02
+#define DWC3_DGCMD_XMIT_FUNCTION	0x03
+#define DWC3_DGCMD_SELECTED_FIFO_FLUSH	0x09
+#define DWC3_DGCMD_ALL_FIFO_FLUSH	0x0a
+#define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
+#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK	0x10
+
+/* Device Endpoint Command Register */
+#define DWC3_DEPCMD_PARAM_SHIFT		16
+#define DWC3_DEPCMD_PARAM(x)		(x << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x)	((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_STATUS_MASK		(0x0f << 12)
+#define DWC3_DEPCMD_STATUS(x)		((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_HIPRI_FORCERM	(1 << 11)
+#define DWC3_DEPCMD_CMDACT		(1 << 10)
+#define DWC3_DEPCMD_CMDIOC		(1 << 8)
+
+#define DWC3_DEPCMD_DEPSTARTCFG		(0x09 << 0)
+#define DWC3_DEPCMD_ENDTRANSFER		(0x08 << 0)
+#define DWC3_DEPCMD_UPDATETRANSFER	(0x07 << 0)
+#define DWC3_DEPCMD_STARTTRANSFER	(0x06 << 0)
+#define DWC3_DEPCMD_CLEARSTALL		(0x05 << 0)
+#define DWC3_DEPCMD_SETSTALL		(0x04 << 0)
+#define DWC3_DEPCMD_GETSEQNUMBER	(0x03 << 0)
+#define DWC3_DEPCMD_SETTRANSFRESOURCE	(0x02 << 0)
+#define DWC3_DEPCMD_SETEPCONFIG		(0x01 << 0)
+
+/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
+#define DWC3_DALEPENA_EP(n)		(1 << n)
+
+#define DWC3_DEPCMD_TYPE_CONTROL	0
+#define DWC3_DEPCMD_TYPE_ISOC		1
+#define DWC3_DEPCMD_TYPE_BULK		2
+#define DWC3_DEPCMD_TYPE_INTR		3
+
+/* Structures */
+
+struct dwc3_trb_hw;
+
+/**
+ * struct dwc3_event_buffer - Software event buffer representation
+ * @list: a list of event buffers
+ * @buf: _THE_ buffer
+ * @length: size of this buffer
+ * @dma: dma_addr_t
+ * @dwc: pointer to DWC controller
+ */
+struct dwc3_event_buffer {
+	void			*buf;
+	unsigned		length;
+	unsigned int		lpos;
+
+	dma_addr_t		dma;
+
+	struct dwc3		*dwc;
+};
+
+#define DWC3_EP_FLAG_STALLED	(1 << 0)
+#define DWC3_EP_FLAG_WEDGED	(1 << 1)
+
+#define DWC3_EP_DIRECTION_TX	true
+#define DWC3_EP_DIRECTION_RX	false
+
+#define DWC3_TRB_NUM		32
+#define DWC3_TRB_MASK		(DWC3_TRB_NUM - 1)
+
+/**
+ * struct dwc3_ep - device side endpoint representation
+ * @endpoint: usb endpoint
+ * @request_list: list of requests for this endpoint
+ * @req_queued: list of requests on this ep which have TRBs setup
+ * @trb_pool: array of transaction buffers
+ * @trb_pool_dma: dma address of @trb_pool
+ * @free_slot: next slot which is going to be used
+ * @busy_slot: first slot which is owned by HW
+ * @desc: usb_endpoint_descriptor pointer
+ * @dwc: pointer to DWC controller
+ * @flags: endpoint flags (wedged, stalled, ...)
+ * @current_trb: index of current used trb
+ * @number: endpoint number (1 - 15)
+ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
+ * @res_trans_idx: Resource transfer index
+ * @interval: the intervall on which the ISOC transfer is started
+ * @name: a human readable name e.g. ep1out-bulk
+ * @direction: true for TX, false for RX
+ * @stream_capable: true when streams are enabled
+ */
+struct dwc3_ep {
+	struct usb_ep		endpoint;
+	struct list_head	request_list;
+	struct list_head	req_queued;
+
+	struct dwc3_trb_hw	*trb_pool;
+	dma_addr_t		trb_pool_dma;
+	u32			free_slot;
+	u32			busy_slot;
+	const struct usb_endpoint_descriptor *desc;
+	struct dwc3		*dwc;
+
+	unsigned		flags;
+#define DWC3_EP_ENABLED		(1 << 0)
+#define DWC3_EP_STALL		(1 << 1)
+#define DWC3_EP_WEDGE		(1 << 2)
+#define DWC3_EP_BUSY		(1 << 4)
+#define DWC3_EP_PENDING_REQUEST	(1 << 5)
+
+	/* This last one is specific to EP0 */
+#define DWC3_EP0_DIR_IN		(1 << 31)
+
+	unsigned		current_trb;
+
+	u8			number;
+	u8			type;
+	u8			res_trans_idx;
+	u32			interval;
+
+	char			name[20];
+
+	unsigned		direction:1;
+	unsigned		stream_capable:1;
+};
+
+enum dwc3_phy {
+	DWC3_PHY_UNKNOWN = 0,
+	DWC3_PHY_USB3,
+	DWC3_PHY_USB2,
+};
+
+enum dwc3_ep0_next {
+	DWC3_EP0_UNKNOWN = 0,
+	DWC3_EP0_COMPLETE,
+	DWC3_EP0_NRDY_SETUP,
+	DWC3_EP0_NRDY_DATA,
+	DWC3_EP0_NRDY_STATUS,
+};
+
+enum dwc3_ep0_state {
+	EP0_UNCONNECTED		= 0,
+	EP0_SETUP_PHASE,
+	EP0_DATA_PHASE,
+	EP0_STATUS_PHASE,
+};
+
+enum dwc3_link_state {
+	/* In SuperSpeed */
+	DWC3_LINK_STATE_U0		= 0x00, /* in HS, means ON */
+	DWC3_LINK_STATE_U1		= 0x01,
+	DWC3_LINK_STATE_U2		= 0x02, /* in HS, means SLEEP */
+	DWC3_LINK_STATE_U3		= 0x03, /* in HS, means SUSPEND */
+	DWC3_LINK_STATE_SS_DIS		= 0x04,
+	DWC3_LINK_STATE_RX_DET		= 0x05, /* in HS, means Early Suspend */
+	DWC3_LINK_STATE_SS_INACT	= 0x06,
+	DWC3_LINK_STATE_POLL		= 0x07,
+	DWC3_LINK_STATE_RECOV		= 0x08,
+	DWC3_LINK_STATE_HRESET		= 0x09,
+	DWC3_LINK_STATE_CMPLY		= 0x0a,
+	DWC3_LINK_STATE_LPBK		= 0x0b,
+	DWC3_LINK_STATE_MASK		= 0x0f,
+};
+
+enum dwc3_device_state {
+	DWC3_DEFAULT_STATE,
+	DWC3_ADDRESS_STATE,
+	DWC3_CONFIGURED_STATE,
+};
+
+/**
+ * struct dwc3_trb - transfer request block
+ * @bpl: lower 32bit of the buffer
+ * @bph: higher 32bit of the buffer
+ * @length: buffer size (up to 16mb - 1)
+ * @pcm1: packet count m1
+ * @trbsts: trb status
+ *	0 = ok
+ *	1 = missed isoc
+ *	2 = setup pending
+ * @hwo: hardware owner of descriptor
+ * @lst: last trb
+ * @chn: chain buffers
+ * @csp: continue on short packets (only supported on isoc eps)
+ * @trbctl: trb control
+ *	1 = normal
+ *	2 = control-setup
+ *	3 = control-status-2
+ *	4 = control-status-3
+ *	5 = control-data (first trb of data stage)
+ *	6 = isochronous-first (first trb of service interval)
+ *	7 = isochronous
+ *	8 = link trb
+ *	others = reserved
+ * @isp_imi: interrupt on short packet / interrupt on missed isoc
+ * @ioc: interrupt on complete
+ * @sid_sofn: Stream ID / SOF Number
+ */
+struct dwc3_trb {
+	u64             bplh;
+
+	union {
+		struct {
+			u32             length:24;
+			u32             pcm1:2;
+			u32             reserved27_26:2;
+			u32             trbsts:4;
+#define DWC3_TRB_STS_OKAY                       0
+#define DWC3_TRB_STS_MISSED_ISOC                1
+#define DWC3_TRB_STS_SETUP_PENDING              2
+		};
+		u32 len_pcm;
+	};
+
+	union {
+		struct {
+			u32             hwo:1;
+			u32             lst:1;
+			u32             chn:1;
+			u32             csp:1;
+			u32             trbctl:6;
+			u32             isp_imi:1;
+			u32             ioc:1;
+			u32             reserved13_12:2;
+			u32             sid_sofn:16;
+			u32             reserved31_30:2;
+		};
+		u32 control;
+	};
+} __packed;
+
+/**
+ * struct dwc3_trb_hw - transfer request block (hw format)
+ * @bpl: DW0-3
+ * @bph: DW4-7
+ * @size: DW8-B
+ * @trl: DWC-F
+ */
+struct dwc3_trb_hw {
+	__le32		bpl;
+	__le32		bph;
+	__le32		size;
+	__le32		ctrl;
+} __packed;
+
+static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
+{
+	hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
+	hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
+	hw->size = cpu_to_le32p(&nat->len_pcm);
+	/* HWO is written last */
+	hw->ctrl = cpu_to_le32p(&nat->control);
+}
+
+static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
+{
+	u64 bplh;
+
+	bplh = le32_to_cpup(&hw->bpl);
+	bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
+	nat->bplh = bplh;
+
+	nat->len_pcm = le32_to_cpup(&hw->size);
+	nat->control = le32_to_cpup(&hw->ctrl);
+}
+
+/**
+ * dwc3_hwparams - copy of HWPARAMS registers
+ * @hwparams0 - GHWPARAMS0
+ * @hwparams1 - GHWPARAMS1
+ * @hwparams2 - GHWPARAMS2
+ * @hwparams3 - GHWPARAMS3
+ * @hwparams4 - GHWPARAMS4
+ * @hwparams5 - GHWPARAMS5
+ * @hwparams6 - GHWPARAMS6
+ * @hwparams7 - GHWPARAMS7
+ * @hwparams8 - GHWPARAMS8
+ */
+struct dwc3_hwparams {
+	u32	hwparams0;
+	u32	hwparams1;
+	u32	hwparams2;
+	u32	hwparams3;
+	u32	hwparams4;
+	u32	hwparams5;
+	u32	hwparams6;
+	u32	hwparams7;
+	u32	hwparams8;
+};
+
+/**
+ * struct dwc3 - representation of our controller
+ * @ctrl_req: usb control request which is used for ep0
+ * @ep0_trb: trb which is used for the ctrl_req
+ * @ep0_bounce: bounce buffer for ep0
+ * @setup_buf: used while precessing STD USB requests
+ * @ctrl_req_addr: dma address of ctrl_req
+ * @ep0_trb: dma address of ep0_trb
+ * @ep0_usb_req: dummy req used while handling STD USB requests
+ * @setup_buf_addr: dma address of setup_buf
+ * @ep0_bounce_addr: dma address of ep0_bounce
+ * @lock: for synchronizing
+ * @dev: pointer to our struct device
+ * @event_buffer_list: a list of event buffers
+ * @gadget: device side representation of the peripheral controller
+ * @gadget_driver: pointer to the gadget driver
+ * @regs: base address for our registers
+ * @regs_size: address space size
+ * @irq: IRQ number
+ * @revision: revision register contents
+ * @is_selfpowered: true when we are selfpowered
+ * @three_stage_setup: set if we perform a three phase setup
+ * @ep0_status_pending: ep0 status response without a req is pending
+ * @ep0_bounced: true when we used bounce buffer
+ * @ep0_expect_in: true when we expect a DATA IN transfer
+ * @start_config_issued: true when StartConfig command has been issued
+ * @ep0_next_event: hold the next expected event
+ * @ep0state: state of endpoint zero
+ * @link_state: link state
+ * @speed: device speed (super, high, full, low)
+ * @mem: points to start of memory which is used for this struct.
+ * @hwparams: copy of hwparams registers
+ * @root: debugfs root folder pointer
+ */
+struct dwc3 {
+	struct usb_ctrlrequest	*ctrl_req;
+	struct dwc3_trb_hw	*ep0_trb;
+	void			*ep0_bounce;
+	u8			*setup_buf;
+	dma_addr_t		ctrl_req_addr;
+	dma_addr_t		ep0_trb_addr;
+	dma_addr_t		setup_buf_addr;
+	dma_addr_t		ep0_bounce_addr;
+	struct usb_request	ep0_usb_req;
+	/* device lock */
+	spinlock_t		lock;
+	struct device		*dev;
+
+	struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM];
+	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];
+
+	struct usb_gadget	gadget;
+	struct usb_gadget_driver *gadget_driver;
+
+	void __iomem		*regs;
+	size_t			regs_size;
+
+	int			irq;
+
+	u32			revision;
+
+#define DWC3_REVISION_173A	0x5533173a
+#define DWC3_REVISION_175A	0x5533175a
+#define DWC3_REVISION_180A	0x5533180a
+#define DWC3_REVISION_183A	0x5533183a
+#define DWC3_REVISION_185A	0x5533185a
+#define DWC3_REVISION_188A	0x5533188a
+#define DWC3_REVISION_190A	0x5533190a
+
+	unsigned		is_selfpowered:1;
+	unsigned		three_stage_setup:1;
+	unsigned		ep0_status_pending:1;
+	unsigned		ep0_bounced:1;
+	unsigned		ep0_expect_in:1;
+	unsigned		start_config_issued:1;
+
+	enum dwc3_ep0_next	ep0_next_event;
+	enum dwc3_ep0_state	ep0state;
+	enum dwc3_link_state	link_state;
+	enum dwc3_device_state	dev_state;
+
+	u8			speed;
+	void			*mem;
+
+	struct dwc3_hwparams	hwparams;
+	struct dentry		*root;
+};
+
+/* -------------------------------------------------------------------------- */
+
+#define DWC3_TRBSTS_OK			0
+#define DWC3_TRBSTS_MISSED_ISOC		1
+#define DWC3_TRBSTS_SETUP_PENDING	2
+
+#define DWC3_TRBCTL_NORMAL		1
+#define DWC3_TRBCTL_CONTROL_SETUP	2
+#define DWC3_TRBCTL_CONTROL_STATUS2	3
+#define DWC3_TRBCTL_CONTROL_STATUS3	4
+#define DWC3_TRBCTL_CONTROL_DATA	5
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST	6
+#define DWC3_TRBCTL_ISOCHRONOUS		7
+#define DWC3_TRBCTL_LINK_TRB		8
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_event_type {
+	u32	is_devspec:1;
+	u32	type:6;
+	u32	reserved8_31:25;
+} __packed;
+
+#define DWC3_DEPEVT_XFERCOMPLETE	0x01
+#define DWC3_DEPEVT_XFERINPROGRESS	0x02
+#define DWC3_DEPEVT_XFERNOTREADY	0x03
+#define DWC3_DEPEVT_RXTXFIFOEVT		0x04
+#define DWC3_DEPEVT_STREAMEVT		0x06
+#define DWC3_DEPEVT_EPCMDCMPLT		0x07
+
+/**
+ * struct dwc3_event_depvt - Device Endpoint Events
+ * @one_bit: indicates this is an endpoint event (not used)
+ * @endpoint_number: number of the endpoint
+ * @endpoint_event: The event we have:
+ *	0x00	- Reserved
+ *	0x01	- XferComplete
+ *	0x02	- XferInProgress
+ *	0x03	- XferNotReady
+ *	0x04	- RxTxFifoEvt (IN->Underrun, OUT->Overrun)
+ *	0x05	- Reserved
+ *	0x06	- StreamEvt
+ *	0x07	- EPCmdCmplt
+ * @reserved11_10: Reserved, don't use.
+ * @status: Indicates the status of the event. Refer to databook for
+ *	more information.
+ * @parameters: Parameters of the current event. Refer to databook for
+ *	more information.
+ */
+struct dwc3_event_depevt {
+	u32	one_bit:1;
+	u32	endpoint_number:5;
+	u32	endpoint_event:4;
+	u32	reserved11_10:2;
+	u32	status:4;
+#define DEPEVT_STATUS_BUSERR    (1 << 0)
+#define DEPEVT_STATUS_SHORT     (1 << 1)
+#define DEPEVT_STATUS_IOC       (1 << 2)
+#define DEPEVT_STATUS_LST	(1 << 3)
+
+/* Stream event only */
+#define DEPEVT_STREAMEVT_FOUND		1
+#define DEPEVT_STREAMEVT_NOTFOUND	2
+
+/* Control-only Status */
+#define DEPEVT_STATUS_CONTROL_SETUP	0
+#define DEPEVT_STATUS_CONTROL_DATA	1
+#define DEPEVT_STATUS_CONTROL_STATUS	2
+
+	u32	parameters:16;
+} __packed;
+
+/**
+ * struct dwc3_event_devt - Device Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's a device event. Should read as 0x00
+ * @type: indicates the type of device event.
+ *	0	- DisconnEvt
+ *	1	- USBRst
+ *	2	- ConnectDone
+ *	3	- ULStChng
+ *	4	- WkUpEvt
+ *	5	- Reserved
+ *	6	- EOPF
+ *	7	- SOF
+ *	8	- Reserved
+ *	9	- ErrticErr
+ *	10	- CmdCmplt
+ *	11	- EvntOverflow
+ *	12	- VndrDevTstRcved
+ * @reserved15_12: Reserved, not used
+ * @event_info: Information about this event
+ * @reserved31_24: Reserved, not used
+ */
+struct dwc3_event_devt {
+	u32	one_bit:1;
+	u32	device_event:7;
+	u32	type:4;
+	u32	reserved15_12:4;
+	u32	event_info:8;
+	u32	reserved31_24:8;
+} __packed;
+
+/**
+ * struct dwc3_event_gevt - Other Core Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's (0x03) Carkit or (0x04) I2C event.
+ * @phy_port_number: self-explanatory
+ * @reserved31_12: Reserved, not used.
+ */
+struct dwc3_event_gevt {
+	u32	one_bit:1;
+	u32	device_event:7;
+	u32	phy_port_number:4;
+	u32	reserved31_12:20;
+} __packed;
+
+/**
+ * union dwc3_event - representation of Event Buffer contents
+ * @raw: raw 32-bit event
+ * @type: the type of the event
+ * @depevt: Device Endpoint Event
+ * @devt: Device Event
+ * @gevt: Global Event
+ */
+union dwc3_event {
+	u32				raw;
+	struct dwc3_event_type		type;
+	struct dwc3_event_depevt	depevt;
+	struct dwc3_event_devt		devt;
+	struct dwc3_event_gevt		gevt;
+};
+
+/*
+ * DWC3 Features to be used as Driver Data
+ */
+
+#define DWC3_HAS_PERIPHERAL		BIT(0)
+#define DWC3_HAS_XHCI			BIT(1)
+#define DWC3_HAS_OTG			BIT(3)
+
+#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
new file mode 100644
index 0000000..5894ee8
--- /dev/null
+++ b/drivers/usb/dwc3/debug.h
@@ -0,0 +1,50 @@
+/**
+ * debug.h - DesignWare USB3 DRD Controller Debug Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+
+#ifdef CONFIG_DEBUG_FS
+extern int dwc3_debugfs_init(struct dwc3 *);
+extern void dwc3_debugfs_exit(struct dwc3 *);
+#else
+static inline int dwc3_debugfs_init(struct dwc3 *d)
+{  return 0;  }
+static inline void dwc3_debugfs_exit(struct dwc3 *d)
+{  }
+#endif
+
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
new file mode 100644
index 0000000..da1ad77
--- /dev/null
+++ b/drivers/usb/dwc3/debugfs.c
@@ -0,0 +1,441 @@
+/**
+ * debugfs.c - DesignWare USB3 DRD Controller DebugFS file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+struct dwc3_register {
+	const char	*name;
+	u32		offset;
+};
+
+#define dump_register(nm)				\
+{							\
+	.name	= __stringify(nm),			\
+	.offset	= DWC3_ ##nm,				\
+}
+
+static const struct dwc3_register dwc3_regs[] = {
+	dump_register(GSBUSCFG0),
+	dump_register(GSBUSCFG1),
+	dump_register(GTXTHRCFG),
+	dump_register(GRXTHRCFG),
+	dump_register(GCTL),
+	dump_register(GEVTEN),
+	dump_register(GSTS),
+	dump_register(GSNPSID),
+	dump_register(GGPIO),
+	dump_register(GUID),
+	dump_register(GUCTL),
+	dump_register(GBUSERRADDR0),
+	dump_register(GBUSERRADDR1),
+	dump_register(GPRTBIMAP0),
+	dump_register(GPRTBIMAP1),
+	dump_register(GHWPARAMS0),
+	dump_register(GHWPARAMS1),
+	dump_register(GHWPARAMS2),
+	dump_register(GHWPARAMS3),
+	dump_register(GHWPARAMS4),
+	dump_register(GHWPARAMS5),
+	dump_register(GHWPARAMS6),
+	dump_register(GHWPARAMS7),
+	dump_register(GDBGFIFOSPACE),
+	dump_register(GDBGLTSSM),
+	dump_register(GPRTBIMAP_HS0),
+	dump_register(GPRTBIMAP_HS1),
+	dump_register(GPRTBIMAP_FS0),
+	dump_register(GPRTBIMAP_FS1),
+
+	dump_register(GUSB2PHYCFG(0)),
+	dump_register(GUSB2PHYCFG(1)),
+	dump_register(GUSB2PHYCFG(2)),
+	dump_register(GUSB2PHYCFG(3)),
+	dump_register(GUSB2PHYCFG(4)),
+	dump_register(GUSB2PHYCFG(5)),
+	dump_register(GUSB2PHYCFG(6)),
+	dump_register(GUSB2PHYCFG(7)),
+	dump_register(GUSB2PHYCFG(8)),
+	dump_register(GUSB2PHYCFG(9)),
+	dump_register(GUSB2PHYCFG(10)),
+	dump_register(GUSB2PHYCFG(11)),
+	dump_register(GUSB2PHYCFG(12)),
+	dump_register(GUSB2PHYCFG(13)),
+	dump_register(GUSB2PHYCFG(14)),
+	dump_register(GUSB2PHYCFG(15)),
+
+	dump_register(GUSB2I2CCTL(0)),
+	dump_register(GUSB2I2CCTL(1)),
+	dump_register(GUSB2I2CCTL(2)),
+	dump_register(GUSB2I2CCTL(3)),
+	dump_register(GUSB2I2CCTL(4)),
+	dump_register(GUSB2I2CCTL(5)),
+	dump_register(GUSB2I2CCTL(6)),
+	dump_register(GUSB2I2CCTL(7)),
+	dump_register(GUSB2I2CCTL(8)),
+	dump_register(GUSB2I2CCTL(9)),
+	dump_register(GUSB2I2CCTL(10)),
+	dump_register(GUSB2I2CCTL(11)),
+	dump_register(GUSB2I2CCTL(12)),
+	dump_register(GUSB2I2CCTL(13)),
+	dump_register(GUSB2I2CCTL(14)),
+	dump_register(GUSB2I2CCTL(15)),
+
+	dump_register(GUSB2PHYACC(0)),
+	dump_register(GUSB2PHYACC(1)),
+	dump_register(GUSB2PHYACC(2)),
+	dump_register(GUSB2PHYACC(3)),
+	dump_register(GUSB2PHYACC(4)),
+	dump_register(GUSB2PHYACC(5)),
+	dump_register(GUSB2PHYACC(6)),
+	dump_register(GUSB2PHYACC(7)),
+	dump_register(GUSB2PHYACC(8)),
+	dump_register(GUSB2PHYACC(9)),
+	dump_register(GUSB2PHYACC(10)),
+	dump_register(GUSB2PHYACC(11)),
+	dump_register(GUSB2PHYACC(12)),
+	dump_register(GUSB2PHYACC(13)),
+	dump_register(GUSB2PHYACC(14)),
+	dump_register(GUSB2PHYACC(15)),
+
+	dump_register(GUSB3PIPECTL(0)),
+	dump_register(GUSB3PIPECTL(1)),
+	dump_register(GUSB3PIPECTL(2)),
+	dump_register(GUSB3PIPECTL(3)),
+	dump_register(GUSB3PIPECTL(4)),
+	dump_register(GUSB3PIPECTL(5)),
+	dump_register(GUSB3PIPECTL(6)),
+	dump_register(GUSB3PIPECTL(7)),
+	dump_register(GUSB3PIPECTL(8)),
+	dump_register(GUSB3PIPECTL(9)),
+	dump_register(GUSB3PIPECTL(10)),
+	dump_register(GUSB3PIPECTL(11)),
+	dump_register(GUSB3PIPECTL(12)),
+	dump_register(GUSB3PIPECTL(13)),
+	dump_register(GUSB3PIPECTL(14)),
+	dump_register(GUSB3PIPECTL(15)),
+
+	dump_register(GTXFIFOSIZ(0)),
+	dump_register(GTXFIFOSIZ(1)),
+	dump_register(GTXFIFOSIZ(2)),
+	dump_register(GTXFIFOSIZ(3)),
+	dump_register(GTXFIFOSIZ(4)),
+	dump_register(GTXFIFOSIZ(5)),
+	dump_register(GTXFIFOSIZ(6)),
+	dump_register(GTXFIFOSIZ(7)),
+	dump_register(GTXFIFOSIZ(8)),
+	dump_register(GTXFIFOSIZ(9)),
+	dump_register(GTXFIFOSIZ(10)),
+	dump_register(GTXFIFOSIZ(11)),
+	dump_register(GTXFIFOSIZ(12)),
+	dump_register(GTXFIFOSIZ(13)),
+	dump_register(GTXFIFOSIZ(14)),
+	dump_register(GTXFIFOSIZ(15)),
+	dump_register(GTXFIFOSIZ(16)),
+	dump_register(GTXFIFOSIZ(17)),
+	dump_register(GTXFIFOSIZ(18)),
+	dump_register(GTXFIFOSIZ(19)),
+	dump_register(GTXFIFOSIZ(20)),
+	dump_register(GTXFIFOSIZ(21)),
+	dump_register(GTXFIFOSIZ(22)),
+	dump_register(GTXFIFOSIZ(23)),
+	dump_register(GTXFIFOSIZ(24)),
+	dump_register(GTXFIFOSIZ(25)),
+	dump_register(GTXFIFOSIZ(26)),
+	dump_register(GTXFIFOSIZ(27)),
+	dump_register(GTXFIFOSIZ(28)),
+	dump_register(GTXFIFOSIZ(29)),
+	dump_register(GTXFIFOSIZ(30)),
+	dump_register(GTXFIFOSIZ(31)),
+
+	dump_register(GRXFIFOSIZ(0)),
+	dump_register(GRXFIFOSIZ(1)),
+	dump_register(GRXFIFOSIZ(2)),
+	dump_register(GRXFIFOSIZ(3)),
+	dump_register(GRXFIFOSIZ(4)),
+	dump_register(GRXFIFOSIZ(5)),
+	dump_register(GRXFIFOSIZ(6)),
+	dump_register(GRXFIFOSIZ(7)),
+	dump_register(GRXFIFOSIZ(8)),
+	dump_register(GRXFIFOSIZ(9)),
+	dump_register(GRXFIFOSIZ(10)),
+	dump_register(GRXFIFOSIZ(11)),
+	dump_register(GRXFIFOSIZ(12)),
+	dump_register(GRXFIFOSIZ(13)),
+	dump_register(GRXFIFOSIZ(14)),
+	dump_register(GRXFIFOSIZ(15)),
+	dump_register(GRXFIFOSIZ(16)),
+	dump_register(GRXFIFOSIZ(17)),
+	dump_register(GRXFIFOSIZ(18)),
+	dump_register(GRXFIFOSIZ(19)),
+	dump_register(GRXFIFOSIZ(20)),
+	dump_register(GRXFIFOSIZ(21)),
+	dump_register(GRXFIFOSIZ(22)),
+	dump_register(GRXFIFOSIZ(23)),
+	dump_register(GRXFIFOSIZ(24)),
+	dump_register(GRXFIFOSIZ(25)),
+	dump_register(GRXFIFOSIZ(26)),
+	dump_register(GRXFIFOSIZ(27)),
+	dump_register(GRXFIFOSIZ(28)),
+	dump_register(GRXFIFOSIZ(29)),
+	dump_register(GRXFIFOSIZ(30)),
+	dump_register(GRXFIFOSIZ(31)),
+
+	dump_register(GEVNTADRLO(0)),
+	dump_register(GEVNTADRHI(0)),
+	dump_register(GEVNTSIZ(0)),
+	dump_register(GEVNTCOUNT(0)),
+
+	dump_register(GHWPARAMS8),
+	dump_register(DCFG),
+	dump_register(DCTL),
+	dump_register(DEVTEN),
+	dump_register(DSTS),
+	dump_register(DGCMDPAR),
+	dump_register(DGCMD),
+	dump_register(DALEPENA),
+
+	dump_register(DEPCMDPAR2(0)),
+	dump_register(DEPCMDPAR2(1)),
+	dump_register(DEPCMDPAR2(2)),
+	dump_register(DEPCMDPAR2(3)),
+	dump_register(DEPCMDPAR2(4)),
+	dump_register(DEPCMDPAR2(5)),
+	dump_register(DEPCMDPAR2(6)),
+	dump_register(DEPCMDPAR2(7)),
+	dump_register(DEPCMDPAR2(8)),
+	dump_register(DEPCMDPAR2(9)),
+	dump_register(DEPCMDPAR2(10)),
+	dump_register(DEPCMDPAR2(11)),
+	dump_register(DEPCMDPAR2(12)),
+	dump_register(DEPCMDPAR2(13)),
+	dump_register(DEPCMDPAR2(14)),
+	dump_register(DEPCMDPAR2(15)),
+	dump_register(DEPCMDPAR2(16)),
+	dump_register(DEPCMDPAR2(17)),
+	dump_register(DEPCMDPAR2(18)),
+	dump_register(DEPCMDPAR2(19)),
+	dump_register(DEPCMDPAR2(20)),
+	dump_register(DEPCMDPAR2(21)),
+	dump_register(DEPCMDPAR2(22)),
+	dump_register(DEPCMDPAR2(23)),
+	dump_register(DEPCMDPAR2(24)),
+	dump_register(DEPCMDPAR2(25)),
+	dump_register(DEPCMDPAR2(26)),
+	dump_register(DEPCMDPAR2(27)),
+	dump_register(DEPCMDPAR2(28)),
+	dump_register(DEPCMDPAR2(29)),
+	dump_register(DEPCMDPAR2(30)),
+	dump_register(DEPCMDPAR2(31)),
+
+	dump_register(DEPCMDPAR1(0)),
+	dump_register(DEPCMDPAR1(1)),
+	dump_register(DEPCMDPAR1(2)),
+	dump_register(DEPCMDPAR1(3)),
+	dump_register(DEPCMDPAR1(4)),
+	dump_register(DEPCMDPAR1(5)),
+	dump_register(DEPCMDPAR1(6)),
+	dump_register(DEPCMDPAR1(7)),
+	dump_register(DEPCMDPAR1(8)),
+	dump_register(DEPCMDPAR1(9)),
+	dump_register(DEPCMDPAR1(10)),
+	dump_register(DEPCMDPAR1(11)),
+	dump_register(DEPCMDPAR1(12)),
+	dump_register(DEPCMDPAR1(13)),
+	dump_register(DEPCMDPAR1(14)),
+	dump_register(DEPCMDPAR1(15)),
+	dump_register(DEPCMDPAR1(16)),
+	dump_register(DEPCMDPAR1(17)),
+	dump_register(DEPCMDPAR1(18)),
+	dump_register(DEPCMDPAR1(19)),
+	dump_register(DEPCMDPAR1(20)),
+	dump_register(DEPCMDPAR1(21)),
+	dump_register(DEPCMDPAR1(22)),
+	dump_register(DEPCMDPAR1(23)),
+	dump_register(DEPCMDPAR1(24)),
+	dump_register(DEPCMDPAR1(25)),
+	dump_register(DEPCMDPAR1(26)),
+	dump_register(DEPCMDPAR1(27)),
+	dump_register(DEPCMDPAR1(28)),
+	dump_register(DEPCMDPAR1(29)),
+	dump_register(DEPCMDPAR1(30)),
+	dump_register(DEPCMDPAR1(31)),
+
+	dump_register(DEPCMDPAR0(0)),
+	dump_register(DEPCMDPAR0(1)),
+	dump_register(DEPCMDPAR0(2)),
+	dump_register(DEPCMDPAR0(3)),
+	dump_register(DEPCMDPAR0(4)),
+	dump_register(DEPCMDPAR0(5)),
+	dump_register(DEPCMDPAR0(6)),
+	dump_register(DEPCMDPAR0(7)),
+	dump_register(DEPCMDPAR0(8)),
+	dump_register(DEPCMDPAR0(9)),
+	dump_register(DEPCMDPAR0(10)),
+	dump_register(DEPCMDPAR0(11)),
+	dump_register(DEPCMDPAR0(12)),
+	dump_register(DEPCMDPAR0(13)),
+	dump_register(DEPCMDPAR0(14)),
+	dump_register(DEPCMDPAR0(15)),
+	dump_register(DEPCMDPAR0(16)),
+	dump_register(DEPCMDPAR0(17)),
+	dump_register(DEPCMDPAR0(18)),
+	dump_register(DEPCMDPAR0(19)),
+	dump_register(DEPCMDPAR0(20)),
+	dump_register(DEPCMDPAR0(21)),
+	dump_register(DEPCMDPAR0(22)),
+	dump_register(DEPCMDPAR0(23)),
+	dump_register(DEPCMDPAR0(24)),
+	dump_register(DEPCMDPAR0(25)),
+	dump_register(DEPCMDPAR0(26)),
+	dump_register(DEPCMDPAR0(27)),
+	dump_register(DEPCMDPAR0(28)),
+	dump_register(DEPCMDPAR0(29)),
+	dump_register(DEPCMDPAR0(30)),
+	dump_register(DEPCMDPAR0(31)),
+
+	dump_register(DEPCMD(0)),
+	dump_register(DEPCMD(1)),
+	dump_register(DEPCMD(2)),
+	dump_register(DEPCMD(3)),
+	dump_register(DEPCMD(4)),
+	dump_register(DEPCMD(5)),
+	dump_register(DEPCMD(6)),
+	dump_register(DEPCMD(7)),
+	dump_register(DEPCMD(8)),
+	dump_register(DEPCMD(9)),
+	dump_register(DEPCMD(10)),
+	dump_register(DEPCMD(11)),
+	dump_register(DEPCMD(12)),
+	dump_register(DEPCMD(13)),
+	dump_register(DEPCMD(14)),
+	dump_register(DEPCMD(15)),
+	dump_register(DEPCMD(16)),
+	dump_register(DEPCMD(17)),
+	dump_register(DEPCMD(18)),
+	dump_register(DEPCMD(19)),
+	dump_register(DEPCMD(20)),
+	dump_register(DEPCMD(21)),
+	dump_register(DEPCMD(22)),
+	dump_register(DEPCMD(23)),
+	dump_register(DEPCMD(24)),
+	dump_register(DEPCMD(25)),
+	dump_register(DEPCMD(26)),
+	dump_register(DEPCMD(27)),
+	dump_register(DEPCMD(28)),
+	dump_register(DEPCMD(29)),
+	dump_register(DEPCMD(30)),
+	dump_register(DEPCMD(31)),
+
+	dump_register(OCFG),
+	dump_register(OCTL),
+	dump_register(OEVTEN),
+	dump_register(OSTS),
+};
+
+static int dwc3_regdump_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	int			i;
+
+	seq_printf(s, "DesignWare USB3 Core Register Dump\n");
+
+	for (i = 0; i < ARRAY_SIZE(dwc3_regs); i++) {
+		seq_printf(s, "%-20s :    %08x\n", dwc3_regs[i].name,
+				dwc3_readl(dwc->regs, dwc3_regs[i].offset));
+	}
+
+	return 0;
+}
+
+static int dwc3_regdump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_regdump_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_regdump_fops = {
+	.open			= dwc3_regdump_open,
+	.read			= seq_read,
+	.release		= single_release,
+};
+
+int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
+{
+	struct dentry		*root;
+	struct dentry		*file;
+	int			ret;
+
+	root = debugfs_create_dir(dev_name(dwc->dev), NULL);
+	if (IS_ERR(root)){
+		ret = PTR_ERR(root);
+		goto err0;
+	}
+
+	dwc->root = root;
+
+	file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
+			&dwc3_regdump_fops);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto err1;
+	}
+	return 0;
+
+err1:
+	debugfs_remove_recursive(root);
+
+err0:
+	return ret;
+}
+
+void __devexit dwc3_debugfs_exit(struct dwc3 *dwc)
+{
+	debugfs_remove_recursive(dwc->root);
+	dwc->root = NULL;
+}
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
new file mode 100644
index 0000000..062552b
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -0,0 +1,401 @@
+/**
+ * dwc3-omap.c - OMAP Specific Glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dwc3-omap.h>
+#include <linux/dma-mapping.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include "io.h"
+
+/*
+ * All these registers belong to OMAP's Wrapper around the
+ * DesignWare USB3 Core.
+ */
+
+#define USBOTGSS_REVISION			0x0000
+#define USBOTGSS_SYSCONFIG			0x0010
+#define USBOTGSS_IRQ_EOI			0x0020
+#define USBOTGSS_IRQSTATUS_RAW_0		0x0024
+#define USBOTGSS_IRQSTATUS_0			0x0028
+#define USBOTGSS_IRQENABLE_SET_0		0x002c
+#define USBOTGSS_IRQENABLE_CLR_0		0x0030
+#define USBOTGSS_IRQSTATUS_RAW_1		0x0034
+#define USBOTGSS_IRQSTATUS_1			0x0038
+#define USBOTGSS_IRQENABLE_SET_1		0x003c
+#define USBOTGSS_IRQENABLE_CLR_1		0x0040
+#define USBOTGSS_UTMI_OTG_CTRL			0x0080
+#define USBOTGSS_UTMI_OTG_STATUS		0x0084
+#define USBOTGSS_MMRAM_OFFSET			0x0100
+#define USBOTGSS_FLADJ				0x0104
+#define USBOTGSS_DEBUG_CFG			0x0108
+#define USBOTGSS_DEBUG_DATA			0x010c
+
+/* SYSCONFIG REGISTER */
+#define USBOTGSS_SYSCONFIG_DMADISABLE		(1 << 16)
+#define USBOTGSS_SYSCONFIG_STANDBYMODE(x)	((x) << 4)
+
+#define USBOTGSS_STANDBYMODE_FORCE_STANDBY	0
+#define USBOTGSS_STANDBYMODE_NO_STANDBY		1
+#define USBOTGSS_STANDBYMODE_SMART_STANDBY	2
+#define USBOTGSS_STANDBYMODE_SMART_WAKEUP	3
+
+#define USBOTGSS_STANDBYMODE_MASK		(0x03 << 4)
+
+#define USBOTGSS_SYSCONFIG_IDLEMODE(x)		((x) << 2)
+
+#define USBOTGSS_IDLEMODE_FORCE_IDLE		0
+#define USBOTGSS_IDLEMODE_NO_IDLE		1
+#define USBOTGSS_IDLEMODE_SMART_IDLE		2
+#define USBOTGSS_IDLEMODE_SMART_WAKEUP		3
+
+#define USBOTGSS_IDLEMODE_MASK			(0x03 << 2)
+
+/* IRQ_EOI REGISTER */
+#define USBOTGSS_IRQ_EOI_LINE_NUMBER		(1 << 0)
+
+/* IRQS0 BITS */
+#define USBOTGSS_IRQO_COREIRQ_ST		(1 << 0)
+
+/* IRQ1 BITS */
+#define USBOTGSS_IRQ1_DMADISABLECLR		(1 << 17)
+#define USBOTGSS_IRQ1_OEVT			(1 << 16)
+#define USBOTGSS_IRQ1_DRVVBUS_RISE		(1 << 13)
+#define USBOTGSS_IRQ1_CHRGVBUS_RISE		(1 << 12)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_RISE		(1 << 11)
+#define USBOTGSS_IRQ1_IDPULLUP_RISE		(1 << 8)
+#define USBOTGSS_IRQ1_DRVVBUS_FALL		(1 << 5)
+#define USBOTGSS_IRQ1_CHRGVBUS_FALL		(1 << 4)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_FALL		(1 << 3)
+#define USBOTGSS_IRQ1_IDPULLUP_FALL		(1 << 0)
+
+/* UTMI_OTG_CTRL REGISTER */
+#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS		(1 << 5)
+#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS		(1 << 4)
+#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS	(1 << 3)
+#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP		(1 << 0)
+
+/* UTMI_OTG_STATUS REGISTER */
+#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE	(1 << 31)
+#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT	(1 << 9)
+#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
+#define USBOTGSS_UTMI_OTG_STATUS_IDDIG		(1 << 4)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSEND	(1 << 3)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID	(1 << 2)
+#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID	(1 << 1)
+
+struct dwc3_omap {
+	/* device lock */
+	spinlock_t		lock;
+
+	struct platform_device	*dwc3;
+	struct device		*dev;
+
+	int			irq;
+	void __iomem		*base;
+
+	void			*context;
+	u32			resource_size;
+
+	u32			dma_status:1;
+};
+
+static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
+{
+	struct dwc3_omap	*omap = _omap;
+	u32			reg;
+
+	spin_lock(&omap->lock);
+
+	reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+
+	if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
+		dev_dbg(omap->dev, "DMA Disable was Cleared\n");
+		omap->dma_status = false;
+	}
+
+	if (reg & USBOTGSS_IRQ1_OEVT)
+		dev_dbg(omap->dev, "OTG Event\n");
+
+	if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE)
+		dev_dbg(omap->dev, "DRVVBUS Rise\n");
+
+	if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE)
+		dev_dbg(omap->dev, "CHRGVBUS Rise\n");
+
+	if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE)
+		dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
+
+	if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE)
+		dev_dbg(omap->dev, "IDPULLUP Rise\n");
+
+	if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL)
+		dev_dbg(omap->dev, "DRVVBUS Fall\n");
+
+	if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL)
+		dev_dbg(omap->dev, "CHRGVBUS Fall\n");
+
+	if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL)
+		dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
+
+	if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
+		dev_dbg(omap->dev, "IDPULLUP Fall\n");
+
+	dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+
+	reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+	dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+
+	spin_unlock(&omap->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit dwc3_omap_probe(struct platform_device *pdev)
+{
+	struct dwc3_omap_data	*pdata = pdev->dev.platform_data;
+	struct platform_device	*dwc3;
+	struct dwc3_omap	*omap;
+	struct resource		*res;
+
+	int			ret = -ENOMEM;
+	int			irq;
+
+	u32			reg;
+
+	void __iomem		*base;
+	void			*context;
+
+	omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+	if (!omap) {
+		dev_err(&pdev->dev, "not enough memory\n");
+		goto err0;
+	}
+
+	platform_set_drvdata(pdev, omap);
+
+	irq = platform_get_irq(pdev, 1);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "missing IRQ resource\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory base resource\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+
+	base = ioremap_nocache(res->start, resource_size(res));
+	if (!base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		goto err1;
+	}
+
+	dwc3 = platform_device_alloc("dwc3-omap", -1);
+	if (!dwc3) {
+		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+		goto err2;
+	}
+
+	context = kzalloc(resource_size(res), GFP_KERNEL);
+	if (!context) {
+		dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
+		goto err3;
+	}
+
+	spin_lock_init(&omap->lock);
+	dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+
+	dwc3->dev.parent = &pdev->dev;
+	dwc3->dev.dma_mask = pdev->dev.dma_mask;
+	dwc3->dev.dma_parms = pdev->dev.dma_parms;
+	omap->resource_size = resource_size(res);
+	omap->context	= context;
+	omap->dev	= &pdev->dev;
+	omap->irq	= irq;
+	omap->base	= base;
+	omap->dwc3	= dwc3;
+
+	reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+
+	if (!pdata) {
+		dev_dbg(&pdev->dev, "missing platform data\n");
+	} else {
+		switch (pdata->utmi_mode) {
+		case DWC3_OMAP_UTMI_MODE_SW:
+			reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+			break;
+		case DWC3_OMAP_UTMI_MODE_HW:
+			reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+			break;
+		default:
+			dev_dbg(&pdev->dev, "UNKNOWN utmi mode %d\n",
+					pdata->utmi_mode);
+		}
+	}
+
+	dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+
+	/* check the DMA Status */
+	reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+	omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
+
+	/* Set No-Idle and No-Standby */
+	reg &= ~(USBOTGSS_STANDBYMODE_MASK
+			| USBOTGSS_IDLEMODE_MASK);
+
+	reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
+		| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
+
+	dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+
+	ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
+			"dwc3-omap", omap);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
+				omap->irq, ret);
+		goto err4;
+	}
+
+	/* enable all IRQs */
+	reg = USBOTGSS_IRQO_COREIRQ_ST;
+	dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+
+	reg = (USBOTGSS_IRQ1_OEVT |
+			USBOTGSS_IRQ1_DRVVBUS_RISE |
+			USBOTGSS_IRQ1_CHRGVBUS_RISE |
+			USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
+			USBOTGSS_IRQ1_IDPULLUP_RISE |
+			USBOTGSS_IRQ1_DRVVBUS_FALL |
+			USBOTGSS_IRQ1_CHRGVBUS_FALL |
+			USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
+			USBOTGSS_IRQ1_IDPULLUP_FALL);
+
+	dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+
+	ret = platform_device_add_resources(dwc3, pdev->resource,
+			pdev->num_resources);
+	if (ret) {
+		dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
+		goto err5;
+	}
+
+	ret = platform_device_add(dwc3);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register dwc3 device\n");
+		goto err5;
+	}
+
+	return 0;
+
+err5:
+	free_irq(omap->irq, omap);
+
+err4:
+	kfree(omap->context);
+
+err3:
+	platform_device_put(dwc3);
+
+err2:
+	iounmap(base);
+
+err1:
+	kfree(omap);
+
+err0:
+	return ret;
+}
+
+static int __devexit dwc3_omap_remove(struct platform_device *pdev)
+{
+	struct dwc3_omap	*omap = platform_get_drvdata(pdev);
+
+	platform_device_unregister(omap->dwc3);
+
+	free_irq(omap->irq, omap);
+	iounmap(omap->base);
+
+	kfree(omap->context);
+	kfree(omap);
+
+	return 0;
+}
+
+static const struct of_device_id of_dwc3_matach[] = {
+	{
+		"ti,dwc3",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_matach);
+
+static struct platform_driver dwc3_omap_driver = {
+	.probe		= dwc3_omap_probe,
+	.remove		= __devexit_p(dwc3_omap_remove),
+	.driver		= {
+		.name	= "omap-dwc3",
+		.of_match_table	= of_dwc3_matach,
+	},
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
+
+static int __devinit dwc3_omap_init(void)
+{
+	return platform_driver_register(&dwc3_omap_driver);
+}
+module_init(dwc3_omap_init);
+
+static void __exit dwc3_omap_exit(void)
+{
+	platform_driver_unregister(&dwc3_omap_driver);
+}
+module_exit(dwc3_omap_exit);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
new file mode 100644
index 0000000..f77c000
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -0,0 +1,219 @@
+/**
+ * dwc3-pci.c - PCI Specific glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+/* FIXME define these in <linux/pci_ids.h> */
+#define PCI_VENDOR_ID_SYNOPSYS		0x16c3
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd
+
+#define DWC3_PCI_DEVS_POSSIBLE	32
+
+struct dwc3_pci {
+	struct device		*dev;
+	struct platform_device	*dwc3;
+};
+
+static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+
+static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
+{
+	int		id;
+
+again:
+	id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+	if (id < DWC3_PCI_DEVS_POSSIBLE) {
+		int old;
+
+		old = test_and_set_bit(id, dwc3_pci_devs);
+		if (old)
+			goto again;
+	} else {
+		dev_err(glue->dev, "no space for new device\n");
+		id = -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
+{
+	int			ret;
+
+	if (id < 0)
+		return;
+
+	ret = test_bit(id, dwc3_pci_devs);
+	WARN(!ret, "Device: %s\nID %d not in use\n",
+			dev_driver_string(glue->dev), id);
+	clear_bit(id, dwc3_pci_devs);
+}
+
+static int __devinit dwc3_pci_probe(struct pci_dev *pci,
+		const struct pci_device_id *id)
+{
+	struct resource		res[2];
+	struct platform_device	*dwc3;
+	struct dwc3_pci		*glue;
+	int			ret = -ENOMEM;
+	int			devid;
+
+	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+	if (!glue) {
+		dev_err(&pci->dev, "not enough memory\n");
+		goto err0;
+	}
+
+	glue->dev	= &pci->dev;
+
+	ret = pci_enable_device(pci);
+	if (ret) {
+		dev_err(&pci->dev, "failed to enable pci device\n");
+		goto err1;
+	}
+
+	pci_set_power_state(pci, PCI_D0);
+	pci_set_master(pci);
+
+	devid = dwc3_pci_get_device_id(glue);
+	if (devid < 0)
+		goto err2;
+
+	dwc3 = platform_device_alloc("dwc3-pci", devid);
+	if (!dwc3) {
+		dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
+		goto err3;
+	}
+
+	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+
+	res[0].start	= pci_resource_start(pci, 0);
+	res[0].end	= pci_resource_end(pci, 0);
+	res[0].name	= "dwc_usb3";
+	res[0].flags	= IORESOURCE_MEM;
+
+	res[1].start	= pci->irq;
+	res[1].name	= "dwc_usb3";
+	res[1].flags	= IORESOURCE_IRQ;
+
+	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
+	if (ret) {
+		dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
+		goto err4;
+	}
+
+	pci_set_drvdata(pci, glue);
+
+	dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
+
+	dwc3->dev.dma_mask = pci->dev.dma_mask;
+	dwc3->dev.dma_parms = pci->dev.dma_parms;
+	dwc3->dev.parent = &pci->dev;
+	glue->dwc3	= dwc3;
+
+	ret = platform_device_add(dwc3);
+	if (ret) {
+		dev_err(&pci->dev, "failed to register dwc3 device\n");
+		goto err4;
+	}
+
+	return 0;
+
+err4:
+	pci_set_drvdata(pci, NULL);
+	platform_device_put(dwc3);
+
+err3:
+	dwc3_pci_put_device_id(glue, devid);
+
+err2:
+	pci_disable_device(pci);
+
+err1:
+	kfree(pci);
+
+err0:
+	return ret;
+}
+
+static void __devexit dwc3_pci_remove(struct pci_dev *pci)
+{
+	struct dwc3_pci	*glue = pci_get_drvdata(pci);
+
+	dwc3_pci_put_device_id(glue, glue->dwc3->id);
+	platform_device_unregister(glue->dwc3);
+	pci_set_drvdata(pci, NULL);
+	pci_disable_device(pci);
+	kfree(glue);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
+	},
+	{  }	/* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
+
+static struct pci_driver dwc3_pci_driver = {
+	.name		= "pci-dwc3",
+	.id_table	= dwc3_pci_id_table,
+	.probe		= dwc3_pci_probe,
+	.remove		= __devexit_p(dwc3_pci_remove),
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
+
+static int __devinit dwc3_pci_init(void)
+{
+	return pci_register_driver(&dwc3_pci_driver);
+}
+module_init(dwc3_pci_init);
+
+static void __exit dwc3_pci_exit(void)
+{
+	pci_unregister_driver(&dwc3_pci_driver);
+}
+module_exit(dwc3_pci_exit);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
new file mode 100644
index 0000000..69a4e43
--- /dev/null
+++ b/drivers/usb/dwc3/ep0.c
@@ -0,0 +1,804 @@
+/**
+ * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event);
+
+static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
+{
+	switch (state) {
+	case EP0_UNCONNECTED:
+		return "Unconnected";
+	case EP0_SETUP_PHASE:
+		return "Setup Phase";
+	case EP0_DATA_PHASE:
+		return "Data Phase";
+	case EP0_STATUS_PHASE:
+		return "Status Phase";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
+		u32 len, u32 type)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_trb_hw		*trb_hw;
+	struct dwc3_trb			trb;
+	struct dwc3_ep			*dep;
+
+	int				ret;
+
+	dep = dwc->eps[epnum];
+	if (dep->flags & DWC3_EP_BUSY) {
+		dev_vdbg(dwc->dev, "%s: still busy\n", dep->name);
+		return 0;
+	}
+
+	trb_hw = dwc->ep0_trb;
+	memset(&trb, 0, sizeof(trb));
+
+	trb.trbctl = type;
+	trb.bplh = buf_dma;
+	trb.length = len;
+
+	trb.hwo	= 1;
+	trb.lst	= 1;
+	trb.ioc	= 1;
+	trb.isp_imi = 1;
+
+	dwc3_trb_to_hw(&trb, trb_hw);
+
+	memset(&params, 0, sizeof(params));
+	params.param0 = upper_32_bits(dwc->ep0_trb_addr);
+	params.param1 = lower_32_bits(dwc->ep0_trb_addr);
+
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_STARTTRANSFER, &params);
+	if (ret < 0) {
+		dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+		return ret;
+	}
+
+	dep->flags |= DWC3_EP_BUSY;
+	dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+			dep->number);
+
+	dwc->ep0_next_event = DWC3_EP0_COMPLETE;
+
+	return 0;
+}
+
+static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
+		struct dwc3_request *req)
+{
+	int			ret = 0;
+
+	req->request.actual	= 0;
+	req->request.status	= -EINPROGRESS;
+	req->epnum		= dep->number;
+
+	list_add_tail(&req->list, &dep->request_list);
+
+	/*
+	 * Gadget driver might not be quick enough to queue a request
+	 * before we get a Transfer Not Ready event on this endpoint.
+	 *
+	 * In that case, we will set DWC3_EP_PENDING_REQUEST. When that
+	 * flag is set, it's telling us that as soon as Gadget queues the
+	 * required request, we should kick the transfer here because the
+	 * IRQ we were waiting for is long gone.
+	 */
+	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+		struct dwc3	*dwc = dep->dwc;
+		unsigned	direction;
+		u32		type;
+
+		direction = !!(dep->flags & DWC3_EP0_DIR_IN);
+
+		if (dwc->ep0state == EP0_STATUS_PHASE) {
+			type = dwc->three_stage_setup
+				? DWC3_TRBCTL_CONTROL_STATUS3
+				: DWC3_TRBCTL_CONTROL_STATUS2;
+		} else if (dwc->ep0state == EP0_DATA_PHASE) {
+			type = DWC3_TRBCTL_CONTROL_DATA;
+		} else {
+			/* should never happen */
+			WARN_ON(1);
+			return 0;
+		}
+
+		ret = dwc3_ep0_start_trans(dwc, direction,
+				req->request.dma, req->request.length, type);
+		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
+				DWC3_EP0_DIR_IN);
+	}
+
+	return ret;
+}
+
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+		gfp_t gfp_flags)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (!dep->desc) {
+		dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+				request, dep->name);
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+
+	/* we share one TRB for ep0/1 */
+	if (!list_empty(&dwc->eps[0]->request_list) ||
+			!list_empty(&dwc->eps[1]->request_list) ||
+			dwc->ep0_status_pending) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	dev_vdbg(dwc->dev, "queueing request %p to %s length %d, state '%s'\n",
+			request, dep->name, request->length,
+			dwc3_ep0_state_string(dwc->ep0state));
+
+	ret = __dwc3_gadget_ep0_queue(dep, req);
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
+{
+	struct dwc3_ep		*dep = dwc->eps[0];
+
+	/* stall is always issued on EP0 */
+	__dwc3_gadget_ep_set_halt(dwc->eps[0], 1);
+	dwc->eps[0]->flags = DWC3_EP_ENABLED;
+
+	if (!list_empty(&dep->request_list)) {
+		struct dwc3_request	*req;
+
+		req = next_request(&dep->request_list);
+		dwc3_gadget_giveback(dep, req, -ECONNRESET);
+	}
+
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+}
+
+void dwc3_ep0_out_start(struct dwc3 *dwc)
+{
+	int				ret;
+
+	ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
+			DWC3_TRBCTL_CONTROL_SETUP);
+	WARN_ON(ret < 0);
+}
+
+static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
+{
+	struct dwc3_ep		*dep;
+	u32			windex = le16_to_cpu(wIndex_le);
+	u32			epnum;
+
+	epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1;
+	if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+		epnum |= 1;
+
+	dep = dwc->eps[epnum];
+	if (dep->flags & DWC3_EP_ENABLED)
+		return dep;
+
+	return NULL;
+}
+
+static void dwc3_ep0_send_status_response(struct dwc3 *dwc)
+{
+	dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr,
+			dwc->ep0_usb_req.length,
+			DWC3_TRBCTL_CONTROL_DATA);
+}
+
+/*
+ * ch 9.4.5
+ */
+static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	struct dwc3_ep		*dep;
+	u32			recip;
+	u16			usb_status = 0;
+	__le16			*response_pkt;
+
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+		/*
+		 * We are self-powered. U1/U2/LTM will be set later
+		 * once we handle this states. RemoteWakeup is 0 on SS
+		 */
+		usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+		break;
+
+	case USB_RECIP_INTERFACE:
+		/*
+		 * Function Remote Wake Capable	D0
+		 * Function Remote Wakeup	D1
+		 */
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+		if (!dep)
+		       return -EINVAL;
+
+		if (dep->flags & DWC3_EP_STALL)
+			usb_status = 1 << USB_ENDPOINT_HALT;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	response_pkt = (__le16 *) dwc->setup_buf;
+	*response_pkt = cpu_to_le16(usb_status);
+	dwc->ep0_usb_req.length = sizeof(*response_pkt);
+	dwc->ep0_status_pending = 1;
+
+	return 0;
+}
+
+static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl, int set)
+{
+	struct dwc3_ep		*dep;
+	u32			recip;
+	u32			wValue;
+	u32			wIndex;
+	u32			reg;
+	int			ret;
+	u32			mode;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+	wIndex = le16_to_cpu(ctrl->wIndex);
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+
+		/*
+		 * 9.4.1 says only only for SS, in AddressState only for
+		 * default control pipe
+		 */
+		switch (wValue) {
+		case USB_DEVICE_U1_ENABLE:
+		case USB_DEVICE_U2_ENABLE:
+		case USB_DEVICE_LTM_ENABLE:
+			if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+				return -EINVAL;
+			if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+				return -EINVAL;
+		}
+
+		/* XXX add U[12] & LTM */
+		switch (wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			break;
+		case USB_DEVICE_U1_ENABLE:
+			break;
+		case USB_DEVICE_U2_ENABLE:
+			break;
+		case USB_DEVICE_LTM_ENABLE:
+			break;
+
+		case USB_DEVICE_TEST_MODE:
+			if ((wIndex & 0xff) != 0)
+				return -EINVAL;
+			if (!set)
+				return -EINVAL;
+
+			mode = wIndex >> 8;
+			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+			reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+
+			switch (mode) {
+			case TEST_J:
+			case TEST_K:
+			case TEST_SE0_NAK:
+			case TEST_PACKET:
+			case TEST_FORCE_EN:
+				reg |= mode << 1;
+				break;
+			default:
+				return -EINVAL;
+			}
+			dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case USB_RECIP_INTERFACE:
+		switch (wValue) {
+		case USB_INTRF_FUNC_SUSPEND:
+			if (wIndex & USB_INTRF_FUNC_SUSPEND_LP)
+				/* XXX enable Low power suspend */
+				;
+			if (wIndex & USB_INTRF_FUNC_SUSPEND_RW)
+				/* XXX enable remote wakeup */
+				;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		switch (wValue) {
+		case USB_ENDPOINT_HALT:
+
+			dep =  dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+			if (!dep)
+				return -EINVAL;
+			ret = __dwc3_gadget_ep_set_halt(dep, set);
+			if (ret)
+				return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	};
+
+	return 0;
+}
+
+static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	u32 addr;
+	u32 reg;
+
+	addr = le16_to_cpu(ctrl->wValue);
+	if (addr > 127)
+		return -EINVAL;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+	reg |= DWC3_DCFG_DEVADDR(addr);
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	if (addr)
+		dwc->dev_state = DWC3_ADDRESS_STATE;
+	else
+		dwc->dev_state = DWC3_DEFAULT_STATE;
+
+	return 0;
+}
+
+static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	int ret;
+
+	spin_unlock(&dwc->lock);
+	ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
+	spin_lock(&dwc->lock);
+	return ret;
+}
+
+static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	u32 cfg;
+	int ret;
+
+	dwc->start_config_issued = false;
+	cfg = le16_to_cpu(ctrl->wValue);
+
+	switch (dwc->dev_state) {
+	case DWC3_DEFAULT_STATE:
+		return -EINVAL;
+		break;
+
+	case DWC3_ADDRESS_STATE:
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		/* if the cfg matches and the cfg is non zero */
+		if (!ret && cfg)
+			dwc->dev_state = DWC3_CONFIGURED_STATE;
+		break;
+
+	case DWC3_CONFIGURED_STATE:
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		if (!cfg)
+			dwc->dev_state = DWC3_ADDRESS_STATE;
+		break;
+	}
+	return 0;
+}
+
+static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	int ret;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_GET_STATUS:
+		dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n");
+		ret = dwc3_ep0_handle_status(dwc, ctrl);
+		break;
+	case USB_REQ_CLEAR_FEATURE:
+		dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n");
+		ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
+		break;
+	case USB_REQ_SET_FEATURE:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n");
+		ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
+		break;
+	case USB_REQ_SET_ADDRESS:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n");
+		ret = dwc3_ep0_set_address(dwc, ctrl);
+		break;
+	case USB_REQ_SET_CONFIGURATION:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
+		ret = dwc3_ep0_set_config(dwc, ctrl);
+		break;
+	default:
+		dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		break;
+	};
+
+	return ret;
+}
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
+	int ret;
+	u32 len;
+
+	if (!dwc->gadget_driver)
+		goto err;
+
+	len = le16_to_cpu(ctrl->wLength);
+	if (!len) {
+		dwc->three_stage_setup = false;
+		dwc->ep0_expect_in = false;
+		dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+	} else {
+		dwc->three_stage_setup = true;
+		dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN);
+		dwc->ep0_next_event = DWC3_EP0_NRDY_DATA;
+	}
+
+	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+		ret = dwc3_ep0_std_request(dwc, ctrl);
+	else
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+
+	if (ret >= 0)
+		return;
+
+err:
+	dwc3_ep0_stall_and_restart(dwc);
+}
+
+static void dwc3_ep0_complete_data(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_request	*r = NULL;
+	struct usb_request	*ur;
+	struct dwc3_trb		trb;
+	struct dwc3_ep		*dep;
+	u32			transferred;
+	u8			epnum;
+
+	epnum = event->endpoint_number;
+	dep = dwc->eps[epnum];
+
+	dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+
+	if (!dwc->ep0_status_pending) {
+		r = next_request(&dwc->eps[0]->request_list);
+		ur = &r->request;
+	} else {
+		ur = &dwc->ep0_usb_req;
+		dwc->ep0_status_pending = 0;
+	}
+
+	dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+
+	if (dwc->ep0_bounced) {
+		struct dwc3_ep	*ep0 = dwc->eps[0];
+
+		transferred = min_t(u32, ur->length,
+				ep0->endpoint.maxpacket - trb.length);
+		memcpy(ur->buf, dwc->ep0_bounce, transferred);
+		dwc->ep0_bounced = false;
+	} else {
+		transferred = ur->length - trb.length;
+		ur->actual += transferred;
+	}
+
+	if ((epnum & 1) && ur->actual < ur->length) {
+		/* for some reason we did not get everything out */
+
+		dwc3_ep0_stall_and_restart(dwc);
+	} else {
+		/*
+		 * handle the case where we have to send a zero packet. This
+		 * seems to be case when req.length > maxpacket. Could it be?
+		 */
+		if (r)
+			dwc3_gadget_giveback(dep, r, 0);
+	}
+}
+
+static void dwc3_ep0_complete_req(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_request	*r;
+	struct dwc3_ep		*dep;
+
+	dep = dwc->eps[0];
+
+	if (!list_empty(&dep->request_list)) {
+		r = next_request(&dep->request_list);
+
+		dwc3_gadget_giveback(dep, r, 0);
+	}
+
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
+			const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
+
+	dep->flags &= ~DWC3_EP_BUSY;
+
+	switch (dwc->ep0state) {
+	case EP0_SETUP_PHASE:
+		dev_vdbg(dwc->dev, "Inspecting Setup Bytes\n");
+		dwc3_ep0_inspect_setup(dwc, event);
+		break;
+
+	case EP0_DATA_PHASE:
+		dev_vdbg(dwc->dev, "Data Phase\n");
+		dwc3_ep0_complete_data(dwc, event);
+		break;
+
+	case EP0_STATUS_PHASE:
+		dev_vdbg(dwc->dev, "Status Phase\n");
+		dwc3_ep0_complete_req(dwc, event);
+		break;
+	default:
+		WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
+	}
+}
+
+static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep;
+	struct dwc3_request	*req;
+	int			ret;
+
+	dep = dwc->eps[0];
+	dwc->ep0state = EP0_DATA_PHASE;
+
+	if (dwc->ep0_status_pending) {
+		dwc3_ep0_send_status_response(dwc);
+		return;
+	}
+
+	if (list_empty(&dep->request_list)) {
+		dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+
+		if (event->endpoint_number)
+			dep->flags |= DWC3_EP0_DIR_IN;
+		return;
+	}
+
+	req = next_request(&dep->request_list);
+	req->direction = !!event->endpoint_number;
+
+	dwc->ep0state = EP0_DATA_PHASE;
+	if (req->request.length == 0) {
+		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+				dwc->ctrl_req_addr, 0,
+				DWC3_TRBCTL_CONTROL_DATA);
+	} else if ((req->request.length % dep->endpoint.maxpacket)
+			&& (event->endpoint_number == 0)) {
+		dwc3_map_buffer_to_dma(req);
+
+		WARN_ON(req->request.length > dep->endpoint.maxpacket);
+
+		dwc->ep0_bounced = true;
+
+		/*
+		 * REVISIT in case request length is bigger than EP0
+		 * wMaxPacketSize, we will need two chained TRBs to handle
+		 * the transfer.
+		 */
+		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+				dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
+				DWC3_TRBCTL_CONTROL_DATA);
+	} else {
+		dwc3_map_buffer_to_dma(req);
+
+		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+				req->request.dma, req->request.length,
+				DWC3_TRBCTL_CONTROL_DATA);
+	}
+
+	WARN_ON(ret < 0);
+}
+
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	u32			type;
+	int			ret;
+
+	dwc->ep0state = EP0_STATUS_PHASE;
+
+	type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
+		: DWC3_TRBCTL_CONTROL_STATUS2;
+
+	ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+			dwc->ctrl_req_addr, 0, type);
+
+	WARN_ON(ret < 0);
+}
+
+static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	switch (event->status) {
+	case DEPEVT_STATUS_CONTROL_SETUP:
+		dev_vdbg(dwc->dev, "Control Setup\n");
+		dwc3_ep0_do_control_setup(dwc, event);
+		break;
+
+	case DEPEVT_STATUS_CONTROL_DATA:
+		dev_vdbg(dwc->dev, "Control Data\n");
+
+		if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
+			dev_vdbg(dwc->dev, "Expected %d got %d\n",
+					dwc->ep0_next_event,
+					DWC3_EP0_NRDY_DATA);
+
+			dwc3_ep0_stall_and_restart(dwc);
+			return;
+		}
+
+		/*
+		 * One of the possible error cases is when Host _does_
+		 * request for Data Phase, but it does so on the wrong
+		 * direction.
+		 *
+		 * Here, we already know ep0_next_event is DATA (see above),
+		 * so we only need to check for direction.
+		 */
+		if (dwc->ep0_expect_in != event->endpoint_number) {
+			dev_vdbg(dwc->dev, "Wrong direction for Data phase\n");
+			dwc3_ep0_stall_and_restart(dwc);
+			return;
+		}
+
+		dwc3_ep0_do_control_data(dwc, event);
+		break;
+
+	case DEPEVT_STATUS_CONTROL_STATUS:
+		dev_vdbg(dwc->dev, "Control Status\n");
+
+		if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
+			dev_vdbg(dwc->dev, "Expected %d got %d\n",
+					dwc->ep0_next_event,
+					DWC3_EP0_NRDY_STATUS);
+
+			dwc3_ep0_stall_and_restart(dwc);
+			return;
+		}
+		dwc3_ep0_do_control_status(dwc, event);
+	}
+}
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+		const const struct dwc3_event_depevt *event)
+{
+	u8			epnum = event->endpoint_number;
+
+	dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n",
+			dwc3_ep_event_string(event->endpoint_event),
+			epnum >> 1, (epnum & 1) ? "in" : "out",
+			dwc3_ep0_state_string(dwc->ep0state));
+
+	switch (event->endpoint_event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		dwc3_ep0_xfer_complete(dwc, event);
+		break;
+
+	case DWC3_DEPEVT_XFERNOTREADY:
+		dwc3_ep0_xfernotready(dwc, event);
+		break;
+
+	case DWC3_DEPEVT_XFERINPROGRESS:
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+	case DWC3_DEPEVT_STREAMEVT:
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		break;
+	}
+}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
new file mode 100644
index 0000000..fa824cf
--- /dev/null
+++ b/drivers/usb/dwc3/gadget.c
@@ -0,0 +1,2104 @@
+/**
+ * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+void dwc3_map_buffer_to_dma(struct dwc3_request *req)
+{
+	struct dwc3			*dwc = req->dep->dwc;
+
+	if (req->request.length == 0) {
+		/* req->request.dma = dwc->setup_buf_addr; */
+		return;
+	}
+
+	if (req->request.dma == DMA_ADDR_INVALID) {
+		req->request.dma = dma_map_single(dwc->dev, req->request.buf,
+				req->request.length, req->direction
+				? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->mapped = true;
+	}
+}
+
+void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
+{
+	struct dwc3			*dwc = req->dep->dwc;
+
+	if (req->request.length == 0) {
+		req->request.dma = DMA_ADDR_INVALID;
+		return;
+	}
+
+	if (req->mapped) {
+		dma_unmap_single(dwc->dev, req->request.dma,
+				req->request.length, req->direction
+				? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->mapped = 0;
+		req->request.dma = DMA_ADDR_INVALID;
+	}
+}
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+		int status)
+{
+	struct dwc3			*dwc = dep->dwc;
+
+	if (req->queued) {
+		dep->busy_slot++;
+		/*
+		 * Skip LINK TRB. We can't use req->trb and check for
+		 * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
+		 * completed (not the LINK TRB).
+		 */
+		if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+				usb_endpoint_xfer_isoc(dep->desc))
+			dep->busy_slot++;
+	}
+	list_del(&req->list);
+
+	if (req->request.status == -EINPROGRESS)
+		req->request.status = status;
+
+	dwc3_unmap_buffer_from_dma(req);
+
+	dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
+			req, dep->name, req->request.actual,
+			req->request.length, status);
+
+	spin_unlock(&dwc->lock);
+	req->request.complete(&req->dep->endpoint, &req->request);
+	spin_lock(&dwc->lock);
+}
+
+static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case DWC3_DEPCMD_DEPSTARTCFG:
+		return "Start New Configuration";
+	case DWC3_DEPCMD_ENDTRANSFER:
+		return "End Transfer";
+	case DWC3_DEPCMD_UPDATETRANSFER:
+		return "Update Transfer";
+	case DWC3_DEPCMD_STARTTRANSFER:
+		return "Start Transfer";
+	case DWC3_DEPCMD_CLEARSTALL:
+		return "Clear Stall";
+	case DWC3_DEPCMD_SETSTALL:
+		return "Set Stall";
+	case DWC3_DEPCMD_GETSEQNUMBER:
+		return "Get Data Sequence Number";
+	case DWC3_DEPCMD_SETTRANSFRESOURCE:
+		return "Set Endpoint Transfer Resource";
+	case DWC3_DEPCMD_SETEPCONFIG:
+		return "Set Endpoint Configuration";
+	default:
+		return "UNKNOWN command";
+	}
+}
+
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+	struct dwc3_ep		*dep = dwc->eps[ep];
+	u32			timeout = 500;
+	u32			reg;
+
+	dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
+			dep->name,
+			dwc3_gadget_ep_cmd_string(cmd), params->param0,
+			params->param1, params->param2);
+
+	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
+	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
+	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
+
+	dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT);
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
+		if (!(reg & DWC3_DEPCMD_CMDACT)) {
+			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+					DWC3_DEPCMD_STATUS(reg));
+			return 0;
+		}
+
+		/*
+		 * We can't sleep here, because it is also called from
+		 * interrupt context.
+		 */
+		timeout--;
+		if (!timeout)
+			return -ETIMEDOUT;
+
+		udelay(1);
+	} while (1);
+}
+
+static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+		struct dwc3_trb_hw *trb)
+{
+	u32		offset = (char *) trb - (char *) dep->trb_pool;
+
+	return dep->trb_pool_dma + offset;
+}
+
+static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
+{
+	struct dwc3		*dwc = dep->dwc;
+
+	if (dep->trb_pool)
+		return 0;
+
+	if (dep->number == 0 || dep->number == 1)
+		return 0;
+
+	dep->trb_pool = dma_alloc_coherent(dwc->dev,
+			sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+			&dep->trb_pool_dma, GFP_KERNEL);
+	if (!dep->trb_pool) {
+		dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
+				dep->name);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void dwc3_free_trb_pool(struct dwc3_ep *dep)
+{
+	struct dwc3		*dwc = dep->dwc;
+
+	dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+			dep->trb_pool, dep->trb_pool_dma);
+
+	dep->trb_pool = NULL;
+	dep->trb_pool_dma = 0;
+}
+
+static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	u32			cmd;
+
+	memset(&params, 0x00, sizeof(params));
+
+	if (dep->number != 1) {
+		cmd = DWC3_DEPCMD_DEPSTARTCFG;
+		/* XferRscIdx == 0 for ep0 and 2 for the remaining */
+		if (dep->number > 1) {
+			if (dwc->start_config_issued)
+				return 0;
+			dwc->start_config_issued = true;
+			cmd |= DWC3_DEPCMD_PARAM(2);
+		}
+
+		return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+	}
+
+	return 0;
+}
+
+static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+
+	memset(&params, 0x00, sizeof(params));
+
+	params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
+		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
+		| DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst);
+
+	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
+		| DWC3_DEPCFG_XFER_NOT_READY_EN;
+
+	if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) {
+		params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
+			| DWC3_DEPCFG_STREAM_EVENT_EN;
+		dep->stream_capable = true;
+	}
+
+	if (usb_endpoint_xfer_isoc(desc))
+		params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
+
+	/*
+	 * We are doing 1:1 mapping for endpoints, meaning
+	 * Physical Endpoints 2 maps to Logical Endpoint 2 and
+	 * so on. We consider the direction bit as part of the physical
+	 * endpoint number. So USB endpoint 0x81 is 0x03.
+	 */
+	params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number);
+
+	/*
+	 * We must use the lower 16 TX FIFOs even though
+	 * HW might have more
+	 */
+	if (dep->direction)
+		params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
+
+	if (desc->bInterval) {
+		params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
+		dep->interval = 1 << (desc->bInterval - 1);
+	}
+
+	return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_SETEPCONFIG, &params);
+}
+
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+
+	memset(&params, 0x00, sizeof(params));
+
+	params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
+
+	return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_SETTRANSFRESOURCE, &params);
+}
+
+/**
+ * __dwc3_gadget_ep_enable - Initializes a HW endpoint
+ * @dep: endpoint to be initialized
+ * @desc: USB Endpoint Descriptor
+ *
+ * Caller should take care of locking
+ */
+static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct dwc3		*dwc = dep->dwc;
+	u32			reg;
+	int			ret = -ENOMEM;
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		ret = dwc3_gadget_start_config(dwc, dep);
+		if (ret)
+			return ret;
+	}
+
+	ret = dwc3_gadget_set_ep_config(dwc, dep, desc);
+	if (ret)
+		return ret;
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		struct dwc3_trb_hw	*trb_st_hw;
+		struct dwc3_trb_hw	*trb_link_hw;
+		struct dwc3_trb		trb_link;
+
+		ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+		if (ret)
+			return ret;
+
+		dep->desc = desc;
+		dep->type = usb_endpoint_type(desc);
+		dep->flags |= DWC3_EP_ENABLED;
+
+		reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+		reg |= DWC3_DALEPENA_EP(dep->number);
+		dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+		if (!usb_endpoint_xfer_isoc(desc))
+			return 0;
+
+		memset(&trb_link, 0, sizeof(trb_link));
+
+		/* Link TRB for ISOC. The HWO but is never reset */
+		trb_st_hw = &dep->trb_pool[0];
+
+		trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
+		trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
+		trb_link.hwo = true;
+
+		trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
+		dwc3_trb_to_hw(&trb_link, trb_link_hw);
+	}
+
+	return 0;
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
+static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_request		*req;
+
+	if (!list_empty(&dep->req_queued))
+		dwc3_stop_active_transfer(dwc, dep->number);
+
+	while (!list_empty(&dep->request_list)) {
+		req = next_request(&dep->request_list);
+
+		dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+	}
+}
+
+/**
+ * __dwc3_gadget_ep_disable - Disables a HW endpoint
+ * @dep: the endpoint to disable
+ *
+ * This function also removes requests which are currently processed ny the
+ * hardware and those which are not yet scheduled.
+ * Caller should take care of locking.
+ */
+static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+{
+	struct dwc3		*dwc = dep->dwc;
+	u32			reg;
+
+	dwc3_remove_requests(dwc, dep);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+	reg &= ~DWC3_DALEPENA_EP(dep->number);
+	dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+	dep->stream_capable = false;
+	dep->desc = NULL;
+	dep->type = 0;
+	dep->flags = 0;
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep0_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	return -EINVAL;
+}
+
+static int dwc3_gadget_ep0_disable(struct usb_ep *ep)
+{
+	return -EINVAL;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct dwc3_ep			*dep;
+	struct dwc3			*dwc;
+	unsigned long			flags;
+	int				ret;
+
+	if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+		pr_debug("dwc3: invalid parameters\n");
+		return -EINVAL;
+	}
+
+	if (!desc->wMaxPacketSize) {
+		pr_debug("dwc3: missing wMaxPacketSize\n");
+		return -EINVAL;
+	}
+
+	dep = to_dwc3_ep(ep);
+	dwc = dep->dwc;
+
+	switch (usb_endpoint_type(desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		strncat(dep->name, "-control", sizeof(dep->name));
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		strncat(dep->name, "-isoc", sizeof(dep->name));
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		strncat(dep->name, "-bulk", sizeof(dep->name));
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		strncat(dep->name, "-int", sizeof(dep->name));
+		break;
+	default:
+		dev_err(dwc->dev, "invalid endpoint transfer type\n");
+	}
+
+	if (dep->flags & DWC3_EP_ENABLED) {
+		dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
+				dep->name);
+		return 0;
+	}
+
+	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_enable(dep, desc);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_disable(struct usb_ep *ep)
+{
+	struct dwc3_ep			*dep;
+	struct dwc3			*dwc;
+	unsigned long			flags;
+	int				ret;
+
+	if (!ep) {
+		pr_debug("dwc3: invalid parameters\n");
+		return -EINVAL;
+	}
+
+	dep = to_dwc3_ep(ep);
+	dwc = dep->dwc;
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
+				dep->name);
+		return 0;
+	}
+
+	snprintf(dep->name, sizeof(dep->name), "ep%d%s",
+			dep->number >> 1,
+			(dep->number & 1) ? "in" : "out");
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_disable(dep);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
+	gfp_t gfp_flags)
+{
+	struct dwc3_request		*req;
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req) {
+		dev_err(dwc->dev, "not enough memory\n");
+		return NULL;
+	}
+
+	req->epnum	= dep->number;
+	req->dep	= dep;
+	req->request.dma = DMA_ADDR_INVALID;
+
+	return &req->request;
+}
+
+static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
+		struct usb_request *request)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+
+	kfree(req);
+}
+
+/*
+ * dwc3_prepare_trbs - setup TRBs from requests
+ * @dep: endpoint for which requests are being prepared
+ * @starting: true if the endpoint is idle and no requests are queued.
+ *
+ * The functions goes through the requests list and setups TRBs for the
+ * transfers. The functions returns once there are not more TRBs available or
+ * it run out of requests.
+ */
+static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
+		bool starting)
+{
+	struct dwc3_request	*req, *n, *ret = NULL;
+	struct dwc3_trb_hw	*trb_hw;
+	struct dwc3_trb		trb;
+	u32			trbs_left;
+
+	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
+
+	/* the first request must not be queued */
+	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
+	/*
+	 * if busy & slot are equal than it is either full or empty. If we are
+	 * starting to proceed requests then we are empty. Otherwise we ar
+	 * full and don't do anything
+	 */
+	if (!trbs_left) {
+		if (!starting)
+			return NULL;
+		trbs_left = DWC3_TRB_NUM;
+		/*
+		 * In case we start from scratch, we queue the ISOC requests
+		 * starting from slot 1. This is done because we use ring
+		 * buffer and have no LST bit to stop us. Instead, we place
+		 * IOC bit TRB_NUM/4. We try to avoid to having an interrupt
+		 * after the first request so we start at slot 1 and have
+		 * 7 requests proceed before we hit the first IOC.
+		 * Other transfer types don't use the ring buffer and are
+		 * processed from the first TRB until the last one. Since we
+		 * don't wrap around we have to start at the beginning.
+		 */
+		if (usb_endpoint_xfer_isoc(dep->desc)) {
+			dep->busy_slot = 1;
+			dep->free_slot = 1;
+		} else {
+			dep->busy_slot = 0;
+			dep->free_slot = 0;
+		}
+	}
+
+	/* The last TRB is a link TRB, not used for xfer */
+	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
+		return NULL;
+
+	list_for_each_entry_safe(req, n, &dep->request_list, list) {
+		unsigned int last_one = 0;
+		unsigned int cur_slot;
+
+		trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+		cur_slot = dep->free_slot;
+		dep->free_slot++;
+
+		/* Skip the LINK-TRB on ISOC */
+		if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+				usb_endpoint_xfer_isoc(dep->desc))
+			continue;
+
+		dwc3_gadget_move_request_queued(req);
+		memset(&trb, 0, sizeof(trb));
+		trbs_left--;
+
+		/* Is our TRB pool empty? */
+		if (!trbs_left)
+			last_one = 1;
+		/* Is this the last request? */
+		if (list_empty(&dep->request_list))
+			last_one = 1;
+
+		/*
+		 * FIXME we shouldn't need to set LST bit always but we are
+		 * facing some weird problem with the Hardware where it doesn't
+		 * complete even though it has been previously started.
+		 *
+		 * While we're debugging the problem, as a workaround to
+		 * multiple TRBs handling, use only one TRB at a time.
+		 */
+		last_one = 1;
+
+		req->trb = trb_hw;
+		if (!ret)
+			ret = req;
+
+		trb.bplh = req->request.dma;
+
+		if (usb_endpoint_xfer_isoc(dep->desc)) {
+			trb.isp_imi = true;
+			trb.csp = true;
+		} else {
+			trb.lst = last_one;
+		}
+
+		if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+			trb.sid_sofn = req->request.stream_id;
+
+		switch (usb_endpoint_type(dep->desc)) {
+		case USB_ENDPOINT_XFER_CONTROL:
+			trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+			break;
+
+		case USB_ENDPOINT_XFER_ISOC:
+			trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+
+			/* IOC every DWC3_TRB_NUM / 4 so we can refill */
+			if (!(cur_slot % (DWC3_TRB_NUM / 4)))
+				trb.ioc = last_one;
+			break;
+
+		case USB_ENDPOINT_XFER_BULK:
+		case USB_ENDPOINT_XFER_INT:
+			trb.trbctl = DWC3_TRBCTL_NORMAL;
+			break;
+		default:
+			/*
+			 * This is only possible with faulty memory because we
+			 * checked it already :)
+			 */
+			BUG();
+		}
+
+		trb.length	= req->request.length;
+		trb.hwo = true;
+
+		dwc3_trb_to_hw(&trb, trb_hw);
+		req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+
+		if (last_one)
+			break;
+	}
+
+	return ret;
+}
+
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+		int start_new)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_request		*req;
+	struct dwc3			*dwc = dep->dwc;
+	int				ret;
+	u32				cmd;
+
+	if (start_new && (dep->flags & DWC3_EP_BUSY)) {
+		dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
+		return -EBUSY;
+	}
+	dep->flags &= ~DWC3_EP_PENDING_REQUEST;
+
+	/*
+	 * If we are getting here after a short-out-packet we don't enqueue any
+	 * new requests as we try to set the IOC bit only on the last request.
+	 */
+	if (start_new) {
+		if (list_empty(&dep->req_queued))
+			dwc3_prepare_trbs(dep, start_new);
+
+		/* req points to the first request which will be sent */
+		req = next_request(&dep->req_queued);
+	} else {
+		/*
+		 * req points to the first request where HWO changed
+		 * from 0 to 1
+		 */
+		req = dwc3_prepare_trbs(dep, start_new);
+	}
+	if (!req) {
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+		return 0;
+	}
+
+	memset(&params, 0, sizeof(params));
+	params.param0 = upper_32_bits(req->trb_dma);
+	params.param1 = lower_32_bits(req->trb_dma);
+
+	if (start_new)
+		cmd = DWC3_DEPCMD_STARTTRANSFER;
+	else
+		cmd = DWC3_DEPCMD_UPDATETRANSFER;
+
+	cmd |= DWC3_DEPCMD_PARAM(cmd_param);
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+	if (ret < 0) {
+		dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+
+		/*
+		 * FIXME we need to iterate over the list of requests
+		 * here and stop, unmap, free and del each of the linked
+		 * requests instead of we do now.
+		 */
+		dwc3_unmap_buffer_from_dma(req);
+		list_del(&req->list);
+		return ret;
+	}
+
+	dep->flags |= DWC3_EP_BUSY;
+	dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+			dep->number);
+	if (!dep->res_trans_idx)
+		printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__);
+	return 0;
+}
+
+static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
+{
+	req->request.actual	= 0;
+	req->request.status	= -EINPROGRESS;
+	req->direction		= dep->direction;
+	req->epnum		= dep->number;
+
+	/*
+	 * We only add to our list of requests now and
+	 * start consuming the list once we get XferNotReady
+	 * IRQ.
+	 *
+	 * That way, we avoid doing anything that we don't need
+	 * to do now and defer it until the point we receive a
+	 * particular token from the Host side.
+	 *
+	 * This will also avoid Host cancelling URBs due to too
+	 * many NACKs.
+	 */
+	dwc3_map_buffer_to_dma(req);
+	list_add_tail(&req->list, &dep->request_list);
+
+	/*
+	 * There is one special case: XferNotReady with
+	 * empty list of requests. We need to kick the
+	 * transfer here in that situation, otherwise
+	 * we will be NAKing forever.
+	 *
+	 * If we get XferNotReady before gadget driver
+	 * has a chance to queue a request, we will ACK
+	 * the IRQ but won't be able to receive the data
+	 * until the next request is queued. The following
+	 * code is handling exactly that.
+	 */
+	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+		int ret;
+		int start_trans;
+
+		start_trans = 1;
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+				dep->flags & DWC3_EP_BUSY)
+			start_trans = 0;
+
+		ret =  __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+		if (ret && ret != -EBUSY) {
+			struct dwc3	*dwc = dep->dwc;
+
+			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+					dep->name);
+		}
+	};
+
+	return 0;
+}
+
+static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
+	gfp_t gfp_flags)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+
+	int				ret;
+
+	if (!dep->desc) {
+		dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+				request, ep->name);
+		return -ESHUTDOWN;
+	}
+
+	dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
+			request, ep->name, request->length);
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_queue(dep, req);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
+		struct usb_request *request)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+	struct dwc3_request		*r = NULL;
+
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+	int				ret = 0;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	list_for_each_entry(r, &dep->request_list, list) {
+		if (r == req)
+			break;
+	}
+
+	if (r != req) {
+		list_for_each_entry(r, &dep->req_queued, list) {
+			if (r == req)
+				break;
+		}
+		if (r == req) {
+			/* wait until it is processed */
+			dwc3_stop_active_transfer(dwc, dep->number);
+			goto out0;
+		}
+		dev_err(dwc->dev, "request %p was not queued to %s\n",
+				request, ep->name);
+		ret = -EINVAL;
+		goto out0;
+	}
+
+	/* giveback the request */
+	dwc3_gadget_giveback(dep, req, -ECONNRESET);
+
+out0:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
+{
+	struct dwc3_gadget_ep_cmd_params	params;
+	struct dwc3				*dwc = dep->dwc;
+	int					ret;
+
+	memset(&params, 0x00, sizeof(params));
+
+	if (value) {
+		if (dep->number == 0 || dep->number == 1) {
+			/*
+			 * Whenever EP0 is stalled, we will restart
+			 * the state machine, thus moving back to
+			 * Setup Phase
+			 */
+			dwc->ep0state = EP0_SETUP_PHASE;
+		}
+
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_SETSTALL, &params);
+		if (ret)
+			dev_err(dwc->dev, "failed to %s STALL on %s\n",
+					value ? "set" : "clear",
+					dep->name);
+		else
+			dep->flags |= DWC3_EP_STALL;
+	} else {
+		if (dep->flags & DWC3_EP_WEDGE)
+			return 0;
+
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_CLEARSTALL, &params);
+		if (ret)
+			dev_err(dwc->dev, "failed to %s STALL on %s\n",
+					value ? "set" : "clear",
+					dep->name);
+		else
+			dep->flags &= ~DWC3_EP_STALL;
+	}
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	if (usb_endpoint_xfer_isoc(dep->desc)) {
+		dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = __dwc3_gadget_ep_set_halt(dep, value);
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+
+	dep->flags |= DWC3_EP_WEDGE;
+
+	return dwc3_gadget_ep_set_halt(ep, 1);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
+	.bLength	= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bmAttributes	= USB_ENDPOINT_XFER_CONTROL,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
+	.enable		= dwc3_gadget_ep0_enable,
+	.disable	= dwc3_gadget_ep0_disable,
+	.alloc_request	= dwc3_gadget_ep_alloc_request,
+	.free_request	= dwc3_gadget_ep_free_request,
+	.queue		= dwc3_gadget_ep0_queue,
+	.dequeue	= dwc3_gadget_ep_dequeue,
+	.set_halt	= dwc3_gadget_ep_set_halt,
+	.set_wedge	= dwc3_gadget_ep_set_wedge,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep_ops = {
+	.enable		= dwc3_gadget_ep_enable,
+	.disable	= dwc3_gadget_ep_disable,
+	.alloc_request	= dwc3_gadget_ep_alloc_request,
+	.free_request	= dwc3_gadget_ep_free_request,
+	.queue		= dwc3_gadget_ep_queue,
+	.dequeue	= dwc3_gadget_ep_dequeue,
+	.set_halt	= dwc3_gadget_ep_set_halt,
+	.set_wedge	= dwc3_gadget_ep_set_wedge,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_get_frame(struct usb_gadget *g)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	u32			reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	return DWC3_DSTS_SOFFN(reg);
+}
+
+static int dwc3_gadget_wakeup(struct usb_gadget *g)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+
+	unsigned long		timeout;
+	unsigned long		flags;
+
+	u32			reg;
+
+	int			ret = 0;
+
+	u8			link_state;
+	u8			speed;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	/*
+	 * According to the Databook Remote wakeup request should
+	 * be issued only when the device is in early suspend state.
+	 *
+	 * We can check that via USB Link State bits in DSTS register.
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+	speed = reg & DWC3_DSTS_CONNECTSPD;
+	if (speed == DWC3_DSTS_SUPERSPEED) {
+		dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	link_state = DWC3_DSTS_USBLNKST(reg);
+
+	switch (link_state) {
+	case DWC3_LINK_STATE_RX_DET:	/* in HS, means Early Suspend */
+	case DWC3_LINK_STATE_U3:	/* in HS, means SUSPEND */
+		break;
+	default:
+		dev_dbg(dwc->dev, "can't wakeup from link state %d\n",
+				link_state);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+
+	/*
+	 * Switch link state to Recovery. In HS/FS/LS this means
+	 * RemoteWakeup Request
+	 */
+	reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	/* wait for at least 2000us */
+	usleep_range(2000, 2500);
+
+	/* write zeroes to Link Change Request */
+	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	/* pool until Link State change to ON */
+	timeout = jiffies + msecs_to_jiffies(100);
+
+	while (!(time_after(jiffies, timeout))) {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+		/* in HS, means ON */
+		if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0)
+			break;
+	}
+
+	if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
+		dev_err(dwc->dev, "failed to send remote wakeup\n");
+		ret = -EINVAL;
+	}
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
+		int is_selfpowered)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+
+	dwc->is_selfpowered = !!is_selfpowered;
+
+	return 0;
+}
+
+static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+{
+	u32			reg;
+	u32			timeout = 500;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	if (is_on)
+		reg |= DWC3_DCTL_RUN_STOP;
+	else
+		reg &= ~DWC3_DCTL_RUN_STOP;
+
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+		if (is_on) {
+			if (!(reg & DWC3_DSTS_DEVCTRLHLT))
+				break;
+		} else {
+			if (reg & DWC3_DSTS_DEVCTRLHLT)
+				break;
+		}
+		timeout--;
+		if (!timeout)
+			break;
+		udelay(1);
+	} while (1);
+
+	dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
+			dwc->gadget_driver
+			? dwc->gadget_driver->function : "no-function",
+			is_on ? "connect" : "disconnect");
+}
+
+static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+
+	is_on = !!is_on;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_gadget_run_stop(dwc, is_on);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static int dwc3_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	struct dwc3_ep		*dep;
+	unsigned long		flags;
+	int			ret = 0;
+	u32			reg;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	if (dwc->gadget_driver) {
+		dev_err(dwc->dev, "%s is already bound to %s\n",
+				dwc->gadget.name,
+				dwc->gadget_driver->driver.name);
+		ret = -EBUSY;
+		goto err0;
+	}
+
+	dwc->gadget_driver	= driver;
+	dwc->gadget.dev.driver	= &driver->driver;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+
+	reg &= ~DWC3_GCTL_SCALEDOWN(3);
+	reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG);
+	reg &= ~DWC3_GCTL_DISSCRAMBLE;
+	reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+
+	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) {
+	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
+		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+		break;
+	default:
+		dev_dbg(dwc->dev, "No power optimization available\n");
+	}
+
+	/*
+	 * WORKAROUND: DWC3 revisions <1.90a have a bug
+	 * when The device fails to connect at SuperSpeed
+	 * and falls back to high-speed mode which causes
+	 * the device to enter in a Connect/Disconnect loop
+	 */
+	if (dwc->revision < DWC3_REVISION_190A)
+		reg |= DWC3_GCTL_U2RSTECN;
+
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_SPEED_MASK);
+	reg |= DWC3_DCFG_SUPERSPEED;
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	dwc->start_config_issued = false;
+
+	/* Start with SuperSpeed Default */
+	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+	dep = dwc->eps[0];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		goto err0;
+	}
+
+	dep = dwc->eps[1];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		goto err1;
+	}
+
+	/* begin to receive SETUP packets */
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+
+err1:
+	__dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	__dwc3_gadget_ep_disable(dwc->eps[0]);
+	__dwc3_gadget_ep_disable(dwc->eps[1]);
+
+	dwc->gadget_driver	= NULL;
+	dwc->gadget.dev.driver	= NULL;
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+static const struct usb_gadget_ops dwc3_gadget_ops = {
+	.get_frame		= dwc3_gadget_get_frame,
+	.wakeup			= dwc3_gadget_wakeup,
+	.set_selfpowered	= dwc3_gadget_set_selfpowered,
+	.pullup			= dwc3_gadget_pullup,
+	.udc_start		= dwc3_gadget_start,
+	.udc_stop		= dwc3_gadget_stop,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+{
+	struct dwc3_ep			*dep;
+	u8				epnum;
+
+	INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+	for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+		if (!dep) {
+			dev_err(dwc->dev, "can't allocate endpoint %d\n",
+					epnum);
+			return -ENOMEM;
+		}
+
+		dep->dwc = dwc;
+		dep->number = epnum;
+		dwc->eps[epnum] = dep;
+
+		snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
+				(epnum & 1) ? "in" : "out");
+		dep->endpoint.name = dep->name;
+		dep->direction = (epnum & 1);
+
+		if (epnum == 0 || epnum == 1) {
+			dep->endpoint.maxpacket = 512;
+			dep->endpoint.ops = &dwc3_gadget_ep0_ops;
+			if (!epnum)
+				dwc->gadget.ep0 = &dep->endpoint;
+		} else {
+			int		ret;
+
+			dep->endpoint.maxpacket = 1024;
+			dep->endpoint.ops = &dwc3_gadget_ep_ops;
+			list_add_tail(&dep->endpoint.ep_list,
+					&dwc->gadget.ep_list);
+
+			ret = dwc3_alloc_trb_pool(dep);
+			if (ret) {
+				dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name);
+				return ret;
+			}
+		}
+		INIT_LIST_HEAD(&dep->request_list);
+		INIT_LIST_HEAD(&dep->req_queued);
+	}
+
+	return 0;
+}
+
+static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
+{
+	struct dwc3_ep			*dep;
+	u8				epnum;
+
+	for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		dep = dwc->eps[epnum];
+		dwc3_free_trb_pool(dep);
+
+		if (epnum != 0 && epnum != 1)
+			list_del(&dep->endpoint.ep_list);
+
+		kfree(dep);
+	}
+}
+
+static void dwc3_gadget_release(struct device *dev)
+{
+	dev_dbg(dev, "%s\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event, int status)
+{
+	struct dwc3_request	*req;
+	struct dwc3_trb         trb;
+	unsigned int		count;
+	unsigned int		s_pkt = 0;
+
+	do {
+		req = next_request(&dep->req_queued);
+		if (!req)
+			break;
+
+		dwc3_trb_to_nat(req->trb, &trb);
+
+		if (trb.hwo && status != -ESHUTDOWN)
+			/*
+			 * We continue despite the error. There is not much we
+			 * can do. If we don't clean in up we loop for ever. If
+			 * we skip the TRB than it gets overwritten reused after
+			 * a while since we use them in a ring buffer. a BUG()
+			 * would help. Lets hope that if this occures, someone
+			 * fixes the root cause instead of looking away :)
+			 */
+			dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
+					dep->name, req->trb);
+		count = trb.length;
+
+		if (dep->direction) {
+			if (count) {
+				dev_err(dwc->dev, "incomplete IN transfer %s\n",
+						dep->name);
+				status = -ECONNRESET;
+			}
+		} else {
+			if (count && (event->status & DEPEVT_STATUS_SHORT))
+				s_pkt = 1;
+		}
+
+		/*
+		 * We assume here we will always receive the entire data block
+		 * which we should receive. Meaning, if we program RX to
+		 * receive 4K but we receive only 2K, we assume that's all we
+		 * should receive and we simply bounce the request back to the
+		 * gadget driver for further processing.
+		 */
+		req->request.actual += req->request.length - count;
+		dwc3_gadget_giveback(dep, req, status);
+		if (s_pkt)
+			break;
+		if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+			break;
+		if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+			break;
+	} while (1);
+
+	if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+		return 0;
+	return 1;
+}
+
+static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
+		struct dwc3_ep *dep, const struct dwc3_event_depevt *event,
+		int start_new)
+{
+	unsigned		status = 0;
+	int			clean_busy;
+
+	if (event->status & DEPEVT_STATUS_BUSERR)
+		status = -ECONNRESET;
+
+	clean_busy =  dwc3_cleanup_done_reqs(dwc, dep, event, status);
+	if (clean_busy) {
+		dep->flags &= ~DWC3_EP_BUSY;
+		dep->res_trans_idx = 0;
+	}
+}
+
+static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
+		struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+{
+	u32 uf;
+
+	if (list_empty(&dep->request_list)) {
+		dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
+			dep->name);
+		return;
+	}
+
+	if (event->parameters) {
+		u32 mask;
+
+		mask = ~(dep->interval - 1);
+		uf = event->parameters & mask;
+		/* 4 micro frames in the future */
+		uf += dep->interval * 4;
+	} else {
+		uf = 0;
+	}
+
+	__dwc3_gadget_kick_transfer(dep, uf, 1);
+}
+
+static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3 *dwc = dep->dwc;
+	struct dwc3_event_depevt mod_ev = *event;
+
+	/*
+	 * We were asked to remove one requests. It is possible that this
+	 * request and a few other were started together and have the same
+	 * transfer index. Since we stopped the complete endpoint we don't
+	 * know how many requests were already completed (and not yet)
+	 * reported and how could be done (later). We purge them all until
+	 * the end of the list.
+	 */
+	mod_ev.status = DEPEVT_STATUS_LST;
+	dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
+	dep->flags &= ~DWC3_EP_BUSY;
+	/* pending requets are ignored and are queued on XferNotReady */
+}
+
+static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	u32 param = event->parameters;
+	u32 cmd_type = (param >> 8) & ((1 << 5) - 1);
+
+	switch (cmd_type) {
+	case DWC3_DEPCMD_ENDTRANSFER:
+		dwc3_process_ep_cmd_complete(dep, event);
+		break;
+	case DWC3_DEPCMD_STARTTRANSFER:
+		dep->res_trans_idx = param & 0x7f;
+		break;
+	default:
+		printk(KERN_ERR "%s() unknown /unexpected type: %d\n",
+				__func__, cmd_type);
+		break;
+	};
+}
+
+static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep;
+	u8			epnum = event->endpoint_number;
+
+	dep = dwc->eps[epnum];
+
+	dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
+			dwc3_ep_event_string(event->endpoint_event));
+
+	if (epnum == 0 || epnum == 1) {
+		dwc3_ep0_interrupt(dwc, event);
+		return;
+	}
+
+	switch (event->endpoint_event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		if (usb_endpoint_xfer_isoc(dep->desc)) {
+			dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
+					dep->name);
+			return;
+		}
+
+		dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
+		break;
+	case DWC3_DEPEVT_XFERINPROGRESS:
+		if (!usb_endpoint_xfer_isoc(dep->desc)) {
+			dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
+					dep->name);
+			return;
+		}
+
+		dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
+		break;
+	case DWC3_DEPEVT_XFERNOTREADY:
+		if (usb_endpoint_xfer_isoc(dep->desc)) {
+			dwc3_gadget_start_isoc(dwc, dep, event);
+		} else {
+			int ret;
+
+			dev_vdbg(dwc->dev, "%s: reason %s\n",
+					dep->name, event->status
+					? "Transfer Active"
+					: "Transfer Not Active");
+
+			ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
+			if (!ret || ret == -EBUSY)
+				return;
+
+			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+					dep->name);
+		}
+
+		break;
+	case DWC3_DEPEVT_STREAMEVT:
+		if (!usb_endpoint_xfer_bulk(dep->desc)) {
+			dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
+					dep->name);
+			return;
+		}
+
+		switch (event->status) {
+		case DEPEVT_STREAMEVT_FOUND:
+			dev_vdbg(dwc->dev, "Stream %d found and started\n",
+					event->parameters);
+
+			break;
+		case DEPEVT_STREAMEVT_NOTFOUND:
+			/* FALLTHROUGH */
+		default:
+			dev_dbg(dwc->dev, "Couldn't find suitable stream\n");
+		}
+		break;
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+		dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
+		break;
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		dwc3_ep_cmd_compl(dep, event);
+		break;
+	}
+}
+
+static void dwc3_disconnect_gadget(struct dwc3 *dwc)
+{
+	if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
+		spin_unlock(&dwc->lock);
+		dwc->gadget_driver->disconnect(&dwc->gadget);
+		spin_lock(&dwc->lock);
+	}
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
+{
+	struct dwc3_ep *dep;
+	struct dwc3_gadget_ep_cmd_params params;
+	u32 cmd;
+	int ret;
+
+	dep = dwc->eps[epnum];
+
+	WARN_ON(!dep->res_trans_idx);
+	if (dep->res_trans_idx) {
+		cmd = DWC3_DEPCMD_ENDTRANSFER;
+		cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
+		cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
+		memset(&params, 0, sizeof(params));
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+		WARN_ON_ONCE(ret);
+		dep->res_trans_idx = 0;
+	}
+}
+
+static void dwc3_stop_active_transfers(struct dwc3 *dwc)
+{
+	u32 epnum;
+
+	for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		struct dwc3_ep *dep;
+
+		dep = dwc->eps[epnum];
+		if (!(dep->flags & DWC3_EP_ENABLED))
+			continue;
+
+		dwc3_remove_requests(dwc, dep);
+	}
+}
+
+static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
+{
+	u32 epnum;
+
+	for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		struct dwc3_ep *dep;
+		struct dwc3_gadget_ep_cmd_params params;
+		int ret;
+
+		dep = dwc->eps[epnum];
+
+		if (!(dep->flags & DWC3_EP_STALL))
+			continue;
+
+		dep->flags &= ~DWC3_EP_STALL;
+
+		memset(&params, 0, sizeof(params));
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+				DWC3_DEPCMD_CLEARSTALL, &params);
+		WARN_ON_ONCE(ret);
+	}
+}
+
+static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
+{
+	dev_vdbg(dwc->dev, "%s\n", __func__);
+#if 0
+	XXX
+	U1/U2 is powersave optimization. Skip it for now. Anyway we need to
+	enable it before we can disable it.
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_INITU1ENA;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	reg &= ~DWC3_DCTL_INITU2ENA;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+#endif
+
+	dwc3_stop_active_transfers(dwc);
+	dwc3_disconnect_gadget(dwc);
+	dwc->start_config_issued = false;
+
+	dwc->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
+{
+	u32			reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+	if (on)
+		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+	else
+		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+}
+
+static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
+{
+	u32			reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+	if (on)
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+	else
+		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
+static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
+{
+	u32			reg;
+
+	dev_vdbg(dwc->dev, "%s\n", __func__);
+
+	/* Enable PHYs */
+	dwc3_gadget_usb2_phy_power(dwc, true);
+	dwc3_gadget_usb3_phy_power(dwc, true);
+
+	if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
+		dwc3_disconnect_gadget(dwc);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	dwc3_stop_active_transfers(dwc);
+	dwc3_clear_stall_all_ep(dwc);
+	dwc->start_config_issued = false;
+
+	/* Reset device address to zero */
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
+static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
+{
+	u32 reg;
+	u32 usb30_clock = DWC3_GCTL_CLK_BUS;
+
+	/*
+	 * We change the clock only at SS but I dunno why I would want to do
+	 * this. Maybe it becomes part of the power saving plan.
+	 */
+
+	if (speed != DWC3_DSTS_SUPERSPEED)
+		return;
+
+	/*
+	 * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
+	 * each time on Connect Done.
+	 */
+	if (!usb30_clock)
+		return;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock);
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
+{
+	switch (speed) {
+	case USB_SPEED_SUPER:
+		dwc3_gadget_usb2_phy_power(dwc, false);
+		break;
+	case USB_SPEED_HIGH:
+	case USB_SPEED_FULL:
+	case USB_SPEED_LOW:
+		dwc3_gadget_usb3_phy_power(dwc, false);
+		break;
+	}
+}
+
+static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_ep		*dep;
+	int			ret;
+	u32			reg;
+	u8			speed;
+
+	dev_vdbg(dwc->dev, "%s\n", __func__);
+
+	memset(&params, 0x00, sizeof(params));
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	speed = reg & DWC3_DSTS_CONNECTSPD;
+	dwc->speed = speed;
+
+	dwc3_update_ram_clk_sel(dwc, speed);
+
+	switch (speed) {
+	case DWC3_DCFG_SUPERSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+		dwc->gadget.ep0->maxpacket = 512;
+		dwc->gadget.speed = USB_SPEED_SUPER;
+		break;
+	case DWC3_DCFG_HIGHSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+		dwc->gadget.ep0->maxpacket = 64;
+		dwc->gadget.speed = USB_SPEED_HIGH;
+		break;
+	case DWC3_DCFG_FULLSPEED2:
+	case DWC3_DCFG_FULLSPEED1:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+		dwc->gadget.ep0->maxpacket = 64;
+		dwc->gadget.speed = USB_SPEED_FULL;
+		break;
+	case DWC3_DCFG_LOWSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
+		dwc->gadget.ep0->maxpacket = 8;
+		dwc->gadget.speed = USB_SPEED_LOW;
+		break;
+	}
+
+	/* Disable unneded PHY */
+	dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
+
+	dep = dwc->eps[0];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		return;
+	}
+
+	dep = dwc->eps[1];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		return;
+	}
+
+	/*
+	 * Configure PHY via GUSB3PIPECTLn if required.
+	 *
+	 * Update GTXFIFOSIZn
+	 *
+	 * In both cases reset values should be sufficient.
+	 */
+}
+
+static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
+{
+	dev_vdbg(dwc->dev, "%s\n", __func__);
+
+	/*
+	 * TODO take core out of low power mode when that's
+	 * implemented.
+	 */
+
+	dwc->gadget_driver->resume(&dwc->gadget);
+}
+
+static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
+		unsigned int evtinfo)
+{
+	/*  The fith bit says SuperSpeed yes or no. */
+	dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
+
+	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
+}
+
+static void dwc3_gadget_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_devt *event)
+{
+	switch (event->type) {
+	case DWC3_DEVICE_EVENT_DISCONNECT:
+		dwc3_gadget_disconnect_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_RESET:
+		dwc3_gadget_reset_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_CONNECT_DONE:
+		dwc3_gadget_conndone_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_WAKEUP:
+		dwc3_gadget_wakeup_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+		dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
+		break;
+	case DWC3_DEVICE_EVENT_EOPF:
+		dev_vdbg(dwc->dev, "End of Periodic Frame\n");
+		break;
+	case DWC3_DEVICE_EVENT_SOF:
+		dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
+		break;
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		dev_vdbg(dwc->dev, "Erratic Error\n");
+		break;
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+		dev_vdbg(dwc->dev, "Command Complete\n");
+		break;
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		dev_vdbg(dwc->dev, "Overflow\n");
+		break;
+	default:
+		dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
+	}
+}
+
+static void dwc3_process_event_entry(struct dwc3 *dwc,
+		const union dwc3_event *event)
+{
+	/* Endpoint IRQ, handle it and return early */
+	if (event->type.is_devspec == 0) {
+		/* depevt */
+		return dwc3_endpoint_interrupt(dwc, &event->depevt);
+	}
+
+	switch (event->type.type) {
+	case DWC3_EVENT_TYPE_DEV:
+		dwc3_gadget_interrupt(dwc, &event->devt);
+		break;
+	/* REVISIT what to do with Carkit and I2C events ? */
+	default:
+		dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw);
+	}
+}
+
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+{
+	struct dwc3_event_buffer *evt;
+	int left;
+	u32 count;
+
+	count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
+	count &= DWC3_GEVNTCOUNT_MASK;
+	if (!count)
+		return IRQ_NONE;
+
+	evt = dwc->ev_buffs[buf];
+	left = count;
+
+	while (left > 0) {
+		union dwc3_event event;
+
+		memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
+		dwc3_process_event_entry(dwc, &event);
+		/*
+		 * XXX we wrap around correctly to the next entry as almost all
+		 * entries are 4 bytes in size. There is one entry which has 12
+		 * bytes which is a regular entry followed by 8 bytes data. ATM
+		 * I don't know how things are organized if were get next to the
+		 * a boundary so I worry about that once we try to handle that.
+		 */
+		evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+		left -= 4;
+
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
+{
+	struct dwc3			*dwc = _dwc;
+	int				i;
+	irqreturn_t			ret = IRQ_NONE;
+
+	spin_lock(&dwc->lock);
+
+	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+		irqreturn_t status;
+
+		status = dwc3_process_event_buf(dwc, i);
+		if (status == IRQ_HANDLED)
+			ret = status;
+	}
+
+	spin_unlock(&dwc->lock);
+
+	return ret;
+}
+
+/**
+ * dwc3_gadget_init - Initializes gadget related registers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+int __devinit dwc3_gadget_init(struct dwc3 *dwc)
+{
+	u32					reg;
+	int					ret;
+	int					irq;
+
+	dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+			&dwc->ctrl_req_addr, GFP_KERNEL);
+	if (!dwc->ctrl_req) {
+		dev_err(dwc->dev, "failed to allocate ctrl request\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+			&dwc->ep0_trb_addr, GFP_KERNEL);
+	if (!dwc->ep0_trb) {
+		dev_err(dwc->dev, "failed to allocate ep0 trb\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	dwc->setup_buf = dma_alloc_coherent(dwc->dev,
+			sizeof(*dwc->setup_buf) * 2,
+			&dwc->setup_buf_addr, GFP_KERNEL);
+	if (!dwc->setup_buf) {
+		dev_err(dwc->dev, "failed to allocate setup buffer\n");
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
+			512, &dwc->ep0_bounce_addr, GFP_KERNEL);
+	if (!dwc->ep0_bounce) {
+		dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
+		ret = -ENOMEM;
+		goto err3;
+	}
+
+	dev_set_name(&dwc->gadget.dev, "gadget");
+
+	dwc->gadget.ops			= &dwc3_gadget_ops;
+	dwc->gadget.is_dualspeed	= true;
+	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
+	dwc->gadget.dev.parent		= dwc->dev;
+
+	dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
+
+	dwc->gadget.dev.dma_parms	= dwc->dev->dma_parms;
+	dwc->gadget.dev.dma_mask	= dwc->dev->dma_mask;
+	dwc->gadget.dev.release		= dwc3_gadget_release;
+	dwc->gadget.name		= "dwc3-gadget";
+
+	/*
+	 * REVISIT: Here we should clear all pending IRQs to be
+	 * sure we're starting from a well known location.
+	 */
+
+	ret = dwc3_gadget_init_endpoints(dwc);
+	if (ret)
+		goto err4;
+
+	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+	ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
+			"dwc3", dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+				irq, ret);
+		goto err5;
+	}
+
+	/* Enable all but Start and End of Frame IRQs */
+	reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+			DWC3_DEVTEN_EVNTOVERFLOWEN |
+			DWC3_DEVTEN_CMDCMPLTEN |
+			DWC3_DEVTEN_ERRTICERREN |
+			DWC3_DEVTEN_WKUPEVTEN |
+			DWC3_DEVTEN_ULSTCNGEN |
+			DWC3_DEVTEN_CONNECTDONEEN |
+			DWC3_DEVTEN_USBRSTEN |
+			DWC3_DEVTEN_DISCONNEVTEN);
+	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+
+	ret = device_register(&dwc->gadget.dev);
+	if (ret) {
+		dev_err(dwc->dev, "failed to register gadget device\n");
+		put_device(&dwc->gadget.dev);
+		goto err6;
+	}
+
+	ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+	if (ret) {
+		dev_err(dwc->dev, "failed to register udc\n");
+		goto err7;
+	}
+
+	return 0;
+
+err7:
+	device_unregister(&dwc->gadget.dev);
+
+err6:
+	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+	free_irq(irq, dwc);
+
+err5:
+	dwc3_gadget_free_endpoints(dwc);
+
+err4:
+	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
+			dwc->ep0_bounce_addr);
+
+err3:
+	dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+			dwc->setup_buf, dwc->setup_buf_addr);
+
+err2:
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+			dwc->ep0_trb, dwc->ep0_trb_addr);
+
+err1:
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+			dwc->ctrl_req, dwc->ctrl_req_addr);
+
+err0:
+	return ret;
+}
+
+void dwc3_gadget_exit(struct dwc3 *dwc)
+{
+	int			irq;
+	int			i;
+
+	usb_del_gadget_udc(&dwc->gadget);
+	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+	free_irq(irq, dwc);
+
+	for (i = 0; i < ARRAY_SIZE(dwc->eps); i++)
+		__dwc3_gadget_ep_disable(dwc->eps[i]);
+
+	dwc3_gadget_free_endpoints(dwc);
+
+	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
+			dwc->ep0_bounce_addr);
+
+	dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+			dwc->setup_buf, dwc->setup_buf_addr);
+
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+			dwc->ep0_trb, dwc->ep0_trb_addr);
+
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+			dwc->ctrl_req, dwc->ctrl_req_addr);
+
+	device_unregister(&dwc->gadget.dev);
+}
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
new file mode 100644
index 0000000..71145a44
--- /dev/null
+++ b/drivers/usb/dwc3/gadget.h
@@ -0,0 +1,211 @@
+/**
+ * gadget.h - DesignWare USB3 DRD Gadget Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_GADGET_H
+#define __DRIVERS_USB_DWC3_GADGET_H
+
+#include <linux/list.h>
+#include <linux/usb/gadget.h>
+#include "io.h"
+
+struct dwc3;
+#define to_dwc3_ep(ep)		(container_of(ep, struct dwc3_ep, endpoint))
+#define gadget_to_dwc(g)	(container_of(g, struct dwc3, gadget))
+
+/* DEPCFG parameter 1 */
+#define DWC3_DEPCFG_INT_NUM(n)		((n) << 0)
+#define DWC3_DEPCFG_XFER_COMPLETE_EN	(1 << 8)
+#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN	(1 << 9)
+#define DWC3_DEPCFG_XFER_NOT_READY_EN	(1 << 10)
+#define DWC3_DEPCFG_FIFO_ERROR_EN	(1 << 11)
+#define DWC3_DEPCFG_STREAM_EVENT_EN	(1 << 13)
+#define DWC3_DEPCFG_BINTERVAL_M1(n)	((n) << 16)
+#define DWC3_DEPCFG_STREAM_CAPABLE	(1 << 24)
+#define DWC3_DEPCFG_EP_NUMBER(n)	((n) << 25)
+#define DWC3_DEPCFG_BULK_BASED		(1 << 30)
+#define DWC3_DEPCFG_FIFO_BASED		(1 << 31)
+
+/* DEPCFG parameter 0 */
+#define DWC3_DEPCFG_EP_TYPE(n)		((n) << 1)
+#define DWC3_DEPCFG_MAX_PACKET_SIZE(n)	((n) << 3)
+#define DWC3_DEPCFG_FIFO_NUMBER(n)	((n) << 17)
+#define DWC3_DEPCFG_BURST_SIZE(n)	((n) << 22)
+#define DWC3_DEPCFG_DATA_SEQ_NUM(n)	((n) << 26)
+#define DWC3_DEPCFG_IGN_SEQ_NUM		(1 << 31)
+
+/* DEPXFERCFG parameter 0 */
+#define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff)
+
+struct dwc3_gadget_ep_cmd_params {
+	u32	param2;
+	u32	param1;
+	u32	param0;
+};
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_request {
+	struct usb_request	request;
+	struct list_head	list;
+	struct dwc3_ep		*dep;
+
+	u8			epnum;
+	struct dwc3_trb_hw	*trb;
+	dma_addr_t		trb_dma;
+
+	unsigned		direction:1;
+	unsigned		mapped:1;
+	unsigned		queued:1;
+};
+#define to_dwc3_request(r)	(container_of(r, struct dwc3_request, request))
+
+static inline struct dwc3_request *next_request(struct list_head *list)
+{
+	if (list_empty(list))
+		return NULL;
+
+	return list_first_entry(list, struct dwc3_request, list);
+}
+
+static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
+{
+	struct dwc3_ep		*dep = req->dep;
+
+	req->queued = true;
+	list_move_tail(&req->list, &dep->req_queued);
+}
+
+#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
+int dwc3_gadget_init(struct dwc3 *dwc);
+void dwc3_gadget_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
+static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
+static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+	return 0;
+}
+#endif
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+		int status);
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
+void dwc3_ep0_out_start(struct dwc3 *dwc);
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+		gfp_t gfp_flags);
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+void dwc3_map_buffer_to_dma(struct dwc3_request *req);
+void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
+
+/**
+ * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
+ * @dwc: DesignWare USB3 Pointer
+ * @number: DWC endpoint number
+ *
+ * Caller should take care of locking
+ */
+static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
+{
+	u32			res_id;
+
+	res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
+
+	return DWC3_DEPCMD_GET_RSC_IDX(res_id);
+}
+
+/**
+ * dwc3_gadget_event_string - returns event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_string(u8 event)
+{
+	switch (event) {
+	case DWC3_DEVICE_EVENT_DISCONNECT:
+		return "Disconnect";
+	case DWC3_DEVICE_EVENT_RESET:
+		return "Reset";
+	case DWC3_DEVICE_EVENT_CONNECT_DONE:
+		return "Connection Done";
+	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+		return "Link Status Change";
+	case DWC3_DEVICE_EVENT_WAKEUP:
+		return "WakeUp";
+	case DWC3_DEVICE_EVENT_EOPF:
+		return "End-Of-Frame";
+	case DWC3_DEVICE_EVENT_SOF:
+		return "Start-Of-Frame";
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		return "Erratic Error";
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+		return "Command Complete";
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		return "Overflow";
+	}
+
+	return "UNKNOWN";
+}
+
+/**
+ * dwc3_ep_event_string - returns event name
+ * @event: then event code
+ */
+static inline const char *dwc3_ep_event_string(u8 event)
+{
+	switch (event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		return "Transfer Complete";
+	case DWC3_DEPEVT_XFERINPROGRESS:
+		return "Transfer In-Progress";
+	case DWC3_DEPEVT_XFERNOTREADY:
+		return "Transfer Not Ready";
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+		return "FIFO";
+	case DWC3_DEPEVT_STREAMEVT:
+		return "Stream";
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		return "Endpoint Command Complete";
+	}
+
+	return "UNKNOWN";
+}
+
+#endif /* __DRIVERS_USB_DWC3_GADGET_H */
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
new file mode 100644
index 0000000..bc957db
--- /dev/null
+++ b/drivers/usb/dwc3/io.h
@@ -0,0 +1,54 @@
+/**
+ * io.h - DesignWare USB3 DRD IO Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_IO_H
+#define __DRIVERS_USB_DWC3_IO_H
+
+#include <asm/io.h>
+
+static inline u32 dwc3_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel(value, base + offset);
+}
+
+#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 97e7aa4..092e115 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -386,6 +386,18 @@
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
+config USB_GADGET_DWC3
+	tristate "DesignWare USB3.0 (DRD) Controller"
+	depends on USB_DWC3
+	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SUPERSPEED
+	help
+	  DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+	  which can be configured for peripheral-only, host-only, hub-only
+	  and Dual-Role operation. This Controller was first integrated into
+	  the OMAP5 series of processors. More information about the OMAP5
+	  version of this controller, refer to http://www.ti.com/omap5.
+
 #
 # Controllers available in both integrated and discrete versions
 #
@@ -673,6 +685,12 @@
 	bool
 	depends on USB_GADGET
 
+# Selected by UDC drivers that support super-speed opperation
+config USB_GADGET_SUPERSPEED
+	bool
+	depends on USB_GADGET
+	depends on USB_GADGET_DUALSPEED
+
 #
 # USB Gadget Drivers
 #
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 141f649..655a7ee 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -3,6 +3,7 @@
 #
 ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
 
+obj-$(CONFIG_USB_GADGET)	+= udc-core.o
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
 obj-$(CONFIG_USB_AMD5536UDC)	+= amd5536udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 95e8138..70f2b37 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1438,10 +1438,15 @@
 	return 0;
 }
 
+static int amd5536_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int amd5536_stop(struct usb_gadget_driver *driver);
 /* gadget operations */
 static const struct usb_gadget_ops udc_ops = {
 	.wakeup		= udc_wakeup,
 	.get_frame	= udc_get_frame,
+	.start		= amd5536_start,
+	.stop		= amd5536_stop,
 };
 
 /* Setups endpoint parameters, adds endpoints to linked list */
@@ -1955,7 +1960,7 @@
 }
 
 /* Called by gadget driver to register itself */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int amd5536_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct udc		*dev = udc;
@@ -2002,7 +2007,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 /* shutdown requests and disconnect from gadget */
 static void
@@ -2027,7 +2031,7 @@
 }
 
 /* Called by gadget driver to unregister itself */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int amd5536_stop(struct usb_gadget_driver *driver)
 {
 	struct udc	*dev = udc;
 	unsigned long	flags;
@@ -2057,8 +2061,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 /* Clear pending NAK bits */
 static void udc_process_cnak_queue(struct udc *dev)
@@ -3134,6 +3136,7 @@
 
 	dev = pci_get_drvdata(pdev);
 
+	usb_del_gadget_udc(&udc->gadget);
 	/* gadget driver must not be registered */
 	BUG_ON(dev->driver != NULL);
 
@@ -3382,8 +3385,13 @@
 		"driver version: %s(for Geode5536 B1)\n", tmp);
 	udc = dev;
 
+	retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
+	if (retval)
+		goto finished;
+
 	retval = device_register(&dev->gadget.dev);
 	if (retval) {
+		usb_del_gadget_udc(&dev->gadget);
 		put_device(&dev->gadget.dev);
 		goto finished;
 	}
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index c0c6c1e..7e731de 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1388,6 +1388,7 @@
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.unbind		= android_usb_unbind,
+	.max_speed	= USB_SPEED_SUPER
 };
 
 static int
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index f4690ff..98cbc06c 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -985,12 +985,18 @@
 	return 0;
 }
 
+static int at91_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int at91_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops at91_udc_ops = {
 	.get_frame		= at91_get_frame,
 	.wakeup			= at91_wakeup,
 	.set_selfpowered	= at91_set_selfpowered,
 	.vbus_session		= at91_vbus_session,
 	.pullup			= at91_pullup,
+	.start			= at91_start,
+	.stop			= at91_stop,
 
 	/*
 	 * VBUS-powered devices may also also want to support bigger
@@ -1628,7 +1634,7 @@
 		schedule_work(&udc->vbus_timer_work);
 }
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int at91_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct at91_udc	*udc = &controller;
@@ -1672,9 +1678,8 @@
 	DBG("bound to %s\n", driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int at91_stop(struct usb_gadget_driver *driver)
 {
 	struct at91_udc *udc = &controller;
 	unsigned long	flags;
@@ -1696,7 +1701,6 @@
 	DBG("unbound from %s\n", driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1854,13 +1858,18 @@
 		DBG("no VBUS detection, assuming always-on\n");
 		udc->vbus = 1;
 	}
+	retval = usb_add_gadget_udc(dev, &udc->gadget);
+	if (retval)
+		goto fail4;
 	dev_set_drvdata(dev, udc);
 	device_init_wakeup(dev, 1);
 	create_debug_file(udc);
 
 	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
 	return 0;
-
+fail4:
+	if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled)
+		free_irq(udc->board.vbus_pin, udc);
 fail3:
 	if (udc->board.vbus_pin > 0)
 		gpio_free(udc->board.vbus_pin);
@@ -1887,6 +1896,7 @@
 
 	DBG("remove\n");
 
+	usb_del_gadget_udc(&udc->gadget);
 	if (udc->driver)
 		return -EBUSY;
 
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index db1a659..e6b970a 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1007,10 +1007,16 @@
 	return 0;
 }
 
+static int atmel_usba_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int atmel_usba_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops usba_udc_ops = {
 	.get_frame		= usba_udc_get_frame,
 	.wakeup			= usba_udc_wakeup,
 	.set_selfpowered	= usba_udc_set_selfpowered,
+	.start			= atmel_usba_start,
+	.stop			= atmel_usba_stop,
 };
 
 static struct usb_endpoint_descriptor usba_ep0_desc = {
@@ -1789,7 +1795,7 @@
 	return IRQ_HANDLED;
 }
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int atmel_usba_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct usba_udc *udc = &the_udc;
@@ -1842,9 +1848,8 @@
 	udc->gadget.dev.driver = NULL;
 	return ret;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int atmel_usba_stop(struct usb_gadget_driver *driver)
 {
 	struct usba_udc *udc = &the_udc;
 	unsigned long flags;
@@ -1880,7 +1885,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 static int __init usba_udc_probe(struct platform_device *pdev)
 {
@@ -2021,12 +2025,24 @@
 		}
 	}
 
+	ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	usba_init_debugfs(udc);
 	for (i = 1; i < pdata->num_ep; i++)
 		usba_ep_init_debugfs(udc, &usba_ep[i]);
 
 	return 0;
 
+err_add_udc:
+	if (gpio_is_valid(pdata->vbus_pin)) {
+		free_irq(gpio_to_irq(udc->vbus_pin), udc);
+		gpio_free(udc->vbus_pin);
+	}
+
+	device_unregister(&udc->gadget.dev);
+
 err_device_add:
 	free_irq(irq, udc);
 err_request_irq:
@@ -2053,6 +2069,8 @@
 
 	udc = platform_get_drvdata(pdev);
 
+	usb_del_gadget_udc(&udc->gadget);
+
 	for (i = 1; i < pdata->num_ep; i++)
 		usba_ep_cleanup_debugfs(&usba_ep[i]);
 	usba_cleanup_debugfs(udc);
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c
index 93b999e..9d89ae47 100644
--- a/drivers/usb/gadget/audio.c
+++ b/drivers/usb/gadget/audio.c
@@ -165,6 +165,7 @@
 	.name		= "g_audio",
 	.dev		= &device_desc,
 	.strings	= audio_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(audio_unbind),
 };
 
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
index 2720ab0..b1c1afb 100644
--- a/drivers/usb/gadget/cdc2.c
+++ b/drivers/usb/gadget/cdc2.c
@@ -244,6 +244,7 @@
 	.name		= "g_cdc",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(cdc_unbind),
 };
 
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index ff4bbad..0fc9a03 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2485,6 +2485,7 @@
 	} while (mEp->dir != direction);
 
 	mEp->desc = NULL;
+	mEp->ep.desc = NULL;
 
 	spin_unlock_irqrestore(mEp->lock, flags);
 	return retval;
@@ -2857,7 +2858,9 @@
 	return 0;
 }
 
-
+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)
@@ -2868,17 +2871,19 @@
 	.wakeup		= ci13xxx_wakeup,
 	.vbus_draw	= ci13xxx_vbus_draw,
 	.pullup		= ci13xxx_pullup,
+	.start		= ci13xxx_start,
+	.stop		= ci13xxx_stop,
 };
 
 /**
- * usb_gadget_probe_driver: register a gadget driver
+ * ci13xxx_start: register a gadget driver
  * @driver: the driver being registered
  * @bind: the driver's bind callback
  *
- * Check usb_gadget_probe_driver() at <linux/usb/gadget.h> for details.
+ * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
  * Interrupts are enabled here.
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int ci13xxx_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct ci13xxx *udc = _udc;
@@ -2960,10 +2965,12 @@
 	if (retval)
 		goto done;
 	spin_unlock_irqrestore(udc->lock, flags);
-	retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
+	udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
+	retval = usb_ep_enable(&udc->ep0out.ep);
 	if (retval)
 		return retval;
-	retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
+	udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
+	retval = usb_ep_enable(&udc->ep0in.ep);
 	if (retval)
 		return retval;
 	spin_lock_irqsave(udc->lock, flags);
@@ -3008,14 +3015,13 @@
 		pm_runtime_put_sync(&udc->gadget.dev);
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 /**
- * usb_gadget_unregister_driver: unregister a gadget driver
+ * ci13xxx_stop: unregister a gadget driver
  *
  * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
  */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int ci13xxx_stop(struct usb_gadget_driver *driver)
 {
 	struct ci13xxx *udc = _udc;
 	unsigned long i, flags;
@@ -3074,7 +3080,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /******************************************************************************
  * BUS block
@@ -3249,12 +3254,23 @@
 		if (retval)
 			goto remove_dbg;
 	}
+
+	retval = usb_add_gadget_udc(dev, &udc->gadget);
+	if (retval)
+		goto remove_trans;
+
 	pm_runtime_no_callbacks(&udc->gadget.dev);
 	pm_runtime_enable(&udc->gadget.dev);
 
 	_udc = udc;
 	return retval;
 
+remove_trans:
+	if (udc->transceiver) {
+		otg_set_peripheral(udc->transceiver, &udc->gadget);
+		otg_put_transceiver(udc->transceiver);
+	}
+
 	err("error = %i", retval);
 remove_dbg:
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
@@ -3284,6 +3300,7 @@
 		err("EINVAL");
 		return;
 	}
+	usb_del_gadget_udc(&udc->gadget);
 
 	if (udc->transceiver) {
 		otg_set_peripheral(udc->transceiver, &udc->gadget);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4c33695..c9d9c07 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -27,7 +27,7 @@
 #include <linux/utsname.h>
 
 #include <linux/usb/composite.h>
-
+#include <asm/unaligned.h>
 
 /*
  * The code in this file is utility code, used to build a gadget driver
@@ -74,6 +74,130 @@
 static char composite_manufacturer[50];
 
 /*-------------------------------------------------------------------------*/
+/**
+ * next_ep_desc() - advance to the next EP descriptor
+ * @t: currect pointer within descriptor array
+ *
+ * Return: next EP descriptor or NULL
+ *
+ * Iterate over @t until either EP descriptor found or
+ * NULL (that indicates end of list) encountered
+ */
+static struct usb_descriptor_header**
+next_ep_desc(struct usb_descriptor_header **t)
+{
+	for (; *t; t++) {
+		if ((*t)->bDescriptorType == USB_DT_ENDPOINT)
+			return t;
+	}
+	return NULL;
+}
+
+/*
+ * for_each_ep_desc()- iterate over endpoint descriptors in the
+ *		descriptors list
+ * @start:	pointer within descriptor array.
+ * @ep_desc:	endpoint descriptor to use as the loop cursor
+ */
+#define for_each_ep_desc(start, ep_desc) \
+	for (ep_desc = next_ep_desc(start); \
+	      ep_desc; ep_desc = next_ep_desc(ep_desc+1))
+
+/**
+ * config_ep_by_speed() - configures the given endpoint
+ * according to gadget speed.
+ * @g: pointer to the gadget
+ * @f: usb function
+ * @_ep: the endpoint to configure
+ *
+ * Return: error code, 0 on success
+ *
+ * This function chooses the right descriptors for a given
+ * endpoint according to gadget speed and saves it in the
+ * endpoint desc field. If the endpoint already has a descriptor
+ * assigned to it - overwrites it with currently corresponding
+ * descriptor. The endpoint maxpacket field is updated according
+ * to the chosen descriptor.
+ * Note: the supplied function should hold all the descriptors
+ * for supported speeds
+ */
+int config_ep_by_speed(struct usb_gadget *g,
+			struct usb_function *f,
+			struct usb_ep *_ep)
+{
+	struct usb_endpoint_descriptor *chosen_desc = NULL;
+	struct usb_descriptor_header **speed_desc = NULL;
+
+	struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
+	int want_comp_desc = 0;
+
+	struct usb_descriptor_header **d_spd; /* cursor for speed desc */
+
+	if (!g || !f || !_ep)
+		return -EIO;
+
+	/* select desired speed */
+	switch (g->speed) {
+	case USB_SPEED_SUPER:
+		if (gadget_is_superspeed(g)) {
+			speed_desc = f->ss_descriptors;
+			want_comp_desc = 1;
+			break;
+		}
+		/* else: Fall trough */
+	case USB_SPEED_HIGH:
+		if (gadget_is_dualspeed(g)) {
+			speed_desc = f->hs_descriptors;
+			break;
+		}
+		/* else: fall through */
+	default:
+		speed_desc = f->descriptors;
+	}
+	/* find descriptors */
+	for_each_ep_desc(speed_desc, d_spd) {
+		chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
+		if (chosen_desc->bEndpointAddress == _ep->address)
+			goto ep_found;
+	}
+	return -EIO;
+
+ep_found:
+	/* commit results */
+	_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
+	_ep->desc = chosen_desc;
+	_ep->comp_desc = NULL;
+	_ep->maxburst = 0;
+	_ep->mult = 0;
+	if (!want_comp_desc)
+		return 0;
+
+	/*
+	 * Companion descriptor should follow EP descriptor
+	 * USB 3.0 spec, #9.6.7
+	 */
+	comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
+	if (!comp_desc ||
+	    (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
+		return -EIO;
+	_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;
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+			/* mult: bits 1:0 of bmAttributes */
+			_ep->mult = comp_desc->bmAttributes & 0x3;
+			break;
+		default:
+			/* Do nothing for control endpoints */
+			break;
+		}
+	}
+	return 0;
+}
 
 /**
  * usb_add_function() - add a function to a configuration
@@ -123,6 +247,8 @@
 		config->fullspeed = true;
 	if (!config->highspeed && function->hs_descriptors)
 		config->highspeed = true;
+	if (!config->superspeed && function->ss_descriptors)
+		config->superspeed = true;
 
 done:
 	if (value)
@@ -266,10 +392,17 @@
 	list_for_each_entry(f, &config->functions, list) {
 		struct usb_descriptor_header **descriptors;
 
-		if (speed == USB_SPEED_HIGH)
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
 			descriptors = f->hs_descriptors;
-		else
+			break;
+		default:
 			descriptors = f->descriptors;
+		}
+
 		if (!descriptors)
 			continue;
 		status = usb_descriptor_fillbuf(next, len,
@@ -292,9 +425,10 @@
 	u8				type = w_value >> 8;
 	enum usb_device_speed		speed = USB_SPEED_UNKNOWN;
 
-	if (gadget_is_dualspeed(gadget)) {
-		int			hs = 0;
-
+	if (gadget->speed == USB_SPEED_SUPER)
+		speed = gadget->speed;
+	else if (gadget_is_dualspeed(gadget)) {
+		int	hs = 0;
 		if (gadget->speed == USB_SPEED_HIGH)
 			hs = 1;
 		if (type == USB_DT_OTHER_SPEED_CONFIG)
@@ -308,13 +442,20 @@
 	w_value &= 0xff;
 	list_for_each_entry(c, &cdev->configs, list) {
 		/* ignore configs that won't work at this speed */
-		if (speed == USB_SPEED_HIGH) {
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			if (!c->superspeed)
+				continue;
+			break;
+		case USB_SPEED_HIGH:
 			if (!c->highspeed)
 				continue;
-		} else {
+			break;
+		default:
 			if (!c->fullspeed)
 				continue;
 		}
+
 		if (w_value == 0)
 			return config_buf(c, speed, cdev->req->buf, type);
 		w_value--;
@@ -328,16 +469,22 @@
 	struct usb_configuration	*c;
 	unsigned			count = 0;
 	int				hs = 0;
+	int				ss = 0;
 
 	if (gadget_is_dualspeed(gadget)) {
 		if (gadget->speed == USB_SPEED_HIGH)
 			hs = 1;
+		if (gadget->speed == USB_SPEED_SUPER)
+			ss = 1;
 		if (type == USB_DT_DEVICE_QUALIFIER)
 			hs = !hs;
 	}
 	list_for_each_entry(c, &cdev->configs, list) {
 		/* ignore configs that won't work at this speed */
-		if (hs) {
+		if (ss) {
+			if (!c->superspeed)
+				continue;
+		} else if (hs) {
 			if (!c->highspeed)
 				continue;
 		} else {
@@ -349,6 +496,71 @@
 	return count;
 }
 
+/**
+ * bos_desc() - prepares the BOS descriptor.
+ * @cdev: pointer to usb_composite device to generate the bos
+ *	descriptor for
+ *
+ * This function generates the BOS (Binary Device Object)
+ * descriptor and its device capabilities descriptors. The BOS
+ * descriptor should be supported by a SuperSpeed device.
+ */
+static int bos_desc(struct usb_composite_dev *cdev)
+{
+	struct usb_ext_cap_descriptor	*usb_ext;
+	struct usb_ss_cap_descriptor	*ss_cap;
+	struct usb_dcd_config_params	dcd_config_params;
+	struct usb_bos_descriptor	*bos = cdev->req->buf;
+
+	bos->bLength = USB_DT_BOS_SIZE;
+	bos->bDescriptorType = USB_DT_BOS;
+
+	bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
+	bos->bNumDeviceCaps = 0;
+
+	/*
+	 * A SuperSpeed device shall include the USB2.0 extension descriptor
+	 * and shall support LPM when operating in USB2.0 HS mode.
+	 */
+	usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
+	usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
+	usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+	usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+
+	/*
+	 * The Superspeed USB Capability descriptor shall be implemented by all
+	 * SuperSpeed devices.
+	 */
+	ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+	ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+	ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+	ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+	ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+				USB_FULL_SPEED_OPERATION |
+				USB_HIGH_SPEED_OPERATION |
+				USB_5GBPS_OPERATION);
+	ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+
+	/* Get Controller configuration */
+	if (cdev->gadget->ops->get_config_params)
+		cdev->gadget->ops->get_config_params(&dcd_config_params);
+	else {
+		dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
+		dcd_config_params.bU2DevExitLat =
+			cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+	}
+	ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+	ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
+
+	return le16_to_cpu(bos->wTotalLength);
+}
+
 static void device_qual(struct usb_composite_dev *cdev)
 {
 	struct usb_qualifier_descriptor	*qual = cdev->req->buf;
@@ -361,7 +573,7 @@
 	qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
 	qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
 	/* ASSUME same EP0 fifo size at both speeds */
-	qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0;
+	qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
 	qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
 	qual->bRESERVED = 0;
 }
@@ -392,28 +604,46 @@
 	unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
 	int			tmp;
 
-	if (cdev->config)
-		reset_config(cdev);
-
 	if (number) {
 		list_for_each_entry(c, &cdev->configs, list) {
 			if (c->bConfigurationValue == number) {
+				/*
+				 * We disable the FDs of the previous
+				 * configuration only if the new configuration
+				 * is a valid one
+				 */
+				if (cdev->config)
+					reset_config(cdev);
 				result = 0;
 				break;
 			}
 		}
 		if (result < 0)
 			goto done;
-	} else
+	} else { /* Zero configuration value - need to reset the config */
+		if (cdev->config)
+			reset_config(cdev);
 		result = 0;
+	}
 
 	INFO(cdev, "%s speed config #%d: %s\n",
 		({ char *speed;
 		switch (gadget->speed) {
-		case USB_SPEED_LOW:	speed = "low"; break;
-		case USB_SPEED_FULL:	speed = "full"; break;
-		case USB_SPEED_HIGH:	speed = "high"; break;
-		default:		speed = "?"; break;
+		case USB_SPEED_LOW:
+			speed = "low";
+			break;
+		case USB_SPEED_FULL:
+			speed = "full";
+			break;
+		case USB_SPEED_HIGH:
+			speed = "high";
+			break;
+		case USB_SPEED_SUPER:
+			speed = "super";
+			break;
+		default:
+			speed = "?";
+			break;
 		} ; speed; }), number, c ? c->label : "unconfigured");
 
 	if (!c)
@@ -435,10 +665,16 @@
 		 * function's setup callback instead of the current
 		 * configuration's setup callback.
 		 */
-		if (gadget->speed == USB_SPEED_HIGH)
+		switch (gadget->speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
 			descriptors = f->hs_descriptors;
-		else
+			break;
+		default:
 			descriptors = f->descriptors;
+		}
 
 		for (; *descriptors; ++descriptors) {
 			struct usb_endpoint_descriptor *ep;
@@ -533,8 +769,9 @@
 	} else {
 		unsigned	i;
 
-		DBG(cdev, "cfg %d/%p speeds:%s%s\n",
+		DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
 			config->bConfigurationValue, config,
+			config->superspeed ? " super" : "",
 			config->highspeed ? " high" : "",
 			config->fullspeed
 				? (gadget_is_dualspeed(cdev->gadget)
@@ -852,12 +1089,14 @@
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 	struct usb_request		*req = cdev->req;
 	int				value = -EOPNOTSUPP;
+	int				status = 0;
 	u16				w_index = le16_to_cpu(ctrl->wIndex);
 	u8				intf = w_index & 0xFF;
 	u16				w_value = le16_to_cpu(ctrl->wValue);
 	u16				w_length = le16_to_cpu(ctrl->wLength);
 	struct usb_function		*f = NULL;
 	u8				endp;
+	struct usb_configuration *c;
 
 
 	if (w_length > USB_BUFSIZ)
@@ -883,18 +1122,29 @@
 		case USB_DT_DEVICE:
 			cdev->desc.bNumConfigurations =
 				count_configs(cdev, USB_DT_DEVICE);
+			cdev->desc.bMaxPacketSize0 =
+				cdev->gadget->ep0->maxpacket;
+			if (gadget_is_superspeed(gadget)) {
+				if (gadget->speed >= USB_SPEED_SUPER)
+					cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+				else
+					cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+			}
+
 			value = min(w_length, (u16) sizeof cdev->desc);
 			memcpy(req->buf, &cdev->desc, value);
 			break;
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget_is_dualspeed(gadget))
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
 				break;
 			device_qual(cdev);
 			value = min_t(int, w_length,
 				sizeof(struct usb_qualifier_descriptor));
 			break;
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget_is_dualspeed(gadget))
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
 				break;
 			/* FALLTHROUGH */
 		case USB_DT_CONFIG:
@@ -902,12 +1152,28 @@
 			if (value >= 0)
 				value = min(w_length, (u16) value);
 			break;
+		case USB_DT_OTG:
+			if (!gadget_is_otg(gadget))
+				break;
+			c = list_first_entry(&cdev->configs,
+				struct usb_configuration, list);
+			if (c && c->descriptors)
+				value = usb_find_descriptor_fillbuf(req->buf,
+						USB_BUFSIZ, c->descriptors,
+						USB_DT_OTG);
+			break;
 		case USB_DT_STRING:
 			value = get_string(cdev, req->buf,
 					w_index, w_value & 0xff);
 			if (value >= 0)
 				value = min(w_length, (u16) value);
 			break;
+		case USB_DT_BOS:
+			if (gadget_is_superspeed(gadget)) {
+				value = bos_desc(cdev);
+				value = min(w_length, (u16) value);
+			}
+			break;
 		}
 		break;
 
@@ -975,6 +1241,61 @@
 		*((u8 *)req->buf) = value;
 		value = min(w_length, (u16) 1);
 		break;
+
+	/*
+	 * USB 3.0 additions:
+	 * Function driver should handle get_status request. If such cb
+	 * wasn't supplied we respond with default value = 0
+	 * Note: function driver should supply such cb only for the first
+	 * interface of the function
+	 */
+	case USB_REQ_GET_STATUS:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
+			goto unknown;
+		value = 2;	/* This is the length of the get_status reply */
+		put_unaligned_le16(0, req->buf);
+		if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+			break;
+		f = cdev->config->interface[intf];
+		if (!f)
+			break;
+		status = f->get_status ? f->get_status(f) : 0;
+		if (status < 0)
+			break;
+		put_unaligned_le16(status & 0x0000ffff, req->buf);
+		break;
+	/*
+	 * Function drivers should handle SetFeature/ClearFeature
+	 * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
+	 * only for the first interface of the function
+	 */
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
+			goto unknown;
+		switch (w_value) {
+		case USB_INTRF_FUNC_SUSPEND:
+			if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+				break;
+			f = cdev->config->interface[intf];
+			if (!f)
+				break;
+			value = 0;
+			if (f->func_suspend)
+				value = f->func_suspend(f, w_index >> 8);
+			if (value < 0) {
+				ERROR(cdev,
+				      "func_suspend() returned error %d\n",
+				      value);
+				value = 0;
+			}
+			break;
+		}
+		break;
 	default:
 unknown:
 		VDBG(cdev,
@@ -1166,7 +1487,6 @@
 		goto fail;
 
 	cdev->desc = *composite->dev;
-	cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
 	/* standardized runtime overrides for device ID data */
 	if (idVendor)
@@ -1273,7 +1593,11 @@
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver composite_driver = {
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+	.speed		= USB_SPEED_SUPER,
+#else
 	.speed		= USB_SPEED_HIGH,
+#endif
 
 	.unbind		= composite_unbind,
 
@@ -1319,6 +1643,8 @@
 		driver->iProduct = driver->name;
 	composite_driver.function =  (char *) driver->name;
 	composite_driver.driver.name = driver->name;
+	composite_driver.speed = min((u8)composite_driver.speed,
+				     (u8)driver->max_speed);
 	composite = driver;
 	composite_gadget_bind = bind;
 
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 09084fd..870e662 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -28,6 +28,40 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
+/**
+ * usb_find_descriptor_fillbuf - fill buffer with the requested descriptor
+ * @buf: Buffer to be filled
+ * @buflen: Size of buf
+ * @src: Array of descriptor pointers, terminated by null pointer.
+ * @desc_type: bDescriptorType field of the requested descriptor.
+ *
+ * Copies the requested descriptor into the buffer, returning the length
+ * or a negative error code if it is not found or can't be copied.  Useful
+ * when DT_OTG descriptor is requested.
+ */
+int
+usb_find_descriptor_fillbuf(void *buf, unsigned buflen,
+		const struct usb_descriptor_header **src, u8 desc_type)
+{
+	if (!src)
+		return -EINVAL;
+
+	for (; NULL != *src; src++) {
+		unsigned len;
+
+		if ((*src)->bDescriptorType != desc_type)
+			continue;
+
+		len = (*src)->bLength;
+		if (len > buflen)
+			return -EINVAL;
+
+		memcpy(buf, *src, len);
+		return len;
+	}
+
+	return -ENOENT;
+}
 
 /**
  * usb_descriptor_fillbuf - fill buffer with descriptors
@@ -164,29 +198,3 @@
 
 	return ret;
 }
-
-/**
- * usb_find_endpoint - find a copy of an endpoint descriptor
- * @src: original vector of descriptors
- * @copy: copy of @src
- * @match: endpoint descriptor found in @src
- *
- * This returns the copy of the @match descriptor made for @copy.  Its
- * intended use is to help remembering the endpoint descriptor to use
- * when enabling a given endpoint.
- */
-struct usb_endpoint_descriptor *
-usb_find_endpoint(
-	struct usb_descriptor_header **src,
-	struct usb_descriptor_header **copy,
-	struct usb_endpoint_descriptor *match
-)
-{
-	while (*src) {
-		if (*src == (void *) match)
-			return (void *)*copy;
-		src++;
-		copy++;
-	}
-	return NULL;
-}
diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c
index dbe92ee..8beefdd 100644
--- a/drivers/usb/gadget/dbgp.c
+++ b/drivers/usb/gadget/dbgp.c
@@ -173,7 +173,9 @@
 
 static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
 {
-	int err = usb_ep_enable(ep, desc);
+	int err;
+	ep->desc = desc;
+	err = usb_ep_enable(ep);
 	ep->driver_data = dbgp.gadget;
 	return err;
 }
@@ -268,8 +270,8 @@
 	dbgp.serial->in = dbgp.i_ep;
 	dbgp.serial->out = dbgp.o_ep;
 
-	dbgp.serial->in_desc = &i_desc;
-	dbgp.serial->out_desc = &o_desc;
+	dbgp.serial->in->desc = &i_desc;
+	dbgp.serial->out->desc = &o_desc;
 
 	if (gserial_setup(gadget, 1) < 0) {
 		stp = 3;
@@ -312,7 +314,6 @@
 
 	dbgp.req->length = DBGP_REQ_EP0_LEN;
 	gadget->ep0->driver_data = gadget;
-	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
 #ifdef CONFIG_USB_G_DBGP_SERIAL
 	dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
@@ -363,6 +364,7 @@
 			dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
 			len = sizeof device_desc;
 			data = &device_desc;
+			device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 			break;
 		case USB_DT_DEBUG:
 			dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index d3dcabc..cbcb4c7 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -425,10 +425,18 @@
 		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 		({ char *val;
 		 switch (desc->bmAttributes & 0x03) {
-		 case USB_ENDPOINT_XFER_BULK: val = "bulk"; break;
-		 case USB_ENDPOINT_XFER_ISOC: val = "iso"; break;
-		 case USB_ENDPOINT_XFER_INT: val = "intr"; break;
-		 default: val = "ctrl"; break;
+		 case USB_ENDPOINT_XFER_BULK:
+			 val = "bulk";
+			 break;
+		 case USB_ENDPOINT_XFER_ISOC:
+			 val = "iso";
+			 break;
+		 case USB_ENDPOINT_XFER_INT:
+			 val = "intr";
+			 break;
+		 default:
+			 val = "ctrl";
+			 break;
 		 }; val; }),
 		max);
 
@@ -710,11 +718,17 @@
 	return 0;
 }
 
+static int dummy_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int dummy_udc_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops dummy_ops = {
 	.get_frame	= dummy_g_get_frame,
 	.wakeup		= dummy_wakeup,
 	.set_selfpowered = dummy_set_selfpowered,
 	.pullup		= dummy_pullup,
+	.start		= dummy_udc_start,
+	.stop		= dummy_udc_stop,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -747,8 +761,7 @@
  * for each driver that registers:  just add to a big root hub.
  */
 
-int
-usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int dummy_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct dummy	*dum = the_controller;
@@ -812,10 +825,8 @@
 	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int
-usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int dummy_udc_stop(struct usb_gadget_driver *driver)
 {
 	struct dummy	*dum = the_controller;
 	unsigned long	flags;
@@ -845,7 +856,6 @@
 	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
 	return 0;
 }
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
 
 #undef is_enabled
 
@@ -892,11 +902,20 @@
 		return rc;
 	}
 
+	rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
+	if (rc < 0)
+		goto err_udc;
+
 	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
 	if (rc < 0)
-		device_unregister (&dum->gadget.dev);
-	else
-		platform_set_drvdata(pdev, dum);
+		goto err_dev;
+	platform_set_drvdata(pdev, dum);
+	return rc;
+
+err_dev:
+	usb_del_gadget_udc(&dum->gadget);
+err_udc:
+	device_unregister(&dum->gadget.dev);
 	return rc;
 }
 
@@ -904,6 +923,7 @@
 {
 	struct dummy	*dum = platform_get_drvdata (pdev);
 
+	usb_del_gadget_udc(&dum->gadget);
 	platform_set_drvdata (pdev, NULL);
 	device_remove_file (&dum->gadget.dev, &dev_attr_function);
 	device_unregister (&dum->gadget.dev);
@@ -1786,18 +1806,34 @@
 		urb,
 		({ char *s;
 		 switch (urb->dev->speed) {
-		 case USB_SPEED_LOW:	s = "ls"; break;
-		 case USB_SPEED_FULL:	s = "fs"; break;
-		 case USB_SPEED_HIGH:	s = "hs"; break;
-		 default:		s = "?"; break;
+		 case USB_SPEED_LOW:
+			s = "ls";
+			break;
+		 case USB_SPEED_FULL:
+			s = "fs";
+			break;
+		 case USB_SPEED_HIGH:
+			s = "hs";
+			break;
+		 default:
+			s = "?";
+			break;
 		 }; s; }),
 		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
 		({ char *s; \
 		 switch (usb_pipetype (urb->pipe)) { \
-		 case PIPE_CONTROL:	s = ""; break; \
-		 case PIPE_BULK:	s = "-bulk"; break; \
-		 case PIPE_INTERRUPT:	s = "-int"; break; \
-		 default: 		s = "-iso"; break; \
+		 case PIPE_CONTROL: \
+			s = ""; \
+			break; \
+		 case PIPE_BULK: \
+			s = "-bulk"; \
+			break; \
+		 case PIPE_INTERRUPT: \
+			s = "-int"; \
+			break; \
+		 default: \
+			s = "-iso"; \
+			break; \
 		}; s;}),
 		urb->actual_length, urb->transfer_buffer_length);
 }
@@ -1863,7 +1899,6 @@
 	dum = hcd_to_dummy (hcd);
 
 	device_remove_file (dummy_dev(dum), &dev_attr_urbs);
-	usb_gadget_unregister_driver (dum->driver);
 	dev_info (dummy_dev(dum), "stopped\n");
 }
 
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 9b7360f..2fcfb9b 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -63,13 +63,16 @@
 ep_matches (
 	struct usb_gadget		*gadget,
 	struct usb_ep			*ep,
-	struct usb_endpoint_descriptor	*desc
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
 )
 {
 	u8		type;
 	const char	*tmp;
 	u16		max;
 
+	int		num_req_streams = 0;
+
 	/* endpoint already claimed? */
 	if (NULL != ep->driver_data)
 		return 0;
@@ -129,6 +132,19 @@
 	}
 
 	/*
+	 * Get the number of required streams from the EP companion
+	 * descriptor and see if the EP matches it
+	 */
+	if (usb_endpoint_xfer_bulk(desc)) {
+		if (ep_comp) {
+			num_req_streams = ep_comp->bmAttributes & 0x1f;
+			if (num_req_streams > ep->max_streams)
+				return 0;
+		}
+
+	}
+
+	/*
 	 * If the protocol driver hasn't yet decided on wMaxPacketSize
 	 * and wants to know the maximum possible, provide the info.
 	 */
@@ -142,13 +158,13 @@
 	max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
 	switch (type) {
 	case USB_ENDPOINT_XFER_INT:
-		/* INT:  limit 64 bytes full speed, 1024 high speed */
+		/* INT:  limit 64 bytes full speed, 1024 high/super speed */
 		if (!gadget->is_dualspeed && max > 64)
 			return 0;
 		/* FALLTHROUGH */
 
 	case USB_ENDPOINT_XFER_ISOC:
-		/* ISO:  limit 1023 bytes full speed, 1024 high speed */
+		/* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
 		if (ep->maxpacket < max)
 			return 0;
 		if (!gadget->is_dualspeed && max > 1023)
@@ -183,7 +199,7 @@
 	}
 
 	/* report (variable) full speed bulk maxpacket */
-	if (USB_ENDPOINT_XFER_BULK == type) {
+	if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
 		int size = ep->maxpacket;
 
 		/* min() doesn't work on bitfields with gcc-3.5 */
@@ -191,6 +207,7 @@
 			size = 64;
 		desc->wMaxPacketSize = cpu_to_le16(size);
 	}
+	ep->address = desc->bEndpointAddress;
 	return 1;
 }
 
@@ -207,7 +224,120 @@
 }
 
 /**
- * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
+ * descriptor and ep companion descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *    initialized.  For periodic transfers, the maximum packet
+ *    size must also be initialized.  This is modified on
+ *    success.
+ * @ep_comp: Endpoint companion descriptor, with the required
+ *    number of streams. Will be modified when the chosen EP
+ *    supports a different number of streams.
+ *
+ * This routine replaces the usb_ep_autoconfig when needed
+ * superspeed enhancments. If such enhancemnets are required,
+ * the FD should call usb_ep_autoconfig_ss directly and provide
+ * the additional ep_comp parameter.
+ *
+ * By choosing an endpoint to use with the specified descriptor,
+ * this routine simplifies writing gadget drivers that work with
+ * multiple USB device controllers.  The endpoint would be
+ * passed later to usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration
+ * on your hardware.  This code may not make the best choices
+ * about how to use the USB controller, and it can't know all
+ * the restrictions that may apply. Some combinations of driver
+ * and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed and
+ * the bmAttribute field in the ep companion descriptor is
+ * updated with the assigned number of streams if it is
+ * different from the original value. To prevent the endpoint
+ * from being returned by a later autoconfig call, claim it by
+ * assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig_ss(
+	struct usb_gadget		*gadget,
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
+)
+{
+	struct usb_ep	*ep;
+	u8		type;
+
+	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+	/* First, apply chip-specific "best usage" knowledge.
+	 * This might make a good usb_gadget_ops hook ...
+	 */
+	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
+		/* ep-e, ep-f are PIO with only 64 byte fifos */
+		ep = find_ep (gadget, "ep-e");
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
+			return ep;
+		ep = find_ep (gadget, "ep-f");
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
+			return ep;
+
+	} else if (gadget_is_goku (gadget)) {
+		if (USB_ENDPOINT_XFER_INT == type) {
+			/* single buffering is enough */
+			ep = find_ep(gadget, "ep3-bulk");
+			if (ep && ep_matches(gadget, ep, desc, ep_comp))
+				return ep;
+		} else if (USB_ENDPOINT_XFER_BULK == type
+				&& (USB_DIR_IN & desc->bEndpointAddress)) {
+			/* DMA may be available */
+			ep = find_ep(gadget, "ep2-bulk");
+			if (ep && ep_matches(gadget, ep, desc,
+					      ep_comp))
+				return ep;
+		}
+
+#ifdef CONFIG_BLACKFIN
+	} else if (gadget_is_musbhdrc(gadget)) {
+		if ((USB_ENDPOINT_XFER_BULK == type) ||
+		    (USB_ENDPOINT_XFER_ISOC == type)) {
+			if (USB_DIR_IN & desc->bEndpointAddress)
+				ep = find_ep (gadget, "ep5in");
+			else
+				ep = find_ep (gadget, "ep6out");
+		} else if (USB_ENDPOINT_XFER_INT == type) {
+			if (USB_DIR_IN & desc->bEndpointAddress)
+				ep = find_ep(gadget, "ep1in");
+			else
+				ep = find_ep(gadget, "ep2out");
+		} else
+			ep = NULL;
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
+			return ep;
+#endif
+	}
+
+	/* Second, look at endpoints until an unclaimed one looks usable */
+	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+		if (ep_matches(gadget, ep, desc, ep_comp))
+			return ep;
+	}
+
+	/* Fail */
+	return NULL;
+}
+
+/**
+ * usb_ep_autoconfig() - choose an endpoint matching the
+ * descriptor
  * @gadget: The device to which the endpoint must belong.
  * @desc: Endpoint descriptor, with endpoint direction and transfer mode
  *	initialized.  For periodic transfers, the maximum packet
@@ -236,72 +366,15 @@
  *
  * On failure, this returns a null endpoint descriptor.
  */
-struct usb_ep *usb_ep_autoconfig (
+struct usb_ep *usb_ep_autoconfig(
 	struct usb_gadget		*gadget,
 	struct usb_endpoint_descriptor	*desc
 )
 {
-	struct usb_ep	*ep;
-	u8		type;
-
-	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-
-	/* First, apply chip-specific "best usage" knowledge.
-	 * This might make a good usb_gadget_ops hook ...
-	 */
-	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
-		/* ep-e, ep-f are PIO with only 64 byte fifos */
-		ep = find_ep (gadget, "ep-e");
-		if (ep && ep_matches (gadget, ep, desc))
-			return ep;
-		ep = find_ep (gadget, "ep-f");
-		if (ep && ep_matches (gadget, ep, desc))
-			return ep;
-
-	} else if (gadget_is_goku (gadget)) {
-		if (USB_ENDPOINT_XFER_INT == type) {
-			/* single buffering is enough */
-			ep = find_ep (gadget, "ep3-bulk");
-			if (ep && ep_matches (gadget, ep, desc))
-				return ep;
-		} else if (USB_ENDPOINT_XFER_BULK == type
-				&& (USB_DIR_IN & desc->bEndpointAddress)) {
-			/* DMA may be available */
-			ep = find_ep (gadget, "ep2-bulk");
-			if (ep && ep_matches (gadget, ep, desc))
-				return ep;
-		}
-
-#ifdef CONFIG_BLACKFIN
-	} else if (gadget_is_musbhdrc(gadget)) {
-		if ((USB_ENDPOINT_XFER_BULK == type) ||
-		    (USB_ENDPOINT_XFER_ISOC == type)) {
-			if (USB_DIR_IN & desc->bEndpointAddress)
-				ep = find_ep (gadget, "ep5in");
-			else
-				ep = find_ep (gadget, "ep6out");
-		} else if (USB_ENDPOINT_XFER_INT == type) {
-			if (USB_DIR_IN & desc->bEndpointAddress)
-				ep = find_ep(gadget, "ep1in");
-			else
-				ep = find_ep(gadget, "ep2out");
-		} else
-			ep = NULL;
-		if (ep && ep_matches (gadget, ep, desc))
-			return ep;
-#endif
-	}
-
-	/* Second, look at endpoints until an unclaimed one looks usable */
-	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-		if (ep_matches (gadget, ep, desc))
-			return ep;
-	}
-
-	/* Fail */
-	return NULL;
+	return usb_ep_autoconfig_ss(gadget, desc, NULL);
 }
 
+
 /**
  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
  * @gadget: device for which autoconfig state will be reset
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 1690c9d..ac41858 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -401,6 +401,7 @@
 	.name		= "g_ether",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(eth_unbind),
 };
 
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 05e65e5..0187b69 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -686,17 +686,33 @@
 	int ret;
 
 	DBG(cdev, "acc_function_set_alt intf: %d alt: %d\n", intf, alt);
-	ret = usb_ep_enable(dev->ep_in,
-			ep_choose(cdev->gadget,
-				&acc_highspeed_in_desc,
-				&acc_fullspeed_in_desc));
-	if (ret)
-		return ret;
-	ret = usb_ep_enable(dev->ep_out,
-			ep_choose(cdev->gadget,
-				&acc_highspeed_out_desc,
-				&acc_fullspeed_out_desc));
+
+	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
 	if (ret) {
+		dev->ep_in->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+				dev->ep_in->name, ret);
+			return ret;
+	}
+	ret = usb_ep_enable(dev->ep_in);
+	if (ret) {
+		ERROR(cdev, "failed to enable ep %s, result %d\n",
+			dev->ep_in->name, ret);
+		return ret;
+	}
+
+	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out);
+	if (ret) {
+		dev->ep_out->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+			dev->ep_out->name, ret);
+		usb_ep_disable(dev->ep_in);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->ep_out);
+	if (ret) {
+		ERROR(cdev, "failed to enable ep %s, result %d\n",
+				dev->ep_out->name, ret);
 		usb_ep_disable(dev->ep_in);
 		return ret;
 	}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 380ef87..8e542a4 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -42,12 +42,6 @@
  * descriptors (roughly equivalent to CDC Unions) may sometimes help.
  */
 
-struct acm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 struct f_acm {
 	struct gserial			port;
 	u8				ctrl_id, data_id;
@@ -62,11 +56,7 @@
 	 */
 	spinlock_t			lock;
 
-	struct acm_ep_descs		fs;
-	struct acm_ep_descs		hs;
-
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 
 	struct usb_cdc_line_coding	port_line_coding;	/* 8-N-1 etc */
@@ -497,10 +487,10 @@
 		} else {
 			VDBG(cdev, "init acm ctrl interface %d\n", intf);
 		}
-		acm->notify_desc = ep_choose(cdev->gadget,
-				acm->hs.notify,
-				acm->fs.notify);
-		usb_ep_enable(acm->notify, acm->notify_desc);
+		if (config_ep_by_speed(cdev->gadget, f, acm->notify))
+			return -EINVAL;
+
+		usb_ep_enable(acm->notify);
 		acm->notify->driver_data = acm;
 
 	} else if (intf == acm->data_id) {
@@ -510,10 +500,15 @@
 		} else {
 			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
 		}
-		acm->port.in_desc = ep_choose(cdev->gadget,
-				acm->hs.in, acm->fs.in);
-		acm->port.out_desc = ep_choose(cdev->gadget,
-				acm->hs.out, acm->fs.out);
+		if (config_ep_by_speed(cdev->gadget, f,
+				acm->port.in) ||
+			config_ep_by_speed(cdev->gadget, f,
+				acm->port.out)) {
+			acm->port.in->desc = NULL;
+			acm->port.out->desc = NULL;
+			return -EINVAL;
+		}
+
 		acm_port_connect(acm);
 
 	} else
@@ -729,18 +724,11 @@
 	acm->notify_req->complete = acm_cdc_notify_complete;
 	acm->notify_req->context = acm;
 
-	/* copy descriptors, and track endpoint copies */
+	/* copy descriptors */
 	f->descriptors = usb_copy_descriptors(acm_fs_function);
 	if (!f->descriptors)
 		goto fail;
 
-	acm->fs.in = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_in_desc);
-	acm->fs.out = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_out_desc);
-	acm->fs.notify = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -753,17 +741,10 @@
 		acm_hs_notify_desc.bEndpointAddress =
 				acm_fs_notify_desc.bEndpointAddress;
 
-		/* copy descriptors, and track endpoint copies */
+		/* copy descriptors */
 		f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		acm->hs.in = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_in_desc);
-		acm->hs.out = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_out_desc);
-		acm->hs.notify = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_notify_desc);
 	}
 
 	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index cae0136..0cf6d48 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -510,17 +510,33 @@
 	int ret;
 
 	DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt);
-	ret = usb_ep_enable(dev->ep_in,
-			ep_choose(cdev->gadget,
-				&adb_highspeed_in_desc,
-				&adb_fullspeed_in_desc));
-	if (ret)
-		return ret;
-	ret = usb_ep_enable(dev->ep_out,
-			ep_choose(cdev->gadget,
-				&adb_highspeed_out_desc,
-				&adb_fullspeed_out_desc));
+
+	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
 	if (ret) {
+		dev->ep_in->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+				dev->ep_in->name, ret);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->ep_in);
+	if (ret) {
+		ERROR(cdev, "failed to enable ep %s, result %d\n",
+			dev->ep_in->name, ret);
+		return ret;
+	}
+
+	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out);
+	if (ret) {
+		dev->ep_out->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+			dev->ep_out->name, ret);
+		usb_ep_disable(dev->ep_in);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->ep_out);
+	if (ret) {
+		ERROR(cdev, "failed to enable ep %s, result %d\n",
+				dev->ep_out->name, ret);
 		usb_ep_disable(dev->ep_in);
 		return ret;
 	}
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index 8ee330a..02a0270 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -279,7 +279,6 @@
 
 	/* endpoints handle full and/or high speeds */
 	struct usb_ep			*out_ep;
-	struct usb_endpoint_descriptor	*out_desc;
 
 	spinlock_t			lock;
 	struct f_audio_buf *copy_buf;
@@ -575,7 +574,7 @@
 
 	if (intf == 1) {
 		if (alt == 1) {
-			usb_ep_enable(out_ep, audio->out_desc);
+			usb_ep_enable(out_ep);
 			out_ep->driver_data = audio;
 			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
 			if (IS_ERR(audio->copy_buf))
@@ -677,6 +676,7 @@
 	if (!ep)
 		goto fail;
 	audio->out_ep = ep;
+	audio->out_ep->desc = &as_out_ep_desc;
 	ep->driver_data = cdev;	/* claim */
 
 	status = -ENOMEM;
@@ -776,7 +776,6 @@
 	audio->card.func.set_alt = f_audio_set_alt;
 	audio->card.func.setup = f_audio_setup;
 	audio->card.func.disable = f_audio_disable;
-	audio->out_desc = &as_out_ep_desc;
 
 	control_selector_init(audio);
 
diff --git a/drivers/usb/gadget/f_ccid.c b/drivers/usb/gadget/f_ccid.c
index a11f439..c8f144a 100644
--- a/drivers/usb/gadget/f_ccid.c
+++ b/drivers/usb/gadget/f_ccid.c
@@ -33,12 +33,6 @@
 /* number of tx requests to allocate */
 #define TX_REQ_MAX 4
 
-struct ccid_descs {
-	struct usb_endpoint_descriptor *in;
-	struct usb_endpoint_descriptor *out;
-	struct usb_endpoint_descriptor *notify;
-};
-
 struct ccid_ctrl_dev {
 	atomic_t opened;
 	struct list_head tx_q;
@@ -64,16 +58,10 @@
 	int ifc_id;
 	spinlock_t lock;
 	atomic_t online;
-	/* usb descriptors */
-	struct ccid_descs fs;
-	struct ccid_descs hs;
 	/* usb eps*/
 	struct usb_ep *notify;
 	struct usb_ep *in;
 	struct usb_ep *out;
-	struct usb_endpoint_descriptor *in_desc;
-	struct usb_endpoint_descriptor *out_desc;
-	struct usb_endpoint_descriptor *notify_desc;
 	struct usb_request *notify_req;
 	struct ccid_ctrl_dev ctrl_dev;
 	struct ccid_bulk_dev bulk_dev;
@@ -436,10 +424,14 @@
 	}
 
 	/* choose the descriptors and enable endpoints */
-	ccid_dev->notify_desc = ep_choose(cdev->gadget,
-				ccid_dev->hs.notify,
-				ccid_dev->fs.notify);
-	ret = usb_ep_enable(ccid_dev->notify, ccid_dev->notify_desc);
+	ret = config_ep_by_speed(cdev->gadget, f, ccid_dev->notify);
+	if (ret) {
+		ccid_dev->notify->desc = NULL;
+		pr_err("%s: config_ep_by_speed failed for ep#%s, err#%d\n",
+				__func__, ccid_dev->notify->name, ret);
+		goto free_bulk_in;
+	}
+	ret = usb_ep_enable(ccid_dev->notify);
 	if (ret) {
 		pr_err("%s: usb ep#%s enable failed, err#%d\n",
 				__func__, ccid_dev->notify->name, ret);
@@ -447,18 +439,28 @@
 	}
 	ccid_dev->notify->driver_data = ccid_dev;
 
-	ccid_dev->in_desc = ep_choose(cdev->gadget,
-			ccid_dev->hs.in, ccid_dev->fs.in);
-	ret = usb_ep_enable(ccid_dev->in, ccid_dev->in_desc);
+	ret = config_ep_by_speed(cdev->gadget, f, ccid_dev->in);
+	if (ret) {
+		ccid_dev->in->desc = NULL;
+		pr_err("%s: config_ep_by_speed failed for ep#%s, err#%d\n",
+				__func__, ccid_dev->in->name, ret);
+		goto disable_ep_notify;
+	}
+	ret = usb_ep_enable(ccid_dev->in);
 	if (ret) {
 		pr_err("%s: usb ep#%s enable failed, err#%d\n",
 				__func__, ccid_dev->in->name, ret);
 		goto disable_ep_notify;
 	}
 
-	ccid_dev->out_desc = ep_choose(cdev->gadget,
-			ccid_dev->hs.out, ccid_dev->fs.out);
-	ret = usb_ep_enable(ccid_dev->out, ccid_dev->out_desc);
+	ret = config_ep_by_speed(cdev->gadget, f, ccid_dev->out);
+	if (ret) {
+		ccid_dev->out->desc = NULL;
+		pr_err("%s: config_ep_by_speed failed for ep#%s, err#%d\n",
+				__func__, ccid_dev->out->name, ret);
+		goto disable_ep_in;
+	}
+	ret = usb_ep_enable(ccid_dev->out);
 	if (ret) {
 		pr_err("%s: usb ep#%s enable failed, err#%d\n",
 				__func__, ccid_dev->out->name, ret);
@@ -538,16 +540,6 @@
 	if (!f->descriptors)
 		goto ep_auto_out_fail;
 
-	ccid_dev->fs.in = usb_find_endpoint(ccid_fs_descs,
-					f->descriptors,
-					&ccid_fs_in_desc);
-	ccid_dev->fs.out = usb_find_endpoint(ccid_fs_descs,
-					f->descriptors,
-					&ccid_fs_out_desc);
-	ccid_dev->fs.notify = usb_find_endpoint(ccid_fs_descs,
-					f->descriptors,
-					&ccid_fs_notify_desc);
-
 	if (gadget_is_dualspeed(cdev->gadget)) {
 		ccid_hs_in_desc.bEndpointAddress =
 				ccid_fs_in_desc.bEndpointAddress;
@@ -560,13 +552,6 @@
 		f->hs_descriptors = usb_copy_descriptors(ccid_hs_descs);
 		if (!f->hs_descriptors)
 			goto ep_auto_out_fail;
-
-		ccid_dev->hs.in = usb_find_endpoint(ccid_hs_descs,
-				f->hs_descriptors, &ccid_hs_in_desc);
-		ccid_dev->hs.out = usb_find_endpoint(ccid_hs_descs,
-				f->hs_descriptors, &ccid_hs_out_desc);
-		ccid_dev->hs.notify = usb_find_endpoint(ccid_hs_descs,
-				f->hs_descriptors, &ccid_hs_notify_desc);
 	}
 
 	pr_debug("%s: CCID %s Speed, IN:%s OUT:%s\n", __func__,
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index 987ae65..c4c7941 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -108,8 +108,6 @@
 	struct usb_function function;
 	struct usb_ep *out;
 	struct usb_ep *in;
-	struct usb_endpoint_descriptor  *in_desc;
-	struct usb_endpoint_descriptor  *out_desc;
 	struct list_head read_pool;
 	struct list_head write_pool;
 	struct work_struct config_work;
@@ -514,21 +512,22 @@
 	unsigned long flags;
 	int rc = 0;
 
-	dev->in_desc = ep_choose(cdev->gadget,
-			(struct usb_endpoint_descriptor *)f->hs_descriptors[1],
-			(struct usb_endpoint_descriptor *)f->descriptors[1]);
-	dev->out_desc = ep_choose(cdev->gadget,
-			(struct usb_endpoint_descriptor *)f->hs_descriptors[2],
-			(struct usb_endpoint_descriptor *)f->descriptors[2]);
+	if (config_ep_by_speed(cdev->gadget, f, dev->in) ||
+	    config_ep_by_speed(cdev->gadget, f, dev->out)) {
+		dev->in->desc = NULL;
+		dev->out->desc = NULL;
+		return -EINVAL;
+	}
+
 	dev->in->driver_data = dev;
-	rc = usb_ep_enable(dev->in, dev->in_desc);
+	rc = usb_ep_enable(dev->in);
 	if (rc) {
 		ERROR(dev->cdev, "can't enable %s, result %d\n",
 						dev->in->name, rc);
 		return rc;
 	}
 	dev->out->driver_data = dev;
-	rc = usb_ep_enable(dev->out, dev->out_desc);
+	rc = usb_ep_enable(dev->out);
 	if (rc) {
 		ERROR(dev->cdev, "can't enable %s, result %d\n",
 						dev->out->name, rc);
@@ -630,7 +629,7 @@
 	/* claim the channel for this USB interface */
 	_ch->priv_usb = dev;
 
-	dev->update_pid_and_serial_num = update_pid; 
+	dev->update_pid_and_serial_num = update_pid;
 	dev->cdev = c->cdev;
 	dev->function.name = _ch->name;
 	dev->function.descriptors = fs_diag_desc;
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 544257a8..ddedbc83 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -46,11 +46,6 @@
  * and also means that a get_alt() method is required.
  */
 
-struct ecm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
 
 enum ecm_notify_state {
 	ECM_NOTIFY_NONE,		/* don't notify */
@@ -64,11 +59,7 @@
 
 	char				ethaddr[14];
 
-	struct ecm_ep_descs		fs;
-	struct ecm_ep_descs		hs;
-
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	u8				notify_state;
 	bool				is_open;
@@ -464,13 +455,13 @@
 		if (ecm->notify->driver_data) {
 			VDBG(cdev, "reset ecm control %d\n", intf);
 			usb_ep_disable(ecm->notify);
-		} else {
-			VDBG(cdev, "init ecm ctrl %d\n", intf);
-			ecm->notify_desc = ep_choose(cdev->gadget,
-					ecm->hs.notify,
-					ecm->fs.notify);
 		}
-		usb_ep_enable(ecm->notify, ecm->notify_desc);
+		if (!(ecm->notify->desc)) {
+			VDBG(cdev, "init ecm ctrl %d\n", intf);
+			if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
+				goto fail;
+		}
+		usb_ep_enable(ecm->notify);
 		ecm->notify->driver_data = ecm;
 
 	/* Data interface has two altsettings, 0 and 1 */
@@ -483,12 +474,17 @@
 			gether_disconnect(&ecm->port);
 		}
 
-		if (!ecm->port.in) {
+		if (!ecm->port.in_ep->desc ||
+		    !ecm->port.out_ep->desc) {
 			DBG(cdev, "init ecm\n");
-			ecm->port.in = ep_choose(cdev->gadget,
-					ecm->hs.in, ecm->fs.in);
-			ecm->port.out = ep_choose(cdev->gadget,
-					ecm->hs.out, ecm->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       ecm->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       ecm->port.out_ep)) {
+				ecm->port.in_ep->desc = NULL;
+				ecm->port.out_ep->desc = NULL;
+				goto fail;
+			}
 		}
 
 		/* CDC Ethernet only sends data in non-default altsettings.
@@ -549,7 +545,7 @@
 	if (ecm->notify->driver_data) {
 		usb_ep_disable(ecm->notify);
 		ecm->notify->driver_data = NULL;
-		ecm->notify_desc = NULL;
+		ecm->notify->desc = NULL;
 	}
 }
 
@@ -665,13 +661,6 @@
 	if (!f->descriptors)
 		goto fail;
 
-	ecm->fs.in = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_in_desc);
-	ecm->fs.out = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_out_desc);
-	ecm->fs.notify = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -688,13 +677,6 @@
 		f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		ecm->hs.in = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_in_desc);
-		ecm->hs.out = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_out_desc);
-		ecm->hs.notify = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_notify_desc);
 	}
 
 	/* NOTE:  all that is done without knowing or caring about
@@ -723,9 +705,9 @@
 	/* we might as well release our claims on endpoints */
 	if (ecm->notify)
 		ecm->notify->driver_data = NULL;
-	if (ecm->port.out)
+	if (ecm->port.out_ep->desc)
 		ecm->port.out_ep->driver_data = NULL;
-	if (ecm->port.in)
+	if (ecm->port.in_ep->desc)
 		ecm->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index b3c3042..3e41274 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -35,17 +35,9 @@
  * Ethernet link.
  */
 
-struct eem_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_eem {
 	struct gether			port;
 	u8				ctrl_id;
-
-	struct eem_ep_descs		fs;
-	struct eem_ep_descs		hs;
 };
 
 static inline struct f_eem *func_to_eem(struct usb_function *f)
@@ -176,12 +168,16 @@
 			gether_disconnect(&eem->port);
 		}
 
-		if (!eem->port.in) {
+		if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
 			DBG(cdev, "init eem\n");
-			eem->port.in = ep_choose(cdev->gadget,
-					eem->hs.in, eem->fs.in);
-			eem->port.out = ep_choose(cdev->gadget,
-					eem->hs.out, eem->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       eem->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       eem->port.out_ep)) {
+				eem->port.in_ep->desc = NULL;
+				eem->port.out_ep->desc = NULL;
+				goto fail;
+			}
 		}
 
 		/* zlps should not occur because zero-length EEM packets
@@ -253,11 +249,6 @@
 	if (!f->descriptors)
 		goto fail;
 
-	eem->fs.in = usb_find_endpoint(eem_fs_function,
-			f->descriptors, &eem_fs_in_desc);
-	eem->fs.out = usb_find_endpoint(eem_fs_function,
-			f->descriptors, &eem_fs_out_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -272,11 +263,6 @@
 		f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		eem->hs.in = usb_find_endpoint(eem_hs_function,
-				f->hs_descriptors, &eem_hs_in_desc);
-		eem->hs.out = usb_find_endpoint(eem_hs_function,
-				f->hs_descriptors, &eem_hs_out_desc);
 	}
 
 	DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
@@ -289,9 +275,9 @@
 		usb_free_descriptors(f->descriptors);
 
 	/* we might as well release our claims on endpoints */
-	if (eem->port.out)
+	if (eem->port.out_ep->desc)
 		eem->port.out_ep->driver_data = NULL;
-	if (eem->port.in)
+	if (eem->port.in_ep->desc)
 		eem->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 19fffcc..c161a9a 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1544,7 +1544,8 @@
 		ds = ep->descs[ep->descs[1] ? 1 : 0];
 
 		ep->ep->driver_data = ep;
-		ret = usb_ep_enable(ep->ep, ds);
+		ep->ep->desc = ds;
+		ret = usb_ep_enable(ep->ep);
 		if (likely(!ret)) {
 			epfile->ep = ep;
 			epfile->in = usb_endpoint_dir_in(ds);
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 598e7e2..403a48b 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -59,8 +59,6 @@
 	struct cdev			cdev;
 	struct usb_function		func;
 	struct usb_ep			*in_ep;
-	struct usb_endpoint_descriptor	*fs_in_ep_desc;
-	struct usb_endpoint_descriptor	*hs_in_ep_desc;
 };
 
 static inline struct f_hidg *func_to_hidg(struct usb_function *f)
@@ -416,7 +414,6 @@
 {
 	struct usb_composite_dev		*cdev = f->config->cdev;
 	struct f_hidg				*hidg = func_to_hidg(f);
-	const struct usb_endpoint_descriptor	*ep_desc;
 	int status = 0;
 
 	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
@@ -426,9 +423,13 @@
 		if (hidg->in_ep->driver_data != NULL)
 			usb_ep_disable(hidg->in_ep);
 
-		ep_desc = ep_choose(f->config->cdev->gadget,
-				hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
-		status = usb_ep_enable(hidg->in_ep, ep_desc);
+		status = config_ep_by_speed(f->config->cdev->gadget, f,
+					    hidg->in_ep);
+		if (status) {
+			ERROR(cdev, "config_ep_by_speed FAILED!\n");
+			goto fail;
+		}
+		status = usb_ep_enable(hidg->in_ep);
 		if (status < 0) {
 			ERROR(cdev, "Enable endpoint FAILED!\n");
 			goto fail;
@@ -498,21 +499,12 @@
 	if (!f->descriptors)
 		goto fail;
 
-	hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors,
-						f->descriptors,
-						&hidg_fs_in_ep_desc);
-
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 		hidg_hs_in_ep_desc.bEndpointAddress =
 			hidg_fs_in_ep_desc.bEndpointAddress;
 		f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
 		if (!f->hs_descriptors)
 			goto fail;
-		hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors,
-							f->hs_descriptors,
-							&hidg_hs_in_ep_desc);
-	} else {
-		hidg->hs_in_ep_desc = NULL;
 	}
 
 	mutex_init(&hidg->lock);
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index b37960f..3756326 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -250,26 +250,27 @@
 enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 {
 	int					result = 0;
-	const struct usb_endpoint_descriptor	*src, *sink;
 	struct usb_ep				*ep;
 	struct usb_request			*req;
 	unsigned				i;
 
-	src = ep_choose(cdev->gadget,
-			&hs_loop_source_desc, &fs_loop_source_desc);
-	sink = ep_choose(cdev->gadget,
-			&hs_loop_sink_desc, &fs_loop_sink_desc);
-
 	/* one endpoint writes data back IN to the host */
 	ep = loop->in_ep;
-	result = usb_ep_enable(ep, src);
+	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+	if (result)
+		return result;
+	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
 	ep->driver_data = loop;
 
 	/* one endpoint just reads OUT packets */
 	ep = loop->out_ep;
-	result = usb_ep_enable(ep, sink);
+	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+	if (result)
+		goto fail0;
+
+	result = usb_ep_enable(ep);
 	if (result < 0) {
 fail0:
 		ep = loop->in_ep;
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 55d9a307..3d35c78 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -112,8 +112,7 @@
  * is not loaded (an empty string as "filename" in the fsg_config
  * structure causes error).  The CD-ROM emulation includes a single
  * data track and no audio tracks; hence there need be only one
- * backing file per LUN.  Note also that the CD-ROM block length is
- * set to 512 rather than the more common value 2048.
+ * backing file per LUN.
  *
  *
  * MSF includes support for module parameters.  If gadget using it
@@ -749,7 +748,6 @@
 	u32			amount_left;
 	loff_t			file_offset, file_offset_tmp;
 	unsigned int		amount;
-	unsigned int		partial_page;
 	ssize_t			nread;
 #ifdef CONFIG_USB_MSC_PROFILING
 	ktime_t			start, diff;
@@ -778,7 +776,7 @@
 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		return -EINVAL;
 	}
-	file_offset = ((loff_t) lba) << 9;
+	file_offset = ((loff_t) lba) << curlun->blkbits;
 
 	/* Carry out the file reads */
 	amount_left = common->data_size_from_cmnd;
@@ -791,18 +789,10 @@
 		 * Try to read the remaining amount.
 		 * But don't read more than the buffer size.
 		 * And don't try to read past the end of the file.
-		 * Finally, if we're not at a page boundary, don't read past
-		 *	the next page.
-		 * If this means reading 0 then we were asked to read past
-		 *	the end of file.
 		 */
 		amount = min(amount_left, FSG_BUFLEN);
 		amount = min((loff_t)amount,
 			     curlun->file_length - file_offset);
-		partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
-		if (partial_page > 0)
-			amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
-					     partial_page);
 
 		/* Wait for the next buffer to become available */
 		bh = common->next_buffhd_to_fill;
@@ -819,7 +809,8 @@
 		if (amount == 0) {
 			curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			bh->inreq->length = 0;
 			bh->state = BUF_STATE_FULL;
@@ -851,18 +842,25 @@
 		} else if (nread < amount) {
 			LDBG(curlun, "partial file read: %d/%u\n",
 			     (int)nread, amount);
-			nread -= (nread & 511);	/* Round down to a block */
+			nread = round_down(nread, curlun->blksize);
 		}
 		file_offset  += nread;
 		amount_left  -= nread;
 		common->residue -= nread;
+
+		/*
+		 * Except at the end of the transfer, nread will be
+		 * equal to the buffer size, which is divisible by the
+		 * bulk-in maxpacket size.
+		 */
 		bh->inreq->length = nread;
 		bh->state = BUF_STATE_FULL;
 
 		/* If an error occurred, report it and its position */
 		if (nread < amount) {
 			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -893,7 +891,6 @@
 	u32			amount_left_to_req, amount_left_to_write;
 	loff_t			usb_offset, file_offset, file_offset_tmp;
 	unsigned int		amount;
-	unsigned int		partial_page;
 	ssize_t			nwritten;
 	int			rc;
 
@@ -944,7 +941,7 @@
 
 	/* Carry out the file writes */
 	get_some_more = 1;
-	file_offset = usb_offset = ((loff_t) lba) << 9;
+	file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
 	amount_left_to_req = common->data_size_from_cmnd;
 	amount_left_to_write = common->data_size_from_cmnd;
 
@@ -956,41 +953,21 @@
 
 			/*
 			 * Figure out how much we want to get:
-			 * Try to get the remaining amount.
-			 * But don't get more than the buffer size.
-			 * And don't try to go past the end of the file.
-			 * If we're not at a page boundary,
-			 *	don't go past the next page.
-			 * If this means getting 0, then we were asked
-			 *	to write past the end of file.
-			 * Finally, round down to a block boundary.
+			 * Try to get the remaining amount,
+			 * but not more than the buffer size.
 			 */
 			amount = min(amount_left_to_req, FSG_BUFLEN);
-			amount = min((loff_t)amount,
-				     curlun->file_length - usb_offset);
-			partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
-			if (partial_page > 0)
-				amount = min(amount,
-	(unsigned int)PAGE_CACHE_SIZE - partial_page);
 
-			if (amount == 0) {
+			/* Beyond the end of the backing file? */
+			if (usb_offset >= curlun->file_length) {
 				get_some_more = 0;
 				curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-				curlun->sense_data_info = usb_offset >> 9;
+				curlun->sense_data_info =
+					usb_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				continue;
 			}
-			amount -= amount & 511;
-			if (amount == 0) {
-
-				/*
-				 * Why were we were asked to transfer a
-				 * partial block?
-				 */
-				get_some_more = 0;
-				continue;
-			}
 
 			/* Get the next buffer */
 			usb_offset += amount;
@@ -1000,12 +977,11 @@
 				get_some_more = 0;
 
 			/*
-			 * amount is always divisible by 512, hence by
-			 * the bulk-out maxpacket size
+			 * Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
+			 * the bulk-out maxpacket size.
 			 */
-			bh->outreq->length = amount;
-			bh->bulk_out_intended_length = amount;
-			bh->outreq->short_not_ok = 1;
+			set_bulk_out_req_length(common, bh, amount);
 			if (!start_out_transfer(common, bh))
 				/* Dunno what to do if common->fsg is NULL */
 				return -EIO;
@@ -1035,7 +1011,8 @@
 			/* Did something go wrong with the transfer? */
 			if (bh->outreq->status != 0) {
 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
-				curlun->sense_data_info = file_offset >> 9;
+				curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				break;
 			}
@@ -1049,6 +1026,16 @@
 				amount = curlun->file_length - file_offset;
 			}
 
+			/* Don't accept excess data.  The spec doesn't say
+			 * what to do in this case.  We'll ignore the error.
+			 */
+			amount = min(amount, bh->bulk_out_intended_length);
+
+			/* Don't write a partial block */
+			amount = round_down(amount, curlun->blksize);
+			if (amount == 0)
+				goto empty_write;
+
 			/* Perform the write */
 			file_offset_tmp = file_offset;
 #ifdef CONFIG_USB_MSC_PROFILING
@@ -1075,8 +1062,7 @@
 			} else if (nwritten < amount) {
 				LDBG(curlun, "partial file write: %d/%u\n",
 				     (int)nwritten, amount);
-				nwritten -= (nwritten & 511);
-				/* Round down to a block */
+				nwritten = round_down(nwritten, curlun->blksize);
 			}
 			file_offset += nwritten;
 			amount_left_to_write -= nwritten;
@@ -1085,7 +1071,8 @@
 			/* If an error occurred, report it and its position */
 			if (nwritten < amount) {
 				curlun->sense_data = SS_WRITE_ERROR;
-				curlun->sense_data_info = file_offset >> 9;
+				curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 #ifdef CONFIG_USB_CSW_HACK
 				write_error_after_csw_sent = 1;
@@ -1117,8 +1104,10 @@
 				}
 			}
 #endif
+
+ empty_write:
 			/* Did the host decide to stop early? */
-			if (bh->outreq->actual != bh->outreq->length) {
+			if (bh->outreq->actual < bh->bulk_out_intended_length) {
 				common->short_packet_received = 1;
 				break;
 			}
@@ -1198,8 +1187,8 @@
 		return -EIO;		/* No default reply */
 
 	/* Prepare to carry out the file verify */
-	amount_left = verification_length << 9;
-	file_offset = ((loff_t) lba) << 9;
+	amount_left = verification_length << curlun->blkbits;
+	file_offset = ((loff_t) lba) << curlun->blkbits;
 
 	/* Write out all the dirty buffers before invalidating them */
 	fsg_lun_fsync_sub(curlun);
@@ -1217,8 +1206,6 @@
 		 * Try to read the remaining amount, but not more than
 		 * the buffer size.
 		 * And don't try to read past the end of the file.
-		 * If this means reading 0 then we were asked to read
-		 * past the end of file.
 		 */
 		amount = min(amount_left, FSG_BUFLEN);
 		amount = min((loff_t)amount,
@@ -1226,7 +1213,8 @@
 		if (amount == 0) {
 			curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info =
+				file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1248,11 +1236,12 @@
 		} else if (nread < amount) {
 			LDBG(curlun, "partial file verify: %d/%u\n",
 			     (int)nread, amount);
-			nread -= nread & 511;	/* Round down to a sector */
+			nread = round_down(nread, curlun->blksize);
 		}
 		if (nread == 0) {
 			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info =
+				file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1358,7 +1347,7 @@
 
 	put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
 						/* Max logical block */
-	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
 	return 8;
 }
 
@@ -1595,7 +1584,7 @@
 
 	put_unaligned_be32(curlun->num_sectors, &buf[0]);
 						/* Number of blocks */
-	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
 	buf[4] = 0x02;				/* Current capacity */
 	return 12;
 }
@@ -1675,7 +1664,7 @@
 			common->next_buffhd_to_drain = bh->next;
 
 			/* A short packet or an error ends everything */
-			if (bh->outreq->actual != bh->outreq->length ||
+			if (bh->outreq->actual < bh->bulk_out_intended_length ||
 			    bh->outreq->status != 0) {
 				raise_exception(common,
 						FSG_STATE_ABORT_BULK_OUT);
@@ -1691,12 +1680,11 @@
 			amount = min(common->usb_amount_left, FSG_BUFLEN);
 
 			/*
-			 * amount is always divisible by 512, hence by
+			 * Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
 			 * the bulk-out maxpacket size.
 			 */
-			bh->outreq->length = amount;
-			bh->bulk_out_intended_length = amount;
-			bh->outreq->short_not_ok = 1;
+			set_bulk_out_req_length(common, bh, amount);
 			if (!start_out_transfer(common, bh))
 				/* Dunno what to do if common->fsg is NULL */
 				return -EIO;
@@ -2103,7 +2091,8 @@
 
 	case READ_6:
 		i = common->cmnd[4];
-		common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+				common->curlun->blkbits;
 		reply = check_command(common, 6, DATA_DIR_TO_HOST,
 				      (7<<1) | (1<<4), 1,
 				      "READ(6)");
@@ -2113,7 +2102,8 @@
 
 	case READ_10:
 		common->data_size_from_cmnd =
-				get_unaligned_be16(&common->cmnd[7]) << 9;
+				get_unaligned_be16(&common->cmnd[7]) <<
+						common->curlun->blkbits;
 		reply = check_command(common, 10, DATA_DIR_TO_HOST,
 				      (1<<1) | (0xf<<2) | (3<<7), 1,
 				      "READ(10)");
@@ -2123,7 +2113,8 @@
 
 	case READ_12:
 		common->data_size_from_cmnd =
-				get_unaligned_be32(&common->cmnd[6]) << 9;
+				get_unaligned_be32(&common->cmnd[6]) <<
+						common->curlun->blkbits;
 		reply = check_command(common, 12, DATA_DIR_TO_HOST,
 				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
 				      "READ(12)");
@@ -2223,7 +2214,8 @@
 
 	case WRITE_6:
 		i = common->cmnd[4];
-		common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+					common->curlun->blkbits;
 		reply = check_command(common, 6, DATA_DIR_FROM_HOST,
 				      (7<<1) | (1<<4), 1,
 				      "WRITE(6)");
@@ -2233,7 +2225,8 @@
 
 	case WRITE_10:
 		common->data_size_from_cmnd =
-				get_unaligned_be16(&common->cmnd[7]) << 9;
+				get_unaligned_be16(&common->cmnd[7]) <<
+						common->curlun->blkbits;
 		reply = check_command(common, 10, DATA_DIR_FROM_HOST,
 				      (1<<1) | (0xf<<2) | (3<<7), 1,
 				      "WRITE(10)");
@@ -2243,7 +2236,8 @@
 
 	case WRITE_12:
 		common->data_size_from_cmnd =
-				get_unaligned_be32(&common->cmnd[6]) << 9;
+				get_unaligned_be32(&common->cmnd[6]) <<
+						common->curlun->blkbits;
 		reply = check_command(common, 12, DATA_DIR_FROM_HOST,
 				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
 				      "WRITE(12)");
@@ -2378,7 +2372,6 @@
 
 	/* Queue a request to read a Bulk-only CBW */
 	set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
-	bh->outreq->short_not_ok = 1;
 	if (!start_out_transfer(common, bh))
 		/* Don't know what to do if common->fsg is NULL */
 		return -EIO;
@@ -2405,18 +2398,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
-		const struct usb_endpoint_descriptor *d)
-{
-	int	rc;
-
-	ep->driver_data = common;
-	rc = usb_ep_enable(ep, d);
-	if (rc)
-		ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
-	return rc;
-}
-
 static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 		struct usb_request **preq)
 {
@@ -2466,7 +2447,6 @@
 	common->fsg = new_fsg;
 	fsg = common->fsg;
 
-
 	/* Allocate the requests */
 	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
 		struct fsg_buffhd	*bh = &common->buffhds[i];
@@ -2496,31 +2476,37 @@
 {
 	struct fsg_dev *fsg = fsg_from_func(f);
 	struct fsg_common *common = fsg->common;
-	const struct usb_endpoint_descriptor *d;
 	int rc;
 
 	/* Enable the endpoints */
-	d = fsg_ep_desc(common->gadget,
-			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
-	rc = enable_endpoint(common, fsg->bulk_in, d);
+	rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
 	if (rc)
 		return rc;
+	rc = usb_ep_enable(fsg->bulk_in);
+	if (rc)
+		return rc;
+	fsg->bulk_in->driver_data = common;
 	fsg->bulk_in_enabled = 1;
 
-	d = fsg_ep_desc(common->gadget,
-			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
-	rc = enable_endpoint(common, fsg->bulk_out, d);
-	if (rc) {
-		usb_ep_disable(fsg->bulk_in);
-		fsg->bulk_in_enabled = 0;
-		return rc;
-	}
+	rc = config_ep_by_speed(common->gadget, &(fsg->function),
+				fsg->bulk_out);
+	if (rc)
+		goto reset_bulk_int;
+	rc = usb_ep_enable(fsg->bulk_out);
+	if (rc)
+		goto reset_bulk_int;
+	fsg->bulk_out->driver_data = common;
 	fsg->bulk_out_enabled = 1;
-	common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+	common->bulk_out_maxpacket = le16_to_cpu(fsg->bulk_in->desc->wMaxPacketSize);
 	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 	fsg->common->new_fsg = fsg;
 	raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
 	return USB_GADGET_DELAYED_STATUS;
+
+reset_bulk_int:
+	usb_ep_disable(fsg->bulk_in);
+	fsg->bulk_in_enabled = 0;
+	return rc;
 }
 
 static void fsg_disable(struct usb_function *f)
@@ -3087,6 +3073,7 @@
 	fsg_common_put(common);
 	usb_free_descriptors(fsg->function.descriptors);
 	usb_free_descriptors(fsg->function.hs_descriptors);
+	usb_free_descriptors(fsg->function.ss_descriptors);
 	kfree(fsg);
 }
 
@@ -3137,6 +3124,28 @@
 		}
 	}
 
+	if (gadget_is_superspeed(gadget)) {
+		unsigned	max_burst;
+
+		/* Calculate bMaxBurst, we know packet size is 1024 */
+		max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
+
+		fsg_ss_bulk_in_desc.bEndpointAddress =
+			fsg_fs_bulk_in_desc.bEndpointAddress;
+		fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+		fsg_ss_bulk_out_desc.bEndpointAddress =
+			fsg_fs_bulk_out_desc.bEndpointAddress;
+		fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+
+		f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
+		if (unlikely(!f->ss_descriptors)) {
+			usb_free_descriptors(f->hs_descriptors);
+			usb_free_descriptors(f->descriptors);
+			return -ENOMEM;
+		}
+	}
+
 	return 0;
 
 autoconf_fail:
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 2829231..c85d499 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -410,15 +410,6 @@
 	ep->driver_data = dev;		/* claim the endpoint */
 	dev->ep_out = ep;
 
-	ep = usb_ep_autoconfig(cdev->gadget, out_desc);
-	if (!ep) {
-		DBG(cdev, "usb_ep_autoconfig for ep_out failed\n");
-		return -ENODEV;
-	}
-	DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name);
-	ep->driver_data = dev;		/* claim the endpoint */
-	dev->ep_out = ep;
-
 	ep = usb_ep_autoconfig(cdev->gadget, intr_desc);
 	if (!ep) {
 		DBG(cdev, "usb_ep_autoconfig for ep_intr failed\n");
@@ -1132,21 +1123,38 @@
 	int ret;
 
 	DBG(cdev, "mtp_function_set_alt intf: %d alt: %d\n", intf, alt);
-	ret = usb_ep_enable(dev->ep_in,
-			ep_choose(cdev->gadget,
-				&mtp_highspeed_in_desc,
-				&mtp_fullspeed_in_desc));
-	if (ret)
-		return ret;
-	ret = usb_ep_enable(dev->ep_out,
-			ep_choose(cdev->gadget,
-				&mtp_highspeed_out_desc,
-				&mtp_fullspeed_out_desc));
+
+	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
 	if (ret) {
+		dev->ep_in->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+			dev->ep_in->name, ret);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->ep_in);
+	if (ret) {
+		ERROR(cdev, "failed to enable ep %s, result %d\n",
+			dev->ep_in->name, ret);
+		return ret;
+	}
+
+	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out);
+	if (ret) {
+		dev->ep_out->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+			dev->ep_out->name, ret);
 		usb_ep_disable(dev->ep_in);
 		return ret;
 	}
-	ret = usb_ep_enable(dev->ep_intr, &mtp_intr_desc);
+	ret = usb_ep_enable(dev->ep_out);
+	if (ret) {
+		ERROR(cdev, "failed to enable ep %s, result %d\n",
+			dev->ep_out->name, ret);
+		usb_ep_disable(dev->ep_in);
+		return ret;
+	}
+	dev->ep_intr->desc = &mtp_intr_desc;
+	ret = usb_ep_enable(dev->ep_intr);
 	if (ret) {
 		usb_ep_disable(dev->ep_out);
 		usb_ep_disable(dev->ep_in);
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index 86902a6..ae69ed7 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -48,12 +48,6 @@
 #define NCM_NDP_HDR_CRC		0x01000000
 #define NCM_NDP_HDR_NOCRC	0x00000000
 
-struct ncm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 enum ncm_notify_state {
 	NCM_NOTIFY_NONE,		/* don't notify */
 	NCM_NOTIFY_CONNECT,		/* issue CONNECT next */
@@ -66,11 +60,7 @@
 
 	char				ethaddr[14];
 
-	struct ncm_ep_descs		fs;
-	struct ncm_ep_descs		hs;
-
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	u8				notify_state;
 	bool				is_open;
@@ -802,13 +792,14 @@
 		if (ncm->notify->driver_data) {
 			DBG(cdev, "reset ncm control %d\n", intf);
 			usb_ep_disable(ncm->notify);
-		} else {
-			DBG(cdev, "init ncm ctrl %d\n", intf);
-			ncm->notify_desc = ep_choose(cdev->gadget,
-					ncm->hs.notify,
-					ncm->fs.notify);
 		}
-		usb_ep_enable(ncm->notify, ncm->notify_desc);
+
+		if (!(ncm->notify->desc)) {
+			DBG(cdev, "init ncm ctrl %d\n", intf);
+			if (config_ep_by_speed(cdev->gadget, f, ncm->notify))
+				goto fail;
+		}
+		usb_ep_enable(ncm->notify);
 		ncm->notify->driver_data = ncm;
 
 	/* Data interface has two altsettings, 0 and 1 */
@@ -829,14 +820,17 @@
 		if (alt == 1) {
 			struct net_device	*net;
 
-			if (!ncm->port.in) {
+			if (!ncm->port.in_ep->desc ||
+			    !ncm->port.out_ep->desc) {
 				DBG(cdev, "init ncm\n");
-				ncm->port.in = ep_choose(cdev->gadget,
-							 ncm->hs.in,
-							 ncm->fs.in);
-				ncm->port.out = ep_choose(cdev->gadget,
-							  ncm->hs.out,
-							  ncm->fs.out);
+				if (config_ep_by_speed(cdev->gadget, f,
+						       ncm->port.in_ep) ||
+				    config_ep_by_speed(cdev->gadget, f,
+						       ncm->port.out_ep)) {
+					ncm->port.in_ep->desc = NULL;
+					ncm->port.out_ep->desc = NULL;
+					goto fail;
+				}
 			}
 
 			/* TODO */
@@ -1111,7 +1105,7 @@
 	if (ncm->notify->driver_data) {
 		usb_ep_disable(ncm->notify);
 		ncm->notify->driver_data = NULL;
-		ncm->notify_desc = NULL;
+		ncm->notify->desc = NULL;
 	}
 }
 
@@ -1228,13 +1222,6 @@
 	if (!f->descriptors)
 		goto fail;
 
-	ncm->fs.in = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_in_desc);
-	ncm->fs.out = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_out_desc);
-	ncm->fs.notify = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_notify_desc);
-
 	/*
 	 * support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
@@ -1252,13 +1239,6 @@
 		f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
 		if (!f->hs_descriptors)
 			goto fail;
-
-		ncm->hs.in = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_in_desc);
-		ncm->hs.out = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_out_desc);
-		ncm->hs.notify = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_notify_desc);
 	}
 
 	/*
@@ -1288,9 +1268,9 @@
 	/* we might as well release our claims on endpoints */
 	if (ncm->notify)
 		ncm->notify->driver_data = NULL;
-	if (ncm->port.out)
+	if (ncm->port.out_ep->desc)
 		ncm->port.out_ep->driver_data = NULL;
-	if (ncm->port.in)
+	if (ncm->port.in_ep->desc)
 		ncm->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
index 8f8c643..394502a 100644
--- a/drivers/usb/gadget/f_obex.c
+++ b/drivers/usb/gadget/f_obex.c
@@ -39,20 +39,12 @@
  * ready to handle the commands.
  */
 
-struct obex_ep_descs {
-	struct usb_endpoint_descriptor	*obex_in;
-	struct usb_endpoint_descriptor	*obex_out;
-};
-
 struct f_obex {
 	struct gserial			port;
 	u8				ctrl_id;
 	u8				data_id;
 	u8				port_num;
 	u8				can_activate;
-
-	struct obex_ep_descs		fs;
-	struct obex_ep_descs		hs;
 };
 
 static inline struct f_obex *func_to_obex(struct usb_function *f)
@@ -227,12 +219,16 @@
 			gserial_disconnect(&obex->port);
 		}
 
-		if (!obex->port.in_desc) {
+		if (!obex->port.in->desc || !obex->port.out->desc) {
 			DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
-			obex->port.in_desc = ep_choose(cdev->gadget,
-					obex->hs.obex_in, obex->fs.obex_in);
-			obex->port.out_desc = ep_choose(cdev->gadget,
-					obex->hs.obex_out, obex->fs.obex_out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       obex->port.in) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       obex->port.out)) {
+				obex->port.out->desc = NULL;
+				obex->port.in->desc = NULL;
+				goto fail;
+			}
 		}
 
 		if (alt == 1) {
@@ -346,11 +342,6 @@
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(fs_function);
 
-	obex->fs.obex_in = usb_find_endpoint(fs_function,
-			f->descriptors, &obex_fs_ep_in_desc);
-	obex->fs.obex_out = usb_find_endpoint(fs_function,
-			f->descriptors, &obex_fs_ep_out_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -364,11 +355,6 @@
 
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(hs_function);
-
-		obex->hs.obex_in = usb_find_endpoint(hs_function,
-				f->hs_descriptors, &obex_hs_ep_in_desc);
-		obex->hs.obex_out = usb_find_endpoint(hs_function,
-				f->hs_descriptors, &obex_hs_ep_out_desc);
 	}
 
 	/* Avoid letting this gadget enumerate until the userspace
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 5e14950..0d6d260 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -427,17 +427,16 @@
 		spin_lock(&port->lock);
 		__pn_reset(f);
 		if (alt == 1) {
-			struct usb_endpoint_descriptor *out, *in;
 			int i;
 
-			out = ep_choose(gadget,
-					&pn_hs_sink_desc,
-					&pn_fs_sink_desc);
-			in = ep_choose(gadget,
-					&pn_hs_source_desc,
-					&pn_fs_source_desc);
-			usb_ep_enable(fp->out_ep, out);
-			usb_ep_enable(fp->in_ep, in);
+			if (config_ep_by_speed(gadget, f, fp->in_ep) ||
+			    config_ep_by_speed(gadget, f, fp->out_ep)) {
+				fp->in_ep->desc = NULL;
+				fp->out_ep->desc = NULL;
+				return -EINVAL;
+			}
+			usb_ep_enable(fp->out_ep);
+			usb_ep_enable(fp->in_ep);
 
 			port->usb = fp;
 			fp->out_ep->driver_data = fp;
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index d846c4e..cc26c85 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -25,11 +25,6 @@
 #define RMNET_NOTIFY_INTERVAL	5
 #define RMNET_MAX_NOTIFY_SIZE	sizeof(struct usb_cdc_notification)
 
-struct rmnet_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
 
 #define ACM_CTRL_DTR	(1 << 0)
 
@@ -46,13 +41,8 @@
 
 	spinlock_t			lock;
 
-	/* usb descriptors */
-	struct rmnet_descs		fs;
-	struct rmnet_descs		hs;
-
 	/* usb eps*/
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 
 	/* control info */
@@ -481,10 +471,16 @@
 		pr_debug("%s: reset port:%d\n", __func__, dev->port_num);
 		usb_ep_disable(dev->notify);
 	}
-	dev->notify_desc = ep_choose(cdev->gadget,
-				dev->hs.notify,
-				dev->fs.notify);
-	ret = usb_ep_enable(dev->notify, dev->notify_desc);
+
+	ret = config_ep_by_speed(cdev->gadget, f, dev->notify);
+	if (ret) {
+		dev->notify->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+					dev->notify->name, ret);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->notify);
+
 	if (ret) {
 		pr_err("%s: usb ep#%s enable failed, err#%d\n",
 				__func__, dev->notify->name, ret);
@@ -497,10 +493,12 @@
 		gport_rmnet_disconnect(dev);
 	}
 
-	dev->port.in_desc = ep_choose(cdev->gadget,
-			dev->hs.in, dev->fs.in);
-	dev->port.out_desc = ep_choose(cdev->gadget,
-			dev->hs.out, dev->fs.out);
+	if (config_ep_by_speed(cdev->gadget, f, dev->port.in) ||
+	    config_ep_by_speed(cdev->gadget, f, dev->port.out)) {
+			dev->port.in->desc = NULL;
+			dev->port.out->desc = NULL;
+			return -EINVAL;
+	}
 
 	ret = gport_rmnet_connect(dev);
 
@@ -854,16 +852,6 @@
 	if (!f->descriptors)
 		goto fail;
 
-	dev->fs.in = usb_find_endpoint(rmnet_fs_function,
-					f->descriptors,
-					&rmnet_fs_in_desc);
-	dev->fs.out = usb_find_endpoint(rmnet_fs_function,
-					f->descriptors,
-					&rmnet_fs_out_desc);
-	dev->fs.notify = usb_find_endpoint(rmnet_fs_function,
-					f->descriptors,
-					&rmnet_fs_notify_desc);
-
 	if (gadget_is_dualspeed(cdev->gadget)) {
 		rmnet_hs_in_desc.bEndpointAddress =
 				rmnet_fs_in_desc.bEndpointAddress;
@@ -877,13 +865,6 @@
 
 		if (!f->hs_descriptors)
 			goto fail;
-
-		dev->hs.in = usb_find_endpoint(rmnet_hs_function,
-				f->hs_descriptors, &rmnet_hs_in_desc);
-		dev->hs.out = usb_find_endpoint(rmnet_hs_function,
-				f->hs_descriptors, &rmnet_hs_out_desc);
-		dev->hs.notify = usb_find_endpoint(rmnet_hs_function,
-				f->hs_descriptors, &rmnet_hs_notify_desc);
 	}
 
 	pr_info("%s: RmNet(%d) %s Speed, IN:%s OUT:%s\n",
diff --git a/drivers/usb/gadget/f_rmnet_sdio.c b/drivers/usb/gadget/f_rmnet_sdio.c
index f63d939..8019356 100644
--- a/drivers/usb/gadget/f_rmnet_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_sdio.c
@@ -1255,17 +1255,58 @@
 	struct usb_composite_dev *cdev = dev->cdev;
 	int ret = 0;
 
+	/* Enable epin */
 	dev->epin->driver_data = dev;
-	usb_ep_enable(dev->epin, ep_choose(cdev->gadget,
-				&rmnet_sdio_hs_in_desc,
-				&rmnet_sdio_fs_in_desc));
+	ret = config_ep_by_speed(cdev->gadget, f, dev->epin);
+	if (ret) {
+		dev->epin->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+			dev->epin->name, ret);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->epin);
+	if (ret) {
+		ERROR(cdev, "can't enable %s, result %d\n",
+			dev->epin->name, ret);
+		return ret;
+	}
+
+	/* Enable epout */
 	dev->epout->driver_data = dev;
-	usb_ep_enable(dev->epout, ep_choose(cdev->gadget,
-				&rmnet_sdio_hs_out_desc,
-				&rmnet_sdio_fs_out_desc));
-	usb_ep_enable(dev->epnotify, ep_choose(cdev->gadget,
-				&rmnet_sdio_hs_notify_desc,
-				&rmnet_sdio_fs_notify_desc));
+	ret = config_ep_by_speed(cdev->gadget, f, dev->epout);
+	if (ret) {
+		dev->epout->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+			dev->epout->name, ret);
+		usb_ep_disable(dev->epin);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->epout);
+	if (ret) {
+		ERROR(cdev, "can't enable %s, result %d\n",
+			dev->epout->name, ret);
+		usb_ep_disable(dev->epin);
+		return ret;
+	}
+
+	/* Enable epnotify */
+	ret = config_ep_by_speed(cdev->gadget, f, dev->epnotify);
+	if (ret) {
+		dev->epnotify->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+			dev->epnotify->name, ret);
+		usb_ep_disable(dev->epin);
+		usb_ep_disable(dev->epout);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->epnotify);
+	if (ret) {
+		ERROR(cdev, "can't enable %s, result %d\n",
+			dev->epnotify->name, ret);
+		usb_ep_disable(dev->epin);
+		usb_ep_disable(dev->epout);
+		return ret;
+	}
 
 	/* allocate notification */
 	dev->notify_req = rmnet_sdio_alloc_req(dev->epnotify,
diff --git a/drivers/usb/gadget/f_rmnet_smd.c b/drivers/usb/gadget/f_rmnet_smd.c
index 2049dc0..b71f646 100644
--- a/drivers/usb/gadget/f_rmnet_smd.c
+++ b/drivers/usb/gadget/f_rmnet_smd.c
@@ -956,17 +956,32 @@
 	struct usb_composite_dev *cdev = dev->cdev;
 	int ret = 0;
 
-	ret = usb_ep_enable(dev->epin, ep_choose(cdev->gadget,
-				&rmnet_smd_hs_in_desc,
-				&rmnet_smd_fs_in_desc));
+	/* Enable epin endpoint */
+	ret = config_ep_by_speed(cdev->gadget, f, dev->epin);
+	if (ret) {
+		dev->epin->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failed for ep %s, result %d\n",
+			dev->epin->name, ret);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->epin);
 	if (ret) {
 		ERROR(cdev, "can't enable %s, result %d\n",
 					dev->epin->name, ret);
 		return ret;
 	}
-	ret = usb_ep_enable(dev->epout, ep_choose(cdev->gadget,
-				&rmnet_smd_hs_out_desc,
-				&rmnet_smd_fs_out_desc));
+
+	/* Enable epout endpoint */
+	ret = config_ep_by_speed(cdev->gadget, f, dev->epout);
+	if (ret) {
+		dev->epout->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failed for ep %s, result %d\n",
+					dev->epout->name, ret);
+		usb_ep_disable(dev->epin);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->epout);
+
 	if (ret) {
 		ERROR(cdev, "can't enable %s, result %d\n",
 					dev->epout->name, ret);
@@ -974,9 +989,17 @@
 		return ret;
 	}
 
-	ret = usb_ep_enable(dev->epnotify, ep_choose(cdev->gadget,
-				&rmnet_smd_hs_notify_desc,
-				&rmnet_smd_fs_notify_desc));
+	/* Enable epnotify endpoint */
+	ret = config_ep_by_speed(cdev->gadget, f, dev->epnotify);
+	if (ret) {
+		dev->epnotify->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failed for ep %s, result %d\n",
+			dev->epnotify->name, ret);
+		usb_ep_disable(dev->epin);
+		usb_ep_disable(dev->epout);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->epnotify);
 	if (ret) {
 		ERROR(cdev, "can't enable %s, result %d\n",
 					dev->epnotify->name, ret);
diff --git a/drivers/usb/gadget/f_rmnet_smd_sdio.c b/drivers/usb/gadget/f_rmnet_smd_sdio.c
index e39125d..175afe3 100644
--- a/drivers/usb/gadget/f_rmnet_smd_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_smd_sdio.c
@@ -1354,6 +1354,7 @@
 								function);
 	struct rmnet_mux_sdio_dev *sdio_dev = &dev->sdio_dev;
 	struct usb_composite_dev *cdev = dev->cdev;
+	int ret = 0;
 
 	/* allocate notification */
 	dev->notify_req = rmnet_mux_alloc_req(dev->epnotify,
@@ -1365,18 +1366,59 @@
 	dev->notify_req->complete = rmnet_mux_notify_complete;
 	dev->notify_req->context = dev;
 	dev->notify_req->length = RMNET_MUX_SDIO_MAX_NFY_SZE;
-	usb_ep_enable(dev->epnotify, ep_choose(cdev->gadget,
-				&rmnet_mux_hs_notify_desc,
-				&rmnet_mux_fs_notify_desc));
 
+	/* Enable epin */
 	dev->epin->driver_data = dev;
-	usb_ep_enable(dev->epin, ep_choose(cdev->gadget,
-				&rmnet_mux_hs_in_desc,
-				&rmnet_mux_fs_in_desc));
+	ret = config_ep_by_speed(cdev->gadget, f, dev->epin);
+	if (ret) {
+			dev->epin->desc = NULL;
+			ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+				dev->epin->name, ret);
+			return ret;
+	}
+	ret = usb_ep_enable(dev->epin);
+	if (ret) {
+		ERROR(cdev, "can't enable %s, result %d\n",
+		dev->epin->name, ret);
+		return ret;
+	}
+
+	/* Enable epout */
 	dev->epout->driver_data = dev;
-	usb_ep_enable(dev->epout, ep_choose(cdev->gadget,
-				&rmnet_mux_hs_out_desc,
-				&rmnet_mux_fs_out_desc));
+	ret = config_ep_by_speed(cdev->gadget, f, dev->epout);
+	if (ret) {
+		dev->epout->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+				dev->epout->name, ret);
+		usb_ep_disable(dev->epin);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->epout);
+	if (ret) {
+		ERROR(cdev, "can't enable %s, result %d\n",
+			dev->epout->name, ret);
+		usb_ep_disable(dev->epin);
+		return ret;
+	}
+
+	/* Enable epnotify */
+	ret = config_ep_by_speed(cdev->gadget, f, dev->epnotify);
+	if (ret) {
+		dev->epnotify->desc = NULL;
+		ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+			dev->epnotify->name, ret);
+		usb_ep_disable(dev->epin);
+		usb_ep_disable(dev->epout);
+		return ret;
+	}
+	ret = usb_ep_enable(dev->epnotify);
+	if (ret) {
+		ERROR(cdev, "can't enable %s, result %d\n",
+			dev->epnotify->name, ret);
+		usb_ep_disable(dev->epin);
+		usb_ep_disable(dev->epout);
+		return ret;
+	}
 
 	dev->dpkts_tolaptop = 0;
 	dev->cpkts_tolaptop = 0;
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index d03b11b..4a74dcf 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -76,12 +76,6 @@
  *   - MS-Windows drivers sometimes emit undocumented requests.
  */
 
-struct rndis_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 struct f_rndis {
 	struct gether			port;
 	u8				ctrl_id, data_id;
@@ -90,12 +84,7 @@
 	const char			*manufacturer;
 	int				config;
 
-
-	struct rndis_ep_descs		fs;
-	struct rndis_ep_descs		hs;
-
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	atomic_t			notify_count;
 };
@@ -486,13 +475,13 @@
 		if (rndis->notify->driver_data) {
 			VDBG(cdev, "reset rndis control %d\n", intf);
 			usb_ep_disable(rndis->notify);
-		} else {
-			VDBG(cdev, "init rndis ctrl %d\n", intf);
 		}
-		rndis->notify_desc = ep_choose(cdev->gadget,
-				rndis->hs.notify,
-				rndis->fs.notify);
-		usb_ep_enable(rndis->notify, rndis->notify_desc);
+		if (!rndis->notify->desc) {
+			VDBG(cdev, "init rndis ctrl %d\n", intf);
+			if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
+				goto fail;
+		}
+		usb_ep_enable(rndis->notify);
 		rndis->notify->driver_data = rndis;
 
 	} else if (intf == rndis->data_id) {
@@ -503,13 +492,17 @@
 			gether_disconnect(&rndis->port);
 		}
 
-		if (!rndis->port.in) {
+		if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
 			DBG(cdev, "init rndis\n");
+			if (config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.out_ep)) {
+				rndis->port.in_ep->desc = NULL;
+				rndis->port.out_ep->desc = NULL;
+				goto fail;
+			}
 		}
-		rndis->port.in = ep_choose(cdev->gadget,
-				rndis->hs.in, rndis->fs.in);
-		rndis->port.out = ep_choose(cdev->gadget,
-				rndis->hs.out, rndis->fs.out);
 
 		/* Avoid ZLPs; they can be troublesome. */
 		rndis->port.is_zlp_ok = false;
@@ -664,13 +657,6 @@
 	if (!f->descriptors)
 		goto fail;
 
-	rndis->fs.in = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_in_desc);
-	rndis->fs.out = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_out_desc);
-	rndis->fs.notify = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -688,13 +674,6 @@
 
 		if (!f->hs_descriptors)
 			goto fail;
-
-		rndis->hs.in = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_in_desc);
-		rndis->hs.out = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_out_desc);
-		rndis->hs.notify = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_notify_desc);
 	}
 
 	rndis->port.open = rndis_open;
@@ -737,9 +716,9 @@
 	/* we might as well release our claims on endpoints */
 	if (rndis->notify)
 		rndis->notify->driver_data = NULL;
-	if (rndis->port.out)
+	if (rndis->port.out_ep->desc)
 		rndis->port.out_ep->driver_data = NULL;
-	if (rndis->port.in)
+	if (rndis->port.in_ep->desc)
 		rndis->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index de8c8ed..8d9f090 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -29,21 +29,12 @@
  */
 #define GSERIAL_NO_PORTS 2
 
-struct gser_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-#ifdef CONFIG_MODEM_SUPPORT
-	struct usb_endpoint_descriptor	*notify;
-#endif
-};
 
 struct f_gser {
 	struct gserial			port;
 	u8				data_id;
 	u8				port_num;
 
-	struct gser_descs		fs;
-	struct gser_descs		hs;
 	u8				online;
 	enum transport_type		transport;
 
@@ -51,7 +42,6 @@
 	u8				pending;
 	spinlock_t			lock;
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 
 	struct usb_cdc_line_coding	port_line_coding;
@@ -478,10 +468,15 @@
 		DBG(cdev, "reset generic ctl ttyGS%d\n", gser->port_num);
 		usb_ep_disable(gser->notify);
 	}
-	gser->notify_desc = ep_choose(cdev->gadget,
-			gser->hs.notify,
-			gser->fs.notify);
-	rc = usb_ep_enable(gser->notify, gser->notify_desc);
+
+	if (!gser->notify->desc) {
+		if (config_ep_by_speed(cdev->gadget, f, gser->notify)) {
+			gser->notify->desc = NULL;
+			return -EINVAL;
+		}
+	}
+	rc = usb_ep_enable(gser->notify);
+
 	if (rc) {
 		ERROR(cdev, "can't enable %s, result %d\n",
 					gser->notify->name, rc);
@@ -493,13 +488,16 @@
 	if (gser->port.in->driver_data) {
 		DBG(cdev, "reset generic data ttyGS%d\n", gser->port_num);
 		gport_disconnect(gser);
-	} else {
-		DBG(cdev, "activate generic data ttyGS%d\n", gser->port_num);
 	}
-	gser->port.in_desc = ep_choose(cdev->gadget,
-			gser->hs.in, gser->fs.in);
-	gser->port.out_desc = ep_choose(cdev->gadget,
-			gser->hs.out, gser->fs.out);
+	if (!gser->port.in->desc || !gser->port.out->desc) {
+		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
+		if (config_ep_by_speed(cdev->gadget, f, gser->port.in) ||
+			config_ep_by_speed(cdev->gadget, f, gser->port.out)) {
+			gser->port.in->desc = NULL;
+			gser->port.out->desc = NULL;
+			return -EINVAL;
+		}
+	}
 
 	gport_connect(gser);
 
@@ -744,16 +742,6 @@
 	if (!f->descriptors)
 		goto fail;
 
-	gser->fs.in = usb_find_endpoint(gser_fs_function,
-			f->descriptors, &gser_fs_in_desc);
-	gser->fs.out = usb_find_endpoint(gser_fs_function,
-			f->descriptors, &gser_fs_out_desc);
-#ifdef CONFIG_MODEM_SUPPORT
-	gser->fs.notify = usb_find_endpoint(gser_fs_function,
-			f->descriptors, &gser_fs_notify_desc);
-#endif
-
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -774,14 +762,6 @@
 		if (!f->hs_descriptors)
 			goto fail;
 
-		gser->hs.in = usb_find_endpoint(gser_hs_function,
-				f->hs_descriptors, &gser_hs_in_desc);
-		gser->hs.out = usb_find_endpoint(gser_hs_function,
-				f->hs_descriptors, &gser_hs_out_desc);
-#ifdef CONFIG_MODEM_SUPPORT
-		gser->hs.notify = usb_find_endpoint(gser_hs_function,
-				f->hs_descriptors, &gser_hs_notify_desc);
-#endif
 	}
 
 	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index e403a53..caf2f95 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -343,15 +343,14 @@
 enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
 {
 	int					result = 0;
-	const struct usb_endpoint_descriptor	*src, *sink;
 	struct usb_ep				*ep;
 
-	src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
-	sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
-
 	/* one endpoint writes (sources) zeroes IN (to the host) */
 	ep = ss->in_ep;
-	result = usb_ep_enable(ep, src);
+	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+	if (result)
+		return result;
+	result = usb_ep_enable(ep);
 	if (result < 0)
 		return result;
 	ep->driver_data = ss;
@@ -367,7 +366,10 @@
 
 	/* one endpoint reads (sinks) anything OUT (from the host) */
 	ep = ss->out_ep;
-	result = usb_ep_enable(ep, sink);
+	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+	if (result)
+		goto fail;
+	result = usb_ep_enable(ep);
 	if (result < 0)
 		goto fail;
 	ep->driver_data = ss;
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index 8675ca4..93bf676 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -57,18 +57,10 @@
  * caring about specific product and vendor IDs.
  */
 
-struct geth_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_gether {
 	struct gether			port;
 
 	char				ethaddr[14];
-
-	struct geth_descs		fs;
-	struct geth_descs		hs;
 };
 
 static inline struct f_gether *func_to_geth(struct usb_function *f)
@@ -243,10 +235,12 @@
 	}
 
 	DBG(cdev, "init + activate cdc subset\n");
-	geth->port.in = ep_choose(cdev->gadget,
-			geth->hs.in, geth->fs.in);
-	geth->port.out = ep_choose(cdev->gadget,
-			geth->hs.out, geth->fs.out);
+	if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) ||
+	    config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) {
+		geth->port.in_ep->desc = NULL;
+		geth->port.out_ep->desc = NULL;
+		return -EINVAL;
+	}
 
 	net = gether_connect(&geth->port);
 	return IS_ERR(net) ? PTR_ERR(net) : 0;
@@ -297,12 +291,6 @@
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(fs_eth_function);
 
-	geth->fs.in = usb_find_endpoint(fs_eth_function,
-			f->descriptors, &fs_subset_in_desc);
-	geth->fs.out = usb_find_endpoint(fs_eth_function,
-			f->descriptors, &fs_subset_out_desc);
-
-
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -315,11 +303,6 @@
 
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
-
-		geth->hs.in = usb_find_endpoint(hs_eth_function,
-				f->hs_descriptors, &hs_subset_in_desc);
-		geth->hs.out = usb_find_endpoint(hs_eth_function,
-				f->hs_descriptors, &hs_subset_out_desc);
 	}
 
 	/* NOTE:  all that is done without knowing or caring about
@@ -334,9 +317,9 @@
 
 fail:
 	/* we might as well release our claims on endpoints */
-	if (geth->port.out)
+	if (geth->port.out_ep->desc)
 		geth->port.out_ep->driver_data = NULL;
-	if (geth->port.in)
+	if (geth->port.in_ep->desc)
 		geth->port.in_ep->driver_data = NULL;
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index be446b7..df74d03 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -262,8 +262,10 @@
 		if (uvc->state != UVC_STATE_CONNECTED)
 			return 0;
 
-		if (uvc->video.ep)
-			usb_ep_enable(uvc->video.ep, &uvc_streaming_ep);
+		if (uvc->video.ep) {
+			uvc->video.ep->desc = &uvc_streaming_ep;
+			usb_ep_enable(uvc->video.ep);
+		}
 
 		memset(&v4l2_event, 0, sizeof(v4l2_event));
 		v4l2_event.type = UVC_EVENT_STREAMON;
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 0360f56..b17ecd8 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -69,8 +69,7 @@
  * each LUN would be settable independently as a disk drive or a CD-ROM
  * drive, but currently all LUNs have to be the same type.  The CD-ROM
  * emulation includes a single data track and no audio tracks; hence there
- * need be only one backing file per LUN.  Note also that the CD-ROM block
- * length is set to 512 rather than the more common value 2048.
+ * need be only one backing file per LUN.
  *
  * Requirements are modest; only a bulk-in and a bulk-out endpoint are
  * needed (an interrupt-out endpoint is also needed for CBI).  The memory
@@ -533,6 +532,18 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* Maxpacket and other transfer characteristics vary by speed. */
+static struct usb_endpoint_descriptor *
+fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+		struct usb_endpoint_descriptor *hs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
+/*-------------------------------------------------------------------------*/
+
 /*
  * DESCRIPTORS ... most are static, but strings and (full) configuration
  * descriptors are built on demand.  Also the (static) config and interface
@@ -586,7 +597,19 @@
 	.bNumConfigurations =	1,
 };
 
+static int populate_bos(struct fsg_dev *fsg, u8 *buf)
+{
+	memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
+	buf += USB_DT_BOS_SIZE;
 
+	memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
+	buf += USB_DT_USB_EXT_CAP_SIZE;
+
+	memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
+
+	return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
+		+ USB_DT_USB_EXT_CAP_SIZE;
+}
 
 /*
  * Config descriptors must agree with the code that sets configurations
@@ -929,20 +952,28 @@
 
 		case USB_DT_DEVICE:
 			VDBG(fsg, "get device descriptor\n");
+			device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
 			value = sizeof device_desc;
 			memcpy(req->buf, &device_desc, value);
 			break;
 		case USB_DT_DEVICE_QUALIFIER:
 			VDBG(fsg, "get device qualifier\n");
-			if (!gadget_is_dualspeed(fsg->gadget))
+			if (!gadget_is_dualspeed(fsg->gadget) ||
+					fsg->gadget->speed == USB_SPEED_SUPER)
 				break;
+			/*
+			 * Assume ep0 uses the same maxpacket value for both
+			 * speeds
+			 */
+			dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
 			value = sizeof dev_qualifier;
 			memcpy(req->buf, &dev_qualifier, value);
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
 			VDBG(fsg, "get other-speed config descriptor\n");
-			if (!gadget_is_dualspeed(fsg->gadget))
+			if (!gadget_is_dualspeed(fsg->gadget) ||
+					fsg->gadget->speed == USB_SPEED_SUPER)
 				break;
 			goto get_config;
 		case USB_DT_CONFIG:
@@ -961,7 +992,15 @@
 			value = usb_gadget_get_string(&fsg_stringtab,
 					w_value & 0xff, req->buf);
 			break;
+
+		case USB_DT_BOS:
+			VDBG(fsg, "get bos descriptor\n");
+
+			if (gadget_is_superspeed(fsg->gadget))
+				value = populate_bos(fsg, req->buf);
+			break;
 		}
+
 		break;
 
 	/* One config, two speeds */
@@ -1130,7 +1169,6 @@
 	u32			amount_left;
 	loff_t			file_offset, file_offset_tmp;
 	unsigned int		amount;
-	unsigned int		partial_page;
 	ssize_t			nread;
 
 	/* Get the starting Logical Block Address and check that it's
@@ -1152,7 +1190,7 @@
 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		return -EINVAL;
 	}
-	file_offset = ((loff_t) lba) << 9;
+	file_offset = ((loff_t) lba) << curlun->blkbits;
 
 	/* Carry out the file reads */
 	amount_left = fsg->data_size_from_cmnd;
@@ -1165,17 +1203,10 @@
 		 * Try to read the remaining amount.
 		 * But don't read more than the buffer size.
 		 * And don't try to read past the end of the file.
-		 * Finally, if we're not at a page boundary, don't read past
-		 *	the next page.
-		 * If this means reading 0 then we were asked to read past
-		 *	the end of file. */
+		 */
 		amount = min((unsigned int) amount_left, mod_data.buflen);
 		amount = min((loff_t) amount,
 				curlun->file_length - file_offset);
-		partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
-		if (partial_page > 0)
-			amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
-					partial_page);
 
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
@@ -1190,7 +1221,7 @@
 		if (amount == 0) {
 			curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info = file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			bh->inreq->length = 0;
 			bh->state = BUF_STATE_FULL;
@@ -1215,18 +1246,23 @@
 		} else if (nread < amount) {
 			LDBG(curlun, "partial file read: %d/%u\n",
 					(int) nread, amount);
-			nread -= (nread & 511);	// Round down to a block
+			nread = round_down(nread, curlun->blksize);
 		}
 		file_offset  += nread;
 		amount_left  -= nread;
 		fsg->residue -= nread;
+
+		/* Except at the end of the transfer, nread will be
+		 * equal to the buffer size, which is divisible by the
+		 * bulk-in maxpacket size.
+		 */
 		bh->inreq->length = nread;
 		bh->state = BUF_STATE_FULL;
 
 		/* If an error occurred, report it and its position */
 		if (nread < amount) {
 			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info = file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1256,7 +1292,6 @@
 	u32			amount_left_to_req, amount_left_to_write;
 	loff_t			usb_offset, file_offset, file_offset_tmp;
 	unsigned int		amount;
-	unsigned int		partial_page;
 	ssize_t			nwritten;
 	int			rc;
 
@@ -1297,7 +1332,7 @@
 
 	/* Carry out the file writes */
 	get_some_more = 1;
-	file_offset = usb_offset = ((loff_t) lba) << 9;
+	file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
 	amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
 
 	while (amount_left_to_write > 0) {
@@ -1307,38 +1342,20 @@
 		if (bh->state == BUF_STATE_EMPTY && get_some_more) {
 
 			/* Figure out how much we want to get:
-			 * Try to get the remaining amount.
-			 * But don't get more than the buffer size.
-			 * And don't try to go past the end of the file.
-			 * If we're not at a page boundary,
-			 *	don't go past the next page.
-			 * If this means getting 0, then we were asked
-			 *	to write past the end of file.
-			 * Finally, round down to a block boundary. */
+			 * Try to get the remaining amount,
+			 * but not more than the buffer size.
+			 */
 			amount = min(amount_left_to_req, mod_data.buflen);
-			amount = min((loff_t) amount, curlun->file_length -
-					usb_offset);
-			partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
-			if (partial_page > 0)
-				amount = min(amount,
-	(unsigned int) PAGE_CACHE_SIZE - partial_page);
 
-			if (amount == 0) {
+			/* Beyond the end of the backing file? */
+			if (usb_offset >= curlun->file_length) {
 				get_some_more = 0;
 				curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-				curlun->sense_data_info = usb_offset >> 9;
+				curlun->sense_data_info = usb_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				continue;
 			}
-			amount -= (amount & 511);
-			if (amount == 0) {
-
-				/* Why were we were asked to transfer a
-				 * partial block? */
-				get_some_more = 0;
-				continue;
-			}
 
 			/* Get the next buffer */
 			usb_offset += amount;
@@ -1347,11 +1364,11 @@
 			if (amount_left_to_req == 0)
 				get_some_more = 0;
 
-			/* amount is always divisible by 512, hence by
-			 * the bulk-out maxpacket size */
-			bh->outreq->length = bh->bulk_out_intended_length =
-					amount;
-			bh->outreq->short_not_ok = 1;
+			/* Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
+			 * the bulk-out maxpacket size.
+			 */
+			set_bulk_out_req_length(fsg, bh, amount);
 			start_transfer(fsg, fsg->bulk_out, bh->outreq,
 					&bh->outreq_busy, &bh->state);
 			fsg->next_buffhd_to_fill = bh->next;
@@ -1370,7 +1387,7 @@
 			/* Did something go wrong with the transfer? */
 			if (bh->outreq->status != 0) {
 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
-				curlun->sense_data_info = file_offset >> 9;
+				curlun->sense_data_info = file_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				break;
 			}
@@ -1384,6 +1401,16 @@
 				amount = curlun->file_length - file_offset;
 			}
 
+			/* Don't accept excess data.  The spec doesn't say
+			 * what to do in this case.  We'll ignore the error.
+			 */
+			amount = min(amount, bh->bulk_out_intended_length);
+
+			/* Don't write a partial block */
+			amount = round_down(amount, curlun->blksize);
+			if (amount == 0)
+				goto empty_write;
+
 			/* Perform the write */
 			file_offset_tmp = file_offset;
 			nwritten = vfs_write(curlun->filp,
@@ -1402,8 +1429,7 @@
 			} else if (nwritten < amount) {
 				LDBG(curlun, "partial file write: %d/%u\n",
 						(int) nwritten, amount);
-				nwritten -= (nwritten & 511);
-						// Round down to a block
+				nwritten = round_down(nwritten, curlun->blksize);
 			}
 			file_offset += nwritten;
 			amount_left_to_write -= nwritten;
@@ -1412,13 +1438,14 @@
 			/* If an error occurred, report it and its position */
 			if (nwritten < amount) {
 				curlun->sense_data = SS_WRITE_ERROR;
-				curlun->sense_data_info = file_offset >> 9;
+				curlun->sense_data_info = file_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				break;
 			}
 
+ empty_write:
 			/* Did the host decide to stop early? */
-			if (bh->outreq->actual != bh->outreq->length) {
+			if (bh->outreq->actual < bh->bulk_out_intended_length) {
 				fsg->short_packet_received = 1;
 				break;
 			}
@@ -1494,8 +1521,8 @@
 		return -EIO;		// No default reply
 
 	/* Prepare to carry out the file verify */
-	amount_left = verification_length << 9;
-	file_offset = ((loff_t) lba) << 9;
+	amount_left = verification_length << curlun->blkbits;
+	file_offset = ((loff_t) lba) << curlun->blkbits;
 
 	/* Write out all the dirty buffers before invalidating them */
 	fsg_lun_fsync_sub(curlun);
@@ -1513,15 +1540,14 @@
 		 * Try to read the remaining amount, but not more than
 		 * the buffer size.
 		 * And don't try to read past the end of the file.
-		 * If this means reading 0 then we were asked to read
-		 * past the end of file. */
+		 */
 		amount = min((unsigned int) amount_left, mod_data.buflen);
 		amount = min((loff_t) amount,
 				curlun->file_length - file_offset);
 		if (amount == 0) {
 			curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info = file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1544,11 +1570,11 @@
 		} else if (nread < amount) {
 			LDBG(curlun, "partial file verify: %d/%u\n",
 					(int) nread, amount);
-			nread -= (nread & 511);	// Round down to a sector
+			nread = round_down(nread, curlun->blksize);
 		}
 		if (nread == 0) {
 			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info = file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1662,7 +1688,7 @@
 
 	put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
 						/* Max logical block */
-	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	put_unaligned_be32(curlun->blksize, &buf[4]);	/* Block length */
 	return 8;
 }
 
@@ -1884,7 +1910,7 @@
 
 	put_unaligned_be32(curlun->num_sectors, &buf[0]);
 						/* Number of blocks */
-	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	put_unaligned_be32(curlun->blksize, &buf[4]);	/* Block length */
 	buf[4] = 0x02;				/* Current capacity */
 	return 12;
 }
@@ -1963,7 +1989,7 @@
 			fsg->next_buffhd_to_drain = bh->next;
 
 			/* A short packet or an error ends everything */
-			if (bh->outreq->actual != bh->outreq->length ||
+			if (bh->outreq->actual < bh->bulk_out_intended_length ||
 					bh->outreq->status != 0) {
 				raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
 				return -EINTR;
@@ -1977,11 +2003,11 @@
 			amount = min(fsg->usb_amount_left,
 					(u32) mod_data.buflen);
 
-			/* amount is always divisible by 512, hence by
-			 * the bulk-out maxpacket size */
-			bh->outreq->length = bh->bulk_out_intended_length =
-					amount;
-			bh->outreq->short_not_ok = 1;
+			/* Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
+			 * the bulk-out maxpacket size.
+			 */
+			set_bulk_out_req_length(fsg, bh, amount);
 			start_transfer(fsg, fsg->bulk_out, bh->outreq,
 					&bh->outreq_busy, &bh->state);
 			fsg->next_buffhd_to_fill = bh->next;
@@ -2409,7 +2435,7 @@
 
 	case READ_6:
 		i = fsg->cmnd[4];
-		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
 				(7<<1) | (1<<4), 1,
 				"READ(6)")) == 0)
@@ -2418,7 +2444,7 @@
 
 	case READ_10:
 		fsg->data_size_from_cmnd =
-				get_unaligned_be16(&fsg->cmnd[7]) << 9;
+				get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
 				(1<<1) | (0xf<<2) | (3<<7), 1,
 				"READ(10)")) == 0)
@@ -2427,7 +2453,7 @@
 
 	case READ_12:
 		fsg->data_size_from_cmnd =
-				get_unaligned_be32(&fsg->cmnd[6]) << 9;
+				get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
 				(1<<1) | (0xf<<2) | (0xf<<6), 1,
 				"READ(12)")) == 0)
@@ -2513,7 +2539,7 @@
 
 	case WRITE_6:
 		i = fsg->cmnd[4];
-		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
 				(7<<1) | (1<<4), 1,
 				"WRITE(6)")) == 0)
@@ -2522,7 +2548,7 @@
 
 	case WRITE_10:
 		fsg->data_size_from_cmnd =
-				get_unaligned_be16(&fsg->cmnd[7]) << 9;
+				get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
 				(1<<1) | (0xf<<2) | (3<<7), 1,
 				"WRITE(10)")) == 0)
@@ -2531,7 +2557,7 @@
 
 	case WRITE_12:
 		fsg->data_size_from_cmnd =
-				get_unaligned_be32(&fsg->cmnd[6]) << 9;
+				get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
 				(1<<1) | (0xf<<2) | (0xf<<6), 1,
 				"WRITE(12)")) == 0)
@@ -2660,7 +2686,6 @@
 
 		/* Queue a request to read a Bulk-only CBW */
 		set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
-		bh->outreq->short_not_ok = 1;
 		start_transfer(fsg, fsg->bulk_out, bh->outreq,
 				&bh->outreq_busy, &bh->state);
 
@@ -2713,7 +2738,8 @@
 	int	rc;
 
 	ep->driver_data = fsg;
-	rc = usb_ep_enable(ep, d);
+	ep->desc = d;
+	rc = usb_ep_enable(ep);
 	if (rc)
 		ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
 	return rc;
@@ -2784,13 +2810,15 @@
 
 	/* Enable the endpoints */
 	d = fsg_ep_desc(fsg->gadget,
-			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
+			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
+			&fsg_ss_bulk_in_desc);
 	if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
 		goto reset;
 	fsg->bulk_in_enabled = 1;
 
 	d = fsg_ep_desc(fsg->gadget,
-			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
+			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
+			&fsg_ss_bulk_out_desc);
 	if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
 		goto reset;
 	fsg->bulk_out_enabled = 1;
@@ -2799,7 +2827,8 @@
 
 	if (transport_is_cbi()) {
 		d = fsg_ep_desc(fsg->gadget,
-				&fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc);
+				&fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
+				&fsg_ss_intr_in_desc);
 		if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
 			goto reset;
 		fsg->intr_in_enabled = 1;
@@ -3416,7 +3445,6 @@
 	}
 
 	/* Fix up the descriptors */
-	device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
 	device_desc.idVendor = cpu_to_le16(mod_data.vendor);
 	device_desc.idProduct = cpu_to_le16(mod_data.product);
 	device_desc.bcdDevice = cpu_to_le16(mod_data.release);
@@ -3430,9 +3458,6 @@
 	if (gadget_is_dualspeed(gadget)) {
 		fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-		/* Assume ep0 uses the same maxpacket value for both speeds */
-		dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
-
 		/* Assume endpoint addresses are the same for both speeds */
 		fsg_hs_bulk_in_desc.bEndpointAddress =
 			fsg_fs_bulk_in_desc.bEndpointAddress;
@@ -3442,6 +3467,24 @@
 			fsg_fs_intr_in_desc.bEndpointAddress;
 	}
 
+	if (gadget_is_superspeed(gadget)) {
+		unsigned		max_burst;
+
+		fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+
+		/* Calculate bMaxBurst, we know packet size is 1024 */
+		max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
+
+		/* Assume endpoint addresses are the same for both speeds */
+		fsg_ss_bulk_in_desc.bEndpointAddress =
+			fsg_fs_bulk_in_desc.bEndpointAddress;
+		fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+		fsg_ss_bulk_out_desc.bEndpointAddress =
+			fsg_fs_bulk_out_desc.bEndpointAddress;
+		fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+	}
+
 	if (gadget_is_otg(gadget))
 		fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
 
@@ -3556,11 +3599,7 @@
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver		fsg_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	.speed		= USB_SPEED_HIGH,
-#else
-	.speed		= USB_SPEED_FULL,
-#endif
+	.speed		= USB_SPEED_SUPER,
 	.function	= (char *) fsg_string_product,
 	.unbind		= fsg_unbind,
 	.disconnect	= fsg_disconnect,
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 3a68e09..3bf872e 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -1927,6 +1927,10 @@
 	return -ENOTSUPP;
 }
 
+static int fsl_qe_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int fsl_qe_stop(struct usb_gadget_driver *driver);
+
 /* defined in usb_gadget.h */
 static struct usb_gadget_ops qe_gadget_ops = {
 	.get_frame = qe_get_frame,
@@ -1935,6 +1939,8 @@
 	.vbus_session = qe_vbus_session,
 	.vbus_draw = qe_vbus_draw,
 	.pullup = qe_pullup,
+	.start = fsl_qe_start,
+	.stop = fsl_qe_stop,
 };
 
 /*-------------------------------------------------------------------------
@@ -2320,7 +2326,7 @@
 /*-------------------------------------------------------------------------
 	Gadget driver probe and unregister.
  --------------------------------------------------------------------------*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int fsl_qe_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	int retval;
@@ -2369,9 +2375,8 @@
 		udc_controller->gadget.name, driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int fsl_qe_stop(struct usb_gadget_driver *driver)
 {
 	struct qe_ep *loop_ep;
 	unsigned long flags;
@@ -2411,7 +2416,6 @@
 			driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /* udc structure's alloc and setup, include ep-param alloc */
 static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev)
@@ -2662,11 +2666,17 @@
 	if (ret)
 		goto err6;
 
+	ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget);
+	if (ret)
+		goto err7;
+
 	dev_info(udc_controller->dev,
 			"%s USB controller initialized as device\n",
 			(udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
 	return 0;
 
+err7:
+	device_unregister(&udc_controller->gadget.dev);
 err6:
 	free_irq(udc_controller->usb_irq, udc_controller);
 err5:
@@ -2721,6 +2731,8 @@
 	if (!udc_controller)
 		return -ENODEV;
 
+	usb_del_gadget_udc(&udc_controller->gadget);
+
 	udc_controller->done = &done;
 	tasklet_disable(&udc_controller->rx_tasklet);
 
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 4e48331..4763cc3 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1244,6 +1244,9 @@
 	return 0;
 }
 
+static int fsl_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int fsl_stop(struct usb_gadget_driver *driver);
 /* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
 	.get_frame = fsl_get_frame,
@@ -1252,6 +1255,8 @@
 	.vbus_session = fsl_vbus_session,
 	.vbus_draw = fsl_vbus_draw,
 	.pullup = fsl_pullup,
+	.start = fsl_start,
+	.stop = fsl_stop,
 };
 
 /* Set protocol stall on ep0, protocol stall will automatically be cleared
@@ -1927,7 +1932,7 @@
  * Hook to gadget drivers
  * Called by initialization code of gadget drivers
 *----------------------------------------------------------------*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int fsl_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	int retval = -ENODEV;
@@ -1995,10 +2000,9 @@
 		       retval);
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 /* Disconnect from gadget driver */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int fsl_stop(struct usb_gadget_driver *driver)
 {
 	struct fsl_ep *loop_ep;
 	unsigned long flags;
@@ -2041,7 +2045,6 @@
 	       driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /*-------------------------------------------------------------------------
 		PROC File System Support
@@ -2590,9 +2593,16 @@
 		ret = -ENOMEM;
 		goto err_unregister;
 	}
+
+	ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget);
+	if (ret)
+		goto err_del_udc;
+
 	create_proc_file();
 	return 0;
 
+err_del_udc:
+	dma_pool_destroy(udc_controller->td_pool);
 err_unregister:
 	device_unregister(&udc_controller->gadget.dev);
 err_free_irq:
@@ -2624,6 +2634,8 @@
 
 	if (!udc_controller)
 		return -ENODEV;
+
+	usb_del_gadget_udc(&udc_controller->gadget);
 	udc_controller->done = &done;
 
 	fsl_udc_clk_release();
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index 763d462..9cf53c6 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -1500,7 +1500,7 @@
 /*------------------------------------------------------------------------*/
 static struct fusb300 *the_controller;
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int fusb300_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct fusb300 *fusb300 = the_controller;
@@ -1544,9 +1544,8 @@
 
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int fusb300_udc_stop(struct usb_gadget_driver *driver)
 {
 	struct fusb300 *fusb300 = the_controller;
 
@@ -1562,7 +1561,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 /*--------------------------------------------------------------------------*/
 
 static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
@@ -1572,12 +1570,15 @@
 
 static struct usb_gadget_ops fusb300_gadget_ops = {
 	.pullup		= fusb300_udc_pullup,
+	.start		= fusb300_udc_start,
+	.stop		= fusb300_udc_stop,
 };
 
 static int __exit fusb300_remove(struct platform_device *pdev)
 {
 	struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev);
 
+	usb_del_gadget_udc(&fusb300->gadget);
 	iounmap(fusb300->reg);
 	free_irq(platform_get_irq(pdev, 0), fusb300);
 
@@ -1702,9 +1703,15 @@
 		goto clean_up3;
 
 	init_controller(fusb300);
+	ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 
 	return 0;
+err_add_udc:
+	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
 
 clean_up3:
 	free_irq(ires->start, fusb300);
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index ebf6970..704c280 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -162,6 +162,7 @@
 	.name		= DRIVER_NAME,
 	.dev		= &gfs_dev_desc,
 	.strings	= gfs_dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= gfs_unbind,
 	.iProduct	= DRIVER_DESC,
 };
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index da312d4..7a9d57d 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -120,6 +120,12 @@
 #define gadget_is_ci13xxx_pci(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_DWC3
+#define gadget_is_dwc3(g)		(!strcmp("dwc3-gadget", (g)->name))
+#else
+#define gadget_is_dwc3(g)	0
+#endif
+
 #ifdef CONFIG_USB_GADGET_MSM_72K
 #define	gadget_is_msm72k(g)	!strcmp("msm72k_udc", (g)->name)
 #else
@@ -240,6 +246,8 @@
 		return 0x31;
 	else if (gadget_is_ci13xxx_msm_hsic(gadget))
 		return 0x32;
+	else if (gadget_is_dwc3(gadget))
+		return 0x33;
 
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 47b86b9..8b9220e 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -537,14 +537,16 @@
 	struct usb_ep *ep;
 	unsigned i;
 
-	err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
+	dev->in_ep->desc = &bulk_in_desc;
+	err = usb_ep_enable(dev->in_ep);
 	if (err) {
 		ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
 		goto fail;
 	}
 	dev->in_ep->driver_data = dev;
 
-	err = usb_ep_enable(dev->out_ep, &bulk_out_desc);
+	dev->out_ep->desc = &bulk_out_desc;
+	err = usb_ep_enable(dev->out_ep);
 	if (err) {
 		ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
 		goto fail;
@@ -693,6 +695,7 @@
 		switch (w_value >> 8) {
 
 		case USB_DT_DEVICE:
+			device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 			value = min(w_length, (u16) sizeof(device_desc));
 			memcpy(req->buf, &device_desc, value);
 			break;
@@ -1247,8 +1250,6 @@
 
 	dev->req->complete = gmidi_setup_complete;
 
-	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-
 	gadget->ep0->driver_data = dev;
 
 	INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index bf6e11c..7f87805 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -996,8 +996,14 @@
 	return -EOPNOTSUPP;
 }
 
+static int goku_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int goku_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops goku_ops = {
 	.get_frame	= goku_get_frame,
+	.start		= goku_start,
+	.stop		= goku_stop,
 	// no remote wakeup
 	// not selfpowered
 };
@@ -1344,7 +1350,7 @@
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int goku_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct goku_udc	*dev = the_controller;
@@ -1382,7 +1388,6 @@
 	DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 static void
 stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
@@ -1408,7 +1413,7 @@
 		udc_enable(dev);
 }
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int goku_stop(struct usb_gadget_driver *driver)
 {
 	struct goku_udc	*dev = the_controller;
 	unsigned long	flags;
@@ -1429,8 +1434,6 @@
 	DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -1730,6 +1733,8 @@
 
 	DBG(dev, "%s\n", __func__);
 
+	usb_del_gadget_udc(&dev->gadget);
+
 	BUG_ON(dev->driver);
 
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
@@ -1854,6 +1859,10 @@
 		goto err;
 	}
 	dev->registered = 1;
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (retval)
+		goto err;
+
 	return 0;
 
 err:
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
index 2523e54..9fb5750 100644
--- a/drivers/usb/gadget/hid.c
+++ b/drivers/usb/gadget/hid.c
@@ -255,6 +255,7 @@
 	.name		= "g_hid",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(hid_unbind),
 };
 
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index ade4006..692fd9b 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1237,9 +1237,14 @@
  *******************************************************************************
  */
 
+static int imx_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int imx_udc_stop(struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops imx_udc_ops = {
 	.get_frame	 = imx_udc_get_frame,
 	.wakeup		 = imx_udc_wakeup,
+	.start		= imx_udc_start,
+	.stop		= imx_udc_stop,
 };
 
 static struct imx_udc_struct controller = {
@@ -1324,7 +1329,7 @@
  * USB gadget driver functions
  *******************************************************************************
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int imx_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct imx_udc_struct *imx_usb = &controller;
@@ -1368,9 +1373,8 @@
 	imx_usb->gadget.dev.driver = NULL;
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int imx_udc_stop(struct usb_gadget_driver *driver)
 {
 	struct imx_udc_struct *imx_usb = &controller;
 
@@ -1394,7 +1398,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /*******************************************************************************
  * Module functions
@@ -1504,8 +1507,14 @@
 	imx_usb->timer.function = handle_config;
 	imx_usb->timer.data = (unsigned long)imx_usb;
 
-	return 0;
+	ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
+	if (ret)
+		goto fail4;
 
+	return 0;
+fail4:
+	for (i = 0; i < IMX_USB_NB_EP + 1; i++)
+		free_irq(imx_usb->usbd_int[i], imx_usb);
 fail3:
 	clk_put(clk);
 	clk_disable(clk);
@@ -1525,6 +1534,7 @@
 	struct imxusb_platform_data *pdata = pdev->dev.platform_data;
 	int i;
 
+	usb_del_gadget_udc(&imx_usb->gadget);
 	imx_udc_disable(imx_usb);
 	del_timer(&imx_usb->timer);
 
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index a56876a..1b24099 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -832,14 +832,16 @@
 	switch (data->dev->gadget->speed) {
 	case USB_SPEED_LOW:
 	case USB_SPEED_FULL:
-		value = usb_ep_enable (ep, &data->desc);
+		ep->desc = &data->desc;
+		value = usb_ep_enable(ep);
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 		break;
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 	case USB_SPEED_HIGH:
 		/* fails if caller didn't provide that descriptor... */
-		value = usb_ep_enable (ep, &data->hs_desc);
+		ep->desc = &data->hs_desc;
+		value = usb_ep_enable(ep);
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 		break;
@@ -1345,7 +1347,7 @@
 	qual.bDeviceProtocol = desc->bDeviceProtocol;
 
 	/* assumes ep0 uses the same value for both speeds ... */
-	qual.bMaxPacketSize0 = desc->bMaxPacketSize0;
+	qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
 
 	qual.bNumConfigurations = 1;
 	qual.bRESERVED = 0;
@@ -1402,7 +1404,6 @@
 		}
 
 		dev->state = STATE_DEV_CONNECTED;
-		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
 
 		INFO (dev, "connected\n");
 		event = next_event (dev, GADGETFS_CONNECT);
@@ -1430,6 +1431,7 @@
 
 		case USB_DT_DEVICE:
 			value = min (w_length, (u16) sizeof *dev->dev);
+			dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
 			req->buf = dev->dev;
 			break;
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
@@ -1710,7 +1712,6 @@
 	set_gadget_data (gadget, dev);
 	dev->gadget = gadget;
 	gadget->ep0->driver_data = dev;
-	dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
 
 	/* preallocate control response and buffer */
 	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index 9cee88a..d8403ae 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -1321,7 +1321,9 @@
 	return 0;
 }
 
-
+static int langwell_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int langwell_stop(struct usb_gadget_driver *driver);
 /* device controller usb_gadget_ops structure */
 static const struct usb_gadget_ops langwell_ops = {
 
@@ -1342,6 +1344,9 @@
 
 	/* D+ pullup, software-controlled connect/disconnect to USB host */
 	.pullup		= langwell_pullup,
+
+	.start		= langwell_start,
+	.stop		= langwell_stop,
 };
 
 
@@ -1852,7 +1857,7 @@
  * the driver might get unbound.
  */
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int langwell_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct langwell_udc	*dev = the_controller;
@@ -1914,11 +1919,9 @@
 	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-
 
 /* unregister gadget driver */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int langwell_stop(struct usb_gadget_driver *driver)
 {
 	struct langwell_udc	*dev = the_controller;
 	unsigned long		flags;
@@ -1965,8 +1968,6 @@
 	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -3373,6 +3374,10 @@
 	if (retval)
 		goto error;
 
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (retval)
+		goto error;
+
 	retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);
 	if (retval)
 		goto error;
@@ -3403,6 +3408,7 @@
 
 	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
+	usb_del_gadget_udc(&dev->gadget);
 	/* disable interrupt and set controller to stop state */
 	langwell_udc_stop(dev);
 
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 084aa08..11d3782 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1454,7 +1454,7 @@
 /*-------------------------------------------------------------------------*/
 static struct m66592 *the_controller;
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int m66592_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct m66592 *m66592 = the_controller;
@@ -1506,9 +1506,8 @@
 
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int m66592_stop(struct usb_gadget_driver *driver)
 {
 	struct m66592 *m66592 = the_controller;
 	unsigned long flags;
@@ -1533,7 +1532,6 @@
 	m66592->driver = NULL;
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /*-------------------------------------------------------------------------*/
 static int m66592_get_frame(struct usb_gadget *_gadget)
@@ -1544,12 +1542,16 @@
 
 static struct usb_gadget_ops m66592_gadget_ops = {
 	.get_frame		= m66592_get_frame,
+	.start			= m66592_start,
+	.stop			= m66592_stop,
 };
 
 static int __exit m66592_remove(struct platform_device *pdev)
 {
 	struct m66592		*m66592 = dev_get_drvdata(&pdev->dev);
 
+	usb_del_gadget_udc(&m66592->gadget);
+
 	del_timer_sync(&m66592->timer);
 	iounmap(m66592->reg);
 	free_irq(platform_get_irq(pdev, 0), m66592);
@@ -1691,9 +1693,16 @@
 
 	init_controller(m66592);
 
+	ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	return 0;
 
+err_add_udc:
+	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+
 clean_up3:
 #ifdef CONFIG_HAVE_CLK
 	if (m66592->pdata->on_chip) {
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index 0182242..1b2d135 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -169,6 +169,7 @@
 	.name		= "g_mass_storage",
 	.dev		= &msg_device_desc,
 	.iProduct	= DRIVER_DESC,
+	.max_speed	= USB_SPEED_SUPER,
 	.needs_serial	= 1,
 };
 
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index ea62262..28e217b 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -1453,7 +1453,10 @@
 
 static int usb_free(struct usb_info *ui, int ret)
 {
-	dev_dbg(&ui->pdev->dev, "usb_free(%d)\n", ret);
+	if (ret)
+		dev_dbg(&ui->pdev->dev, "usb_free(%d)\n", ret);
+
+	usb_del_gadget_udc(&ui->gadget);
 
 	if (ui->xceiv)
 		otg_put_transceiver(ui->xceiv);
@@ -2385,6 +2388,11 @@
 
 }
 
+static int msm72k_gadget_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int msm72k_gadget_stop(struct usb_gadget_driver *driver);
+
+
 static const struct usb_gadget_ops msm72k_ops = {
 	.get_frame	= msm72k_get_frame,
 	.vbus_session	= msm72k_udc_vbus_session,
@@ -2392,6 +2400,8 @@
 	.pullup		= msm72k_pullup,
 	.wakeup		= msm72k_wakeup,
 	.set_selfpowered = msm72k_set_selfpowered,
+	.start		= msm72k_gadget_start,
+	.stop		= msm72k_gadget_stop
 };
 
 static void usb_do_remote_wakeup(struct work_struct *w)
@@ -2585,6 +2595,10 @@
 	ui->gadget.is_otg = 1;
 #endif
 
+	retval = usb_add_gadget_udc(&pdev->dev, &ui->gadget);
+	if (retval)
+		return usb_free(ui, retval);
+
 	ui->sdev.name = DRIVER_NAME;
 	ui->sdev.print_name = print_switch_name;
 	ui->sdev.print_state = print_switch_state;
@@ -2629,7 +2643,7 @@
 	return 0;
 }
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int msm72k_gadget_start(struct usb_gadget_driver *driver,
 			    int (*bind)(struct usb_gadget *))
 {
 	struct usb_info *ui = the_usb_info;
@@ -2715,9 +2729,8 @@
 	ui->gadget.dev.driver = NULL;
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int msm72k_gadget_stop(struct usb_gadget_driver *driver)
 {
 	struct usb_info *dev = the_usb_info;
 
@@ -2754,7 +2767,6 @@
 		"unregistered gadget driver '%s'\n", driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 static int msm72k_udc_runtime_suspend(struct device *dev)
@@ -2781,8 +2793,16 @@
 	.runtime_idle = msm72k_udc_runtime_idle
 };
 
+static int __exit msm72k_remove(struct platform_device *pdev)
+{
+	struct usb_info *ui = container_of(&pdev, struct usb_info, pdev);
+
+	return usb_free(ui, 0);
+}
+
 static struct platform_driver usb_driver = {
 	.probe = msm72k_probe,
+	.remove = msm72k_remove,
 	.driver = { .name = "msm_hsusb",
 		    .pm = &msm72k_udc_dev_pm_ops, },
 };
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index d9feced..8c7b747 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -351,6 +351,7 @@
 	.name		= "g_multi",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(multi_unbind),
 	.iProduct	= DRIVER_DESC,
 	.needs_serial	= 1,
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index b1a8146..6adf38c 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -1128,6 +1128,9 @@
 	return 0;
 }
 
+static int mv_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int mv_udc_stop(struct usb_gadget_driver *driver);
 /* device controller usb_gadget_ops structure */
 static const struct usb_gadget_ops mv_ops = {
 
@@ -1139,6 +1142,8 @@
 
 	/* D+ pullup, software-controlled connect/disconnect to USB host */
 	.pullup		= mv_udc_pullup,
+	.start		= mv_udc_start,
+	.stop		= mv_udc_stop,
 };
 
 static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter)
@@ -1230,7 +1235,7 @@
 	}
 }
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int mv_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct mv_udc *udc = the_controller;
@@ -1270,9 +1275,8 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int mv_udc_stop(struct usb_gadget_driver *driver)
 {
 	struct mv_udc *udc = the_controller;
 	unsigned long flags;
@@ -1296,7 +1300,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 static int
 udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
@@ -1880,9 +1883,10 @@
 static int mv_udc_remove(struct platform_device *dev)
 {
 	struct mv_udc *udc = the_controller;
-
 	DECLARE_COMPLETION(done);
 
+	usb_del_gadget_udc(&udc->gadget);
+
 	udc->done = &done;
 
 	/* free memory allocated in probe */
@@ -2074,11 +2078,12 @@
 
 	the_controller = udc;
 
-	goto out;
+	retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
+	if (!retval)
+		return retval;
 error:
 	if (udc)
 		mv_udc_remove(udc->dev);
-out:
 	return retval;
 }
 
diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c
index 99c179a..62ee508 100644
--- a/drivers/usb/gadget/ncm.c
+++ b/drivers/usb/gadget/ncm.c
@@ -228,6 +228,7 @@
 	.name		= "g_ncm",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(gncm_unbind),
 };
 
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 476d88e..1e6ea6f 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -1410,11 +1410,17 @@
 	return 0;
 }
 
+static int net2280_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int net2280_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops net2280_ops = {
 	.get_frame	= net2280_get_frame,
 	.wakeup		= net2280_wakeup,
 	.set_selfpowered = net2280_set_selfpowered,
 	.pullup		= net2280_pullup,
+	.start		= net2280_start,
+	.stop		= net2280_stop,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1930,7 +1936,7 @@
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int net2280_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct net2280		*dev = the_controller;
@@ -1994,7 +2000,6 @@
 	dev->driver = NULL;
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 static void
 stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
@@ -2022,7 +2027,7 @@
 	usb_reinit (dev);
 }
 
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int net2280_stop(struct usb_gadget_driver *driver)
 {
 	struct net2280	*dev = the_controller;
 	unsigned long	flags;
@@ -2049,8 +2054,6 @@
 	DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -2732,6 +2735,8 @@
 {
 	struct net2280		*dev = pci_get_drvdata (pdev);
 
+	usb_del_gadget_udc(&dev->gadget);
+
 	BUG_ON(dev->driver);
 
 	/* then clean up the resources we allocated during probe() */
@@ -2916,6 +2921,9 @@
 	retval = device_create_file (&pdev->dev, &dev_attr_registers);
 	if (retval) goto done;
 
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (retval)
+		goto done;
 	return 0;
 
 done:
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c
index 55ca63ad3..c7fb772 100644
--- a/drivers/usb/gadget/nokia.c
+++ b/drivers/usb/gadget/nokia.c
@@ -241,6 +241,7 @@
 	.name		= "g_nokia",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(nokia_unbind),
 };
 
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 82fd249..740c7da 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -1375,6 +1375,10 @@
 	return 0;
 }
 
+static int omap_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int omap_udc_stop(struct usb_gadget_driver *driver);
+
 static struct usb_gadget_ops omap_gadget_ops = {
 	.get_frame		= omap_get_frame,
 	.wakeup			= omap_wakeup,
@@ -1382,6 +1386,8 @@
 	.vbus_session		= omap_vbus_session,
 	.vbus_draw		= omap_vbus_draw,
 	.pullup			= omap_pullup,
+	.start			= omap_udc_start,
+	.stop			= omap_udc_stop,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -2102,7 +2108,7 @@
 		);
 }
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int omap_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	int		status = -ENODEV;
@@ -2186,9 +2192,8 @@
 		omap_udc_enable_clock(0);
 	return status;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int omap_udc_stop(struct usb_gadget_driver *driver)
 {
 	unsigned long	flags;
 	int		status = -ENODEV;
@@ -2222,8 +2227,6 @@
 	DBG("unregistered driver '%s'\n", driver->driver.name);
 	return status;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -2991,9 +2994,16 @@
 
 	create_proc_file();
 	status = device_add(&udc->gadget.dev);
+	if (status)
+		goto cleanup4;
+
+	status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
 	if (!status)
 		return status;
 	/* If fail, fall through */
+cleanup4:
+	remove_proc_file();
+
 #ifdef	USE_ISO
 cleanup3:
 	free_irq(pdev->resource[2].start, udc);
@@ -3029,6 +3039,8 @@
 
 	if (!udc)
 		return -ENODEV;
+
+	usb_del_gadget_udc(&udc->gadget);
 	if (udc->driver)
 		return -EBUSY;
 
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 68dbcc3..f96615a 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -1176,6 +1176,9 @@
 	return -EOPNOTSUPP;
 }
 
+static int pch_udc_start(struct usb_gadget_driver *driver,
+	int (*bind)(struct usb_gadget *));
+static int pch_udc_stop(struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops pch_udc_ops = {
 	.get_frame = pch_udc_pcd_get_frame,
 	.wakeup = pch_udc_pcd_wakeup,
@@ -1183,6 +1186,8 @@
 	.pullup = pch_udc_pcd_pullup,
 	.vbus_session = pch_udc_pcd_vbus_session,
 	.vbus_draw = pch_udc_pcd_vbus_draw,
+	.start	= pch_udc_start,
+	.stop	= pch_udc_stop,
 };
 
 /**
@@ -2690,7 +2695,7 @@
 	return 0;
 }
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pch_udc_start(struct usb_gadget_driver *driver,
 	int (*bind)(struct usb_gadget *))
 {
 	struct pch_udc_dev	*dev = pch_udc;
@@ -2733,9 +2738,8 @@
 	dev->connected = 1;
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pch_udc_stop(struct usb_gadget_driver *driver)
 {
 	struct pch_udc_dev	*dev = pch_udc;
 
@@ -2761,7 +2765,6 @@
 	pch_udc_set_disconnect(dev);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 static void pch_udc_shutdown(struct pci_dev *pdev)
 {
@@ -2778,6 +2781,8 @@
 {
 	struct pch_udc_dev	*dev = pci_get_drvdata(pdev);
 
+	usb_del_gadget_udc(&dev->gadget);
+
 	/* gadget driver must not be registered */
 	if (dev->driver)
 		dev_err(&pdev->dev,
@@ -2953,6 +2958,9 @@
 
 	/* Put the device in disconnected state till a driver is bound */
 	pch_udc_set_disconnect(dev);
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (retval)
+		goto finished;
 	return 0;
 
 finished:
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 271ef94..d5df8dd 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -89,8 +89,7 @@
 	u8			config;
 	s8			interface;
 	struct usb_ep		*in_ep, *out_ep;
-	const struct usb_endpoint_descriptor
-				*in, *out;
+
 	struct list_head	rx_reqs;	/* List of free RX structs */
 	struct list_head	rx_reqs_active;	/* List of Active RX xfers */
 	struct list_head	rx_buffers;	/* List of completed xfers */
@@ -895,19 +894,20 @@
 {
 	int			result = 0;
 
-	dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
+	dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
 	dev->in_ep->driver_data = dev;
 
-	dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc);
+	dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
+				    &fs_ep_out_desc);
 	dev->out_ep->driver_data = dev;
 
-	result = usb_ep_enable(dev->in_ep, dev->in);
+	result = usb_ep_enable(dev->in_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
 		goto done;
 	}
 
-	result = usb_ep_enable(dev->out_ep, dev->out);
+	result = usb_ep_enable(dev->out_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
 		goto done;
@@ -918,8 +918,8 @@
 	if (result != 0) {
 		(void) usb_ep_disable(dev->in_ep);
 		(void) usb_ep_disable(dev->out_ep);
-		dev->in = NULL;
-		dev->out = NULL;
+		dev->in_ep->desc = NULL;
+		dev->out_ep->desc = NULL;
 	}
 
 	/* caller is responsible for cleanup on error */
@@ -933,12 +933,14 @@
 
 	DBG(dev, "%s\n", __func__);
 
-	if (dev->in)
+	if (dev->in_ep->desc)
 		usb_ep_disable(dev->in_ep);
 
-	if (dev->out)
+	if (dev->out_ep->desc)
 		usb_ep_disable(dev->out_ep);
 
+	dev->in_ep->desc = NULL;
+	dev->out_ep->desc = NULL;
 	dev->interface = -1;
 }
 
@@ -1104,9 +1106,9 @@
 		list_add(&req->list, &dev->tx_reqs);
 	}
 
-	if (usb_ep_enable(dev->in_ep, dev->in))
+	if (usb_ep_enable(dev->in_ep))
 		DBG(dev, "Failed to enable USB in_ep\n");
-	if (usb_ep_enable(dev->out_ep, dev->out))
+	if (usb_ep_enable(dev->out_ep))
 		DBG(dev, "Failed to enable USB out_ep\n");
 
 	wake_up_interruptible(&dev->rx_wait);
@@ -1146,6 +1148,8 @@
 			switch (wValue >> 8) {
 
 			case USB_DT_DEVICE:
+				device_desc.bMaxPacketSize0 =
+					gadget->ep0->maxpacket;
 				value = min(wLength, (u16) sizeof device_desc);
 				memcpy(req->buf, &device_desc, value);
 				break;
@@ -1153,6 +1157,12 @@
 			case USB_DT_DEVICE_QUALIFIER:
 				if (!gadget->is_dualspeed)
 					break;
+				/*
+				 * assumes ep0 uses the same value for both
+				 * speeds
+				 */
+				dev_qualifier.bMaxPacketSize0 =
+					gadget->ep0->maxpacket;
 				value = min(wLength,
 						(u16) sizeof dev_qualifier);
 				memcpy(req->buf, &dev_qualifier, value);
@@ -1448,15 +1458,11 @@
 	out_ep->driver_data = out_ep;	/* claim */
 
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
-	/* assumes ep0 uses the same value for both speeds ... */
-	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
-
-	/* and that all endpoints are dual-speed */
+	/* assumes that all endpoints are dual-speed */
 	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
 	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
 #endif	/* DUALSPEED */
 
-	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 	usb_gadget_set_selfpowered(gadget);
 
 	if (gadget->is_otg) {
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 7745454..e4e59b4 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -1011,12 +1011,18 @@
 	return -EOPNOTSUPP;
 }
 
+static int pxa25x_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int pxa25x_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops pxa25x_udc_ops = {
 	.get_frame	= pxa25x_udc_get_frame,
 	.wakeup		= pxa25x_udc_wakeup,
 	.vbus_session	= pxa25x_udc_vbus_session,
 	.pullup		= pxa25x_udc_pullup,
 	.vbus_draw	= pxa25x_udc_vbus_draw,
+	.start		= pxa25x_start,
+	.stop		= pxa25x_stop,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1263,7 +1269,7 @@
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pxa25x_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct pxa25x_udc	*dev = the_controller;
@@ -1322,7 +1328,6 @@
 bind_fail:
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 static void
 stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
@@ -1351,7 +1356,7 @@
 	udc_reinit(dev);
 }
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pxa25x_stop(struct usb_gadget_driver *driver)
 {
 	struct pxa25x_udc	*dev = the_controller;
 
@@ -1379,8 +1384,6 @@
 	dump_state(dev);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -2231,8 +2234,11 @@
 #endif
 	create_debug_files(dev);
 
-	return 0;
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (!retval)
+		return retval;
 
+	remove_debug_files(dev);
 #ifdef	CONFIG_ARCH_LUBBOCK
 lubbock_fail0:
 	free_irq(LUBBOCK_USB_DISC_IRQ, dev);
@@ -2261,6 +2267,7 @@
 {
 	struct pxa25x_udc *dev = platform_get_drvdata(pdev);
 
+	usb_del_gadget_udc(&dev->gadget);
 	if (dev->driver)
 		return -EBUSY;
 
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 5760769..85b68c7 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1680,12 +1680,18 @@
 	return -EOPNOTSUPP;
 }
 
+static int pxa27x_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int pxa27x_udc_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops pxa_udc_ops = {
 	.get_frame	= pxa_udc_get_frame,
 	.wakeup		= pxa_udc_wakeup,
 	.pullup		= pxa_udc_pullup,
 	.vbus_session	= pxa_udc_vbus_session,
 	.vbus_draw	= pxa_udc_vbus_draw,
+	.start		= pxa27x_udc_start,
+	.stop		= pxa27x_udc_stop,
 };
 
 /**
@@ -1791,7 +1797,7 @@
 }
 
 /**
- * usb_gadget_probe_driver - Register gadget driver
+ * pxa27x_start - Register gadget driver
  * @driver: gadget driver
  * @bind: bind function
  *
@@ -1805,7 +1811,7 @@
  *
  * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pxa27x_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct pxa_udc *udc = the_controller;
@@ -1860,8 +1866,6 @@
 	udc->gadget.dev.driver = NULL;
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-
 
 /**
  * stop_activity - Stops udc endpoints
@@ -1888,12 +1892,12 @@
 }
 
 /**
- * usb_gadget_unregister_driver - Unregister the gadget driver
+ * pxa27x_udc_stop - Unregister the gadget driver
  * @driver: gadget driver
  *
  * Returns 0 if no error, -ENODEV, -EINVAL otherwise
  */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pxa27x_udc_stop(struct usb_gadget_driver *driver)
 {
 	struct pxa_udc *udc = the_controller;
 
@@ -1917,7 +1921,6 @@
 		return otg_set_peripheral(udc->transceiver, NULL);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /**
  * handle_ep0_ctrl_req - handle control endpoint control request
@@ -2516,9 +2519,14 @@
 			driver_name, IRQ_USB, retval);
 		goto err_irq;
 	}
+	retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+	if (retval)
+		goto err_add_udc;
 
 	pxa_init_debugfs(udc);
 	return 0;
+err_add_udc:
+	free_irq(udc->irq, udc);
 err_irq:
 	iounmap(udc->regs);
 err_map:
@@ -2537,6 +2545,7 @@
 	struct pxa_udc *udc = platform_get_drvdata(_dev);
 	int gpio = udc->mach->gpio_pullup;
 
+	usb_del_gadget_udc(&udc->gadget);
 	usb_gadget_unregister_driver(udc->driver);
 	free_irq(udc->irq, udc);
 	pxa_cleanup_debugfs(udc);
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index 6dcc1f6..51b655f 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1410,7 +1410,7 @@
 /*-------------------------------------------------------------------------*/
 static struct r8a66597 *the_controller;
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int r8a66597_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct r8a66597 *r8a66597 = the_controller;
@@ -1462,9 +1462,8 @@
 
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int r8a66597_stop(struct usb_gadget_driver *driver)
 {
 	struct r8a66597 *r8a66597 = the_controller;
 	unsigned long flags;
@@ -1488,7 +1487,6 @@
 	r8a66597->driver = NULL;
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /*-------------------------------------------------------------------------*/
 static int r8a66597_get_frame(struct usb_gadget *_gadget)
@@ -1499,12 +1497,15 @@
 
 static struct usb_gadget_ops r8a66597_gadget_ops = {
 	.get_frame		= r8a66597_get_frame,
+	.start			= r8a66597_start,
+	.stop			= r8a66597_stop,
 };
 
 static int __exit r8a66597_remove(struct platform_device *pdev)
 {
 	struct r8a66597		*r8a66597 = dev_get_drvdata(&pdev->dev);
 
+	usb_del_gadget_udc(&r8a66597->gadget);
 	del_timer_sync(&r8a66597->timer);
 	iounmap(r8a66597->reg);
 	free_irq(platform_get_irq(pdev, 0), r8a66597);
@@ -1647,9 +1648,15 @@
 
 	init_controller(r8a66597);
 
+	ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	return 0;
 
+err_add_udc:
+	r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
 clean_up3:
 	free_irq(irq, r8a66597);
 clean_up2:
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 0dfee28..8bdee67c 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -2574,7 +2574,7 @@
 	return 0;
 }
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int s3c_hsotg_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct s3c_hsotg *hsotg = our_hsotg;
@@ -2745,9 +2745,8 @@
 	hsotg->gadget.dev.driver = NULL;
 	return ret;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
 {
 	struct s3c_hsotg *hsotg = our_hsotg;
 	int ep;
@@ -2775,7 +2774,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
 {
@@ -2784,6 +2782,8 @@
 
 static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
 	.get_frame	= s3c_hsotg_gadget_getframe,
+	.start		= s3c_hsotg_start,
+	.stop		= s3c_hsotg_stop,
 };
 
 /**
@@ -3403,6 +3403,10 @@
 	for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)
 		s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
 
+	ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	s3c_hsotg_create_debug(hsotg);
 
 	s3c_hsotg_dump(hsotg);
@@ -3410,6 +3414,11 @@
 	our_hsotg = hsotg;
 	return 0;
 
+err_add_udc:
+	s3c_hsotg_gate(pdev, false);
+	clk_disable(hsotg->clk);
+	clk_put(hsotg->clk);
+
 err_regs:
 	iounmap(hsotg->regs);
 
@@ -3427,6 +3436,8 @@
 {
 	struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
 
+	usb_del_gadget_udc(&hsotg->gadget);
+
 	s3c_hsotg_delete_debug(hsotg);
 
 	usb_gadget_unregister_driver(hsotg->driver);
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index d5e3e1e..dc9f428 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -1133,7 +1133,7 @@
 	return IRQ_HANDLED;
 }
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int s3c_hsudc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct s3c_hsudc *hsudc = the_controller;
@@ -1181,9 +1181,8 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
 {
 	struct s3c_hsudc *hsudc = the_controller;
 	unsigned long flags;
@@ -1210,7 +1209,6 @@
 			driver->driver.name);
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc)
 {
@@ -1224,6 +1222,8 @@
 
 static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
 	.get_frame	= s3c_hsudc_gadget_getframe,
+	.start		= s3c_hsudc_start,
+	.stop		= s3c_hsudc_stop,
 };
 
 static int s3c_hsudc_probe(struct platform_device *pdev)
@@ -1311,7 +1311,15 @@
 
 	disable_irq(hsudc->irq);
 	local_irq_enable();
+
+	ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	return 0;
+err_add_udc:
+	clk_disable(hsudc->uclk);
+	clk_put(hsudc->uclk);
 err_clk:
 	free_irq(hsudc->irq, hsudc);
 err_irq:
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 100f263..1c19cd3 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1552,6 +1552,10 @@
 	return -ENOTSUPP;
 }
 
+static int s3c2410_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int s3c2410_udc_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops s3c2410_ops = {
 	.get_frame		= s3c2410_udc_get_frame,
 	.wakeup			= s3c2410_udc_wakeup,
@@ -1559,6 +1563,8 @@
 	.pullup			= s3c2410_udc_pullup,
 	.vbus_session		= s3c2410_udc_vbus_session,
 	.vbus_draw		= s3c2410_vbus_draw,
+	.start			= s3c2410_udc_start,
+	.stop			= s3c2410_udc_stop,
 };
 
 static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
@@ -1672,10 +1678,7 @@
 	s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
 }
 
-/*
- *	usb_gadget_probe_driver
- */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int s3c2410_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct s3c2410_udc *udc = the_controller;
@@ -1730,12 +1733,8 @@
 	udc->gadget.dev.driver = NULL;
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-/*
- *	usb_gadget_unregister_driver
- */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int s3c2410_udc_stop(struct usb_gadget_driver *driver)
 {
 	struct s3c2410_udc *udc = the_controller;
 
@@ -1955,6 +1954,10 @@
 			goto err_vbus_irq;
 	}
 
+	retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+	if (retval)
+		goto err_add_udc;
+
 	if (s3c2410_udc_debugfs_root) {
 		udc->regs_info = debugfs_create_file("registers", S_IRUGO,
 				s3c2410_udc_debugfs_root,
@@ -1967,6 +1970,10 @@
 
 	return 0;
 
+err_add_udc:
+	if (udc_info && !udc_info->udc_command &&
+			gpio_is_valid(udc_info->pullup_pin))
+		gpio_free(udc_info->pullup_pin);
 err_vbus_irq:
 	if (udc_info && udc_info->vbus_pin > 0)
 		free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
@@ -1992,6 +1999,8 @@
 	unsigned int irq;
 
 	dev_dbg(&pdev->dev, "%s()\n", __func__);
+
+	usb_del_gadget_udc(&udc->gadget);
 	if (udc->driver)
 		return -EBUSY;
 
@@ -2105,8 +2114,6 @@
 	debugfs_remove(s3c2410_udc_debugfs_root);
 }
 
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 module_init(udc_init);
 module_exit(udc_exit);
 
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 1ac57a9..ed1b816 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -242,6 +242,7 @@
 	.name		= "g_serial",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 };
 
 static int __init init(void)
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 1505967..43a54f1 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -247,6 +247,8 @@
 	u32		sense_data_info;
 	u32		unit_attention_data;
 
+	unsigned int	blkbits;	/* Bits of logical block size of bound block device */
+	unsigned int	blksize;	/* logical block size of bound block device */
 	struct device	dev;
 #ifdef CONFIG_USB_MSC_PROFILING
 	spinlock_t	lock;
@@ -509,12 +511,128 @@
 	NULL,
 };
 
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
+	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/*.bMaxBurst =		DYNAMIC, */
+};
+
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
+	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/*.bMaxBurst =		DYNAMIC, */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_ss_intr_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(2),
+	.bInterval =		9,	/* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = {
+	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	.wBytesPerInterval =	cpu_to_le16(2),
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_SS_FUNCTION_PRE_EP_ENTRIES	2
+#else
+#  define FSG_SS_FUNCTION_PRE_EP_ENTRIES	1
+#endif
+
+#endif
+
+static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = {
+	.bLength =		USB_DT_USB_EXT_CAP_SIZE,
+	.bDescriptorType =	USB_DT_DEVICE_CAPABILITY,
+	.bDevCapabilityType =	USB_CAP_TYPE_EXT,
+
+	.bmAttributes =		cpu_to_le32(USB_LPM_SUPPORT),
+};
+
+static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
+	.bLength =		USB_DT_USB_SS_CAP_SIZE,
+	.bDescriptorType =	USB_DT_DEVICE_CAPABILITY,
+	.bDevCapabilityType =	USB_SS_CAP_TYPE,
+
+	/* .bmAttributes = LTM is not supported yet */
+
+	.wSpeedSupported =	cpu_to_le16(USB_LOW_SPEED_OPERATION
+		| USB_FULL_SPEED_OPERATION
+		| USB_HIGH_SPEED_OPERATION
+		| USB_5GBPS_OPERATION),
+	.bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
+	.bU1devExitLat =	USB_DEFAULT_U1_DEV_EXIT_LAT,
+	.bU2DevExitLat =	USB_DEFAULT_U2_DEV_EXIT_LAT,
+};
+
+static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
+	.bLength =		USB_DT_BOS_SIZE,
+	.bDescriptorType =	USB_DT_BOS,
+
+	.wTotalLength =		USB_DT_BOS_SIZE
+				+ USB_DT_USB_EXT_CAP_SIZE
+				+ USB_DT_USB_SS_CAP_SIZE,
+
+	.bNumDeviceCaps =	2,
+};
+
+static struct usb_descriptor_header *fsg_ss_function[] = {
+#ifndef FSG_NO_OTG
+	(struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+	(struct usb_descriptor_header *) &fsg_intf_desc,
+	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
+	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
+	(struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
+	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
+#ifndef FSG_NO_INTR_EP
+	(struct usb_descriptor_header *) &fsg_ss_intr_in_desc,
+	(struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc,
+#endif
+	NULL,
+};
+
 /* Maxpacket and other transfer characteristics vary by speed. */
-static struct usb_endpoint_descriptor *
+static __maybe_unused struct usb_endpoint_descriptor *
 fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
-		struct usb_endpoint_descriptor *hs)
+		struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *ss)
 {
-	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+		return ss;
+	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
 		return hs;
 	return fs;
 }
@@ -596,13 +714,24 @@
 		rc = (int) size;
 		goto out;
 	}
-	num_sectors = size >> 9;	/* File size in 512-byte blocks */
+
+	if (curlun->cdrom) {
+		curlun->blksize = 2048;
+		curlun->blkbits = 11;
+	} else if (inode->i_bdev) {
+		curlun->blksize = bdev_logical_block_size(inode->i_bdev);
+		curlun->blkbits = blksize_bits(curlun->blksize);
+	} else {
+		curlun->blksize = 512;
+		curlun->blkbits = 9;
+	}
+
+	num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */
 	min_sectors = 1;
 	if (curlun->cdrom) {
-		num_sectors &= ~3;	/* Reduce to a multiple of 2048 */
-		min_sectors = 300*4;	/* Smallest track is 300 frames */
-		if (num_sectors >= 256*60*75*4) {
-			num_sectors = (256*60*75 - 1) * 4;
+		min_sectors = 300;	/* Smallest track is 300 frames */
+		if (num_sectors >= 256*60*75) {
+			num_sectors = 256*60*75 - 1;
 			LINFO(curlun, "file too big: %s\n", filename);
 			LINFO(curlun, "using only first %d blocks\n",
 					(int) num_sectors);
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 6299cdd..36270d4 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -704,7 +704,7 @@
 	int ret;
 	unsigned long flags;
 
-	ret = usb_ep_enable(port->gr->in, port->gr->in_desc);
+	ret = usb_ep_enable(port->gr->in);
 	if (ret) {
 		pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
 				__func__, port->gr->in);
@@ -712,7 +712,7 @@
 	}
 	port->gr->in->driver_data = port;
 
-	ret = usb_ep_enable(port->gr->out, port->gr->out_desc);
+	ret = usb_ep_enable(port->gr->out);
 	if (ret) {
 		pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
 				__func__, port->gr->out);
@@ -1125,7 +1125,7 @@
 	d = &port->data_ch;
 
 	if (trans == USB_GADGET_XPORT_BAM) {
-		ret = usb_ep_enable(gr->in, gr->in_desc);
+		ret = usb_ep_enable(gr->in);
 		if (ret) {
 			pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
 					__func__, gr->in);
@@ -1133,7 +1133,7 @@
 		}
 		gr->in->driver_data = port;
 
-		ret = usb_ep_enable(gr->out, gr->out_desc);
+		ret = usb_ep_enable(gr->out);
 		if (ret) {
 			pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
 					__func__, gr->out);
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 818e2a6..abf147a 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -754,8 +754,6 @@
 	struct gdata_port		*port;
 	struct gserial			*gser;
 	struct grmnet			*gr;
-	struct usb_endpoint_descriptor	*in_desc;
-	struct usb_endpoint_descriptor	*out_desc;
 	unsigned long			flags;
 	int				ret = 0;
 
@@ -788,8 +786,6 @@
 		port->rx_q_size = ghsic_data_serial_rx_q_size;
 		gser->in->driver_data = port;
 		gser->out->driver_data = port;
-		in_desc = gser->in_desc;
-		out_desc = gser->out_desc;
 	} else {
 		gr = gptr;
 
@@ -805,18 +801,16 @@
 		port->rx_q_size = ghsic_data_rmnet_rx_q_size;
 		gr->in->driver_data = port;
 		gr->out->driver_data = port;
-		in_desc = gr->in_desc;
-		out_desc = gr->out_desc;
 	}
 
-	ret = usb_ep_enable(port->in, in_desc);
+	ret = usb_ep_enable(port->in);
 	if (ret) {
 		pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
 				__func__, port->in);
 		goto fail;
 	}
 
-	ret = usb_ep_enable(port->out, out_desc);
+	ret = usb_ep_enable(port->out);
 	if (ret) {
 		pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
 				__func__, port->out);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index b5a30fe..39c53da 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -693,8 +693,8 @@
 		usb_ep_disable(link->out_ep);
 		if (netif_carrier_ok(net)) {
 			DBG(dev, "host still using in/out endpoints\n");
-			usb_ep_enable(link->in_ep, link->in);
-			usb_ep_enable(link->out_ep, link->out);
+			usb_ep_enable(link->in_ep);
+			usb_ep_enable(link->out_ep);
 		}
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -891,7 +891,7 @@
 		return ERR_PTR(-EINVAL);
 
 	link->in_ep->driver_data = dev;
-	result = usb_ep_enable(link->in_ep, link->in);
+	result = usb_ep_enable(link->in_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n",
 			link->in_ep->name, result);
@@ -899,7 +899,7 @@
 	}
 
 	link->out_ep->driver_data = dev;
-	result = usb_ep_enable(link->out_ep, link->out);
+	result = usb_ep_enable(link->out_ep);
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n",
 			link->out_ep->name, result);
@@ -988,7 +988,7 @@
 	}
 	spin_unlock(&dev->req_lock);
 	link->in_ep->driver_data = NULL;
-	link->in = NULL;
+	link->in_ep->desc = NULL;
 
 	usb_ep_disable(link->out_ep);
 	spin_lock(&dev->req_lock);
@@ -1003,7 +1003,7 @@
 	}
 	spin_unlock(&dev->req_lock);
 	link->out_ep->driver_data = NULL;
-	link->out = NULL;
+	link->out_ep->desc = NULL;
 
 	/* finish forgetting about this USB link episode */
 	dev->header_len = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 64b65f9..4677241 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -52,10 +52,6 @@
 	struct usb_ep			*in_ep;
 	struct usb_ep			*out_ep;
 
-	/* descriptors match device speed at gether_connect() time */
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-
 	bool				is_zlp_ok;
 
 	u16				cdc_filter;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index fd1e124f..386101c 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -29,8 +29,6 @@
 
 	struct usb_ep			*in;
 	struct usb_ep			*out;
-	struct usb_endpoint_descriptor	*in_desc;
-	struct usb_endpoint_descriptor	*out_desc;
 
 	/* to usb host, aka laptop, windows pc etc. Will
 	 * be filled by usb driver of rmnet functionality
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index 9bd4370..14dc73a 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -931,7 +931,7 @@
 	gser->notify_modem = gsdio_ctrl_notify_modem;
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
-	ret = usb_ep_enable(gser->in, gser->in_desc);
+	ret = usb_ep_enable(gser->in);
 	if (ret) {
 		pr_err("%s: failed to enable in ep w/ err:%d\n",
 					__func__, ret);
@@ -940,7 +940,7 @@
 	}
 	gser->in->driver_data = port;
 
-	ret = usb_ep_enable(gser->out, gser->out_desc);
+	ret = usb_ep_enable(gser->out);
 	if (ret) {
 		pr_err("%s: failed to enable in ep w/ err:%d\n",
 					__func__, ret);
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index ca5f11b..10a255d 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -1524,12 +1524,12 @@
 	port = ports[port_num].port;
 
 	/* activate the endpoints */
-	status = usb_ep_enable(gser->in, gser->in_desc);
+	status = usb_ep_enable(gser->in);
 	if (status < 0)
 		return status;
 	gser->in->driver_data = port;
 
-	status = usb_ep_enable(gser->out, gser->out_desc);
+	status = usb_ep_enable(gser->out);
 	if (status < 0)
 		goto fail_out;
 	gser->out->driver_data = port;
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
index c937006..dadc507 100644
--- a/drivers/usb/gadget/u_serial.h
+++ b/drivers/usb/gadget/u_serial.h
@@ -35,8 +35,6 @@
 
 	struct usb_ep			*in;
 	struct usb_ep			*out;
-	struct usb_endpoint_descriptor	*in_desc;
-	struct usb_endpoint_descriptor	*out_desc;
 
 	/* REVISIT avoid this CDC-ACM support harder ... */
 	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index 95adf5d..0e9ad48 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -660,7 +660,7 @@
 	port->nbytes_tolaptop = 0;
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
-	ret = usb_ep_enable(gser->in, gser->in_desc);
+	ret = usb_ep_enable(gser->in);
 	if (ret) {
 		pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
 				__func__, gser->in);
@@ -669,7 +669,7 @@
 	}
 	gser->in->driver_data = port;
 
-	ret = usb_ep_enable(gser->out, gser->out_desc);
+	ret = usb_ep_enable(gser->out);
 	if (ret) {
 		pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
 				__func__, gser->out);
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
new file mode 100644
index 0000000..2f77e469
--- /dev/null
+++ b/drivers/usb/gadget/udc-core.c
@@ -0,0 +1,485 @@
+/**
+ * udc.c - Core UDC Framework
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/**
+ * struct usb_udc - describes one usb device controller
+ * @driver - the gadget driver pointer. For use by the class code
+ * @dev - the child device to the actual controller
+ * @gadget - the gadget. For use by the class code
+ * @list - for use by the udc class driver
+ *
+ * This represents the internal data structure which is used by the UDC-class
+ * to hold information about udc driver and gadget together.
+ */
+struct usb_udc {
+	struct usb_gadget_driver	*driver;
+	struct usb_gadget		*gadget;
+	struct device			dev;
+	struct list_head		list;
+};
+
+static struct class *udc_class;
+static struct device_type udc_device_type;
+static LIST_HEAD(udc_list);
+static DEFINE_MUTEX(udc_lock);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * usb_gadget_start - tells usb device controller to start up
+ * @gadget: The gadget we want to get started
+ * @driver: The driver we want to bind to @gadget
+ * @bind: The bind function for @driver
+ *
+ * This call is issued by the UDC Class driver when it's about
+ * to register a gadget driver to the device controller, before
+ * calling gadget driver's bind() method.
+ *
+ * It allows the controller to be powered off until strictly
+ * necessary to have it powered on.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *))
+{
+	return gadget->ops->start(driver, bind);
+}
+
+/**
+ * usb_gadget_udc_start - tells usb device controller to start up
+ * @gadget: The gadget we want to get started
+ * @driver: The driver we want to bind to @gadget
+ *
+ * This call is issued by the UDC Class driver when it's about
+ * to register a gadget driver to the device controller, before
+ * calling gadget driver's bind() method.
+ *
+ * It allows the controller to be powered off until strictly
+ * necessary to have it powered on.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_udc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	return gadget->ops->udc_start(gadget, driver);
+}
+
+/**
+ * usb_gadget_stop - tells usb device controller we don't need it anymore
+ * @gadget: The device we want to stop activity
+ * @driver: The driver to unbind from @gadget
+ *
+ * This call is issued by the UDC Class driver after calling
+ * gadget driver's unbind() method.
+ *
+ * The details are implementation specific, but it can go as
+ * far as powering off UDC completely and disable its data
+ * line pullups.
+ */
+static inline void usb_gadget_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	gadget->ops->stop(driver);
+}
+
+/**
+ * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
+ * @gadget: The device we want to stop activity
+ * @driver: The driver to unbind from @gadget
+ *
+ * This call is issued by the UDC Class driver after calling
+ * gadget driver's unbind() method.
+ *
+ * The details are implementation specific, but it can go as
+ * far as powering off UDC completely and disable its data
+ * line pullups.
+ */
+static inline void usb_gadget_udc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	gadget->ops->udc_stop(gadget, driver);
+}
+
+/**
+ * usb_udc_release - release the usb_udc struct
+ * @dev: the dev member within usb_udc
+ *
+ * This is called by driver's core in order to free memory once the last
+ * reference is released.
+ */
+static void usb_udc_release(struct device *dev)
+{
+	struct usb_udc *udc;
+
+	udc = container_of(dev, struct usb_udc, dev);
+	dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+	kfree(udc);
+}
+
+/**
+ * usb_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+	struct usb_udc		*udc;
+	int			ret = -ENOMEM;
+
+	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		goto err1;
+
+	device_initialize(&udc->dev);
+	udc->dev.release = usb_udc_release;
+	udc->dev.class = udc_class;
+	udc->dev.parent = parent;
+	ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
+	if (ret)
+		goto err2;
+
+	udc->gadget = gadget;
+
+	mutex_lock(&udc_lock);
+	list_add_tail(&udc->list, &udc_list);
+
+	ret = device_add(&udc->dev);
+	if (ret)
+		goto err3;
+
+	mutex_unlock(&udc_lock);
+
+	return 0;
+err3:
+	list_del(&udc->list);
+	mutex_unlock(&udc_lock);
+
+err2:
+	put_device(&udc->dev);
+
+err1:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
+
+static int udc_is_newstyle(struct usb_udc *udc)
+{
+	if (udc->gadget->ops->udc_start && udc->gadget->ops->udc_stop)
+		return 1;
+	return 0;
+}
+
+
+static void usb_gadget_remove_driver(struct usb_udc *udc)
+{
+	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
+			udc->gadget->name);
+
+	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+
+	if (udc_is_newstyle(udc)) {
+		udc->driver->disconnect(udc->gadget);
+		udc->driver->unbind(udc->gadget);
+		usb_gadget_udc_stop(udc->gadget, udc->driver);
+		usb_gadget_disconnect(udc->gadget);
+	} else {
+		usb_gadget_stop(udc->gadget, udc->driver);
+	}
+
+	udc->driver = NULL;
+	udc->dev.driver = NULL;
+}
+
+/**
+ * usb_del_gadget_udc - deletes @udc from udc_list
+ * @gadget: the gadget to be removed.
+ *
+ * This, will call usb_gadget_unregister_driver() if
+ * the @udc is still busy.
+ */
+void usb_del_gadget_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc		*udc = NULL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			goto found;
+
+	dev_err(gadget->dev.parent, "gadget not registered.\n");
+	mutex_unlock(&udc_lock);
+
+	return;
+
+found:
+	dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
+
+	list_del(&udc->list);
+	mutex_unlock(&udc_lock);
+
+	if (udc->driver)
+		usb_gadget_remove_driver(udc);
+
+	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
+	device_unregister(&udc->dev);
+}
+EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
+
+/* ------------------------------------------------------------------------- */
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *))
+{
+	struct usb_udc		*udc = NULL;
+	int			ret;
+
+	if (!driver || !bind || !driver->setup)
+		return -EINVAL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list) {
+		/* For now we take the first one */
+		if (!udc->driver)
+			goto found;
+	}
+
+	pr_debug("couldn't find an available UDC\n");
+	mutex_unlock(&udc_lock);
+	return -ENODEV;
+
+found:
+	dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
+			driver->function);
+
+	udc->driver = driver;
+	udc->dev.driver = &driver->driver;
+
+	if (udc_is_newstyle(udc)) {
+		ret = bind(udc->gadget);
+		if (ret)
+			goto err1;
+		ret = usb_gadget_udc_start(udc->gadget, driver);
+		if (ret) {
+			driver->unbind(udc->gadget);
+			goto err1;
+		}
+		usb_gadget_connect(udc->gadget);
+	} else {
+
+		ret = usb_gadget_start(udc->gadget, driver, bind);
+		if (ret)
+			goto err1;
+
+	}
+
+	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+	mutex_unlock(&udc_lock);
+	return 0;
+
+err1:
+	dev_err(&udc->dev, "failed to start %s: %d\n",
+			udc->driver->function, ret);
+	udc->driver = NULL;
+	udc->dev.driver = NULL;
+	mutex_unlock(&udc_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_udc		*udc = NULL;
+	int			ret = -ENODEV;
+
+	if (!driver || !driver->unbind)
+		return -EINVAL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->driver == driver) {
+			usb_gadget_remove_driver(udc);
+			ret = 0;
+			break;
+		}
+
+	mutex_unlock(&udc_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
+
+/* ------------------------------------------------------------------------- */
+
+static ssize_t usb_udc_srp_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t n)
+{
+	struct usb_udc		*udc = dev_get_drvdata(dev);
+
+	if (sysfs_streq(buf, "1"))
+		usb_gadget_wakeup(udc->gadget);
+
+	return n;
+}
+static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
+
+static ssize_t usb_udc_softconn_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t n)
+{
+	struct usb_udc		*udc = dev_get_drvdata(dev);
+
+	if (sysfs_streq(buf, "connect")) {
+		usb_gadget_connect(udc->gadget);
+	} else if (sysfs_streq(buf, "disconnect")) {
+		usb_gadget_disconnect(udc->gadget);
+	} else {
+		dev_err(dev, "unsupported command '%s'\n", buf);
+		return -EINVAL;
+	}
+
+	return n;
+}
+static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
+
+static ssize_t usb_udc_speed_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct usb_udc		*udc = dev_get_drvdata(dev);
+	struct usb_gadget	*gadget = udc->gadget;
+
+	switch (gadget->speed) {
+	case USB_SPEED_LOW:
+		return snprintf(buf, PAGE_SIZE, "low-speed\n");
+	case USB_SPEED_FULL:
+		return snprintf(buf, PAGE_SIZE, "full-speed\n");
+	case USB_SPEED_HIGH:
+		return snprintf(buf, PAGE_SIZE, "high-speed\n");
+	case USB_SPEED_WIRELESS:
+		return snprintf(buf, PAGE_SIZE, "wireless\n");
+	case USB_SPEED_SUPER:
+		return snprintf(buf, PAGE_SIZE, "super-speed\n");
+	case USB_SPEED_UNKNOWN:	/* FALLTHROUGH */
+	default:
+		return snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
+	}
+}
+static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL);
+
+#define USB_UDC_ATTR(name)					\
+ssize_t usb_udc_##name##_show(struct device *dev,		\
+		struct device_attribute *attr, char *buf)	\
+{								\
+	struct usb_udc		*udc = dev_get_drvdata(dev);	\
+	struct usb_gadget	*gadget = udc->gadget;		\
+								\
+	return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name);	\
+}								\
+static DEVICE_ATTR(name, S_IRUSR, usb_udc_##name##_show, NULL)
+
+static USB_UDC_ATTR(is_dualspeed);
+static USB_UDC_ATTR(is_otg);
+static USB_UDC_ATTR(is_a_peripheral);
+static USB_UDC_ATTR(b_hnp_enable);
+static USB_UDC_ATTR(a_hnp_support);
+static USB_UDC_ATTR(a_alt_hnp_support);
+
+static struct attribute *usb_udc_attrs[] = {
+	&dev_attr_srp.attr,
+	&dev_attr_soft_connect.attr,
+	&dev_attr_speed.attr,
+
+	&dev_attr_is_dualspeed.attr,
+	&dev_attr_is_otg.attr,
+	&dev_attr_is_a_peripheral.attr,
+	&dev_attr_b_hnp_enable.attr,
+	&dev_attr_a_hnp_support.attr,
+	&dev_attr_a_alt_hnp_support.attr,
+	NULL,
+};
+
+static const struct attribute_group usb_udc_attr_group = {
+	.attrs = usb_udc_attrs,
+};
+
+static const struct attribute_group *usb_udc_attr_groups[] = {
+	&usb_udc_attr_group,
+	NULL,
+};
+
+static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev);
+	int			ret;
+
+	ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name);
+	if (ret) {
+		dev_err(dev, "failed to add uevent USB_UDC_NAME\n");
+		return ret;
+	}
+
+	if (udc->driver) {
+		ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
+				udc->driver->function);
+		if (ret) {
+			dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int __init usb_udc_init(void)
+{
+	udc_class = class_create(THIS_MODULE, "udc");
+	if (IS_ERR(udc_class)) {
+		pr_err("failed to create udc class --> %ld\n",
+				PTR_ERR(udc_class));
+		return PTR_ERR(udc_class);
+	}
+
+	udc_class->dev_uevent = usb_udc_uevent;
+	udc_device_type.groups = usb_udc_attr_groups;
+
+	return 0;
+}
+subsys_initcall(usb_udc_init);
+
+static void __exit usb_udc_exit(void)
+{
+	class_destroy(udc_class);
+}
+module_exit(usb_udc_exit);
+
+MODULE_DESCRIPTION("UDC Framework");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c
index a5a0fdb..df6882d 100644
--- a/drivers/usb/gadget/webcam.c
+++ b/drivers/usb/gadget/webcam.c
@@ -373,6 +373,7 @@
 	.name		= "g_webcam",
 	.dev		= &webcam_device_descriptor,
 	.strings	= webcam_device_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= webcam_unbind,
 };
 
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 6d16db9..af7e7c3 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -340,6 +340,7 @@
 	.name		= "zero",
 	.dev		= &device_desc,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= zero_unbind,
 	.suspend	= zero_suspend,
 	.resume		= zero_resume,
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index ece6785..bda6745 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -189,6 +189,13 @@
 	  for chip-to-chip interconnect (having maximum circuit length of
 	  10cm) as it removes the analog transceivers.
 
+config USB_EHCI_MSM_HOST4
+	bool "Support for MSM on-chip EHCI USB controller# 4"
+	depends on USB_EHCI_HCD && ARCH_MSM && ARCH_APQ8064
+	---help---
+	  Enables support for the EHCI Compliant USB Host controller# 4
+	  present on the Qualcomm chipsets.
+
 config USB_EHCI_TEGRA
        boolean "NVIDIA Tegra HCD support"
        depends on USB_EHCI_HCD && ARCH_TEGRA
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 4f6fe3e..4318efb 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -48,6 +48,7 @@
 	struct regulator			*hsusb_1p8;
 	struct regulator			*vbus;
 	bool					async_int;
+	bool					vbus_on;
 	atomic_t				in_lpm;
 	struct wake_lock			wlock;
 };
@@ -174,17 +175,24 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-#define HSUSB_PHY_SUSP_DIG_VOL  500000
+#define HSUSB_PHY_SUSP_DIG_VOL_P50  500000
+#define HSUSB_PHY_SUSP_DIG_VOL_P75  750000
 static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
 {
+	struct msm_usb_host_platform_data *pdata;
 	int max_vol = HSUSB_PHY_VDD_DIG_VOL_MAX;
 	int min_vol;
 	int ret;
 
+	pdata = mhcd->dev->platform_data;
+
 	if (high)
 		min_vol = HSUSB_PHY_VDD_DIG_VOL_MIN;
+	else if (pdata && pdata->dock_connect_irq &&
+			!irq_read_line(pdata->dock_connect_irq))
+		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P75;
 	else
-		min_vol = HSUSB_PHY_SUSP_DIG_VOL;
+		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P50;
 
 	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
@@ -205,29 +213,6 @@
 }
 #endif
 
-static int msm_ehci_init_vbus(struct msm_hcd *mhcd, int init)
-{
-	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
-	struct msm_usb_host_platform_data *pdata;
-
-	if (!init) {
-		regulator_put(mhcd->vbus);
-		return 0;
-	}
-
-	mhcd->vbus = regulator_get(mhcd->dev, "vbus");
-	if (IS_ERR(mhcd->vbus)) {
-		pr_err("Unable to get vbus\n");
-		return -ENODEV;
-	}
-
-	pdata = mhcd->dev->platform_data;
-	if (pdata)
-		hcd->power_budget = pdata->power_budget;
-
-	return 0;
-}
-
 static void msm_ehci_vbus_power(struct msm_hcd *mhcd, bool on)
 {
 	int ret;
@@ -236,21 +221,86 @@
 		pr_err("vbus is NULL.");
 		return;
 	}
+
+	if (mhcd->vbus_on == on)
+		return;
+
 	if (on) {
 		ret = regulator_enable(mhcd->vbus);
 		if (ret) {
 			pr_err("unable to enable vbus\n");
 			return;
 		}
+		mhcd->vbus_on = true;
 	} else {
 		ret = regulator_disable(mhcd->vbus);
 		if (ret) {
 			pr_err("unable to disable vbus\n");
 			return;
 		}
+		mhcd->vbus_on = false;
 	}
 }
 
+static irqreturn_t msm_ehci_dock_connect_irq(int irq, void *data)
+{
+	const struct msm_usb_host_platform_data *pdata;
+	struct msm_hcd *mhcd = data;
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+
+	pdata = mhcd->dev->platform_data;
+
+	if (atomic_read(&mhcd->in_lpm))
+		usb_hcd_resume_root_hub(hcd);
+
+	if (irq_read_line(pdata->dock_connect_irq)) {
+		dev_dbg(mhcd->dev, "%s:Dock removed disable vbus\n", __func__);
+		msm_ehci_vbus_power(mhcd, 0);
+	} else {
+		dev_dbg(mhcd->dev, "%s:Dock connected enable vbus\n", __func__);
+		msm_ehci_vbus_power(mhcd, 1);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int msm_ehci_init_vbus(struct msm_hcd *mhcd, int init)
+{
+	int rc = 0;
+	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+	const struct msm_usb_host_platform_data *pdata;
+
+	pdata = mhcd->dev->platform_data;
+
+	if (!init) {
+		regulator_put(mhcd->vbus);
+		if (pdata && pdata->dock_connect_irq)
+			free_irq(pdata->dock_connect_irq, mhcd);
+		return rc;
+	}
+
+	mhcd->vbus = regulator_get(mhcd->dev, "vbus");
+	if (IS_ERR(mhcd->vbus)) {
+		pr_err("Unable to get vbus\n");
+		return -ENODEV;
+	}
+
+	if (pdata) {
+		hcd->power_budget = pdata->power_budget;
+
+		if (pdata->dock_connect_irq) {
+			rc = request_threaded_irq(pdata->dock_connect_irq, NULL,
+					msm_ehci_dock_connect_irq,
+					IRQF_TRIGGER_FALLING |
+					IRQF_TRIGGER_RISING |
+					IRQF_ONESHOT, "msm_ehci_host", mhcd);
+			if (!rc)
+				enable_irq_wake(pdata->dock_connect_irq);
+		}
+	}
+	return rc;
+}
+
 static int msm_ehci_ldo_enable(struct msm_hcd *mhcd, int on)
 {
 	int ret = 0;
@@ -772,6 +822,7 @@
 	struct usb_hcd *hcd;
 	struct resource *res;
 	struct msm_hcd *mhcd;
+	const struct msm_usb_host_platform_data *pdata;
 	int ret;
 
 	dev_dbg(&pdev->dev, "ehci_msm2 probe\n");
@@ -859,8 +910,10 @@
 		goto vbus_deinit;
 	}
 
-	/*TBD:for now enable vbus here*/
-	msm_ehci_vbus_power(mhcd, 1);
+	pdata = mhcd->dev->platform_data;
+	if (pdata && (!pdata->dock_connect_irq ||
+				!irq_read_line(pdata->dock_connect_irq)))
+		msm_ehci_vbus_power(mhcd, 1);
 
 	device_init_wakeup(&pdev->dev, 1);
 	wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
@@ -903,6 +956,7 @@
 	pm_runtime_set_suspended(&pdev->dev);
 
 	usb_remove_hcd(hcd);
+
 	msm_ehci_vbus_power(mhcd, 0);
 	msm_ehci_init_vbus(mhcd, 0);
 	msm_ehci_ldo_enable(mhcd, 0);
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 5ab987e..9794918 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -82,6 +82,7 @@
 			urb->status, urb->actual_length);
 
 	if (urb->status == -EPROTO) {
+		dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
 		/* save error so that subsequent read/write returns ESHUTDOWN */
 		dev->err = urb->status;
 		return;
@@ -119,27 +120,36 @@
 	if (dev->err)
 		return -ESHUTDOWN;
 
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb) {
 		dev_err(&dev->udev->dev, "unable to allocate urb\n");
 		return -ENOMEM;
 	}
 
+	ret = usb_autopm_get_interface(dev->ifc);
+	if (ret < 0) {
+		dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
+		usb_free_urb(urb);
+		return ret;
+	}
+
 	pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
 	usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
 				diag_bridge_read_cb, dev);
 	usb_anchor_urb(urb, &dev->submitted);
 	dev->pending_reads++;
 
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	ret = usb_submit_urb(urb, GFP_KERNEL);
 	if (ret) {
 		dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
 		dev->pending_reads--;
 		usb_unanchor_urb(urb);
 		usb_free_urb(urb);
+		usb_autopm_put_interface(dev->ifc);
 		return ret;
 	}
 
+	usb_autopm_put_interface(dev->ifc);
 	usb_free_urb(urb);
 
 	return 0;
@@ -153,7 +163,10 @@
 
 	dev_dbg(&dev->udev->dev, "%s:\n", __func__);
 
+	usb_autopm_put_interface_async(dev->ifc);
+
 	if (urb->status == -EPROTO) {
+		dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
 		/* save error so that subsequent read/write returns ESHUTDOWN */
 		dev->err = urb->status;
 		return;
@@ -191,24 +204,32 @@
 	if (dev->err)
 		return -ESHUTDOWN;
 
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb) {
 		err("unable to allocate urb");
 		return -ENOMEM;
 	}
 
+	ret = usb_autopm_get_interface(dev->ifc);
+	if (ret < 0) {
+		dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
+		usb_free_urb(urb);
+		return ret;
+	}
+
 	pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
 	usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
 				diag_bridge_write_cb, dev);
 	usb_anchor_urb(urb, &dev->submitted);
 	dev->pending_writes++;
 
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	ret = usb_submit_urb(urb, GFP_KERNEL);
 	if (ret) {
 		dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
 		dev->pending_writes--;
 		usb_unanchor_urb(urb);
 		usb_free_urb(urb);
+		usb_autopm_put_interface(dev->ifc);
 		return ret;
 	}
 
@@ -381,6 +402,37 @@
 	usb_set_intfdata(ifc, NULL);
 }
 
+static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
+{
+	struct diag_bridge	*dev = usb_get_intfdata(ifc);
+	struct diag_bridge_ops	*cbs = dev->ops;
+	int ret = 0;
+
+	if (cbs && cbs->suspend) {
+		ret = cbs->suspend(cbs->ctxt);
+		if (ret) {
+			dev_dbg(&dev->udev->dev,
+				"%s: diag veto'd suspend\n", __func__);
+			return ret;
+		}
+
+		usb_kill_anchored_urbs(&dev->submitted);
+	}
+
+	return ret;
+}
+
+static int diag_bridge_resume(struct usb_interface *ifc)
+{
+	struct diag_bridge	*dev = usb_get_intfdata(ifc);
+	struct diag_bridge_ops	*cbs = dev->ops;
+
+
+	if (cbs && cbs->resume)
+		cbs->resume(cbs->ctxt);
+
+	return 0;
+}
 
 #define VALID_INTERFACE_NUM	0
 static const struct usb_device_id diag_bridge_ids[] = {
@@ -401,7 +453,10 @@
 	.name =		"diag_bridge",
 	.probe =	diag_bridge_probe,
 	.disconnect =	diag_bridge_disconnect,
+	.suspend =	diag_bridge_suspend,
+	.resume =	diag_bridge_resume,
 	.id_table =	diag_bridge_ids,
+	.supports_autosuspend = 1,
 };
 
 static int __init diag_bridge_init(void)
@@ -410,8 +465,7 @@
 
 	ret = usb_register(&diag_bridge_driver);
 	if (ret) {
-		err("%s: unable to register diag driver",
-				__func__);
+		err("%s: unable to register diag driver", __func__);
 		return ret;
 	}
 
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index a77d98f..cce819f 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -1013,6 +1013,7 @@
 #define PID9001_IFACE_MASK	0xC
 #define PID9034_IFACE_MASK	0xC
 #define PID9048_IFACE_MASK	0x18
+#define PID904C_IFACE_MASK	0x28
 
 static const struct usb_device_id bridge_ids[] = {
 	{ USB_DEVICE(0x5c6, 0x9001),
@@ -1024,6 +1025,9 @@
 	{ USB_DEVICE(0x5c6, 0x9048),
 	.driver_info = PID9048_IFACE_MASK,
 	},
+	{ USB_DEVICE(0x5c6, 0x904c),
+	.driver_info = PID904C_IFACE_MASK,
+	},
 
 	{ } /* Terminating entry */
 };
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 548338c..784910a 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1715,6 +1715,10 @@
 	return 0;
 }
 
+static int musb_gadget_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int musb_gadget_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops musb_gadget_operations = {
 	.get_frame		= musb_gadget_get_frame,
 	.wakeup			= musb_gadget_wakeup,
@@ -1722,6 +1726,8 @@
 	/* .vbus_session		= musb_gadget_vbus_session, */
 	.vbus_draw		= musb_gadget_vbus_draw,
 	.pullup			= musb_gadget_pullup,
+	.start			= musb_gadget_start,
+	.stop			= musb_gadget_stop,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -1846,7 +1852,16 @@
 	if (status != 0) {
 		put_device(&musb->g.dev);
 		the_gadget = NULL;
+		return status;
 	}
+	status = usb_add_gadget_udc(musb->controller, &musb->g);
+	if (status)
+		goto err;
+
+	return 0;
+err:
+	device_unregister(&musb->g.dev);
+	the_gadget = NULL;
 	return status;
 }
 
@@ -1855,6 +1870,7 @@
 	if (musb != the_gadget)
 		return;
 
+	usb_del_gadget_udc(&musb->g);
 	device_unregister(&musb->g.dev);
 	the_gadget = NULL;
 }
@@ -1871,7 +1887,7 @@
  * @param bind the driver's bind function
  * @return <0 if error, 0 if everything is fine
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int musb_gadget_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
 	struct musb		*musb = the_gadget;
@@ -1973,7 +1989,6 @@
 err0:
 	return retval;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
 {
@@ -2023,7 +2038,7 @@
  *
  * @param driver the gadget driver to unregister
  */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int musb_gadget_stop(struct usb_gadget_driver *driver)
 {
 	struct musb	*musb = the_gadget;
 	unsigned long	flags;
@@ -2082,8 +2097,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 /* ----------------------------------------------------------------------- */
 
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 6964835..dd07d4e 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -67,6 +67,7 @@
 static DECLARE_COMPLETION(pmic_vbus_init);
 static struct msm_otg *the_msm_otg;
 static bool debug_aca_enabled;
+static bool debug_bus_voting_enabled;
 
 /* Prevent idle power collapse(pc) while operating in peripheral mode */
 static void otg_pm_qos_update_latency(struct msm_otg *dev, int vote)
@@ -1155,7 +1156,7 @@
 		 */
 		otg_pm_qos_update_latency(motg, 1);
 		/* Configure BUS performance parameters for MAX bandwidth */
-		if (motg->bus_perf_client) {
+		if (motg->bus_perf_client && debug_bus_voting_enabled) {
 			ret = msm_bus_scale_client_update_request(
 					motg->bus_perf_client, 1);
 			if (ret)
@@ -2232,13 +2233,64 @@
 	.release = single_release,
 };
 
+static int msm_otg_bus_show(struct seq_file *s, void *unused)
+{
+	if (debug_bus_voting_enabled)
+		seq_printf(s, "enabled\n");
+	else
+		seq_printf(s, "disabled\n");
+
+	return 0;
+}
+
+static int msm_otg_bus_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_bus_show, inode->i_private);
+}
+
+static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char buf[8];
+	int ret;
+	struct seq_file *s = file->private_data;
+	struct msm_otg *motg = s->private;
+
+	memset(buf, 0x00, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "enable", 6)) {
+		/* Do not vote here. Let OTG statemachine decide when to vote */
+		debug_bus_voting_enabled = true;
+	} else {
+		debug_bus_voting_enabled = false;
+		if (motg->bus_perf_client) {
+			ret = msm_bus_scale_client_update_request(
+					motg->bus_perf_client, 0);
+			if (ret)
+				dev_err(motg->otg.dev, "%s: Failed to devote "
+					   "for bus bw %d\n", __func__, ret);
+		}
+	}
+
+	return count;
+}
+
+const struct file_operations msm_otg_bus_fops = {
+	.open = msm_otg_bus_open,
+	.read = seq_read,
+	.write = msm_otg_bus_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 static struct dentry *msm_otg_dbg_root;
-static struct dentry *msm_otg_dbg_mode;
-static struct dentry *msm_otg_chg_type;
-static struct dentry *msm_otg_dbg_aca;
 
 static int msm_otg_debugfs_init(struct msm_otg *motg)
 {
+	struct dentry *msm_otg_dentry;
 
 	msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
 
@@ -2248,35 +2300,43 @@
 	if (motg->pdata->mode == USB_OTG &&
 		motg->pdata->otg_control == OTG_USER_CONTROL) {
 
-		msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO |
+		msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
 			S_IWUSR, msm_otg_dbg_root, motg,
 			&msm_otg_mode_fops);
 
-		if (!msm_otg_dbg_mode) {
+		if (!msm_otg_dentry) {
 			debugfs_remove(msm_otg_dbg_root);
 			msm_otg_dbg_root = NULL;
 			return -ENODEV;
 		}
 	}
 
-	msm_otg_chg_type = debugfs_create_file("chg_type", S_IRUGO,
+	msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
 		msm_otg_dbg_root, motg,
 		&msm_otg_chg_fops);
 
-	if (!msm_otg_chg_type) {
+	if (!msm_otg_dentry) {
 		debugfs_remove_recursive(msm_otg_dbg_root);
 		return -ENODEV;
 	}
 
-	msm_otg_dbg_aca = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
+	msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
 		msm_otg_dbg_root, motg,
 		&msm_otg_aca_fops);
 
-	if (!msm_otg_dbg_aca) {
+	if (!msm_otg_dentry) {
 		debugfs_remove_recursive(msm_otg_dbg_root);
 		return -ENODEV;
 	}
 
+	msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
+		msm_otg_dbg_root, motg,
+		&msm_otg_bus_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
 	return 0;
 }
 
@@ -2642,6 +2702,8 @@
 		if (!motg->bus_perf_client)
 			dev_err(motg->otg.dev, "%s: Failed to register BUS "
 						"scaling client!!\n", __func__);
+		else
+			debug_bus_voting_enabled = true;
 	}
 
 	return 0;
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 547486c..486d129 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -1179,7 +1179,7 @@
  *
  */
 struct usbhsg_gpriv *the_controller;
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int usbhsg_gadget_start(struct usb_gadget_driver *driver,
 			    int (*bind)(struct usb_gadget *))
 {
 	struct usbhsg_gpriv *gpriv = the_controller;
@@ -1229,9 +1229,8 @@
 
 	return ret;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int usbhsg_gadget_stop(struct usb_gadget_driver *driver)
 {
 	struct usbhsg_gpriv *gpriv = the_controller;
 	struct usbhs_priv *priv;
@@ -1260,7 +1259,6 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /*
  *		usb gadget ops
@@ -1275,6 +1273,8 @@
 
 static struct usb_gadget_ops usbhsg_gadget_ops = {
 	.get_frame		= usbhsg_get_frame,
+	.start			= usbhsg_gadget_start,
+	.stop			= usbhsg_gadget_stop,
 };
 
 static int usbhsg_start(struct usbhs_priv *priv)
@@ -1294,6 +1294,7 @@
 	struct device *dev = usbhs_priv_to_dev(priv);
 	int pipe_size = usbhs_get_dparam(priv, pipe_size);
 	int i;
+	int ret;
 
 	gpriv = kzalloc(sizeof(struct usbhsg_gpriv), GFP_KERNEL);
 	if (!gpriv) {
@@ -1304,6 +1305,7 @@
 	uep = kzalloc(sizeof(struct usbhsg_uep) * pipe_size, GFP_KERNEL);
 	if (!uep) {
 		dev_err(dev, "Could not allocate ep\n");
+		ret = -ENOMEM;
 		goto usbhs_mod_gadget_probe_err_gpriv;
 	}
 
@@ -1366,20 +1368,28 @@
 
 	the_controller = gpriv;
 
+	ret = usb_add_gadget_udc(dev, &gpriv->gadget);
+	if (ret)
+		goto err_add_udc;
+
+
 	dev_info(dev, "gadget probed\n");
 
 	return 0;
+err_add_udc:
+	kfree(gpriv->uep);
 
 usbhs_mod_gadget_probe_err_gpriv:
 	kfree(gpriv);
 
-	return -ENOMEM;
+	return ret;
 }
 
 void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv)
 {
 	struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
 
+	usb_del_gadget_udc(&gpriv->gadget);
 	kfree(gpriv->uep);
 	kfree(gpriv);
 }
diff --git a/drivers/usb/serial/csvt.c b/drivers/usb/serial/csvt.c
index 5bfb2dc..28eba8a 100644
--- a/drivers/usb/serial/csvt.c
+++ b/drivers/usb/serial/csvt.c
@@ -46,7 +46,7 @@
 };
 
 static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x904c, 0xff, 0x00, 0xff)},
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x904c, 0xff, 0xfe, 0xff)},
 	{}, /* terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 44e887cb..ef022c1 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -1,7 +1,7 @@
 /*
  * Qualcomm Serial USB driver
  *
- *	Copyright (c) 2008, 2012 QUALCOMM Incorporated.
+ *	Copyright (c) 2008, 2012 Code Aurora Forum. All rights reserved.
  *	Copyright (c) 2009 Greg Kroah-Hartman <gregkh@suse.de>
  *	Copyright (c) 2009 Novell Inc.
  *
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 0110df9..032cdfe 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -178,6 +178,11 @@
 	bool
 	select FB_MSM_MIPI_DSI
 
+config FB_MSM_MIPI_DSI_ORISE
+        bool
+        select FB_MSM_MIPI_DSI
+        default n
+
 config FB_MSM_MIPI_DSI_TC358764_DSI2LVDS
 	bool
 	select FB_MSM_MIPI_DSI
@@ -285,6 +290,16 @@
 	select FB_MSM_MIPI_DSI_NOVATEK
 	default n
 
+config FB_MSM_MIPI_ORISE_VIDEO_720P_PT
+	bool
+	select FB_MSM_MIPI_DSI_ORISE
+	default n
+
+config FB_MSM_MIPI_ORISE_CMD_720P_PT
+	bool
+	select FB_MSM_MIPI_DSI_ORISE
+	default n
+
 config FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT
 	bool
 	select FB_MSM_MIPI_DSI_RENESAS
@@ -459,6 +474,8 @@
 	select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT
 	select FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT
 	select FB_MSM_MIPI_NT35510_CMD_WVGA_PT
+	select FB_MSM_MIPI_ORISE_VIDEO_720P_PT
+	select FB_MSM_MIPI_ORISE_CMD_720P_PT
 	select FB_MSM_MIPI_SIMULATOR_VIDEO
 	select FB_MSM_MIPI_CHIMEI_WXGA
 	select FB_MSM_MIPI_CHIMEI_WUXGA
@@ -514,6 +531,8 @@
 	select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT
 	select FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT
 	select FB_MSM_MIPI_NT35510_CMD_WVGA_PT
+	select FB_MSM_MIPI_ORISE_VIDEO_720P_PT
+	select FB_MSM_MIPI_ORISE_CMD_720P_PT
 	select FB_MSM_MIPI_SIMULATOR_VIDEO
 	select FB_MSM_MIPI_CHIMEI_WXGA
 	select FB_MSM_MIPI_CHIMEI_WUXGA
@@ -570,6 +589,14 @@
 	bool "MIPI NOVATEK CMD QHD PT Panel"
 	select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT
 
+config FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL
+	bool "MIPI ORISE VIDEO 720P PT Panel"
+	select FB_MSM_MIPI_ORISE_VIDEO_720P_PT
+
+config FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL
+	bool "MIPI ORISE CMD 720P PT Panel"
+	select FB_MSM_MIPI_ORISE_CMD_720P_PT
+
 config FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL
 	bool "MIPI Renesas Video FWVGA PT Panel"
 	select FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT
@@ -609,6 +636,7 @@
 	  Support for EBI2 TMD QVGA (240x320) and Epson QCIF (176x220) panel
 
 config FB_MSM_HDMI_AS_PRIMARY
+	depends on FB_MSM_HDMI_COMMON
 	bool "Use HDMI as primary panel"
 	---help---
 	Support for using HDMI as primary
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index 2bdab74..eae79a2 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -74,6 +74,7 @@
 # MIPI manufacture
 obj-$(CONFIG_FB_MSM_MIPI_DSI_TOSHIBA) += mipi_toshiba.o
 obj-$(CONFIG_FB_MSM_MIPI_DSI_NOVATEK) += mipi_novatek.o
+obj-$(CONFIG_FB_MSM_MIPI_DSI_ORISE) += mipi_orise.o
 obj-$(CONFIG_FB_MSM_MIPI_DSI_RENESAS) += mipi_renesas.o
 obj-$(CONFIG_FB_MSM_MIPI_DSI_TRULY) += mipi_truly.o
 obj-$(CONFIG_FB_MSM_MIPI_DSI_NT35510) += mipi_NT35510.o
@@ -116,6 +117,7 @@
 ifeq ($(CONFIG_FB_MSM_MIPI_PANEL_DETECT),y)
 obj-y += mipi_toshiba_video_wvga_pt.o mipi_toshiba_video_wsvga_pt.o mipi_toshiba_video_wuxga.o
 obj-y += mipi_novatek_video_qhd_pt.o mipi_novatek_cmd_qhd_pt.o
+obj-y += mipi_orise_video_720p_pt.o mipi_orise_cmd_720p_pt.o
 obj-y += mipi_renesas_video_fwvga_pt.o mipi_renesas_cmd_fwvga_pt.o
 obj-y += mipi_NT35510_video_wvga_pt.o mipi_NT35510_cmd_wvga_pt.o
 obj-y += mipi_chimei_wxga_pt.o
@@ -126,6 +128,8 @@
 obj-$(CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT) += mipi_toshiba_video_wsvga_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA) += mipi_toshiba_video_wuxga.o
 obj-$(CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT) += mipi_novatek_video_qhd_pt.o
+obj-$(CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT) += mipi_orise_video_720p_pt.o
+obj-$(CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT) += mipi_orise_cmd_720p_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT) += mipi_novatek_cmd_qhd_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT) += mipi_renesas_video_fwvga_pt.o
 obj-$(CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT) += mipi_renesas_cmd_fwvga_pt.o
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 0a86a50..d6f59aa 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -347,11 +347,12 @@
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	ssize_t ret = strnlen(buf, PAGE_SIZE);
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-	int hpd = 1;
-#else
-	int hpd = atoi(buf);
-#endif
+	int hpd;
+	if (hdmi_prim_display)
+		hpd = 1;
+	else
+		hpd = atoi(buf);
+
 	if (external_common_state->hpd_feature) {
 		if (hpd == 0 && external_common_state->hpd_feature_on) {
 			external_common_state->hpd_feature(0);
@@ -652,6 +653,14 @@
 	return ret;
 }
 
+static ssize_t hdmi_common_rda_hdmi_primary(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n",
+		hdmi_prim_display);
+	DEV_DBG("%s: '%d'\n", __func__,	hdmi_prim_display);
+	return ret;
+}
 
 static DEVICE_ATTR(video_mode, S_IRUGO | S_IWUGO,
 	external_common_rda_video_mode, external_common_wta_video_mode);
@@ -671,6 +680,7 @@
 static DEVICE_ATTR(format_3d, S_IRUGO | S_IWUGO, hdmi_3d_rda_format_3d,
 	hdmi_3d_wta_format_3d);
 #endif
+static DEVICE_ATTR(hdmi_primary, S_IRUGO, hdmi_common_rda_hdmi_primary, NULL);
 
 static struct attribute *external_common_fs_attrs[] = {
 	&dev_attr_video_mode.attr,
@@ -693,6 +703,7 @@
 	&dev_attr_cec_rd_frame.attr,
 	&dev_attr_cec_wr_frame.attr,
 #endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */
+	&dev_attr_hdmi_primary.attr,
 	NULL,
 };
 static struct attribute_group external_common_fs_attr_group = {
@@ -1567,11 +1578,10 @@
 	pinfo->pdest = DISPLAY_2;
 	pinfo->wait_cycle = 0;
 	pinfo->bpp = 24;
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-	pinfo->fb_num = 2;
-#else
-	pinfo->fb_num = 1;
-#endif
+	if (hdmi_prim_display)
+		pinfo->fb_num = 2;
+	else
+		pinfo->fb_num = 1;
 
 	/* blk */
 	pinfo->lcdc.border_clr = 0;
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index ef357db..1c47d89 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -2475,12 +2475,6 @@
 			goto error;
 		}
 
-		/*
-		 * A small delay is needed here to avoid device crash observed
-		 * during reauthentication in MSM8960
-		 */
-		msleep(20);
-
 		/* 0x0168 HDCP_RCVPORT_DATA12
 		   [23:8] BSTATUS
 		   [7:0] BCAPS */
@@ -4518,12 +4512,13 @@
 {
 	int rc;
 
-	if (cpu_is_msm8930())
-		return 0;
-
 	if (msm_fb_detect_client("hdmi_msm"))
 		return 0;
 
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+	hdmi_prim_display = 1;
+#endif
+
 	hdmi_msm_setup_video_mode_lut();
 	hdmi_msm_state = kzalloc(sizeof(*hdmi_msm_state), GFP_KERNEL);
 	if (!hdmi_msm_state) {
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 6c5a9f9..6dcc293 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -87,6 +87,7 @@
 
 extern struct mdp_ccs mdp_ccs_yuv2rgb ;
 extern struct mdp_ccs mdp_ccs_rgb2yuv ;
+extern unsigned char hdmi_prim_display;
 
 /*
  * MDP Image Structure
@@ -738,6 +739,11 @@
 
 #ifdef CONFIG_MSM_BUS_SCALING
 int mdp_bus_scale_update_request(uint32_t index);
+#else
+static inline int mdp_bus_scale_update_request(uint32_t index)
+{
+	return 0;
+}
 #endif
 
 #ifdef MDP_HW_VSYNC
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index f7f48e4..c4f6a04 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -445,14 +445,7 @@
 }
 #endif
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 void mdp4_dtv_set_black_screen(void);
-#else
-static inline void mdp4_dtv_set_black_screen(void)
-{
-    /* empty */
-}
-#endif
 
 static inline int mdp4_overlay_borderfill_supported(void)
 {
diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c
index ba774b9..09bc9c2 100644
--- a/drivers/video/msm/mdp4_dtv.c
+++ b/drivers/video/msm/mdp4_dtv.c
@@ -225,11 +225,11 @@
 	 * get/set panel specific fb info
 	 */
 	mfd->panel_info = pdata->panel_info;
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-	mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
-#else
-	mfd->fb_imgType = MDP_RGB_565;
-#endif
+	if (hdmi_prim_display)
+		mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
+	else
+		mfd->fb_imgType = MDP_RGB_565;
+
 	fbi = mfd->fbi;
 	fbi->var.pixclock = mfd->panel_info.clk_rate;
 	fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index c020755..033a73c 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -402,7 +402,8 @@
 		pipe->op_mode |= MDP4_OP_SCALEY_EN;
 
 		if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
-			if (pipe->alpha_enable && pipe->dst_h > pipe->src_h)
+			if (pipe->flags & MDP_BACKEND_COMPOSITION &&
+				pipe->alpha_enable && pipe->dst_h > pipe->src_h)
 				pipe->op_mode |= MDP4_OP_SCALEY_PIXEL_RPT;
 			else if (pipe->dst_h <= (pipe->src_h / 4))
 				pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE;
@@ -424,7 +425,8 @@
 		pipe->op_mode |= MDP4_OP_SCALEX_EN;
 
 		if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
-			if (pipe->alpha_enable && pipe->dst_w > pipe->src_w)
+			if (pipe->flags & MDP_BACKEND_COMPOSITION &&
+				pipe->alpha_enable && pipe->dst_w > pipe->src_w)
 				pipe->op_mode |= MDP4_OP_SCALEX_PIXEL_RPT;
 			else if (pipe->dst_w <= (pipe->src_w / 4))
 				pipe->op_mode |= MDP4_OP_SCALEX_MN_PHASE;
@@ -1385,14 +1387,8 @@
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	}
 
-	if (data) {
-		if (pipe_cnt == 1) {
-			mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
-#ifdef CONFIG_MSM_BUS_SCALING
-			mdp_bus_scale_update_request(2);
-#endif
-		}
-	}
+	if (data && pipe_cnt == 1)
+		mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
 }
 
 void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
@@ -1891,7 +1887,7 @@
 
 static int get_img(struct msmfb_data *img, struct fb_info *info,
 	unsigned long *start, unsigned long *len, struct file **srcp_file,
-	struct ion_handle **srcp_ihdl)
+	int *p_need, struct ion_handle **srcp_ihdl)
 {
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -1901,6 +1897,8 @@
 #ifdef CONFIG_ANDROID_PMEM
 	unsigned long vstart;
 #endif
+	*p_need = 0;
+
 	if (img->flags & MDP_BLIT_SRC_GEM) {
 		*srcp_file = NULL;
 		return kgsl_gem_obj_addr(img->memory_id, (int) img->priv,
@@ -1916,8 +1914,10 @@
 			fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
 			if (get_fb_phys_info(start, len, fb_num))
 				ret = -1;
-			else
+			else {
 				*srcp_file = file;
+				*p_need = put_needed;
+			}
 		} else
 			ret = -1;
 		if (ret)
@@ -2034,9 +2034,7 @@
 #define OVERLAY_720P_TILE_SIZE  0x0E6000
 #define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
 
-#ifdef CONFIG_MSM_BUS_SCALING
 #define OVERLAY_BUS_SCALE_TABLE_BASE	6
-#endif
 
 static int mdp4_overlay_is_rgb_type(int format)
 {
@@ -2058,7 +2056,7 @@
 static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req,
 					  struct msm_fb_data_type *mfd)
 {
-	int is_fg;
+	int is_fg, i, cnt;
 
 	if (req->is_fg && ((req->alpha & 0x0ff) == 0xff))
 		is_fg = 1;
@@ -2069,9 +2067,10 @@
 	if (req->flags & MDP_DEINTERLACE)
 		return OVERLAY_PERF_LEVEL1;
 
-	if (ctrl->plist[OVERLAY_PIPE_VG1].pipe_used &&
-	    ctrl->plist[OVERLAY_PIPE_VG2].pipe_used)
-		return OVERLAY_PERF_LEVEL1;
+	for (i = 0, cnt = 0; i < OVERLAY_PIPE_MAX; i++) {
+		if (ctrl->plist[i].pipe_used && ++cnt > 2)
+			return OVERLAY_PERF_LEVEL1;
+	}
 
 	if (mdp4_overlay_is_rgb_type(req->src.format) && is_fg &&
 		((req->src.width * req->src.height) <= OVERLAY_WSVGA_SIZE))
@@ -2114,6 +2113,8 @@
 	if (old_perf_level != cur_perf_level) {
 		mdp_set_core_clk(cur_perf_level);
 		old_perf_level = cur_perf_level;
+		mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE
+					     - cur_perf_level);
 	}
 }
 
@@ -2140,6 +2141,21 @@
 	mfd->ov0_blt_state = mfd->use_ov0_blt;
 }
 
+static void mdp4_overlay1_update_blt_mode(struct msm_fb_data_type *mfd)
+{
+	if (mfd->ov1_blt_state == mfd->use_ov1_blt)
+		return;
+	if (mfd->use_ov1_blt) {
+		mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
+		mdp4_dtv_overlay_blt_start(mfd);
+		pr_debug("%s overlay1 writeback is enabled\n", __func__);
+	} else {
+		mdp4_dtv_overlay_blt_stop(mfd);
+		pr_debug("%s overlay1 writeback is disabled\n", __func__);
+	}
+	mfd->ov1_blt_state = mfd->use_ov1_blt;
+}
+
 static u32 mdp4_overlay_blt_enable(struct mdp_overlay *req,
 	struct msm_fb_data_type *mfd, uint32 perf_level)
 {
@@ -2150,7 +2166,8 @@
 		clk_rate = (&mfd->panel_info.mipi)->dsi_pclk_rate;
 
 	if ((mfd->panel_info.type == LCDC_PANEL) ||
-		(mfd->panel_info.type == MIPI_VIDEO_PANEL))
+	    (mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
+	    (mfd->panel_info.type == DTV_PANEL))
 		pull_mode = 1;
 
 	if (pull_mode && (req->src_rect.h > req->dst_rect.h ||
@@ -2169,7 +2186,8 @@
 			if (req->dst_rect.x != 0)
 				use_blt = 1;
 		}
-		if (mfd->panel_info.xres > 1280)
+		if ((mfd->panel_info.xres > 1280) &&
+		    (mfd->panel_info.type != DTV_PANEL))
 			use_blt = 1;
 	}
 	return use_blt;
@@ -2197,8 +2215,6 @@
 		return -EINTR;
 	}
 
-	perf_level = mdp4_overlay_get_perf_level(req, mfd);
-
 	mixer = mfd->panel_info.pdest;	/* DISPLAY_1 or DISPLAY_2 */
 
 	ret = mdp4_overlay_req2pipe(req, mixer, &pipe, mfd);
@@ -2209,6 +2225,8 @@
 		return ret;
 	}
 
+	perf_level = mdp4_overlay_get_perf_level(req, mfd);
+
 	if (mixer == MDP4_MIXER0) {
 		u32 use_blt = mdp4_overlay_blt_enable(req, mfd,	perf_level);
 		mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
@@ -2252,8 +2270,12 @@
 	}
 
 	if (ctrl->panel_mode & MDP4_PANEL_DTV &&
-	    pipe->mixer_num == MDP4_MIXER1)
+	    pipe->mixer_num == MDP4_MIXER1) {
+		u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
 		mdp4_overlay_dtv_set(mfd, pipe);
+		mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
+		mfd->use_ov1_blt |= (use_blt << (pipe->pipe_ndx-1));
+	}
 
 	if (new_perf_level != perf_level) {
 		u32 old_level = new_perf_level;
@@ -2282,13 +2304,6 @@
 	}
 	mutex_unlock(&mfd->dma->ov_mutex);
 
-#ifdef CONFIG_MSM_BUS_SCALING
-	if (pipe->mixer_num == MDP4_MIXER0) {
-		mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE
-						- perf_level);
-	}
-#endif
-
 	return 0;
 }
 
@@ -2368,8 +2383,14 @@
 			if (!mfd->use_ov0_blt)
 				mdp4_free_writeback_buf(mfd, MDP4_MIXER0);
 		} else {	/* mixer1, DTV, ATV */
-			if (ctrl->panel_mode & MDP4_PANEL_DTV)
+			if (ctrl->panel_mode & MDP4_PANEL_DTV) {
 				mdp4_overlay_dtv_unset(mfd, pipe);
+				mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
+				mdp4_overlay1_update_blt_mode(mfd);
+				if (!mfd->use_ov1_blt)
+					mdp4_free_writeback_buf(mfd,
+								MDP4_MIXER1);
+			}
 		}
 	}
 
@@ -2386,8 +2407,6 @@
 
 	mdp4_overlay_pipe_free(pipe);
 
-	mdp4_set_perf_level();
-
 	mutex_unlock(&mfd->dma->ov_mutex);
 
 	return 0;
@@ -2448,6 +2467,9 @@
 
 	mdp4_mixer_stage_commit(pipe->mixer_num);
 
+	if (mfd->use_ov1_blt)
+		mdp4_overlay1_update_blt_mode(mfd);
+
 	mdp4_overlay_dtv_wait_for_ov(mfd, pipe);
 
 	mutex_unlock(&mfd->dma->ov_mutex);
@@ -2465,6 +2487,7 @@
 	struct file *srcp1_file = NULL, *srcp2_file = NULL;
 	struct ion_handle *srcp0_ihdl = NULL;
 	struct ion_handle *srcp1_ihdl = NULL, *srcp2_ihdl = NULL;
+	int ps0_need, p_need;
 	uint32_t overlay_version = 0;
 	int ret = 0;
 
@@ -2484,7 +2507,7 @@
 		return -EINTR;
 
 	img = &req->data;
-	get_img(img, info, &start, &len, &srcp0_file, &srcp0_ihdl);
+	get_img(img, info, &start, &len, &srcp0_file, &ps0_need, &srcp0_ihdl);
 	if (len == 0) {
 		mutex_unlock(&mfd->dma->ov_mutex);
 		pr_err("%s: pmem Error\n", __func__);
@@ -2503,7 +2526,7 @@
 		if (overlay_version > 0) {
 			img = &req->plane1_data;
 			get_img(img, info, &start, &len, &srcp1_file,
-				&srcp1_ihdl);
+				&p_need, &srcp1_ihdl);
 			if (len == 0) {
 				mutex_unlock(&mfd->dma->ov_mutex);
 				pr_err("%s: Error to get plane1\n", __func__);
@@ -2535,7 +2558,7 @@
 		if (overlay_version > 0) {
 			img = &req->plane1_data;
 			get_img(img, info, &start, &len, &srcp1_file,
-				&srcp1_ihdl);
+				&p_need, &srcp1_ihdl);
 			if (len == 0) {
 				mutex_unlock(&mfd->dma->ov_mutex);
 				pr_err("%s: Error to get plane1\n", __func__);
@@ -2546,7 +2569,7 @@
 
 			img = &req->plane2_data;
 			get_img(img, info, &start, &len, &srcp2_file,
-				&srcp2_ihdl);
+				&p_need, &srcp2_ihdl);
 			if (len == 0) {
 				mutex_unlock(&mfd->dma->ov_mutex);
 				pr_err("%s: Error to get plane2\n", __func__);
@@ -2589,6 +2612,9 @@
 	if (mfd->use_ov0_blt)
 		mdp4_overlay_update_blt_mode(mfd);
 
+	if (mfd->use_ov1_blt)
+		mdp4_overlay1_update_blt_mode(mfd);
+
 	if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
 		mdp4_overlay_vg_setup(pipe);	/* video/graphic pipe */
 	} else {
@@ -2614,8 +2640,11 @@
 	} else if (pipe->mixer_num == MDP4_MIXER1) {
 		ctrl->mixer1_played++;
 		/* enternal interface */
-		if (ctrl->panel_mode & MDP4_PANEL_DTV)
+		if (ctrl->panel_mode & MDP4_PANEL_DTV) {
 			mdp4_overlay_dtv_ov_done_push(mfd, pipe);
+			if (!mfd->use_ov1_blt)
+				mdp4_overlay1_update_blt_mode(mfd);
+			}
 	} else {
 
 		/* primary interface */
@@ -2668,9 +2697,13 @@
 	if (srcp2_file)
 		put_pmem_file(srcp2_file);
 #endif
+	/* only source may use frame buffer */
+	if (img->flags & MDP_MEMORY_ID_TYPE_FB)
+		fput_light(srcp0_file, ps0_need);
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-	if (!IS_ERR_OR_NULL(srcp0_ihdl))
+	else if (!IS_ERR_OR_NULL(srcp0_ihdl))
 		ion_free(mfd->iclient, srcp0_ihdl);
+
 	if (!IS_ERR_OR_NULL(srcp1_ihdl))
 		ion_free(mfd->iclient, srcp1_ihdl);
 	if (!IS_ERR_OR_NULL(srcp2_ihdl))
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 635b104..0b86028 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -102,12 +102,12 @@
 	var = &fbi->var;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-	if (is_mdp4_hw_reset()) {
-		mdp4_hw_init();
-		outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
+	if (hdmi_prim_display) {
+		if (is_mdp4_hw_reset()) {
+			mdp4_hw_init();
+			outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
+		}
 	}
-#endif
 	mdp4_overlay_dmae_cfg(mfd, 0);
 
 	/*
@@ -301,7 +301,7 @@
 		/* MSP_BORDER_COLOR */
 		MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008,
 			(0x0 & 0xFFF));		/* 12-bit R */
-		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	} else {
 		switch (mfd->ibuf.bpp) {
 		case 2:
@@ -312,11 +312,10 @@
 			break;
 		case 4:
 		default:
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-			pipe->src_format = MSMFB_DEFAULT_TYPE;
-#else
-			pipe->src_format = MDP_ARGB_8888;
-#endif
+			if (hdmi_prim_display)
+				pipe->src_format = MSMFB_DEFAULT_TYPE;
+			else
+				pipe->src_format = MDP_ARGB_8888;
 			break;
 		}
 	}
@@ -355,7 +354,7 @@
 	if (pipe != NULL && pipe->mixer_stage == MDP4_MIXER_STAGE_BASE &&
 			pipe->pipe_type == OVERLAY_TYPE_RGB)
 		dtv_pipe = pipe; /* keep it */
-	else if (mdp4_overlay_borderfill_supported())
+	else if (!hdmi_prim_display && mdp4_overlay_borderfill_supported())
 		mdp4_overlay_dtv_alloc_pipe(mfd, OVERLAY_TYPE_BF);
 	else
 		mdp4_overlay_dtv_alloc_pipe(mfd, OVERLAY_TYPE_RGB);
@@ -512,7 +511,6 @@
 	complete_all(&dtv_pipe->comp);
 }
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 void mdp4_dtv_set_black_screen(void)
 {
 	char *rgb_base;
@@ -520,8 +518,9 @@
 	uint32 color = 0x00000000;
 	uint32 temp_src_format;
 
-	if (!dtv_pipe) {
-		pr_err("dtv_pipe is not configured yet\n");
+	if (!dtv_pipe || !hdmi_prim_display) {
+		pr_err("dtv_pipe/hdmi as primary are not"
+			   " configured yet\n");
 		return;
 	}
 	rgb_base = MDP_BASE + MDP4_RGB_BASE;
@@ -540,7 +539,6 @@
 	mdp4_mixer_stage_up(dtv_pipe);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
-#endif
 
 static void mdp4_overlay_dtv_wait4dmae(struct msm_fb_data_type *mfd)
 {
@@ -596,13 +594,11 @@
 
 void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd)
 {
-	mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
 	mdp4_dtv_do_blt(mfd, 1);
 }
 
 void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd)
 {
-	mdp4_free_writeback_buf(mfd, MDP4_MIXER1);
 	mdp4_dtv_do_blt(mfd, 0);
 }
 
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index 4fbb044..8a86fd2 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -51,7 +51,8 @@
 #define MIPI_DSI_PANEL_QHD_PT 5
 #define MIPI_DSI_PANEL_WXGA	6
 #define MIPI_DSI_PANEL_WUXGA	7
-#define DSI_PANEL_MAX	7
+#define MIPI_DSI_PANEL_720P_PT	8
+#define DSI_PANEL_MAX	8
 
 enum {		/* mipi dsi panel */
 	DSI_VIDEO_MODE,
diff --git a/drivers/video/msm/mipi_orise.c b/drivers/video/msm/mipi_orise.c
new file mode 100644
index 0000000..2afbb9b6
--- /dev/null
+++ b/drivers/video/msm/mipi_orise.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_fb.h"
+#include "mipi_dsi.h"
+#include "mipi_orise.h"
+#include "mdp4.h"
+
+
+static struct mipi_dsi_panel_platform_data *mipi_orise_pdata;
+
+static struct dsi_buf orise_tx_buf;
+static struct dsi_buf orise_rx_buf;
+
+static char enter_sleep[2] = {0x10, 0x00}; /* DTYPE_DCS_WRITE */
+static char exit_sleep[2] = {0x11, 0x00}; /* DTYPE_DCS_WRITE */
+static char display_off[2] = {0x28, 0x00}; /* DTYPE_DCS_WRITE */
+static char display_on[2] = {0x29, 0x00}; /* DTYPE_DCS_WRITE */
+
+static struct dsi_cmd_desc orise_video_on_cmds[] = {
+	{DTYPE_DCS_WRITE, 1, 0, 0, 10,
+		sizeof(exit_sleep), exit_sleep},
+	{DTYPE_DCS_WRITE, 1, 0, 0, 10,
+		sizeof(display_on), display_on},
+};
+
+static struct dsi_cmd_desc orise_cmd_on_cmds[] = {
+	{DTYPE_DCS_WRITE, 1, 0, 0, 10,
+		sizeof(exit_sleep), exit_sleep},
+	{DTYPE_DCS_WRITE, 1, 0, 0, 10,
+		sizeof(display_on), display_on},
+};
+
+static struct dsi_cmd_desc orise_display_off_cmds[] = {
+	{DTYPE_DCS_WRITE, 1, 0, 0, 10,
+		sizeof(display_off), display_off},
+	{DTYPE_DCS_WRITE, 1, 0, 0, 120,
+		sizeof(enter_sleep), enter_sleep}
+};
+
+static int mipi_orise_lcd_on(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+	struct mipi_panel_info *mipi;
+	struct msm_panel_info *pinfo;
+
+	mfd = platform_get_drvdata(pdev);
+	if (!mfd)
+		return -ENODEV;
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	pinfo = &mfd->panel_info;
+	mipi  = &mfd->panel_info.mipi;
+
+	if (mipi->mode == DSI_VIDEO_MODE) {
+		mipi_dsi_cmds_tx(mfd, &orise_tx_buf, orise_video_on_cmds,
+			ARRAY_SIZE(orise_video_on_cmds));
+	} else {
+		mipi_dsi_cmds_tx(mfd, &orise_tx_buf, orise_cmd_on_cmds,
+			ARRAY_SIZE(orise_cmd_on_cmds));
+
+		mipi_dsi_cmd_bta_sw_trigger(); /* clean up ack_err_status */
+	}
+
+	return 0;
+}
+
+static int mipi_orise_lcd_off(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+
+	mfd = platform_get_drvdata(pdev);
+
+	if (!mfd)
+		return -ENODEV;
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	mipi_dsi_cmds_tx(mfd, &orise_tx_buf, orise_display_off_cmds,
+			ARRAY_SIZE(orise_display_off_cmds));
+
+	return 0;
+}
+
+
+
+static int __devinit mipi_orise_lcd_probe(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+	struct mipi_panel_info *mipi;
+	struct platform_device *current_pdev;
+	static struct mipi_dsi_phy_ctrl *phy_settings;
+
+	if (pdev->id == 0) {
+		mipi_orise_pdata = pdev->dev.platform_data;
+
+		if (mipi_orise_pdata
+			&& mipi_orise_pdata->phy_ctrl_settings) {
+			phy_settings = (mipi_orise_pdata->phy_ctrl_settings);
+		}
+
+		return 0;
+	}
+
+	current_pdev = msm_fb_add_device(pdev);
+
+	if (current_pdev) {
+		mfd = platform_get_drvdata(current_pdev);
+		if (!mfd)
+			return -ENODEV;
+		if (mfd->key != MFD_KEY)
+			return -EINVAL;
+
+		mipi  = &mfd->panel_info.mipi;
+
+		if (phy_settings != NULL)
+			mipi->dsi_phy_db = phy_settings;
+	}
+	return 0;
+}
+
+static struct platform_driver this_driver = {
+	.probe  = mipi_orise_lcd_probe,
+	.driver = {
+		.name   = "mipi_orise",
+	},
+};
+
+static struct msm_fb_panel_data orise_panel_data = {
+	.on		= mipi_orise_lcd_on,
+	.off		= mipi_orise_lcd_off,
+};
+
+static int ch_used[3];
+
+int mipi_orise_device_register(struct msm_panel_info *pinfo,
+					u32 channel, u32 panel)
+{
+	struct platform_device *pdev = NULL;
+	int ret;
+
+	if ((channel >= 3) || ch_used[channel])
+		return -ENODEV;
+
+	ch_used[channel] = TRUE;
+
+	pdev = platform_device_alloc("mipi_orise", (panel << 8)|channel);
+	if (!pdev)
+		return -ENOMEM;
+
+	orise_panel_data.panel_info = *pinfo;
+
+	ret = platform_device_add_data(pdev, &orise_panel_data,
+		sizeof(orise_panel_data));
+	if (ret) {
+		printk(KERN_ERR
+		  "%s: platform_device_add_data failed!\n", __func__);
+		goto err_device_put;
+	}
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		printk(KERN_ERR
+		  "%s: platform_device_register failed!\n", __func__);
+		goto err_device_put;
+	}
+
+	return 0;
+
+err_device_put:
+	platform_device_put(pdev);
+	return ret;
+}
+
+static int __init mipi_orise_lcd_init(void)
+{
+	mipi_dsi_buf_alloc(&orise_tx_buf, DSI_BUF_SIZE);
+	mipi_dsi_buf_alloc(&orise_rx_buf, DSI_BUF_SIZE);
+
+	return platform_driver_register(&this_driver);
+}
+
+module_init(mipi_orise_lcd_init);
diff --git a/drivers/video/msm/mipi_orise.h b/drivers/video/msm/mipi_orise.h
new file mode 100644
index 0000000..1659479
--- /dev/null
+++ b/drivers/video/msm/mipi_orise.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#ifndef MIPI_ORISE_H
+#define MIPI_ORISE_H
+
+int mipi_orise_device_register(struct msm_panel_info *pinfo,
+					u32 channel, u32 panel);
+
+#endif  /* MIPI_ORISE_H */
diff --git a/drivers/video/msm/mipi_orise_cmd_720p_pt.c b/drivers/video/msm/mipi_orise_cmd_720p_pt.c
new file mode 100644
index 0000000..c2a158d
--- /dev/null
+++ b/drivers/video/msm/mipi_orise_cmd_720p_pt.c
@@ -0,0 +1,96 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_fb.h"
+#include "mipi_dsi.h"
+#include "mipi_orise.h"
+
+static struct msm_panel_info pinfo;
+
+static struct mipi_dsi_phy_ctrl dsi_cmd_mode_phy_db = {
+/* DSI_BIT_CLK at 507MHz, 4 lane, RGB888 */
+	{0x03, 0x0a, 0x04, 0x00, 0x20},
+	/* timing */
+	{0x8c, 0x34, 0x15, 0x00, 0x46, 0x50, 0x1a, 0x38,
+	0x24, 0x03, 0x04, 0xa0},
+    /* phy ctrl */
+	{0x5f, 0x00, 0x00, 0x10},
+    /* strength */
+	{0xff, 0x00, 0x06, 0x00},
+	/* pll control */
+		{0x0, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62,
+	0x40, 0x07, 0x03,
+	0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 },
+};
+
+static int __init mipi_cmd_orise_720p_pt_init(void)
+{
+	int ret;
+
+	if (msm_fb_detect_client("mipi_cmd_orise_720p"))
+		return 0;
+
+	pinfo.xres = 720;
+	pinfo.yres = 1280;
+	pinfo.type = MIPI_CMD_PANEL;
+	pinfo.pdest = DISPLAY_1;
+	pinfo.wait_cycle = 0;
+	pinfo.bpp = 24;
+	pinfo.lcdc.h_back_porch = 160;
+	pinfo.lcdc.h_front_porch = 160;
+	pinfo.lcdc.h_pulse_width = 8;
+	pinfo.lcdc.v_back_porch = 32;
+	pinfo.lcdc.v_front_porch = 32;
+	pinfo.lcdc.v_pulse_width = 1;
+	pinfo.lcdc.border_clr = 0;	/* blk */
+	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
+	pinfo.lcdc.hsync_skew = 0;
+	pinfo.bl_max = 200;
+	pinfo.bl_min = 1;
+	pinfo.fb_num = 2;
+	pinfo.clk_rate = 507000000;
+	pinfo.lcd.vsync_enable = TRUE;
+	pinfo.lcd.hw_vsync_mode = TRUE;
+	pinfo.lcd.refx100 = 6000; /* adjust refx100 to prevent tearing */
+	pinfo.lcd.v_back_porch = 32;
+	pinfo.lcd.v_front_porch = 32;
+	pinfo.lcd.v_pulse_width = 1;
+
+	pinfo.mipi.mode = DSI_CMD_MODE;
+	pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888;
+	pinfo.mipi.vc = 0;
+	pinfo.mipi.data_lane0 = TRUE;
+	pinfo.mipi.data_lane1 = TRUE;
+	pinfo.mipi.data_lane2 = TRUE;
+	pinfo.mipi.data_lane3 = TRUE;
+	pinfo.mipi.t_clk_post = 0x04;
+	pinfo.mipi.t_clk_pre = 0x1e;
+	pinfo.mipi.stream = 0;	/* dma_p */
+	pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE;
+	pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
+	pinfo.mipi.te_sel = 1; /* TE from vsycn gpio */
+	pinfo.mipi.interleave_max = 1;
+	pinfo.mipi.insert_dcs_cmd = TRUE;
+	pinfo.mipi.wr_mem_continue = 0x3c;
+	pinfo.mipi.wr_mem_start = 0x2c;
+	pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db;
+
+	ret = mipi_orise_device_register(&pinfo, MIPI_DSI_PRIM,
+						MIPI_DSI_PANEL_720P_PT);
+	if (ret)
+		pr_err("%s: failed to register device!\n", __func__);
+
+	return ret;
+}
+
+module_init(mipi_cmd_orise_720p_pt_init);
diff --git a/drivers/video/msm/mipi_orise_video_720p_pt.c b/drivers/video/msm/mipi_orise_video_720p_pt.c
new file mode 100644
index 0000000..629ff10
--- /dev/null
+++ b/drivers/video/msm/mipi_orise_video_720p_pt.c
@@ -0,0 +1,97 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_fb.h"
+#include "mipi_dsi.h"
+#include "mipi_orise.h"
+
+static struct msm_panel_info pinfo;
+
+static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = {
+    /* regulator */
+	{0x03, 0x0a, 0x04, 0x00, 0x20},
+	/* timing */
+	{0x83, 0x31, 0x13, 0x00, 0x42, 0x4d, 0x18, 0x35,
+	0x21, 0x03, 0x04, 0xa0},
+    /* phy ctrl */
+	{0x5f, 0x00, 0x00, 0x10},
+    /* strength */
+	{0xff, 0x00, 0x06, 0x00},
+	/* pll control */
+	{0x0, 0x0e, 0x30, 0xc0, 0x00, 0x40, 0x03, 0x62,
+	0x40, 0x07, 0x07,
+	0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 },
+};
+
+static int __init mipi_video_orise_720p_pt_init(void)
+{
+	int ret;
+
+	if (msm_fb_detect_client("mipi_video_orise_720p"))
+		return 0;
+
+	pinfo.xres = 720;
+	pinfo.yres = 1280;
+	pinfo.lcdc.xres_pad = 0;
+	pinfo.lcdc.yres_pad = 0;
+
+	pinfo.type = MIPI_VIDEO_PANEL;
+	pinfo.pdest = DISPLAY_1;
+	pinfo.wait_cycle = 0;
+	pinfo.bpp = 24;
+	pinfo.lcdc.h_back_porch = 160;
+	pinfo.lcdc.h_front_porch = 160;
+	pinfo.lcdc.h_pulse_width = 8;
+	pinfo.lcdc.v_back_porch = 32;
+	pinfo.lcdc.v_front_porch = 32;
+	pinfo.lcdc.v_pulse_width = 1;
+	pinfo.lcdc.border_clr = 0;	/* blk */
+	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
+	pinfo.lcdc.hsync_skew = 0;
+	pinfo.bl_max = 200;
+	pinfo.bl_min = 1;
+	pinfo.fb_num = 2;
+
+	pinfo.mipi.mode = DSI_VIDEO_MODE;
+	pinfo.mipi.pulse_mode_hsa_he = TRUE;
+	pinfo.mipi.hfp_power_stop = TRUE;
+	pinfo.mipi.hbp_power_stop = TRUE;
+	pinfo.mipi.hsa_power_stop = FALSE;
+	pinfo.mipi.eof_bllp_power_stop = TRUE;
+	pinfo.mipi.bllp_power_stop = TRUE;
+	pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT;
+	pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
+	pinfo.mipi.vc = 0;
+	pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB;
+	pinfo.mipi.data_lane0 = TRUE;
+	pinfo.mipi.data_lane1 = TRUE;
+	pinfo.mipi.data_lane2 = TRUE;
+	pinfo.mipi.data_lane3 = TRUE;
+	pinfo.mipi.t_clk_post = 0x04;
+	pinfo.mipi.t_clk_pre = 0x1c;
+	pinfo.mipi.stream = 0; /* dma_p */
+	pinfo.mipi.mdp_trigger = 0;
+	pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
+	pinfo.mipi.frame_rate = 55;
+	pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db;
+	pinfo.mipi.tx_eot_append = TRUE;
+
+	ret = mipi_orise_device_register(&pinfo, MIPI_DSI_PRIM,
+						MIPI_DSI_PANEL_720P_PT);
+	if (ret)
+		printk(KERN_ERR "%s: failed to register device!\n", __func__);
+
+	return ret;
+}
+
+module_init(mipi_video_orise_720p_pt_init);
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.c b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
index fcb5163..1624534 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.c
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
@@ -226,10 +226,14 @@
 static u32 d2l_3d_gpio_enable;
 static u32 d2l_3d_gpio_mode;
 static int d2l_enable_3d;
+static struct i2c_client *d2l_i2c_client;
+static struct i2c_driver d2l_i2c_slave_driver;
 
 static int mipi_d2l_init(void);
 static int mipi_d2l_enable_3d(struct msm_fb_data_type *mfd,
 			      bool enable, bool mode);
+static u32 d2l_i2c_read_reg(struct i2c_client *client, u16 reg);
+static u32 d2l_i2c_write_reg(struct i2c_client *client, u16 reg, u32 val);
 
 /**
  * Read a bridge register
@@ -296,6 +300,20 @@
 	mipi_d2l_read_reg(mfd, SYSSTAT);		/* 0x500 */
 }
 
+static void mipi_d2l_read_status_via_i2c(struct i2c_client *client)
+{
+	u32 tmp = 0;
+
+	tmp = d2l_i2c_read_reg(client, DSIERRCNT);
+	d2l_i2c_write_reg(client, DSIERRCNT, 0xFFFF0000);
+
+	d2l_i2c_read_reg(client, DSI_LANESTATUS0);	/* 0x214 */
+	d2l_i2c_read_reg(client, DSI_LANESTATUS1);	/* 0x218 */
+	d2l_i2c_read_reg(client, DSI_INTSTATUS);	/* 0x220 */
+	d2l_i2c_read_reg(client, SYSSTAT);		/* 0x500 */
+
+	d2l_i2c_write_reg(client, DSIERRCNT, tmp);
+}
 /**
  * Init the D2L bridge via the DSI interface for Video.
  *
@@ -315,12 +333,19 @@
 	u32 vpctrl;
 	u32 htime1;
 	u32 vtime1;
+	u32 htime2;
+	u32 vtime2;
 	u32 ppi_tx_rx_ta; /* BTA Bus-Turn-Around */
 	u32 lvcfg;
 	u32 hbpr;	/* Horizontal Back Porch */
 	u32 hpw;	/* Horizontal Pulse Width */
 	u32 vbpr;	/* Vertical Back Porch */
 	u32 vpw;	/* Vertical Pulse Width */
+
+	u32 hfpr;	/* Horizontal Front Porch */
+	u32 hsize;	/* Horizontal Active size */
+	u32 vfpr;	/* Vertical Front Porch */
+	u32 vsize;	/* Vertical Active size */
 	bool vesa_rgb888 = false;
 
 	lanes_enable = 0x01; /* clock-lane enable */
@@ -345,8 +370,12 @@
 		return -EINVAL;
 	}
 
-	pr_debug("%s.xres=%d.yres=%d.\n",
-		__func__, mfd->panel_info.xres, mfd->panel_info.yres);
+	pr_debug("%s.xres=%d.yres=%d.fps=%d.dst_format=%d.\n",
+		__func__,
+		 mfd->panel_info.xres,
+		 mfd->panel_info.yres,
+		 mfd->panel_info.mipi.frame_rate,
+		 mfd->panel_info.mipi.dst_format);
 
 	hbpr = mfd->panel_info.lcdc.h_back_porch;
 	hpw	= mfd->panel_info.lcdc.h_pulse_width;
@@ -355,6 +384,15 @@
 
 	htime1 = (hbpr << 16) + hpw;
 	vtime1 = (vbpr << 16) + vpw;
+
+	hfpr = mfd->panel_info.lcdc.h_front_porch;
+	hsize = mfd->panel_info.xres;
+	vfpr = mfd->panel_info.lcdc.v_front_porch;
+	vsize = mfd->panel_info.yres;
+
+	htime2 = (hfpr << 16) + hsize;
+	vtime2 = (vfpr << 16) + vsize;
+
 	lvcfg = 0x0003; /* PCLK=DCLK/3, Dual Link, LVEN */
 	vpctrl = 0x01000120; /* Output RGB888 , Event-Mode , */
 	ppi_tx_rx_ta = 0x00040004;
@@ -403,6 +441,8 @@
 	mipi_d2l_write_reg(mfd, VPCTRL, vpctrl); /* RGB888 + Event mode */
 	mipi_d2l_write_reg(mfd, HTIM1, htime1);
 	mipi_d2l_write_reg(mfd, VTIM1, vtime1);
+	mipi_d2l_write_reg(mfd, HTIM2, htime2);
+	mipi_d2l_write_reg(mfd, VTIM2, vtime2);
 	mipi_d2l_write_reg(mfd, VFUEN, 0x00000001);
 	mipi_d2l_write_reg(mfd, LVCFG, lvcfg); /* Enables LVDS tx */
 
@@ -539,6 +579,9 @@
 
 	mipi_d2l_enable_3d(mfd, false, false);
 
+	/* Add I2C driver only after DSI-CLK is running */
+	i2c_add_driver(&d2l_i2c_slave_driver);
+
 	pr_info("%s.ret=%d.\n", __func__, ret);
 
 	return ret;
@@ -589,6 +632,103 @@
 	.set_backlight = mipi_d2l_set_backlight,
 };
 
+static u32 d2l_i2c_read_reg(struct i2c_client *client, u16 reg)
+{
+	int rc;
+	u32 val = 0;
+	u8 buf[6];
+
+	if (client == NULL) {
+		pr_err("%s.invalid i2c client.\n", __func__);
+		return -EINVAL;
+	}
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xFF;
+
+	rc = i2c_master_send(client, buf, sizeof(reg));
+	rc = i2c_master_recv(client, buf, 4);
+
+	if (rc >= 0) {
+		val = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
+		pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, val);
+	} else
+		pr_err("%s.fail.reg=0x%x.\n", __func__, reg);
+
+	return val;
+}
+
+static u32 d2l_i2c_write_reg(struct i2c_client *client, u16 reg, u32 val)
+{
+	int rc;
+	u8 buf[6];
+
+	if (client == NULL) {
+		pr_err("%s.invalid i2c client.\n", __func__);
+		return -EINVAL;
+	}
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xFF;
+
+	buf[2] = (val >> 0) & 0xFF;
+	buf[3] = (val >> 8) & 0xFF;
+	buf[4] = (val >> 16) & 0xFF;
+	buf[5] = (val >> 24) & 0xFF;
+
+	rc = i2c_master_send(client, buf, sizeof(buf));
+
+	if (rc >= 0)
+		pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, val);
+	else
+		pr_err("%s.fail.reg=0x%x.\n", __func__, reg);
+
+	return val;
+}
+
+static int __devinit d2l_i2c_slave_probe(struct i2c_client *client,
+					 const struct i2c_device_id *id)
+{
+	static const u32 i2c_funcs = I2C_FUNC_I2C;
+
+	d2l_i2c_client = client;
+
+	if (!i2c_check_functionality(client->adapter, i2c_funcs)) {
+		pr_err("%s.i2c_check_functionality failed.\n", __func__);
+		return -ENOSYS;
+	} else {
+		pr_debug("%s.i2c_check_functionality OK.\n", __func__);
+	}
+
+	d2l_i2c_read_reg(client, IDREG);
+
+	mipi_d2l_read_status_via_i2c(d2l_i2c_client);
+
+	return 0;
+}
+
+static __devexit int d2l_i2c_slave_remove(struct i2c_client *client)
+{
+	d2l_i2c_client = NULL;
+
+	return 0;
+}
+
+static const struct i2c_device_id d2l_i2c_id[] = {
+	{"tc358764-i2c", 0},
+	{}
+};
+
+static struct i2c_driver d2l_i2c_slave_driver = {
+	.driver = {
+		.name = "tc358764-i2c",
+		.owner = THIS_MODULE
+	},
+	.probe    = d2l_i2c_slave_probe,
+	.remove   = __devexit_p(d2l_i2c_slave_remove),
+	.id_table = d2l_i2c_id,
+};
+
 static int mipi_d2l_enable_3d(struct msm_fb_data_type *mfd,
 			      bool enable, bool mode)
 {
@@ -630,6 +770,8 @@
 			mipi_d2l_enable_3d(d2l_mfd, true, false);
 		else if (data == 0)
 			mipi_d2l_enable_3d(d2l_mfd, false, false);
+		else if (data == 9)
+			mipi_d2l_read_status_via_i2c(d2l_i2c_client);
 		else
 			pr_err("%s.Invalid value=%d.\n", __func__, data);
 	}
diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c
index 3b000ec..0f40c77 100644
--- a/drivers/video/msm/msm_dss_io_8960.c
+++ b/drivers/video/msm/msm_dss_io_8960.c
@@ -11,6 +11,7 @@
  *
  */
 #include <linux/clk.h>
+#include <mach/clk.h>
 #include "msm_fb.h"
 #include "mdp.h"
 #include "mdp4.h"
@@ -634,6 +635,10 @@
 	hdmi_msm_clk(0);
 	udelay(5);
 	hdmi_msm_clk(1);
+
+	clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_ASSERT);
+	udelay(20);
+	clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_DEASSERT);
 }
 
 void hdmi_msm_init_phy(int video_format)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 593f10b..8ff1c75 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -188,12 +188,8 @@
 };
 #endif
 
-#define PANEL_NAME_MAX_LEN 30
 static struct msm_fb_platform_data *msm_fb_pdata;
-static char prim_panel_name[PANEL_NAME_MAX_LEN];
-static char ext_panel_name[PANEL_NAME_MAX_LEN];
-module_param_string(prim_display, prim_panel_name, sizeof(prim_panel_name) , 0);
-module_param_string(ext_display, ext_panel_name, sizeof(ext_panel_name) , 0);
+unsigned char hdmi_prim_display;
 
 int msm_fb_detect_client(const char *name)
 {
@@ -202,19 +198,28 @@
 #ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
 	u32 id;
 #endif
+	if (!msm_fb_pdata)
+		return -EPERM;
+
 	len = strnlen(name, PANEL_NAME_MAX_LEN);
-	if (strnlen(prim_panel_name, PANEL_NAME_MAX_LEN)) {
-		MSM_FB_DEBUG("\n name = %s, prim_display = %s",
-			name, prim_panel_name);
-		if (!strncmp((char *)prim_panel_name, name, len))
+	if (strnlen(msm_fb_pdata->prim_panel_name, PANEL_NAME_MAX_LEN)) {
+		pr_err("\n name = %s, prim_display = %s",
+			name, msm_fb_pdata->prim_panel_name);
+		if (!strncmp((char *)msm_fb_pdata->prim_panel_name,
+			name, len)) {
+			if (!strncmp((char *)msm_fb_pdata->prim_panel_name,
+				"hdmi_msm", len))
+				hdmi_prim_display = 1;
 			return 0;
-		else
+		} else {
 			ret = -EPERM;
+		}
 	}
-	if (strnlen(ext_panel_name, PANEL_NAME_MAX_LEN)) {
-		MSM_FB_DEBUG("\n name = %s, ext_display = %s",
-			name, ext_panel_name);
-		if (!strncmp((char *)ext_panel_name, name, len))
+
+	if (strnlen(msm_fb_pdata->ext_panel_name, PANEL_NAME_MAX_LEN)) {
+		pr_err("\n name = %s, ext_display = %s",
+			name, msm_fb_pdata->ext_panel_name);
+		if (!strncmp((char *)msm_fb_pdata->ext_panel_name, name, len))
 			return 0;
 		else
 			ret = -EPERM;
@@ -1549,6 +1554,7 @@
 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;
+	int hole_offset;
 
 	if (var->rotate != FB_ROTATE_UR)
 		return -EINVAL;
@@ -1643,7 +1649,20 @@
 	if (var->xoffset > (var->xres_virtual - var->xres))
 		return -EINVAL;
 
-	if (var->yoffset > (var->yres_virtual - var->yres))
+	if (!mfd->panel_info.mode2_yres)
+		hole_offset = (mfd->fbi->fix.line_length *
+			mfd->panel_info.yres) % PAGE_SIZE;
+	else
+		hole_offset = (mfd->fbi->fix.line_length *
+			mfd->panel_info.mode2_yres) % PAGE_SIZE;
+
+	if (!hole_offset) {
+		hole_offset = PAGE_SIZE - hole_offset;
+		hole_offset = hole_offset/mfd->fbi->fix.line_length;
+	}
+
+	if (var->yoffset > (var->yres_virtual - var->yres + (hole_offset *
+							(mfd->fb_page - 1))))
 		return -EINVAL;
 
 	return 0;
@@ -3375,11 +3394,10 @@
 	 */
 	if (type == HDMI_PANEL || type == DTV_PANEL ||
 		type == TV_PANEL || type == WRITEBACK_PANEL) {
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-		pdata->panel_info.fb_num = 2;
-#else
-		pdata->panel_info.fb_num = 1;
-#endif
+		if (hdmi_prim_display)
+			pdata->panel_info.fb_num = 2;
+		else
+			pdata->panel_info.fb_num = 1;
 	}
 	else
 		pdata->panel_info.fb_num = MSM_FB_NUM;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 9837f07..a4b46ea 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -177,6 +177,7 @@
 	u32 mem_hid;
 	u32 mdp_rev;
 	u32 use_ov0_blt, ov0_blt_state;
+	u32 use_ov1_blt, ov1_blt_state;
 	u32 writeback_state;
 };
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
index 3f54756..267e924 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -246,6 +246,8 @@
 	DDL_METADATA_ALIGNSIZE(suffix);
 	encoder->suffix = suffix;
 	encoder->output_buf_req.sz += suffix;
+	encoder->output_buf_req.sz =
+		DDL_ALIGN(encoder->output_buf_req.sz, DDL_KILO_BYTE(4));
 }
 
 u32 ddl_set_metadata_params(struct ddl_client_context *ddl,
@@ -454,6 +456,7 @@
 		return;
 	}
 	out_frame->flags |= VCD_FRAME_FLAG_EXTRADATA;
+	DDL_MSG_LOW("processing metadata for encoder");
 	start_addr = (u32) ((u8 *)out_frame->virtual + out_frame->offset);
 	qfiller = (u32 *)((out_frame->data_len +
 				start_addr + 3) & ~3);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 51a72c8..444db9f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -915,10 +915,15 @@
 	}
 	case VCD_I_METADATA_ENABLE:
 	case VCD_I_METADATA_HEADER:
-		DDL_MSG_ERROR("Meta Data Interface is Requested");
-		vcd_status = ddl_set_metadata_params(ddl, property_hdr,
-			property_value);
-		vcd_status = VCD_S_SUCCESS;
+		DDL_MSG_LOW("Meta Data Interface is Requested");
+		if (!res_trk_check_for_sec_session()) {
+			vcd_status = ddl_set_metadata_params(ddl,
+				property_hdr, property_value);
+		} else {
+			DDL_MSG_ERROR("Meta Data Interface is not "
+				"supported in secure session");
+			vcd_status = VCD_ERR_ILLEGAL_OP;
+		}
 	break;
 	case VCD_I_META_BUFFER_MODE:
 		vcd_status = VCD_S_SUCCESS;
@@ -1836,8 +1841,16 @@
 		/*original_buf_req->align <= req_buf_req->align,*/
 		original_buf_req->sz <= req_buf_req->sz)
 		status = true;
-	else
+	else {
 		DDL_MSG_ERROR("ddl_valid_buf_req:Failed");
+		DDL_MSG_ERROR("codec_buf_req: min_cnt=%d, mx_cnt=%d, "
+			"align=%d, sz=%d\n", original_buf_req->min_count,
+			original_buf_req->max_count, original_buf_req->align,
+			original_buf_req->sz);
+		DDL_MSG_ERROR("client_buffs: actual_count=%d, align=%d, "
+			"sz=%d\n", req_buf_req->actual_count,
+			req_buf_req->align,	req_buf_req->sz);
+	}
 	return status;
 }
 
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 8851b52..2f26e01 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -740,16 +740,26 @@
 	mutex_unlock(&resource_context.secure_lock);
 	return rc;
 }
+
+void res_trk_secure_unset(void)
+{
+	mutex_lock(&resource_context.secure_lock);
+	resource_context.secure_session = 0;
+	mutex_unlock(&resource_context.secure_lock);
+}
+
+void res_trk_secure_set(void)
+{
+	mutex_lock(&resource_context.secure_lock);
+	resource_context.secure_session = 1;
+	mutex_unlock(&resource_context.secure_lock);
+}
+
 int res_trk_open_secure_session()
 {
 	int rc;
 	mutex_lock(&resource_context.secure_lock);
-	if (resource_context.secure_session) {
-		pr_err("Secure session already open");
-		rc = -EBUSY;
-		goto error_open;
-	}
-	resource_context.secure_session = 1;
+
 	rc = res_trk_enable_iommu_clocks();
 	if (rc) {
 		pr_err("IOMMU clock enabled failed while open");
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
index f91ddb5..9975573 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
@@ -40,4 +40,6 @@
 int res_trk_check_for_sec_session(void);
 int res_trk_open_secure_session(void);
 int res_trk_close_secure_session(void);
+void res_trk_secure_set(void);
+void res_trk_secure_unset(void);
 #endif
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index 86bf397..bd0d94e 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
@@ -734,6 +734,16 @@
 	return 0;
 }
 
+void res_trk_secure_unset(void)
+{
+	return;
+}
+
+void res_trk_secure_set(void)
+{
+	return;
+}
+
 int res_trk_open_secure_session()
 {
 	return -EINVAL;
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
index 237d143..898195a 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
@@ -35,4 +35,6 @@
 int res_trk_check_for_sec_session(void);
 int res_trk_open_secure_session(void);
 int res_trk_close_secure_session(void);
+void res_trk_secure_set(void);
+void res_trk_secure_unset(void);
 #endif
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index f685cd5..cffb0a9 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -2073,19 +2073,24 @@
 		mutex_unlock(&vid_dec_device_p->lock);
 		return -ENODEV;
 	}
-	if (res_trk_open_secure_session()) {
-		ERR("Secure session operation failure\n");
-		mutex_unlock(&vid_dec_device_p->lock);
-		return -ENODEV;
-	}
+	res_trk_secure_set();
 	file->private_data = vid_dec_open_client();
 	if (!file->private_data) {
-		res_trk_close_secure_session();
-		mutex_unlock(&vid_dec_device_p->lock);
-		return -ENODEV;
+		goto error;
+	}
+
+	if (res_trk_open_secure_session()) {
+		ERR("Secure session operation failure\n");
+		goto error;
 	}
 	mutex_unlock(&vid_dec_device_p->lock);
 	return 0;
+
+error:
+	res_trk_secure_unset();
+	mutex_unlock(&vid_dec_device_p->lock);
+	return -ENODEV;
+
 }
 
 static int vid_dec_open(struct inode *inode, struct file *file)
@@ -2113,8 +2118,8 @@
 	INFO("msm_vidc_dec: Inside %s()", __func__);
 	vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT);
 	vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_INPUT);
-	vid_dec_close_client(client_ctx);
 	res_trk_close_secure_session();
+	vid_dec_close_client(client_ctx);
 	vidc_release_firmware();
 #ifndef USE_RES_TRACKER
 	vidc_disable_clk();
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 6d6dcdc..3c25751fa 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -1575,6 +1575,34 @@
 		}
 		break;
 	}
+	case VEN_IOCTL_SET_EXTRADATA:
+	case VEN_IOCTL_GET_EXTRADATA:
+	{
+		u32 extradata_flag;
+		DBG("VEN_IOCTL_(G)SET_EXTRADATA\n");
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (cmd == VEN_IOCTL_SET_EXTRADATA) {
+			if (copy_from_user(&extradata_flag, venc_msg.in,
+					sizeof(u32)))
+				return -EFAULT;
+			result = vid_enc_set_get_extradata(client_ctx,
+					&extradata_flag, true);
+		} else {
+			result = vid_enc_set_get_extradata(client_ctx,
+					&extradata_flag, false);
+			if (result) {
+				if (copy_to_user(venc_msg.out, &extradata_flag,
+						sizeof(u32)))
+					return -EFAULT;
+			}
+		}
+		if (!result) {
+			ERR("setting VEN_IOCTL_(G)SET_LIVE_MODE failed\n");
+			return -EIO;
+		}
+		break;
+	}
 	case VEN_IOCTL_SET_AC_PREDICTION:
 	case VEN_IOCTL_GET_AC_PREDICTION:
 	case VEN_IOCTL_SET_RVLC:
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index f362f7b..cac5dc4 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -316,6 +316,42 @@
 	return true;
 }
 
+u32 vid_enc_set_get_extradata(struct video_client_ctx *client_ctx,
+		u32 *extradata_flag, u32 set_flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_meta_data_enable vcd_meta_data;
+	u32 vcd_status = VCD_ERR_FAIL;
+	if (!client_ctx || !extradata_flag)
+		return false;
+	vcd_property_hdr.prop_id = VCD_I_METADATA_ENABLE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_meta_data_enable);
+	if (set_flag) {
+		DBG("vcd_set_property: VCD_I_METADATA_ENABLE = %d\n",
+				*extradata_flag);
+		vcd_meta_data.meta_data_enable_flag = *extradata_flag;
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &vcd_meta_data);
+		if (vcd_status) {
+			ERR("%s(): Set VCD_I_METADATA_ENABLE Failed\n",
+				__func__);
+			return false;
+		}
+	} else {
+		vcd_status = vcd_get_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &vcd_meta_data);
+		if (vcd_status) {
+			ERR("%s(): Get VCD_I_METADATA_ENABLE Failed\n",
+				__func__);
+			return false;
+		}
+		*extradata_flag = vcd_meta_data.meta_data_enable_flag;
+		DBG("vcd_get_property: VCD_I_METADATA_ENABLE = %d\n",
+				*extradata_flag);
+	}
+	return true;
+}
+
 u32 vid_enc_set_get_framerate(struct video_client_ctx *client_ctx,
 		struct venc_framerate *frame_rate, u32 set_flag)
 {
@@ -1494,6 +1530,11 @@
 		venc_buf_req->alignment = buffer_req.align;
 		venc_buf_req->bufpoolid = buffer_req.buf_pool_id;
 		venc_buf_req->suffixsize = 0;
+		DBG("%s: actual_count=%d, align=%d, sz=%d, min_count=%d, "
+			"max_count=%d, buf_pool_id=%d\n", __func__,
+			buffer_req.actual_count, buffer_req.align,
+			buffer_req.sz, buffer_req.min_count,
+			buffer_req.max_count, buffer_req.buf_pool_id);
 	}
 	return status;
 }
@@ -1521,6 +1562,11 @@
 	buffer_req.align = venc_buf_req->alignment;
 	buffer_req.buf_pool_id = 0;
 
+	DBG("%s: actual_count=%d, align=%d, sz=%d, min_count=%d, "
+		"max_count=%d, buf_pool_id=%d\n", __func__,
+		buffer_req.actual_count, buffer_req.align, buffer_req.sz,
+		buffer_req.min_count, buffer_req.max_count,
+		buffer_req.buf_pool_id);
 	vcd_status = vcd_set_buffer_requirements(client_ctx->vcd_handle,
 				buffer, &buffer_req);
 
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.h b/drivers/video/msm/vidc/common/enc/venc_internal.h
index a07f7ab..8a07fdb 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.h
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.h
@@ -68,6 +68,9 @@
 u32 vid_enc_set_get_live_mode(struct video_client_ctx *client_ctx,
 		struct venc_switch *encoder_switch, u32 set_flag);
 
+u32 vid_enc_set_get_extradata(struct video_client_ctx *client_ctx,
+		u32 *extradata_flag, u32 set_flag);
+
 u32 vid_enc_set_get_short_header(struct video_client_ctx *client_ctx,
 		struct venc_switch *encoder_switch, u32 set_flag);
 
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 1cb5401..5d3a6a1 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -36,23 +36,11 @@
 #define DIAG_IOCTL_GET_DELAYED_RSP_ID 	8
 #define DIAG_IOCTL_LSM_DEINIT		9
 
-/* Machine ID and corresponding PC Tools IDs */
-#define APQ8060_MACHINE_ID	86
-#define AO8960_MACHINE_ID	87
-#define MSM8660_MACHINE_ID	71
-#define MDM9615_MACHINE_ID	104
-#define APQ8064_MACHINE_ID	109
-#define MSM8930_MACHINE_ID	116
-#define MSM8630_MACHINE_ID	117
-#define MSM8230_MACHINE_ID	118
-#define APQ8030_MACHINE_ID	119
-#define MSM8627_MACHINE_ID	120
-#define MSM8227_MACHINE_ID	121
-#define MSM8260A_MACHINE_ID	123
-#define MSM8974_MACHINE_ID	126
+/* PC Tools IDs */
 #define APQ8060_TOOLS_ID	4062
 #define AO8960_TOOLS_ID		4064
 #define APQ8064_TOOLS_ID	4072
+#define MSM8625_TOOLS_ID	4075
 #define MSM8930_TOOLS_ID	4076
 #define MSM8630_TOOLS_ID	4077
 #define MSM8230_TOOLS_ID	4078
@@ -114,11 +102,11 @@
 
 /* This needs to be modified manually now, when we add
  a new RANGE of SSIDs to the msg_mask_tbl */
-#define MSG_MASK_TBL_CNT		19
+#define MSG_MASK_TBL_CNT		23
 #define EVENT_LAST_ID			0x083F
 
 #define MSG_SSID_0			0
-#define MSG_SSID_0_LAST			68
+#define MSG_SSID_0_LAST			90
 #define MSG_SSID_1			500
 #define MSG_SSID_1_LAST			506
 #define MSG_SSID_2			1000
@@ -126,19 +114,19 @@
 #define MSG_SSID_3			2000
 #define MSG_SSID_3_LAST			2008
 #define MSG_SSID_4			3000
-#define MSG_SSID_4_LAST			3012
+#define MSG_SSID_4_LAST			3014
 #define MSG_SSID_5			4000
 #define MSG_SSID_5_LAST			4010
 #define MSG_SSID_6			4500
 #define MSG_SSID_6_LAST			4526
 #define MSG_SSID_7			4600
-#define MSG_SSID_7_LAST			4611
+#define MSG_SSID_7_LAST			4612
 #define MSG_SSID_8			5000
-#define MSG_SSID_8_LAST			5024
+#define MSG_SSID_8_LAST			5029
 #define MSG_SSID_9			5500
-#define MSG_SSID_9_LAST			5514
+#define MSG_SSID_9_LAST			5516
 #define MSG_SSID_10			6000
-#define MSG_SSID_10_LAST		6050
+#define MSG_SSID_10_LAST		6072
 #define MSG_SSID_11			6500
 #define MSG_SSID_11_LAST		6521
 #define MSG_SSID_12			7000
@@ -155,6 +143,14 @@
 #define MSG_SSID_17_LAST		9008
 #define MSG_SSID_18			9500
 #define MSG_SSID_18_LAST		9509
+#define MSG_SSID_19			10200
+#define MSG_SSID_19_LAST		10210
+#define MSG_SSID_20			10251
+#define MSG_SSID_20_LAST		10255
+#define MSG_SSID_21			10300
+#define MSG_SSID_21_LAST		10300
+#define MSG_SSID_22			10350
+#define MSG_SSID_22_LAST		10361
 
 struct diagpkt_delay_params {
 	void *rsp_ptr;
@@ -249,6 +245,28 @@
 	MSG_LVL_MED,
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
+	MSG_LVL_MED,
+	MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
+	MSG_LVL_LOW,
+	MSG_LVL_MED,
+	MSG_LVL_LOW
 };
 
 static const uint32_t msg_bld_masks_1[] = {
@@ -258,7 +276,7 @@
 	MSG_LVL_LOW,
 	MSG_LVL_HIGH,
 	MSG_LVL_HIGH,
-	MSG_LVL_HIGH,
+	MSG_LVL_HIGH
 };
 
 static const uint32_t msg_bld_masks_2[] = {
@@ -297,7 +315,9 @@
 	MSG_LVL_HIGH,
 	MSG_LVL_HIGH,
 	MSG_LVL_HIGH,
-	MSG_LVL_HIGH
+	MSG_LVL_HIGH,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW
 };
 
 static const uint32_t msg_bld_masks_5[] = {
@@ -310,7 +330,8 @@
 	MSG_LVL_MED,
 	MSG_LVL_MED,
 	MSG_LVL_MED,
-	MSG_LVL_MED,
+	MSG_LVL_MED|MSG_LVL_MED|MSG_MASK_5|MSG_MASK_6|MSG_MASK_7| \
+		MSG_MASK_8|MSG_MASK_9,
 	MSG_LVL_MED
 };
 
@@ -357,6 +378,7 @@
 	MSG_LVL_MED,
 	MSG_LVL_MED,
 	MSG_LVL_MED,
+	MSG_LVL_LOW
 };
 
 static const uint32_t msg_bld_masks_8[] = {
@@ -385,6 +407,11 @@
 	MSG_LVL_MED,
 	MSG_LVL_MED,
 	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED
 };
 
 static const uint32_t msg_bld_masks_9[] = {
@@ -403,6 +430,8 @@
 	MSG_LVL_MED|MSG_MASK_5,
 	MSG_LVL_MED|MSG_MASK_5,
 	MSG_LVL_MED|MSG_MASK_5,
+	MSG_LVL_MED|MSG_MASK_5,
+	MSG_LVL_MED|MSG_MASK_5
 };
 
 static const uint32_t msg_bld_masks_10[] =  {
@@ -462,6 +491,28 @@
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_MED,
+	MSG_LVL_LOW
 };
 
 static const uint32_t msg_bld_masks_11[] = {
@@ -584,6 +635,47 @@
 	MSG_LVL_LOW
 };
 
+static const uint32_t msg_bld_masks_19[] = {
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW
+};
+
+static const uint32_t msg_bld_masks_20[] = {
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW
+};
+
+static const uint32_t msg_bld_masks_21[] = {
+	MSG_LVL_HIGH
+};
+
+static const uint32_t msg_bld_masks_22[] = {
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH
+};
+
 /* LOG CODES */
 
 #define LOG_0	0x0
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 500ee6b..a2391e3 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -29,6 +29,12 @@
 /* MXT_TOUCH_KEYARRAY_T15 */
 #define MXT_KEYARRAY_MAX_KEYS	32
 
+/* Bootoader IDs */
+#define MXT_BOOTLOADER_ID_224		0x0A
+#define MXT_BOOTLOADER_ID_224E		0x06
+#define MXT_BOOTLOADER_ID_1386		0x01
+#define MXT_BOOTLOADER_ID_1386E		0x10
+
 /* Config data for a given maXTouch controller with a specific firmware */
 struct mxt_config_info {
 	const u8 *config;
@@ -37,6 +43,9 @@
 	u8 variant_id;
 	u8 version;
 	u8 build;
+	u8 bootldr_id;
+	/* Points to the firmware name to be upgraded to */
+	const char *fw_name;
 };
 
 /* The platform data for the Atmel maXTouch touchscreen driver */
diff --git a/include/linux/ion.h b/include/linux/ion.h
index caed2a2..ca1f198f 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -493,6 +493,23 @@
  */
 int msm_ion_unsecure_heap(int heap_id);
 
+/**
+ * msm_ion_do_cache_op - do cache operations.
+ *
+ * @client - pointer to ION client.
+ * @handle - pointer to buffer handle.
+ * @vaddr -  virtual address to operate on.
+ * @len - Length of data to do cache operation on.
+ * @cmd - Cache operation to perform:
+ *		ION_IOC_CLEAN_CACHES
+ *		ION_IOC_INV_CACHES
+ *		ION_IOC_CLEAN_INV_CACHES
+ *
+ * Returns 0 on success
+ */
+int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+			void *vaddr, unsigned long len, unsigned int cmd);
+
 #else
 static inline struct ion_client *ion_client_create(struct ion_device *dev,
 				     unsigned int heap_mask, const char *name)
@@ -604,6 +621,14 @@
 {
 	return -ENODEV;
 }
+
+static inline int msm_ion_do_cache_op(struct ion_client *client,
+			struct ion_handle *handle, void *vaddr,
+			unsigned long len, unsigned int cmd)
+{
+	return -ENODEV;
+}
+
 #endif /* CONFIG_ION */
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/libra_sdioif.h b/include/linux/libra_sdioif.h
index 965e2b5..08be83a 100644
--- a/include/linux/libra_sdioif.h
+++ b/include/linux/libra_sdioif.h
@@ -35,6 +35,7 @@
 typedef int (suspend_handler_t)(struct sdio_func *);
 typedef void (resume_handler_t)(struct sdio_func *);
 
+int libra_enable_sdio_irq_in_chip(struct sdio_func *func, u8 enable);
 int    libra_sdio_configure(sdio_irq_handler_t libra_sdio_rxhandler,
 		void (*func_drv_fn)(int *status),
 		u32 funcdrv_timeout, u32 blksize);
diff --git a/include/linux/mfd/pm8xxx/irq.h b/include/linux/mfd/pm8xxx/irq.h
index 1e1fe6c..78fbed3 100644
--- a/include/linux/mfd/pm8xxx/irq.h
+++ b/include/linux/mfd/pm8xxx/irq.h
@@ -39,21 +39,20 @@
 
 #ifdef CONFIG_MFD_PM8XXX_IRQ
 int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq);
-struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev,
+struct pm_irq_chip *pm8xxx_irq_init(struct device *dev,
 				const struct pm8xxx_irq_platform_data *pdata);
-int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip);
+int pm8xxx_irq_exit(struct pm_irq_chip *chip);
 #else
 static inline int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
 {
 	return -ENXIO;
 }
-static inline struct pm_irq_chip * __devinit pm8xxx_irq_init(
-				const struct device *dev,
+static inline struct pm_irq_chip *pm8xxx_irq_init(const struct device *dev,
 				const struct pm8xxx_irq_platform_data *pdata)
 {
 	return ERR_PTR(-ENXIO);
 }
-static inline int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
+static inline int pm8xxx_irq_exit(struct pm_irq_chip *chip)
 {
 	return -ENXIO;
 }
diff --git a/include/linux/mfd/wcd9xxx/wcd9310_registers.h b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
index d2736ea..67c2a6b 100644
--- a/include/linux/mfd/wcd9xxx/wcd9310_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
@@ -897,6 +897,38 @@
 #define TABLA_A_CDC_DEBUG_B5_CTL__POR			(0x00000000)
 #define TABLA_A_CDC_DEBUG_B6_CTL			(0x0000036D)
 #define TABLA_A_CDC_DEBUG_B6_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP1_B1_CTL			(0x00000370)
+#define TABLA_A_CDC_COMP1_B1_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP1_B2_CTL			(0x00000371)
+#define TABLA_A_CDC_COMP1_B2_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP1_B3_CTL			(0x00000372)
+#define TABLA_A_CDC_COMP1_B3_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP1_B4_CTL			(0x00000373)
+#define TABLA_A_CDC_COMP1_B4_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP1_B5_CTL			(0x00000374)
+#define TABLA_A_CDC_COMP1_B5_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP1_B6_CTL			(0x00000375)
+#define TABLA_A_CDC_COMP1_B6_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS		(0x00000376)
+#define TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS__POR	(0x00000000)
+#define TABLA_A_CDC_COMP1_FS_CFG			(0x00000377)
+#define TABLA_A_CDC_COMP1_FS_CFG__POR			(0x00000000)
+#define TABLA_A_CDC_COMP2_B1_CTL			(0x00000378)
+#define TABLA_A_CDC_COMP2_B1_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP2_B2_CTL			(0x00000379)
+#define TABLA_A_CDC_COMP2_B2_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP2_B3_CTL			(0x0000037A)
+#define TABLA_A_CDC_COMP2_B3_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP2_B4_CTL			(0x0000037B)
+#define TABLA_A_CDC_COMP2_B4_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP2_B5_CTL			(0x0000037C)
+#define TABLA_A_CDC_COMP2_B5_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP2_B6_CTL			(0x0000037D)
+#define TABLA_A_CDC_COMP2_B6_CTL__POR			(0x00000000)
+#define TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS		(0x0000037E)
+#define TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS__POR	(0x00000000)
+#define TABLA_A_CDC_COMP2_FS_CFG			(0x0000037F)
+#define TABLA_A_CDC_COMP2_FS_CFG__POR			(0x00000000)
 #define TABLA_A_CDC_CONN_RX1_B1_CTL			(0x00000380)
 #define TABLA_A_CDC_CONN_RX1_B1_CTL__POR			(0x00000000)
 #define TABLA_A_CDC_CONN_RX1_B2_CTL			(0x00000381)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index ff53742..dedbe5c 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -190,6 +190,7 @@
 #define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
 #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
 #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
+#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -328,6 +329,7 @@
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
 #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
@@ -337,6 +339,7 @@
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
 #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 35137d6..73a68c9 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -56,12 +56,15 @@
 #define MMC_TIMING_UHS_SDR50	3
 #define MMC_TIMING_UHS_SDR104	4
 #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
+#define MMC_1_2V_SDR_MODE	3
+#define MMC_1_8V_SDR_MODE	4
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -147,7 +150,9 @@
 	void	(*init_card)(struct mmc_host *host, struct mmc_card *card);
 
 	int	(*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
-	int	(*execute_tuning)(struct mmc_host *host);
+
+	/* The tuning command opcode value is different for SD and eMMC cards */
+	int	(*execute_tuning)(struct mmc_host *host, u32 opcode);
 	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
 	void	(*hw_reset)(struct mmc_host *host);
 };
@@ -239,7 +244,10 @@
 #define MMC_CAP2_CACHE_CTRL	(1 << 1)	/* Allow cache control */
 #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)	/* Notify poweroff supported */
 #define MMC_CAP2_NO_MULTI_READ	(1 << 3)	/* Multiblock reads don't work */
-
+#define MMC_CAP2_HS200_1_8V_SDR	(1 << 5)        /* can support */
+#define MMC_CAP2_HS200_1_2V_SDR	(1 << 6)        /* can support */
+#define MMC_CAP2_HS200		(MMC_CAP2_HS200_1_8V_SDR | \
+				 MMC_CAP2_HS200_1_2V_SDR)
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 	unsigned int        power_notify_type;
 #define MMC_HOST_PW_NOTIFY_NONE		0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 0a72bf8..e124fbe 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -51,6 +51,7 @@
 #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
 #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
 #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
+#define MMC_SEND_TUNING_BLOCK_HS200	21	/* adtc R1  */
 
   /* class 3 */
 #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
@@ -331,13 +332,76 @@
 
 #define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK	0xF	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
+#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+						/* SDR mode @1.2V I/O */
+
+#define EXT_CSD_CARD_TYPE_SDR_200	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
+					 EXT_CSD_CARD_TYPE_SDR_1_2V)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL	(EXT_CSD_CARD_TYPE_SDR_200 | \
+					 EXT_CSD_CARD_TYPE_52 | \
+					 EXT_CSD_CARD_TYPE_26)
+
+#define	EXT_CSD_CARD_TYPE_SDR_1_2V_ALL	(EXT_CSD_CARD_TYPE_SDR_1_2V | \
+					 EXT_CSD_CARD_TYPE_52 | \
+					 EXT_CSD_CARD_TYPE_26)
+
+#define	EXT_CSD_CARD_TYPE_SDR_1_8V_ALL	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
+					 EXT_CSD_CARD_TYPE_52 | \
+					 EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V	(EXT_CSD_CARD_TYPE_SDR_1_2V | \
+						 EXT_CSD_CARD_TYPE_DDR_1_8V | \
+						 EXT_CSD_CARD_TYPE_52 | \
+						 EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
+						 EXT_CSD_CARD_TYPE_DDR_1_8V | \
+						 EXT_CSD_CARD_TYPE_52 | \
+						 EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V	(EXT_CSD_CARD_TYPE_SDR_1_2V | \
+						 EXT_CSD_CARD_TYPE_DDR_1_2V | \
+						 EXT_CSD_CARD_TYPE_52 | \
+						 EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
+						 EXT_CSD_CARD_TYPE_DDR_1_2V | \
+						 EXT_CSD_CARD_TYPE_52 | \
+						 EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52	(EXT_CSD_CARD_TYPE_SDR_1_2V | \
+						 EXT_CSD_CARD_TYPE_DDR_52 | \
+						 EXT_CSD_CARD_TYPE_52 | \
+						 EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52	(EXT_CSD_CARD_TYPE_SDR_1_8V | \
+						 EXT_CSD_CARD_TYPE_DDR_52 | \
+						 EXT_CSD_CARD_TYPE_52 | \
+						 EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V	(EXT_CSD_CARD_TYPE_SDR_200 | \
+						 EXT_CSD_CARD_TYPE_DDR_1_8V | \
+						 EXT_CSD_CARD_TYPE_52 | \
+						 EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V	(EXT_CSD_CARD_TYPE_SDR_200 | \
+						 EXT_CSD_CARD_TYPE_DDR_1_2V | \
+						 EXT_CSD_CARD_TYPE_52 | \
+						 EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52	(EXT_CSD_CARD_TYPE_SDR_200 | \
+						 EXT_CSD_CARD_TYPE_DDR_52 | \
+						 EXT_CSD_CARD_TYPE_52 | \
+						 EXT_CSD_CARD_TYPE_26)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
diff --git a/include/linux/msm_audio.h b/include/linux/msm_audio.h
index 30d74ce..8a35ca0 100644
--- a/include/linux/msm_audio.h
+++ b/include/linux/msm_audio.h
@@ -90,6 +90,9 @@
 #define AUDIO_GET_ACDB_BLK _IOW(AUDIO_IOCTL_MAGIC, 96,  \
 					struct msm_acdb_cmd_device)
 
+#define AUDIO_REGISTER_ION _IOW(AUDIO_IOCTL_MAGIC, 97, unsigned)
+#define AUDIO_DEREGISTER_ION _IOW(AUDIO_IOCTL_MAGIC, 98, unsigned)
+
 #define	AUDIO_MAX_COMMON_IOCTL_NUM	100
 
 
@@ -166,6 +169,11 @@
 	uint32_t unused[2];
 };
 
+struct msm_audio_ion_info {
+	int fd;
+	void *vaddr;
+};
+
 struct msm_audio_pmem_info {
 	int fd;
 	void *vaddr;
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 5e39f89..69ff05b 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -34,6 +34,16 @@
 #define KGSL_CLK_MEM_IFACE 0x00000010
 #define KGSL_CLK_AXI	0x00000020
 
+/*
+ * Reset status values for context
+ */
+enum kgsl_ctx_reset_stat {
+	KGSL_CTX_STAT_NO_ERROR				= 0x00000000,
+	KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT		= 0x00000001,
+	KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT	= 0x00000002,
+	KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT		= 0x00000003
+};
+
 #define KGSL_MAX_PWRLEVELS 5
 
 #define KGSL_CONVERT_TO_MBPS(val) \
@@ -110,6 +120,7 @@
 	KGSL_PROP_MMU_ENABLE 	  = 0x00000006,
 	KGSL_PROP_INTERRUPT_WAITS = 0x00000007,
 	KGSL_PROP_VERSION         = 0x00000008,
+	KGSL_PROP_GPU_RESET_STAT  = 0x00000009
 };
 
 struct kgsl_shadowprop {
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 07d5af65..6442faa 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -140,6 +140,7 @@
 #define MDP_OV_PLAY_NOWAIT		0x00200000
 #define MDP_SOURCE_ROTATED_90		0x00100000
 #define MDP_DPP_HSIC			0x00080000
+#define MDP_BACKEND_COMPOSITION		0x00040000
 #define MDP_BORDERFILL_SUPPORTED	0x00010000
 #define MDP_SECURE_OVERLAY_SESSION      0x00008000
 #define MDP_MEMORY_ID_TYPE_FB		0x00001000
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index 1f264e9..bf149eb 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -52,6 +52,11 @@
 #define VEN_BUFFLAG_EXTRADATA	0x00000040
 #define VEN_BUFFLAG_CODECCONFIG	0x00000080
 
+/*Post processing flags bit masks*/
+#define VEN_EXTRADATA_NONE          0x001
+#define VEN_EXTRADATA_QCOMFILLER    0x002
+#define VEN_EXTRADATA_SLICEINFO     0x100
+
 /*ENCODER CONFIGURATION CONSTANTS*/
 
 /*Encoded video frame types*/
@@ -257,6 +262,8 @@
 #define VEN_IOCTL_GET_RECON_BUFFER_SIZE \
 	_IOW(VEN_IOCTLBASE_NENC, 22, struct venc_ioctl_msg)
 
+
+
 /*ENCODER PROPERTY CONFIGURATION & CAPABILITY IOCTLs*/
 
 /*IOCTL params:SET: InputData - venc_basecfg, OutputData - NULL
@@ -439,6 +446,14 @@
 #define VEN_IOCTL_SET_METABUFFER_MODE \
 	_IOW(VEN_IOCTLBASE_ENC, 47, struct venc_ioctl_msg)
 
+
+/*IOCTL params:SET: InputData - unsigned int, OutputData - NULL.*/
+#define VEN_IOCTL_SET_EXTRADATA \
+	_IOW(VEN_IOCTLBASE_ENC, 48, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - unsigned int.*/
+#define VEN_IOCTL_GET_EXTRADATA \
+	_IOR(VEN_IOCTLBASE_ENC, 49, struct venc_ioctl_msg)
+
 struct venc_switch{
 	unsigned char	status;
 };
diff --git a/include/linux/platform_data/dwc3-omap.h b/include/linux/platform_data/dwc3-omap.h
new file mode 100644
index 0000000..ada4012
--- /dev/null
+++ b/include/linux/platform_data/dwc3-omap.h
@@ -0,0 +1,47 @@
+/**
+ * dwc3-omap.h - OMAP Specific Glue layer, header.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+enum dwc3_omap_utmi_mode {
+	DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
+	DWC3_OMAP_UTMI_MODE_HW,
+	DWC3_OMAP_UTMI_MODE_SW,
+};
+
+struct dwc3_omap_data {
+	enum dwc3_omap_utmi_mode	utmi_mode;
+};
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 583ceb8..60decb6 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -322,6 +322,13 @@
 	unsigned is_b_host:1;		/* true during some HNP roleswitches */
 	unsigned b_hnp_enable:1;	/* OTG: did A-Host enable HNP? */
 	unsigned hnp_support:1;		/* OTG: HNP is supported on OTG port */
+	unsigned quick_hnp:1;		/* OTG: Indiacates if hnp is required
+					   irrespective of host_request flag
+					 */
+	unsigned otg_vbus_off:1;	/* OTG: OTG test device feature bit that
+					 * tells A-device to turn off VBUS after
+					 * B-device is disconnected.
+					 */
 	struct delayed_work hnp_polling;/* OTG: HNP polling work */
 	unsigned sg_tablesize;		/* 0 or largest number of sg list entries */
 
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 736203b..8f60c34 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -34,6 +34,7 @@
 #define __LINUX_USB_CH9_H
 
 #include <linux/types.h>	/* __u8 etc */
+#include <asm/byteorder.h>	/* le16_to_cpu */
 
 /*-------------------------------------------------------------------------*/
 
@@ -133,6 +134,12 @@
 #define	TEST_PACKET	4
 #define	TEST_FORCE_EN	5
 
+/* OTG test mode feature bits
+ * See ECN OTG2.0 spec Table 6-8
+ */
+#define TEST_OTG_SRP_REQD	6
+#define TEST_OTG_HNP_REQD	7
+
 /*
  * New Feature Selectors as added by USB 3.0
  * See USB 3.0 spec Table 9-6
@@ -143,12 +150,20 @@
 #define USB_INTRF_FUNC_SUSPEND	0	/* function suspend */
 
 #define USB_INTR_FUNC_SUSPEND_OPT_MASK	0xFF00
+/*
+ * Suspend Options, Table 9-7 USB 3.0 spec
+ */
+#define USB_INTRF_FUNC_SUSPEND_LP	(1 << (8 + 0))
+#define USB_INTRF_FUNC_SUSPEND_RW	(1 << (8 + 1))
 
 #define USB_ENDPOINT_HALT		0	/* IN/OUT will STALL */
 
-#define OTG_STATUS_SELECTOR	0xF000
-#define THOST_REQ_POLL		2000    /* msec */
-#define HOST_REQUEST_FLAG	0
+#define OTG_STATUS_SELECTOR		0xF000
+#define HOST_REQUEST_FLAG		0
+#define THOST_REQ_POLL			1500    /* msec (1000 - 2000) */
+#define OTG_TTST_SUSP			70	/* msec (0 - 100) */
+
+#define OTG_TTST_VBUS_OFF               1
 
 /* Bit array elements as returned by the USB_REQ_GET_STATUS request. */
 #define USB_DEV_STAT_U1_ENABLED		2	/* transition into U1 state */
@@ -574,6 +589,17 @@
 	return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd);
 }
 
+/**
+ * usb_endpoint_maxp - get endpoint's max packet size
+ * @epd: endpoint to be checked
+ *
+ * Returns @epd's max packet
+ */
+static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd)
+{
+	return __le16_to_cpu(epd->wMaxPacketSize);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
@@ -617,8 +643,10 @@
 	__u8  bDescriptorType;
 
 	__u8  bmAttributes;	/* support for HNP, SRP, etc */
+	__le16 bcdOTG;
 } __attribute__ ((packed));
 
+#define USB_DT_OTG_SIZE		5
 /* from usb_otg_descriptor.bmAttributes */
 #define USB_OTG_SRP		(1 << 0)
 #define USB_OTG_HNP		(1 << 1)	/* swap host/device roles */
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 66a29a9..6938a86 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -59,6 +59,10 @@
  * @hs_descriptors: Table of high speed descriptors, using interface and
  *	string identifiers assigned during @bind().  If this pointer is null,
  *	the function will not be available at high speed.
+ * @ss_descriptors: Table of super speed descriptors, using interface and
+ *	string identifiers assigned during @bind(). If this
+ *	pointer is null after initiation, the function will not
+ *	be available at super speed.
  * @config: assigned when @usb_add_function() is called; this is the
  *	configuration with which this function is associated.
  * @bind: Before the gadget can register, all of its functions bind() to the
@@ -77,6 +81,10 @@
  * @setup: Used for interface-specific control requests.
  * @suspend: Notifies functions when the host stops sending USB traffic.
  * @resume: Notifies functions when the host restarts USB traffic.
+ * @get_status: Returns function status as a reply to
+ *	GetStatus() request when the recepient is Interface.
+ * @func_suspend: callback to be called when
+ *	SetFeature(FUNCTION_SUSPEND) is reseived
  *
  * A single USB function uses one or more interfaces, and should in most
  * cases support operation at both full and high speeds.  Each function is
@@ -106,6 +114,7 @@
 	struct usb_gadget_strings	**strings;
 	struct usb_descriptor_header	**descriptors;
 	struct usb_descriptor_header	**hs_descriptors;
+	struct usb_descriptor_header	**ss_descriptors;
 
 	struct usb_configuration	*config;
 
@@ -132,6 +141,10 @@
 	void			(*suspend)(struct usb_function *);
 	void			(*resume)(struct usb_function *);
 
+	/* USB 3.0 additions */
+	int			(*get_status)(struct usb_function *);
+	int			(*func_suspend)(struct usb_function *,
+						u8 suspend_opt);
 	/* private: */
 	/* internals */
 	struct list_head		list;
@@ -145,20 +158,8 @@
 
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
 
-/**
- * ep_choose - select descriptor endpoint at current device speed
- * @g: gadget, connected and running at some speed
- * @hs: descriptor to use for high speed operation
- * @fs: descriptor to use for full or low speed operation
- */
-static inline struct usb_endpoint_descriptor *
-ep_choose(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
-		struct usb_endpoint_descriptor *fs)
-{
-	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
-		return hs;
-	return fs;
-}
+int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
+			struct usb_ep *_ep);
 
 #define	MAX_CONFIG_INTERFACES		16	/* arbitrary; max 255 */
 
@@ -231,6 +232,7 @@
 	struct list_head	list;
 	struct list_head	functions;
 	u8			next_interface_id;
+	unsigned		superspeed:1;
 	unsigned		highspeed:1;
 	unsigned		fullspeed:1;
 	struct usb_function	*interface[MAX_CONFIG_INTERFACES];
@@ -255,6 +257,7 @@
  *	identifiers.
  * @strings: tables of strings, keyed by identifiers assigned during bind()
  *	and language IDs provided in control requests
+ * @max_speed: Highest speed the driver supports.
  * @needs_serial: set to 1 if the gadget needs userspace to provide
  * 	a serial number.  If one is not provided, warning will be printed.
  * @unbind: Reverses bind; called as a side effect of unregistering
@@ -282,6 +285,7 @@
 	const char				*iManufacturer;
 	const struct usb_device_descriptor	*dev;
 	struct usb_gadget_strings		**strings;
+	enum usb_device_speed			max_speed;
 	unsigned		needs_serial:1;
 
 	int			(*unbind)(struct usb_composite_dev *);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 47e8427..0dbc671 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -27,6 +27,7 @@
  *	field, and the usb controller needs one, it is responsible
  *	for mapping and unmapping the buffer.
  * @length: Length of that data
+ * @stream_id: The stream id, when USB3.0 bulk streams are being used
  * @no_interrupt: If true, hints that no completion irq is needed.
  *	Helpful sometimes with deep request queues that are handled
  *	directly by DMA controllers.
@@ -82,6 +83,7 @@
 	unsigned		length;
 	dma_addr_t		dma;
 
+	unsigned		stream_id:16;
 	unsigned		no_interrupt:1;
 	unsigned		zero:1;
 	unsigned		short_not_ok:1;
@@ -132,8 +134,17 @@
  * @maxpacket:The maximum packet size used on this endpoint.  The initial
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
- * @driver_data:for use by the gadget driver.  all other fields are
- *	read-only to gadget drivers.
+ * @max_streams: The maximum number of streams supported
+ *	by this EP (0 - 16, actual number is 2^n)
+ * @mult: multiplier, 'mult' value for SS Isoc EPs
+ * @maxburst: the maximum number of bursts supported by this EP (for usb3)
+ * @driver_data:for use by the gadget driver.
+ * @address: used to identify the endpoint when finding descriptor that
+ *	matches connection speed
+ * @desc: endpoint descriptor.  This pointer is set before the endpoint is
+ *	enabled and remains valid until the endpoint is disabled.
+ * @comp_desc: In case of SuperSpeed support, this is the endpoint companion
+ *	descriptor that is used to configure the endpoint
  *
  * the bus controller driver lists all the general purpose endpoints in
  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
@@ -146,6 +157,12 @@
 	const struct usb_ep_ops	*ops;
 	struct list_head	ep_list;
 	unsigned		maxpacket:16;
+	unsigned		max_streams:16;
+	unsigned		mult:2;
+	unsigned		maxburst:4;
+	u8			address;
+	const struct usb_endpoint_descriptor	*desc;
+	const struct usb_ss_ep_comp_descriptor	*comp_desc;
 };
 
 /*-------------------------------------------------------------------------*/
@@ -154,11 +171,8 @@
  * usb_ep_enable - configure endpoint, making it usable
  * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
  *	drivers discover endpoints through the ep_list of a usb_gadget.
- * @desc:descriptor for desired behavior.  caller guarantees this pointer
- *	remains valid until the endpoint is disabled; the data byte order
- *	is little-endian (usb-standard).
  *
- * when configurations are set, or when interface settings change, the driver
+ * When configurations are set, or when interface settings change, the driver
  * will enable or disable the relevant endpoints.  while it is enabled, an
  * endpoint may be used for i/o until the driver receives a disconnect() from
  * the host or until the endpoint is disabled.
@@ -173,10 +187,9 @@
  *
  * returns zero, or a negative error code.
  */
-static inline int usb_ep_enable(struct usb_ep *ep,
-				const struct usb_endpoint_descriptor *desc)
+static inline int usb_ep_enable(struct usb_ep *ep)
 {
-	return ep->ops->enable(ep, desc);
+	return ep->ops->enable(ep, ep->desc);
 }
 
 /**
@@ -417,7 +430,16 @@
 
 /*-------------------------------------------------------------------------*/
 
+struct usb_dcd_config_params {
+	__u8  bU1devExitLat;	/* U1 Device exit Latency */
+#define USB_DEFAULT_U1_DEV_EXIT_LAT	0x01	/* Less then 1 microsec */
+	__le16 bU2DevExitLat;	/* U2 Device exit Latency */
+#define USB_DEFAULT_U2_DEV_EXIT_LAT	0x1F4	/* Less then 500 microsec */
+};
+
+
 struct usb_gadget;
+struct usb_gadget_driver;
 
 /* the rest of the api to the controller hardware: device operations,
  * which don't involve endpoints (or i/o).
@@ -431,6 +453,16 @@
 	int	(*pullup) (struct usb_gadget *, int is_on);
 	int	(*ioctl)(struct usb_gadget *,
 				unsigned code, unsigned long param);
+	void	(*get_config_params)(struct usb_dcd_config_params *);
+	int	(*udc_start)(struct usb_gadget *,
+			struct usb_gadget_driver *);
+	int	(*udc_stop)(struct usb_gadget *,
+			struct usb_gadget_driver *);
+
+	/* Those two are deprecated */
+	int	(*start)(struct usb_gadget_driver *,
+			int (*bind)(struct usb_gadget *));
+	int	(*stop)(struct usb_gadget_driver *);
 };
 
 /**
@@ -453,6 +485,9 @@
  *	only supports HNP on a different root port.
  * @b_hnp_enable: OTG device feature flag, indicating that the A-Host
  *	enabled HNP support.
+ * @host_request: A flag set by user when wishes to take up host role.
+ * @otg_srp_reqd: OTG test mode feature to initiate SRP after the end of
+ * current session.
  * @name: Identifies the controller hardware type.  Used in diagnostics
  *	and sometimes configuration.
  * @dev: Driver model state for this abstract device.
@@ -488,6 +523,7 @@
 	unsigned			a_hnp_support:1;
 	unsigned			a_alt_hnp_support:1;
 	unsigned			host_request:1;
+	unsigned			otg_srp_reqd:1;
 	const char			*name;
 	struct device			dev;
 };
@@ -523,6 +559,24 @@
 }
 
 /**
+ * gadget_is_superspeed() - return true if the hardware handles
+ * supperspeed
+ * @g: controller that might support supper speed
+ */
+static inline int gadget_is_superspeed(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+	/*
+	 * runtime test would check "g->is_superspeed" ... that might be
+	 * useful to work around hardware bugs, but is mostly pointless
+	 */
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+/**
  * gadget_is_otg - return true iff the hardware is OTG-ready
  * @g: controller that might have a Mini-AB connector
  *
@@ -823,6 +877,9 @@
  */
 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
 
+extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
+extern void usb_del_gadget_udc(struct usb_gadget *gadget);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify dealing with string descriptors */
@@ -860,6 +917,11 @@
 
 /* utility to simplify managing config descriptors */
 
+/* Find and fill the requested descriptor into buffer */
+int
+usb_find_descriptor_fillbuf(void *, unsigned,
+		const struct usb_descriptor_header **, u8);
+
 /* write vector of descriptors into buffer */
 int usb_descriptor_fillbuf(void *, unsigned,
 		const struct usb_descriptor_header **);
@@ -872,12 +934,6 @@
 struct usb_descriptor_header **usb_copy_descriptors(
 		struct usb_descriptor_header **);
 
-/* return copy of endpoint descriptor given original descriptor set */
-struct usb_endpoint_descriptor *usb_find_endpoint(
-	struct usb_descriptor_header **src,
-	struct usb_descriptor_header **copy,
-	struct usb_endpoint_descriptor *match);
-
 /**
  * usb_free_descriptors - free descriptors returned by usb_copy_descriptors()
  * @v: vector of descriptors
@@ -894,6 +950,11 @@
 extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
 			struct usb_endpoint_descriptor *);
 
+
+extern struct usb_ep *usb_ep_autoconfig_ss(struct usb_gadget *,
+			struct usb_endpoint_descriptor *,
+			struct usb_ss_ep_comp_descriptor *);
+
 extern void usb_ep_autoconfig_reset(struct usb_gadget *);
 
 #endif /* __LINUX_USB_GADGET_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 79fb177..f2ad7e1 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -279,6 +279,7 @@
 
 struct msm_usb_host_platform_data {
 	unsigned int power_budget;
+	unsigned int dock_connect_irq;
 };
 
 struct usb_bam_pipe_connect {
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 3e93de7..fb1ca8c 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -30,4 +30,6 @@
    descriptor */
 #define USB_QUIRK_DELAY_INIT		0x00000040
 
+#define USB_QUIRK_OTG_PET		0x00000080
+
 #endif /* __LINUX_USB_QUIRKS_H */
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 867bd8a..6a7f99b 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -342,6 +342,7 @@
 #define MSM_CAM_RESP_MAX               8
 
 #define MSM_CAM_APP_NOTIFY_EVENT  0
+#define MSM_CAM_APP_NOTIFY_ERROR_EVENT  1
 
 /* this one is used to send ctrl/status up to config thread */
 
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 164d3b4..3ca14ff 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -570,7 +570,7 @@
 struct hci_conn *hci_le_conn_add(struct hci_dev *hdev, bdaddr_t *dst,
 							__u8 addr_type);
 int hci_conn_del(struct hci_conn *conn);
-void hci_conn_hash_flush(struct hci_dev *hdev);
+void hci_conn_hash_flush(struct hci_dev *hdev, u8 is_process);
 void hci_conn_check_pending(struct hci_dev *hdev);
 
 struct hci_chan *hci_chan_add(struct hci_dev *hdev);
@@ -751,7 +751,8 @@
 	int (*connect_ind)	(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
 	int (*connect_cfm)	(struct hci_conn *conn, __u8 status);
 	int (*disconn_ind)	(struct hci_conn *conn);
-	int (*disconn_cfm)	(struct hci_conn *conn, __u8 reason);
+	int (*disconn_cfm)	(struct hci_conn *conn, __u8 reason,
+							__u8 is_process);
 	int (*recv_acldata)	(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
 	int (*recv_scodata)	(struct hci_conn *conn, struct sk_buff *skb);
 	int (*security_cfm)	(struct hci_conn *conn, __u8 status, __u8 encrypt);
@@ -808,17 +809,18 @@
 	return reason;
 }
 
-static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
+static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason,
+							__u8 is_process)
 {
 	register struct hci_proto *hp;
 
 	hp = hci_proto[HCI_PROTO_L2CAP];
 	if (hp && hp->disconn_cfm)
-		hp->disconn_cfm(conn, reason);
+		hp->disconn_cfm(conn, reason, is_process);
 
 	hp = hci_proto[HCI_PROTO_SCO];
 	if (hp && hp->disconn_cfm)
-		hp->disconn_cfm(conn, reason);
+		hp->disconn_cfm(conn, reason, is_process);
 
 	if (conn->disconn_cfm_cb)
 		conn->disconn_cfm_cb(conn, reason);
@@ -1049,6 +1051,7 @@
 int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3]);
 int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
 							u16 sub_ver);
+int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8]);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 9e79fb3..3e8de2c 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -355,3 +355,9 @@
 	__u16	manufacturer;
 	__u16	lmp_subver;
 } __packed;
+
+#define MGMT_EV_REMOTE_FEATURES		0x0019
+struct mgmt_ev_remote_features {
+	bdaddr_t bdaddr;
+	uint8_t features[8];
+} __packed;
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index d08f528..0fabc5b 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -15,6 +15,9 @@
 #include <mach/qdsp6v2/apr.h>
 #include <mach/msm_subsystem_map.h>
 #include <sound/apr_audio.h>
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#include <linux/ion.h>
+#endif
 
 #define IN                      0x000
 #define OUT                     0x001
@@ -94,10 +97,15 @@
 struct audio_buffer {
 	dma_addr_t phys;
 	void       *data;
-	struct msm_mapped_buffer *mem_buffer;
 	uint32_t   used;
 	uint32_t   size;/* size of buffer */
 	uint32_t   actual_size; /* actual number of bytes read by DSP */
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	struct ion_handle *handle;
+	struct ion_client *client;
+#else
+	struct msm_mapped_buffer *mem_buffer;
+#endif
 };
 
 struct audio_aio_write_param {
diff --git a/kernel/power/fbearlysuspend.c b/kernel/power/fbearlysuspend.c
index 1513765..4877372 100644
--- a/kernel/power/fbearlysuspend.c
+++ b/kernel/power/fbearlysuspend.c
@@ -19,7 +19,10 @@
 
 #include "power.h"
 
+#define MAX_BUF 100
+
 static wait_queue_head_t fb_state_wq;
+static int display = 1;
 static DEFINE_SPINLOCK(fb_state_lock);
 static enum {
 	FB_STATE_STOPPED_DRAWING,
@@ -71,10 +74,16 @@
 
 	ret = wait_event_interruptible(fb_state_wq,
 				       fb_state != FB_STATE_DRAWING_OK);
-	if (ret && fb_state == FB_STATE_DRAWING_OK)
+	if (ret && fb_state == FB_STATE_DRAWING_OK) {
 		return ret;
-	else
+	} else {
 		s += sprintf(buf, "sleeping");
+		if (display == 1) {
+			display = 0;
+			sysfs_notify(power_kobj, NULL, "wait_for_fb_status");
+		}
+	}
+
 	return s - buf;
 }
 
@@ -96,28 +105,47 @@
 				       fb_state == FB_STATE_DRAWING_OK);
 	if (ret && fb_state != FB_STATE_DRAWING_OK)
 		return ret;
-	else
+	else {
 		s += sprintf(buf, "awake");
-
+		if (display == 0) {
+			display = 1;
+			sysfs_notify(power_kobj, NULL, "wait_for_fb_status");
+		}
+	}
 	return s - buf;
 }
 
-#define power_ro_attr(_name) \
-static struct kobj_attribute _name##_attr = {	\
-	.attr	= {				\
-		.name = __stringify(_name),	\
-		.mode = 0444,			\
-	},					\
-	.show	= _name##_show,			\
-	.store	= NULL,		\
+static ssize_t wait_for_fb_status_show(struct kobject *kobj,
+				       struct kobj_attribute *attr, char *buf)
+{
+	int ret = 0;
+
+	if (display == 1)
+		ret = snprintf(buf, strnlen("on", MAX_BUF) + 1, "on");
+	else
+		ret = snprintf(buf, strnlen("off", MAX_BUF) + 1, "off");
+
+	return ret;
 }
 
+#define power_ro_attr(_name)				\
+	static struct kobj_attribute _name##_attr = {	\
+		.attr	= {				\
+			.name = __stringify(_name),	\
+			.mode = 0444,			\
+		},					\
+		.show	= _name##_show,			\
+		.store	= NULL,				\
+	}
+
 power_ro_attr(wait_for_fb_sleep);
 power_ro_attr(wait_for_fb_wake);
+power_ro_attr(wait_for_fb_status);
 
 static struct attribute *g[] = {
 	&wait_for_fb_sleep_attr.attr,
 	&wait_for_fb_wake_attr.attr,
+	&wait_for_fb_status_attr.attr,
 	NULL,
 };
 
diff --git a/kernel/power/main.c b/kernel/power/main.c
index ff29679..6aeabf9 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -15,6 +15,8 @@
 
 #include "power.h"
 
+#define MAX_BUF 100
+
 DEFINE_MUTEX(pm_mutex);
 
 #ifdef CONFIG_PM_SLEEP
@@ -23,6 +25,10 @@
 
 static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
 
+static struct hrtimer in_ev_timer;
+static int input_processed;
+static ktime_t touch_evt_timer_val;
+
 int register_pm_notifier(struct notifier_block *nb)
 {
 	return blocking_notifier_chain_register(&pm_chain_head, nb);
@@ -67,6 +73,72 @@
 
 power_attr(pm_async);
 
+static ssize_t
+touch_event_show(struct kobject *kobj,
+		 struct kobj_attribute *attr, char *buf)
+{
+	if (input_processed == 0)
+		return snprintf(buf, strnlen("touch_event", MAX_BUF) + 1,
+				"touch_event");
+	else
+		return snprintf(buf, strnlen("null", MAX_BUF) + 1,
+				"null");
+}
+
+static ssize_t
+touch_event_store(struct kobject *kobj,
+		  struct kobj_attribute *attr,
+		  const char *buf, size_t n)
+{
+
+	hrtimer_cancel(&in_ev_timer);
+	input_processed = 0;
+
+	/* set a timer to notify the userspace to stop processing
+	 * touch event
+	 */
+	hrtimer_start(&in_ev_timer, touch_evt_timer_val, HRTIMER_MODE_REL);
+
+	/* wakeup the userspace poll */
+	sysfs_notify(kobj, NULL, "touch_event");
+
+	return n;
+}
+
+power_attr(touch_event);
+
+static ssize_t
+touch_event_timer_show(struct kobject *kobj,
+		 struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, MAX_BUF, "%lld", touch_evt_timer_val.tv64);
+}
+
+static ssize_t
+touch_event_timer_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val))
+		return -EINVAL;
+
+	touch_evt_timer_val = ktime_set(0, val*1000);
+
+	return n;
+}
+
+power_attr(touch_event_timer);
+
+static enum hrtimer_restart input_event_stop(struct hrtimer *hrtimer)
+{
+	/* wakeup the userspace poll */
+	input_processed = 1;
+	sysfs_notify(power_kobj, NULL, "touch_event");
+	return HRTIMER_NORESTART;
+}
+
 #ifdef CONFIG_PM_DEBUG
 int pm_test_level = TEST_NONE;
 
@@ -313,7 +385,9 @@
 power_attr(wake_unlock);
 #endif
 
-static struct attribute * g[] = {
+static struct attribute *g[] = {
+	&touch_event_attr.attr,
+	&touch_event_timer_attr.attr,
 	&state_attr.attr,
 #ifdef CONFIG_PM_TRACE
 	&pm_trace_attr.attr,
@@ -358,6 +432,11 @@
 		return error;
 	hibernate_image_size_init();
 	hibernate_reserved_size_init();
+
+	touch_evt_timer_val = ktime_set(2, 0);
+	hrtimer_init(&in_ev_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	in_ev_timer.function = &input_event_stop;
+
 	power_kobj = kobject_create_and_add("power", NULL);
 	if (!power_kobj)
 		return -ENOMEM;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 899c538..ca33664 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -728,7 +728,7 @@
 {
 	BT_DBG("conn %p", conn);
 
-	hci_proto_disconn_cfm(conn, reason);
+	hci_proto_disconn_cfm(conn, reason, 0);
 }
 EXPORT_SYMBOL(hci_disconnect);
 
@@ -1027,7 +1027,7 @@
 EXPORT_SYMBOL(hci_chan_modify);
 
 /* Drop all connection on the device */
-void hci_conn_hash_flush(struct hci_dev *hdev)
+void hci_conn_hash_flush(struct hci_dev *hdev, u8 is_process)
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
 	struct list_head *p;
@@ -1043,7 +1043,7 @@
 
 		c->state = BT_CLOSED;
 
-		hci_proto_disconn_cfm(c, 0x16);
+		hci_proto_disconn_cfm(c, 0x16, is_process);
 		hci_conn_del(c);
 	}
 }
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 4c2bd37..c0eb50c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -626,7 +626,7 @@
 	return ret;
 }
 
-static int hci_dev_do_close(struct hci_dev *hdev)
+static int hci_dev_do_close(struct hci_dev *hdev, u8 is_process)
 {
 	unsigned long keepflags = 0;
 
@@ -647,7 +647,7 @@
 
 	hci_dev_lock_bh(hdev);
 	inquiry_cache_flush(hdev);
-	hci_conn_hash_flush(hdev);
+	hci_conn_hash_flush(hdev, is_process);
 	hci_dev_unlock_bh(hdev);
 
 	hci_notify(hdev, HCI_DEV_DOWN);
@@ -714,7 +714,7 @@
 	hdev = hci_dev_get(dev);
 	if (!hdev)
 		return -ENODEV;
-	err = hci_dev_do_close(hdev);
+	err = hci_dev_do_close(hdev, 1);
 	hci_dev_put(hdev);
 	return err;
 }
@@ -740,7 +740,7 @@
 
 	hci_dev_lock_bh(hdev);
 	inquiry_cache_flush(hdev);
-	hci_conn_hash_flush(hdev);
+	hci_conn_hash_flush(hdev, 0);
 	hci_dev_unlock_bh(hdev);
 
 	if (hdev->flush)
@@ -953,7 +953,7 @@
 	if (!blocked)
 		return 0;
 
-	hci_dev_do_close(hdev);
+	hci_dev_do_close(hdev, 0);
 
 	return 0;
 }
@@ -1563,7 +1563,7 @@
 	list_del(&hdev->list);
 	write_unlock_bh(&hci_dev_list_lock);
 
-	hci_dev_do_close(hdev);
+	hci_dev_do_close(hdev, 0);
 
 	for (i = 0; i < NUM_REASSEMBLY; i++)
 		kfree_skb(hdev->reassembly[i]);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index fec6f32..154dc58 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1106,9 +1106,25 @@
 
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
 	if (conn) {
-		if (status && conn->state == BT_CONFIG) {
-			hci_proto_connect_cfm(conn, status);
-			hci_conn_put(conn);
+		if (status) {
+			mgmt_auth_failed(hdev->id, &conn->dst, status);
+			clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+
+			if (conn->state == BT_CONFIG) {
+				conn->state = BT_CONNECTED;
+				hci_proto_connect_cfm(conn, status);
+				hci_conn_put(conn);
+			} else {
+				hci_auth_cfm(conn, status);
+				hci_conn_hold(conn);
+				conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+				hci_conn_put(conn);
+			}
+
+			if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+				hci_encrypt_cfm(conn, status, 0x00);
+			}
 		}
 		conn->auth_initiator = 1;
 	}
@@ -1748,7 +1764,7 @@
 	if (conn->type == LE_LINK)
 		del_timer(&conn->smp_timer);
 
-	hci_proto_disconn_cfm(conn, ev->reason);
+	hci_proto_disconn_cfm(conn, ev->reason, 0);
 	hci_conn_del(conn);
 
 unlock:
@@ -1924,8 +1940,10 @@
 	if (!conn)
 		goto unlock;
 
-	if (!ev->status)
+	if (!ev->status) {
 		memcpy(conn->features, ev->features, 8);
+		mgmt_remote_features(hdev->id, &conn->dst, ev->features);
+	}
 
 	if (conn->state != BT_CONFIG)
 		goto unlock;
@@ -3289,7 +3307,7 @@
 	if (conn) {
 		conn->state = BT_CLOSED;
 
-		hci_proto_disconn_cfm(conn, ev->reason);
+		hci_proto_disconn_cfm(conn, ev->reason, 0);
 		hci_conn_del(conn);
 	}
 
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9662795..6a95c79 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -89,7 +89,7 @@
 static int l2cap_create_cfm(struct hci_chan *chan, u8 status);
 static int l2cap_deaggregate(struct hci_chan *chan, struct l2cap_pinfo *pi);
 static void l2cap_chan_ready(struct sock *sk);
-static void l2cap_conn_del(struct hci_conn *hcon, int err);
+static void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process);
 static u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l);
 static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to);
 
@@ -569,7 +569,7 @@
 		struct hci_chan *ampchan = l2cap_pi(sk)->ampchan;
 		l2cap_pi(sk)->ampchan = NULL;
 		if (!hci_chan_put(ampchan))
-			l2cap_deaggregate(l2cap_pi(sk)->ampchan, l2cap_pi(sk));
+			l2cap_deaggregate(ampchan, l2cap_pi(sk));
 	}
 
 	sk->sk_state = BT_CLOSED;
@@ -1160,7 +1160,7 @@
 	return conn;
 }
 
-static void l2cap_conn_del(struct hci_conn *hcon, int err)
+static void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process)
 {
 	struct l2cap_conn *conn = hcon->l2cap_data;
 	struct sock *sk;
@@ -1181,9 +1181,15 @@
 		BT_DBG("ampcon %p", l2cap_pi(sk)->ampcon);
 		if ((conn->hcon == hcon) || (l2cap_pi(sk)->ampcon == hcon)) {
 			next = l2cap_pi(sk)->next_c;
-			bh_lock_sock(sk);
+			if (is_process)
+				lock_sock(sk);
+			else
+				bh_lock_sock(sk);
 			l2cap_chan_del(sk, err);
-			bh_unlock_sock(sk);
+			if (is_process)
+				release_sock(sk);
+			else
+				bh_unlock_sock(sk);
 			l2cap_sock_kill(sk);
 			sk = next;
 		} else
@@ -7332,7 +7338,7 @@
 
 	case L2CAP_CID_SMP:
 		if (smp_sig_channel(conn, skb))
-			l2cap_conn_del(conn->hcon, EACCES);
+			l2cap_conn_del(conn->hcon, EACCES, 0);
 		break;
 
 	default:
@@ -7407,7 +7413,7 @@
 		if (conn)
 			l2cap_conn_ready(conn);
 	} else
-		l2cap_conn_del(hcon, bt_err(status));
+		l2cap_conn_del(hcon, bt_err(status), 0);
 
 	return 0;
 }
@@ -7424,14 +7430,14 @@
 	return conn->disc_reason;
 }
 
-static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
+static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason, u8 is_process)
 {
 	BT_DBG("hcon %p reason %d", hcon, reason);
 
 	if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
 		return -EINVAL;
 
-	l2cap_conn_del(hcon, bt_err(reason));
+	l2cap_conn_del(hcon, bt_err(reason), is_process);
 
 	return 0;
 }
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 910ef77..64d478b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2672,8 +2672,11 @@
 	if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
 			conn->auth_initiator && rem_cap == 0x03)
 		ev.auto_confirm = 1;
-	else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
+	else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
+		if (!loc_mitm && !rem_mitm)
+			value = 0;
 		goto no_auto_confirm;
+	}
 
 
 	if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
@@ -2929,3 +2932,16 @@
 
 	return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
 }
+
+int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
+{
+	struct mgmt_ev_remote_features ev;
+
+	memset(&ev, 0, sizeof(ev));
+
+	bacpy(&ev.bdaddr, bdaddr);
+	memcpy(ev.features, features, sizeof(ev.features));
+
+	return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
+									NULL);
+}
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 99c4559..f8c3bba 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -62,7 +62,7 @@
 static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
 static void sco_chan_del(struct sock *sk, int err);
 
-static int  sco_conn_del(struct hci_conn *conn, int err);
+static int  sco_conn_del(struct hci_conn *conn, int err, u8 is_process);
 
 static void sco_sock_close(struct sock *sk);
 static void sco_sock_kill(struct sock *sk);
@@ -135,7 +135,7 @@
 	return sk;
 }
 
-static int sco_conn_del(struct hci_conn *hcon, int err)
+static int sco_conn_del(struct hci_conn *hcon, int err, u8 is_process)
 {
 	struct sco_conn *conn = hcon->sco_data;
 	struct sock *sk;
@@ -148,10 +148,16 @@
 	/* Kill socket */
 	sk = sco_chan_get(conn);
 	if (sk) {
-		bh_lock_sock(sk);
+		if (is_process)
+			lock_sock(sk);
+		else
+			bh_lock_sock(sk);
 		sco_sock_clear_timer(sk);
 		sco_chan_del(sk, err);
-		bh_unlock_sock(sk);
+		if (is_process)
+			release_sock(sk);
+		else
+			bh_unlock_sock(sk);
 		sco_sock_kill(sk);
 	}
 
@@ -952,19 +958,19 @@
 		if (conn)
 			sco_conn_ready(conn);
 	} else
-		sco_conn_del(hcon, bt_err(status));
+		sco_conn_del(hcon, bt_err(status), 0);
 
 	return 0;
 }
 
-static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
+static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason, __u8 is_process)
 {
 	BT_DBG("hcon %p reason %d", hcon, reason);
 
 	if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
 		return -EINVAL;
 
-	sco_conn_del(hcon, bt_err(reason));
+	sco_conn_del(hcon, bt_err(reason), is_process);
 
 	return 0;
 }
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 0d41625..4396b07 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -8,9 +8,10 @@
 use strict;
 
 use constant BEFORE_SHORTTEXT => 0;
-use constant IN_SHORTTEXT => 1;
-use constant AFTER_SHORTTEXT => 2;
-use constant CHECK_NEXT_SHORTTEXT => 3;
+use constant IN_SHORTTEXT_BLANKLINE => 1;
+use constant IN_SHORTTEXT => 2;
+use constant AFTER_SHORTTEXT => 3;
+use constant CHECK_NEXT_SHORTTEXT => 4;
 use constant SHORTTEXT_LIMIT => 75;
 
 my $P = $0;
@@ -1233,6 +1234,7 @@
 
 	my $shorttext = BEFORE_SHORTTEXT;
 	my $shorttext_exspc = 0;
+	my $commit_text_present = 0;
 
 	sanitise_line_reset();
 	cleanup_continuation_headers();
@@ -1416,8 +1418,24 @@
 		my $hereprev = "$here\n$prevrawline\n$rawline\n";
 
 		if ($shorttext != AFTER_SHORTTEXT) {
+			if ($shorttext == IN_SHORTTEXT_BLANKLINE && $line=~/\S/) {
+				# the subject line was just processed,
+				# a blank line must be next
+				WARN("non-blank line after summary line\n" . $herecurr);
+				$shorttext = IN_SHORTTEXT;
+				# this non-blank line may or may not be commit text -
+				# a warning has been generated so assume it is commit
+				# text and move on
+				$commit_text_present = 1;
+				# fall through and treat this line as IN_SHORTTEXT
+			}
 			if ($shorttext == IN_SHORTTEXT) {
 				if ($line=~/^---/ || $line=~/^diff.*/) {
+					if ($commit_text_present == 0) {
+						WARN("please add commit text explaining " .
+						     "*why* the change is needed\n" .
+						     $herecurr);
+					}
 					$shorttext = AFTER_SHORTTEXT;
 				} elsif (length($line) > (SHORTTEXT_LIMIT +
 							  $shorttext_exspc)
@@ -1427,7 +1445,25 @@
 					WARN("commit text line over " .
 					     SHORTTEXT_LIMIT .
 					     " characters\n" . $herecurr);
+				} elsif ($line=~/^\s*change-id:/i ||
+					 $line=~/^\s*signed-off-by:/i ||
+					 $line=~/^\s*crs-fixed:/i ||
+					 $line=~/^\s*acked-by:/i) {
+					# this is a tag, there must be commit
+					# text by now
+					if ($commit_text_present == 0) {
+						WARN("please add commit text explaining " .
+						     "*why* the change is needed\n" .
+						     $herecurr);
+						# prevent duplicate warnings
+						$commit_text_present = 1;
+					}
+				} elsif ($line=~/\S/) {
+					$commit_text_present = 1;
 				}
+			} elsif ($shorttext == IN_SHORTTEXT_BLANKLINE) {
+				# case of non-blank line in this state handled above
+				$shorttext = IN_SHORTTEXT;
 			} elsif ($shorttext == CHECK_NEXT_SHORTTEXT) {
 # The Subject line doesn't have to be the last header in the patch.
 # Avoid moving to the IN_SHORTTEXT state until clear of all headers.
@@ -1435,16 +1471,25 @@
 # text which looks like a header is definitely a header.
 				if ($line!~/^[\x21-\x39\x3b-\x7e]+:/) {
 					$shorttext = IN_SHORTTEXT;
-# Check for Subject line followed by a blank line.
+					# Check for Subject line followed by a blank line.
 					if (length($line) != 0) {
 						WARN("non-blank line after " .
 						     "summary line\n" .
 						     $sublinenr . $here .
 						     "\n" . $subjectline .
 						     "\n" . $line . "\n");
+						# this non-blank line may or may not
+						# be commit text - a warning has been
+						# generated so assume it is commit
+						# text and move on
+						$commit_text_present = 1;
 					}
 				}
+			# The next two cases are BEFORE_SHORTTEXT.
 			} elsif ($line=~/^Subject: \[[^\]]*\] (.*)/) {
+				# This is the subject line. Go to
+				# CHECK_NEXT_SHORTTEXT to wait for the commit
+				# text to show up.
 				$shorttext = CHECK_NEXT_SHORTTEXT;
 				$subjectline = $line;
 				$sublinenr = "#$linenr & ";
@@ -1455,7 +1500,10 @@
 					     " characters\n" . $herecurr);
 				}
 			} elsif ($line=~/^    (.*)/) {
-				$shorttext = IN_SHORTTEXT;
+				# Indented format, this must be the summary
+				# line (i.e. git show). There will be no more
+				# headers so we are now in the shorttext.
+				$shorttext = IN_SHORTTEXT_BLANKLINE;
 				$shorttext_exspc = 4;
 				if (length($1) > SHORTTEXT_LIMIT) {
 					WARN("summary line over " .
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 4d40384..2c52866 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -55,16 +55,17 @@
 				echo "+"
 				return
 			fi
-			# If we are past a tagged commit (like
-			# "v2.6.30-rc5-302-g72357d5"), we pretty print it.
-			if atag="`git describe 2>/dev/null`"; then
-				echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
-
-			# If we don't have a tag at all we print -g{commitish}.
-			else
-				printf '%s%s' -g $head
-			fi
 		fi
+		# If we are past a tagged commit (like
+		# "v2.6.30-rc5-302-g72357d5"), we pretty print it but strip
+		# off the v2.6.30-rc5 part because that's in the Makefile.
+		if atag="`git describe 2>/dev/null`"; then
+			atag="-${atag/v$KERNELVERSION-/}"
+		# If we don't have a tag at all we print -g{commitish}.
+		else
+			atag="-g$head"
+		fi
+		printf '%s' "$atag"
 
 		# Is this git on svn?
 		if git config --get svn-remote.svn.url >/dev/null; then
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 1d93d7a..65fe16d 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -30,6 +30,7 @@
 #include <sound/tlv.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
 #include "wcd9304.h"
 
 #define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
@@ -1888,6 +1889,10 @@
 static int sitar_startup(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
+	if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
+			(wcd9xxx->dev->parent != NULL))
+		pm_runtime_get_sync(wcd9xxx->dev->parent);
 	pr_err("%s(): substream = %s  stream = %d\n" , __func__,
 		substream->name, substream->stream);
 
@@ -1897,6 +1902,12 @@
 static void sitar_shutdown(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
+	struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
+	if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
+			(wcd9xxx->dev->parent != NULL)) {
+		pm_runtime_mark_last_busy(wcd9xxx->dev->parent);
+		pm_runtime_put(wcd9xxx->dev->parent);
+	}
 	pr_err("%s(): substream = %s  stream = %d\n" , __func__,
 		substream->name, substream->stream);
 }
@@ -2539,26 +2550,6 @@
 	return 0;
 }
 
-
-static void sitar_lock_sleep(struct sitar_priv *sitar)
-{
-	int ret;
-	while (!(ret = wait_event_timeout(sitar->pm_wq,
-					 atomic_inc_not_zero(&sitar->pm_cnt),
-					 2 * HZ))) {
-		pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
-			__func__, ret, atomic_read(&sitar->pm_cnt));
-		WARN_ON_ONCE(1);
-	}
-}
-
-static void sitar_unlock_sleep(struct sitar_priv *sitar)
-{
-	atomic_dec(&sitar->pm_cnt);
-	wake_up(&sitar->pm_wq);
-}
-
-
 static void btn0_lpress_fn(struct work_struct *work)
 {
 	struct delayed_work *delayed_work;
@@ -2581,7 +2572,6 @@
 		pr_err("%s: Bad sitar private data\n", __func__);
 	}
 
-	sitar_unlock_sleep(sitar);
 }
 
 int sitar_hs_detect(struct snd_soc_codec *codec,
@@ -2628,10 +2618,10 @@
 	struct sitar_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
 	short bias_value;
+	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
 
 	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
 	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
-	sitar_lock_sleep(priv);
 
 	bias_value = sitar_codec_read_dce_result(codec);
 	pr_err("%s: button press interrupt, bias value(DCE Read)=%d\n",
@@ -2648,10 +2638,11 @@
 
 	msleep(100);
 
+	wcd9xxx_lock_sleep(core);
 	if (schedule_delayed_work(&priv->btn0_dwork,
 				 msecs_to_jiffies(400)) == 0) {
 		WARN(1, "Button pressed twice without release event\n");
-		sitar_unlock_sleep(priv);
+		wcd9xxx_unlock_sleep(core);
 	}
 
 	return IRQ_HANDLED;
@@ -2662,10 +2653,10 @@
 	struct sitar_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
 	int ret, mic_voltage;
+	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
 
 	pr_err("%s\n", __func__);
 	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
-	sitar_lock_sleep(priv);
 
 	mic_voltage = sitar_codec_read_dce_result(codec);
 	pr_err("%s: Microphone Voltage on release(DCE Read) = %d\n",
@@ -2687,7 +2678,7 @@
 		} else {
 			/* if scheduled btn0_dwork is canceled from here,
 			* we have to unlock from here instead btn0_work */
-			sitar_unlock_sleep(priv);
+			wcd9xxx_unlock_sleep(core);
 			mic_voltage =
 				sitar_codec_measure_micbias_voltage(codec, 0);
 			pr_err("%s: Mic Voltage on release(new STA) = %d\n",
@@ -2716,7 +2707,6 @@
 	}
 
 	sitar_codec_start_hs_polling(codec);
-	sitar_unlock_sleep(priv);
 	return IRQ_HANDLED;
 }
 
@@ -2860,7 +2850,6 @@
 
 	pr_err("%s\n", __func__);
 	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
-	sitar_lock_sleep(priv);
 
 	is_removal = snd_soc_read(codec, SITAR_A_CDC_MBHC_INT_CTL) & 0x02;
 	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
@@ -2930,7 +2919,6 @@
 		}
 		sitar_codec_shutdown_hs_removal_detect(codec);
 		sitar_codec_enable_hs_detect(codec, 1);
-		sitar_unlock_sleep(priv);
 		return IRQ_HANDLED;
 	}
 
@@ -2988,7 +2976,6 @@
 		sitar_sync_hph_state(priv);
 	}
 
-	sitar_unlock_sleep(priv);
 	return IRQ_HANDLED;
 }
 
@@ -3001,7 +2988,6 @@
 	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
 	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
 	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
-	sitar_lock_sleep(priv);
 
 	usleep_range(priv->calibration->shutdown_plug_removal,
 		priv->calibration->shutdown_plug_removal);
@@ -3031,7 +3017,6 @@
 		sitar_codec_enable_hs_detect(codec, 1);
 	}
 
-	sitar_unlock_sleep(priv);
 	return IRQ_HANDLED;
 }
 
@@ -3045,7 +3030,6 @@
 	int i, j;
 	u8 val;
 
-	sitar_lock_sleep(priv);
 
 	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
 		slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
@@ -3064,7 +3048,6 @@
 			SITAR_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
 	}
 
-	sitar_unlock_sleep(priv);
 	return IRQ_HANDLED;
 }
 
@@ -3486,53 +3469,14 @@
 #ifdef CONFIG_PM
 static int sitar_suspend(struct device *dev)
 {
-	int ret = 0, cnt;
-	struct platform_device *pdev = to_platform_device(dev);
-	struct sitar_priv *sitar = platform_get_drvdata(pdev);
-
-	cnt = atomic_read(&sitar->pm_cnt);
-	if (cnt > 0) {
-		if (wait_event_timeout(sitar->pm_wq,
-					(atomic_cmpxchg(&sitar->pm_cnt, 1, 0)
-						== 1), 5 * HZ)) {
-			dev_dbg(dev, "system suspend pm_cnt %d\n",
-				atomic_read(&sitar->pm_cnt));
-		} else {
-			dev_err(dev, "%s timed out pm_cnt = %d\n",
-				__func__, atomic_read(&sitar->pm_cnt));
-			WARN_ON_ONCE(1);
-			ret = -EBUSY;
-		}
-	} else if (cnt == 0)
-		dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
-			atomic_read(&sitar->pm_cnt));
-	else {
-		WARN(1, "unexpected pm_cnt %d\n", cnt);
-		ret = -EFAULT;
-	}
-
-	return ret;
+	dev_dbg(dev, "%s: system suspend\n", __func__);
+	return 0;
 }
 
 static int sitar_resume(struct device *dev)
 {
-	int ret = 0, cnt;
-	struct platform_device *pdev = to_platform_device(dev);
-	struct sitar_priv *sitar = platform_get_drvdata(pdev);
-
-	cnt = atomic_cmpxchg(&sitar->pm_cnt, 0, 1);
-	if (cnt == 0) {
-		dev_dbg(dev, "system resume, pm_cnt %d\n",
-			atomic_read(&sitar->pm_cnt));
-		wake_up_all(&sitar->pm_wq);
-	} else if (cnt > 0)
-		dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
-	else {
-		WARN(1, "unexpected pm_cnt %d\n", cnt);
-		ret = -EFAULT;
-	}
-
-	return ret;
+	dev_dbg(dev, "%s: system resume\n", __func__);
+	return 0;
 }
 
 static const struct dev_pm_ops sitar_pm_ops = {
diff --git a/sound/soc/codecs/wcd9310-tables.c b/sound/soc/codecs/wcd9310-tables.c
index e0ad541..2cba59d 100644
--- a/sound/soc/codecs/wcd9310-tables.c
+++ b/sound/soc/codecs/wcd9310-tables.c
@@ -451,6 +451,22 @@
 	[TABLA_A_CDC_DEBUG_B4_CTL] = 1,
 	[TABLA_A_CDC_DEBUG_B5_CTL] = 1,
 	[TABLA_A_CDC_DEBUG_B6_CTL] = 1,
+	[TABLA_A_CDC_COMP1_B1_CTL] = 1,
+	[TABLA_A_CDC_COMP1_B2_CTL] = 1,
+	[TABLA_A_CDC_COMP1_B3_CTL] = 1,
+	[TABLA_A_CDC_COMP1_B4_CTL] = 1,
+	[TABLA_A_CDC_COMP1_B5_CTL] = 1,
+	[TABLA_A_CDC_COMP1_B6_CTL] = 1,
+	[TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS] = 1,
+	[TABLA_A_CDC_COMP1_FS_CFG] = 1,
+	[TABLA_A_CDC_COMP2_B1_CTL] = 1,
+	[TABLA_A_CDC_COMP2_B2_CTL] = 1,
+	[TABLA_A_CDC_COMP2_B3_CTL] = 1,
+	[TABLA_A_CDC_COMP2_B4_CTL] = 1,
+	[TABLA_A_CDC_COMP2_B5_CTL] = 1,
+	[TABLA_A_CDC_COMP2_B6_CTL] = 1,
+	[TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS] = 1,
+	[TABLA_A_CDC_COMP2_FS_CFG] = 1,
 	[TABLA_A_CDC_CONN_RX1_B1_CTL] = 1,
 	[TABLA_A_CDC_CONN_RX1_B2_CTL] = 1,
 	[TABLA_A_CDC_CONN_RX1_B3_CTL] = 1,
@@ -993,6 +1009,24 @@
 	[TABLA_A_CDC_DEBUG_B4_CTL] = TABLA_A_CDC_DEBUG_B4_CTL__POR,
 	[TABLA_A_CDC_DEBUG_B5_CTL] = TABLA_A_CDC_DEBUG_B5_CTL__POR,
 	[TABLA_A_CDC_DEBUG_B6_CTL] = TABLA_A_CDC_DEBUG_B6_CTL__POR,
+	[TABLA_A_CDC_COMP1_B1_CTL] = TABLA_A_CDC_COMP1_B1_CTL__POR,
+	[TABLA_A_CDC_COMP1_B2_CTL] = TABLA_A_CDC_COMP1_B2_CTL__POR,
+	[TABLA_A_CDC_COMP1_B3_CTL] = TABLA_A_CDC_COMP1_B3_CTL__POR,
+	[TABLA_A_CDC_COMP1_B4_CTL] = TABLA_A_CDC_COMP1_B4_CTL__POR,
+	[TABLA_A_CDC_COMP1_B5_CTL] = TABLA_A_CDC_COMP1_B5_CTL__POR,
+	[TABLA_A_CDC_COMP1_B6_CTL] = TABLA_A_CDC_COMP1_B6_CTL__POR,
+	[TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS] =
+		TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
+	[TABLA_A_CDC_COMP1_FS_CFG] = TABLA_A_CDC_COMP1_FS_CFG__POR,
+	[TABLA_A_CDC_COMP2_B1_CTL] = TABLA_A_CDC_COMP2_B1_CTL__POR,
+	[TABLA_A_CDC_COMP2_B2_CTL] = TABLA_A_CDC_COMP2_B2_CTL__POR,
+	[TABLA_A_CDC_COMP2_B3_CTL] = TABLA_A_CDC_COMP2_B3_CTL__POR,
+	[TABLA_A_CDC_COMP2_B4_CTL] = TABLA_A_CDC_COMP2_B4_CTL__POR,
+	[TABLA_A_CDC_COMP2_B5_CTL] = TABLA_A_CDC_COMP2_B5_CTL__POR,
+	[TABLA_A_CDC_COMP2_B6_CTL] = TABLA_A_CDC_COMP2_B6_CTL__POR,
+	[TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS] =
+		TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
+	[TABLA_A_CDC_COMP2_FS_CFG] = TABLA_A_CDC_COMP2_FS_CFG__POR,
 	[TABLA_A_CDC_CONN_RX1_B1_CTL] = TABLA_A_CDC_CONN_RX1_B1_CTL__POR,
 	[TABLA_A_CDC_CONN_RX1_B2_CTL] = TABLA_A_CDC_CONN_RX1_B2_CTL__POR,
 	[TABLA_A_CDC_CONN_RX1_B3_CTL] = TABLA_A_CDC_CONN_RX1_B3_CTL__POR,
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index a5427ed..0ae9680 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -29,6 +29,7 @@
 #include <sound/tlv.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
 #include "wcd9310.h"
 
 #define WCD9310_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
@@ -52,6 +53,7 @@
 #define AIF1_CAP 2
 #define AIF2_PB 3
 #define NUM_CODEC_DAIS 3
+#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
 
 struct tabla_codec_dai_data {
 	u32 rate;
@@ -102,6 +104,20 @@
 	BAND_MAX,
 };
 
+enum {
+	COMPANDER_1 = 0,
+	COMPANDER_2,
+	COMPANDER_MAX,
+};
+
+enum {
+	COMPANDER_FS_8KHZ = 0,
+	COMPANDER_FS_16KHZ,
+	COMPANDER_FS_32KHZ,
+	COMPANDER_FS_48KHZ,
+	COMPANDER_FS_MAX,
+};
+
 /* Flags to track of PA and DAC state.
  * PA and DAC should be tracked separately as AUXPGA loopback requires
  * only PA to be turned on without DAC being on. */
@@ -112,6 +128,13 @@
 	TABLA_HPHR_DAC_OFF_ACK
 };
 
+
+struct comp_sample_dependent_params {
+	u32 peak_det_timeout;
+	u32 rms_meter_div_fact;
+	u32 rms_meter_resamp_fact;
+};
+
 /* Data used by MBHC */
 struct mbhc_internal_cal_data {
 	u16 dce_z;
@@ -209,12 +232,56 @@
 
 	/* num of slim ports required */
 	struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
+
+	/*compander*/
+	int comp_enabled[COMPANDER_MAX];
+	u32 comp_fs[COMPANDER_MAX];
 };
 
 #ifdef CONFIG_DEBUG_FS
 struct tabla_priv *debug_tabla_priv;
 #endif
 
+static const u32 comp_shift[] = {
+	0,
+	2,
+};
+
+static const int comp_rx_path[] = {
+	COMPANDER_1,
+	COMPANDER_1,
+	COMPANDER_2,
+	COMPANDER_2,
+	COMPANDER_2,
+	COMPANDER_2,
+	COMPANDER_MAX,
+};
+
+static const struct comp_sample_dependent_params comp_samp_params[] = {
+	{
+		.peak_det_timeout = 0x2,
+		.rms_meter_div_fact = 0x8 << 4,
+		.rms_meter_resamp_fact = 0x21,
+	},
+	{
+		.peak_det_timeout = 0x3,
+		.rms_meter_div_fact = 0x9 << 4,
+		.rms_meter_resamp_fact = 0x28,
+	},
+
+	{
+		.peak_det_timeout = 0x5,
+		.rms_meter_div_fact = 0xB << 4,
+		.rms_meter_resamp_fact = 0x28,
+	},
+
+	{
+		.peak_det_timeout = 0x5,
+		.rms_meter_div_fact = 0xB << 4,
+		.rms_meter_resamp_fact = 0x28,
+	},
+};
+
 static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
@@ -478,6 +545,192 @@
 	return 0;
 }
 
+static int tabla_compander_gain_offset(
+	struct snd_soc_codec *codec, u32 enable,
+	unsigned int reg, int mask,	int event)
+{
+	int pa_mode = snd_soc_read(codec, reg) & mask;
+	int gain_offset = 0;
+	/*  if PMU && enable is 1-> offset is 3
+	 *  if PMU && enable is 0-> offset is 0
+	 *  if PMD && pa_mode is PA -> offset is 0: PMU compander is off
+	 *  if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
+	 */
+
+	if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
+		gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
+	if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
+		gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
+	return gain_offset;
+}
+
+
+static int tabla_config_gain_compander(
+				struct snd_soc_codec *codec,
+				u32 compander, u32 enable, int event)
+{
+	int value = 0;
+	int mask = 1 << 4;
+	int gain = 0;
+	int gain_offset;
+	if (compander >= COMPANDER_MAX) {
+		pr_err("%s: Error, invalid compander channel\n", __func__);
+		return -EINVAL;
+	}
+
+	if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
+		value = 1 << 4;
+
+	if (compander == COMPANDER_1) {
+		gain_offset = tabla_compander_gain_offset(codec, enable,
+				TABLA_A_RX_HPH_L_GAIN, mask, event);
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
+		gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
+		snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
+				0xFF, gain - gain_offset);
+		gain_offset = tabla_compander_gain_offset(codec, enable,
+				TABLA_A_RX_HPH_R_GAIN, mask, event);
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
+		gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
+		snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
+				0xFF, gain - gain_offset);
+	} else if (compander == COMPANDER_2) {
+		gain_offset = tabla_compander_gain_offset(codec, enable,
+				TABLA_A_RX_LINE_1_GAIN, mask, event);
+		snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
+		gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
+		snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
+				0xFF, gain - gain_offset);
+		gain_offset = tabla_compander_gain_offset(codec, enable,
+				TABLA_A_RX_LINE_3_GAIN, mask, event);
+		snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
+		gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
+		snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
+				0xFF, gain - gain_offset);
+		gain_offset = tabla_compander_gain_offset(codec, enable,
+				TABLA_A_RX_LINE_2_GAIN, mask, event);
+		snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
+		gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
+		snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
+				0xFF, gain - gain_offset);
+		gain_offset = tabla_compander_gain_offset(codec, enable,
+				TABLA_A_RX_LINE_4_GAIN, mask, event);
+		snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
+		gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
+		snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
+				0xFF, gain - gain_offset);
+	}
+	return 0;
+}
+static int tabla_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)->max;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
+
+	return 0;
+}
+
+static int tabla_set_compander(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	int comp = ((struct soc_multi_mixer_control *)
+					kcontrol->private_value)->max;
+	int value = ucontrol->value.integer.value[0];
+
+	if (value == tabla->comp_enabled[comp]) {
+		pr_debug("%s: compander #%d enable %d no change\n",
+			    __func__, comp, value);
+		return 0;
+	}
+	tabla->comp_enabled[comp] = value;
+	return 0;
+}
+
+
+static int tabla_config_compander(struct snd_soc_dapm_widget *w,
+						  struct snd_kcontrol *kcontrol,
+						  int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	u32 rate = tabla->comp_fs[w->shift];
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (tabla->comp_enabled[w->shift] != 0) {
+			/* Enable both L/R compander clocks */
+			snd_soc_update_bits(codec,
+					TABLA_A_CDC_CLK_RX_B2_CTL,
+					0x03 << comp_shift[w->shift],
+					0x03 << comp_shift[w->shift]);
+			/* Clar the HALT for the compander*/
+			snd_soc_update_bits(codec,
+					TABLA_A_CDC_COMP1_B1_CTL +
+					w->shift * 8, 1 << 2, 0);
+			/* Toggle compander reset bits*/
+			snd_soc_update_bits(codec,
+					TABLA_A_CDC_CLK_OTHR_RESET_CTL,
+					0x03 << comp_shift[w->shift],
+					0x03 << comp_shift[w->shift]);
+			snd_soc_update_bits(codec,
+					TABLA_A_CDC_CLK_OTHR_RESET_CTL,
+					0x03 << comp_shift[w->shift], 0);
+			tabla_config_gain_compander(codec, w->shift, 1, event);
+			/* Update the RMS meter resampling*/
+			snd_soc_update_bits(codec,
+					TABLA_A_CDC_COMP1_B3_CTL +
+					w->shift * 8, 0xFF, 0x01);
+			/* Wait for 1ms*/
+			usleep_range(1000, 1000);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Set sample rate dependent paramater*/
+		if (tabla->comp_enabled[w->shift] != 0) {
+			snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
+			w->shift * 8, 0x03,	rate);
+			snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
+			w->shift * 8, 0x0F,
+			comp_samp_params[rate].peak_det_timeout);
+			snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
+			w->shift * 8, 0xF0,
+			comp_samp_params[rate].rms_meter_div_fact);
+			snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
+			w->shift * 8, 0xFF,
+			comp_samp_params[rate].rms_meter_resamp_fact);
+			/* Compander enable -> 0x370/0x378*/
+			snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+			w->shift * 8, 0x03, 0x03);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Halt the compander*/
+		snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+			w->shift * 8, 1 << 2, 1 << 2);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Restore the gain */
+		tabla_config_gain_compander(codec, w->shift,
+				tabla->comp_enabled[w->shift], event);
+		/* Disable the compander*/
+		snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+			w->shift * 8, 0x03, 0x00);
+		/* Turn off the clock for compander in pair*/
+		snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
+			0x03 << comp_shift[w->shift], 0);
+		break;
+	}
+	return 0;
+}
+
 static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
 static const struct soc_enum tabla_ear_pa_gain_enum[] = {
 		SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
@@ -695,6 +948,10 @@
 	tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
 	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
 	tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+	SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
+				   tabla_get_compander, tabla_set_compander),
+	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
+				   tabla_get_compander, tabla_set_compander),
 };
 
 static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
@@ -2074,6 +2331,12 @@
 	{"LINEOUT4 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT5 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"},
 	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
@@ -2547,8 +2810,13 @@
 static int tabla_startup(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
+	struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
 	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
 		 substream->name, substream->stream);
+	if ((tabla_core != NULL) &&
+	    (tabla_core->dev != NULL) &&
+	    (tabla_core->dev->parent != NULL))
+		pm_runtime_get_sync(tabla_core->dev->parent);
 
 	return 0;
 }
@@ -2556,8 +2824,15 @@
 static void tabla_shutdown(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
+	struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
 	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
 		 substream->name, substream->stream);
+	if ((tabla_core != NULL) &&
+	    (tabla_core->dev != NULL) &&
+	    (tabla_core->dev->parent != NULL)) {
+		pm_runtime_mark_last_busy(tabla_core->dev->parent);
+		pm_runtime_put(tabla_core->dev->parent);
+	}
 }
 
 int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
@@ -2735,6 +3010,7 @@
 	u8 path, shift;
 	u16 tx_fs_reg, rx_fs_reg;
 	u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
+	u32 compander_fs;
 
 	pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
 						params_rate(params));
@@ -2743,18 +3019,22 @@
 	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;
 	default:
 		pr_err("%s: Invalid sampling rate %d\n", __func__,
@@ -2832,6 +3112,9 @@
 						+ (BITS_PER_REG*(path-1));
 				snd_soc_update_bits(codec, rx_fs_reg,
 						0xE0, rx_fs_rate);
+				if (comp_rx_path[shift] < COMPANDER_MAX)
+					tabla->comp_fs[comp_rx_path[shift]]
+					= compander_fs;
 			}
 		}
 		if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
@@ -3216,6 +3499,13 @@
 	SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
 		tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
 
+	SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
+		tabla_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, 1, 0,
+		tabla_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", TABLA_A_MICB_1_CTL, 7, 0,
 		tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
@@ -4976,6 +5266,10 @@
 	tabla->mbhc_fake_ins_start = 0;
 	tabla->no_mic_headset_override = false;
 	tabla->codec = codec;
+	for (i = 0; i < COMPANDER_MAX; i++) {
+		tabla->comp_enabled[i] = 0;
+		tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
+	}
 	tabla->pdata = dev_get_platdata(codec->dev->parent);
 	tabla->intf_type = wcd9xxx_get_intf_type();
 
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index bcf6784..ae4e403 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -727,6 +727,13 @@
 	return ret;
 }
 
+static int msm_stubrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	rtd->pmdown_time = 0;
+
+	return 0;
+}
+
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -1253,6 +1260,7 @@
 		.no_pcm = 1,
 		/* .be_id = do not care */
 		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.init = &msm_stubrx_init,
 		.ops = &msm_be_ops,
 	},
 	{
@@ -1270,7 +1278,7 @@
 };
 
 struct snd_soc_card snd_soc_card_msm = {
-	.name		= "msm-snd-card",
+	.name		= "apq8064-tabla-snd-card",
 	.dai_link	= msm_dai,
 	.num_links	= ARRAY_SIZE(msm_dai),
 };
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index b01c22c..14da1ba 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -254,6 +254,23 @@
 	mutex_unlock(&routing_lock);
 }
 
+/* Check if FE/BE route is set */
+static bool msm_pcm_routing_route_is_set(u16 be_id, u16 fe_id)
+{
+	bool rc = false;
+
+	if (be_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+		/* recheck FE ID in the mixer control defined in this file */
+		pr_err("%s: bad MM ID\n", __func__);
+		return rc;
+	}
+
+	if (test_bit(fe_id, &msm_bedais[be_id].fe_sessions))
+		rc = true;
+
+	return rc;
+}
+
 static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
 {
 	int session_type, path_type;
@@ -350,10 +367,12 @@
 		(struct soc_mixer_control *)kcontrol->private_value;
 
 
-	if (ucontrol->value.integer.value[0]) {
+	if (ucontrol->value.integer.value[0] &&
+	    msm_pcm_routing_route_is_set(mc->reg, mc->shift) == false) {
 		msm_pcm_routing_process_audio(mc->reg, mc->shift, 1);
 		snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
-	} else {
+	} else if (!ucontrol->value.integer.value[0] &&
+		   msm_pcm_routing_route_is_set(mc->reg, mc->shift) == true) {
 		msm_pcm_routing_process_audio(mc->reg, mc->shift, 0);
 		snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
 	}
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 471284b..5a0f27a 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -217,6 +217,26 @@
 	return 0;
 }
 
+static int msm_voice_rx_device_mute_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		voc_get_rx_device_mute(voc_get_session_id(VOICE_SESSION_NAME));
+	return 0;
+}
+
+static int msm_voice_rx_device_mute_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int mute = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: mute=%d\n", __func__, mute);
+
+	voc_set_rx_device_mute(voc_get_session_id(VOICE_SESSION_NAME), mute);
+
+	return 0;
+}
+
 static const char const *tty_mode[] = {"OFF", "HCO", "VCO", "FULL"};
 static const struct soc_enum msm_tty_mode_enum[] = {
 		SOC_ENUM_SINGLE_EXT(4, tty_mode),
@@ -308,6 +328,9 @@
 }
 
 static struct snd_kcontrol_new msm_voice_controls[] = {
+	SOC_SINGLE_EXT("Voice Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
+				msm_voice_rx_device_mute_get,
+				msm_voice_rx_device_mute_put),
 	SOC_SINGLE_EXT("Voice Tx Mute", SND_SOC_NOPM, 0, 1, 0,
 				msm_voice_mute_get, msm_voice_mute_put),
 	SOC_SINGLE_EXT("Voice Rx Volume", SND_SOC_NOPM, 0, 5, 0,
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index d822af5c..fe31b27 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -240,6 +240,13 @@
 
 		while (cnt >= 0) {
 			if (port->buf[cnt].data) {
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+				ion_unmap_kernel(port->buf[cnt].client,
+						port->buf[cnt].handle);
+				ion_free(port->buf[cnt].client,
+						port->buf[cnt].handle);
+				ion_client_destroy(port->buf[cnt].client);
+#else
 				pr_debug("%s:data[%p]phys[%p][%p] cnt[%d]"
 					 "mem_buffer[%p]\n",
 					__func__, (void *)port->buf[cnt].data,
@@ -259,6 +266,7 @@
 				free_contiguous_memory_by_paddr(
 					port->buf[cnt].phys);
 
+#endif
 				port->buf[cnt].data = NULL;
 				port->buf[cnt].phys = 0;
 				--(port->max_buf_cnt);
@@ -295,6 +303,19 @@
 	}
 
 	if (port->buf[0].data) {
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		ion_unmap_kernel(port->buf[0].client, port->buf[0].handle);
+		ion_free(port->buf[0].client, port->buf[0].handle);
+		ion_client_destroy(port->buf[0].client);
+		pr_debug("%s:data[%p]phys[%p][%p]"
+			", client[%p] handle[%p]\n",
+			__func__,
+			(void *)port->buf[0].data,
+			(void *)port->buf[0].phys,
+			(void *)&port->buf[0].phys,
+			(void *)port->buf[0].client,
+			(void *)port->buf[0].handle);
+#else
 		pr_debug("%s:data[%p]phys[%p][%p]"
 			"mem_buffer[%p]\n",
 			__func__,
@@ -313,6 +334,7 @@
 					" failed\n", __func__);
 		}
 		free_contiguous_memory_by_paddr(port->buf[0].phys);
+#endif
 	}
 
 	while (cnt >= 0) {
@@ -465,6 +487,9 @@
 	int cnt = 0;
 	int rc = 0;
 	struct audio_buffer *buf;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	int len;
+#endif
 
 	if (!(ac) || ((dir != IN) && (dir != OUT)))
 		return -EINVAL;
@@ -494,6 +519,50 @@
 		while (cnt < bufcnt) {
 			if (bufsz > 0) {
 				if (!buf[cnt].data) {
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+					buf[cnt].client = msm_ion_client_create
+						(UINT_MAX, "audio_client");
+					if (IS_ERR_OR_NULL((void *)
+						buf[cnt].client)) {
+						pr_err("%s: ION create client"
+						" for AUDIO failed\n",
+						__func__);
+						goto fail;
+					}
+					buf[cnt].handle = ion_alloc
+						(buf[cnt].client, bufsz, SZ_4K,
+						(0x1 << ION_AUDIO_HEAP_ID));
+					if (IS_ERR_OR_NULL((void *)
+						buf[cnt].handle)) {
+						pr_err("%s: ION memory"
+					" allocation for AUDIO failed\n",
+							__func__);
+						goto fail;
+					}
+
+					rc = ion_phys(buf[cnt].client,
+						buf[cnt].handle,
+						(ion_phys_addr_t *)
+						&buf[cnt].phys,
+						(size_t *)&len);
+					if (rc) {
+						pr_err("%s: ION Get Physical"
+						" for AUDIO failed, rc = %d\n",
+							__func__, rc);
+						goto fail;
+					}
+
+					buf[cnt].data = ion_map_kernel
+					(buf[cnt].client, buf[cnt].handle,
+							 0);
+					if (IS_ERR_OR_NULL((void *)
+						buf[cnt].data)) {
+						pr_err("%s: ION memory"
+				" mapping for AUDIO failed\n", __func__);
+						goto fail;
+					}
+					memset((void *)buf[cnt].data, 0, bufsz);
+#else
 					unsigned int flags = 0;
 					buf[cnt].phys =
 					allocate_contiguous_ebi_nomap(bufsz,
@@ -526,16 +595,15 @@
 						mutex_unlock(&ac->cmd_lock);
 						goto fail;
 					}
+#endif
 					buf[cnt].used = 1;
 					buf[cnt].size = bufsz;
 					buf[cnt].actual_size = bufsz;
-					pr_debug("%s data[%p]phys[%p][%p]"
-						 "mem_buffer[%p]\n",
+					pr_debug("%s data[%p]phys[%p][%p]\n",
 						__func__,
 					   (void *)buf[cnt].data,
 					   (void *)buf[cnt].phys,
-					   (void *)&buf[cnt].phys,
-					   (void *)buf[cnt].mem_buffer);
+					   (void *)&buf[cnt].phys);
 					cnt++;
 				}
 			}
@@ -562,9 +630,12 @@
 {
 	int cnt = 0;
 	int rc = 0;
-	int flags = 0;
 	struct audio_buffer *buf;
-
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	int len;
+#else
+	int flags = 0;
+#endif
 	if (!(ac) || ((dir != IN) && (dir != OUT)))
 		return -EINVAL;
 
@@ -590,6 +661,35 @@
 
 	ac->port[dir].buf = buf;
 
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	buf[0].client = msm_ion_client_create(UINT_MAX, "audio_client");
+	if (IS_ERR_OR_NULL((void *)buf[0].client)) {
+		pr_err("%s: ION create client for AUDIO failed\n", __func__);
+		goto fail;
+	}
+	buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
+				  (0x1 << ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
+		pr_err("%s: ION memory allocation for AUDIO failed\n",
+			__func__);
+		goto fail;
+	}
+
+	rc = ion_phys(buf[0].client, buf[0].handle,
+		  (ion_phys_addr_t *)&buf[0].phys, (size_t *)&len);
+	if (rc) {
+		pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
+			__func__, rc);
+		goto fail;
+	}
+
+	buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle, 0);
+	if (IS_ERR_OR_NULL((void *) buf[0].data)) {
+		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+		goto fail;
+	}
+	memset((void *)buf[0].data, 0, (bufsz * bufcnt));
+#else
 	buf[0].phys = allocate_contiguous_ebi_nomap(bufsz * bufcnt,
 						SZ_4K);
 	if (!buf[0].phys) {
@@ -612,6 +712,7 @@
 		goto fail;
 	}
 	buf[0].data = buf[0].mem_buffer->vaddr;
+#endif
 	if (!buf[0].data) {
 		pr_err("%s:invalid vaddr,"
 			" iomap failed\n", __func__);
@@ -726,6 +827,9 @@
 	if (data->opcode == RESET_EVENTS) {
 		pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
 				data->reset_event, data->reset_proc, ac->apr);
+			if (ac->cb)
+				ac->cb(data->opcode, data->token,
+					(uint32_t *)data->payload, ac->priv);
 		apr_reset(ac->apr);
 		return 0;
 	}
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index f0f833c..0376f34 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -2282,6 +2282,51 @@
 	return -EINVAL;
 }
 
+static int voice_send_rx_device_mute_cmd(struct voice_data *v)
+{
+	struct cvp_set_mute_cmd cvp_mute_cmd;
+	int ret = 0;
+	void *apr_cvp;
+	u16 cvp_handle;
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvp = common.apr_q6_cvp;
+
+	if (!apr_cvp) {
+		pr_err("%s: apr_cvp is NULL.\n", __func__);
+		return -EINVAL;
+	}
+	cvp_handle = voice_get_cvp_handle(v);
+
+	cvp_mute_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvp_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvp_mute_cmd) - APR_HDR_SIZE);
+	cvp_mute_cmd.hdr.src_port = v->session_id;
+	cvp_mute_cmd.hdr.dest_port = cvp_handle;
+	cvp_mute_cmd.hdr.token = 0;
+	cvp_mute_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_MUTE;
+	cvp_mute_cmd.cvp_set_mute.direction = 1;
+	cvp_mute_cmd.cvp_set_mute.mute_flag = v->dev_rx.mute;
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_mute_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending RX device mute cmd\n");
+		return -EINVAL;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int voice_send_vol_index_cmd(struct voice_data *v)
 {
 	struct cvp_set_rx_volume_index_cmd cvp_vol_cmd;
@@ -2883,6 +2928,49 @@
 	return ret;
 }
 
+int voc_set_rx_device_mute(uint16_t session_id, uint32_t mute)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	int ret = 0;
+
+	if (v == NULL) {
+		pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+		return -EINVAL;
+	}
+
+	mutex_lock(&v->lock);
+
+	v->dev_rx.mute = mute;
+
+	if (v->voc_state == VOC_RUN)
+		ret = voice_send_rx_device_mute_cmd(v);
+
+	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
+int voc_get_rx_device_mute(uint16_t session_id)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	int ret = 0;
+
+	if (v == NULL) {
+		pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+		return -EINVAL;
+	}
+
+	mutex_lock(&v->lock);
+
+	ret = v->dev_rx.mute;
+
+	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
 int voc_set_tty_mode(uint16_t session_id, uint8_t tty_mode)
 {
 	struct voice_data *v = voice_get_session(session_id);
@@ -3571,6 +3659,7 @@
 
 		/* initialize dev_rx and dev_tx */
 		common.voice[i].dev_rx.volume = common.default_vol_val;
+		common.voice[i].dev_rx.mute =  0;
 		common.voice[i].dev_tx.mute = common.default_mute_val;
 
 		common.voice[i].dev_tx.port_id = 1;
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 1a24b9c..0edf1c9 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -637,6 +637,8 @@
 #define VSS_MEDIA_ID_G729		0x00010FD0
 /* G.729AB (contains two 10ms vocoder frames. */
 
+#define VSS_IVOCPROC_CMD_SET_MUTE			0x000110EF
+
 #define VOICE_CMD_SET_PARAM				0x00011006
 #define VOICE_CMD_GET_PARAM				0x00011007
 #define VOICE_EVT_GET_PARAM_ACK				0x00011008
@@ -729,6 +731,22 @@
 	/* Size of the volume calibration table in bytes. */
 } __packed;
 
+struct vss_ivocproc_cmd_set_mute_t {
+	uint16_t direction;
+	/*
+	* 0 : TX only.
+	* 1 : RX only.
+	* 2 : TX and Rx.
+	*/
+	uint16_t mute_flag;
+	/*
+	* Mute, un-mute.
+	*
+	* 0 : Disable.
+	* 1 : Enable.
+	*/
+} __packed;
+
 struct cvp_create_full_ctl_session_cmd {
 	struct apr_hdr hdr;
 	struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
@@ -770,6 +788,11 @@
 	struct apr_hdr hdr;
 } __packed;
 
+struct cvp_set_mute_cmd {
+	struct apr_hdr hdr;
+	struct vss_ivocproc_cmd_set_mute_t cvp_set_mute;
+} __packed;
+
 /* CB for up-link packets. */
 typedef void (*ul_cb_fn)(uint8_t *voc_pkt,
 			 uint32_t pkt_len,
@@ -904,6 +927,8 @@
 		      uint32_t dev_type);
 int voc_set_rx_vol_index(uint16_t session_id, uint32_t dir, uint32_t voc_idx);
 int voc_set_tx_mute(uint16_t session_id, uint32_t dir, uint32_t mute);
+int voc_set_rx_device_mute(uint16_t session_id, uint32_t mute);
+int voc_get_rx_device_mute(uint16_t session_id);
 int voc_disable_cvp(uint16_t session_id);
 int voc_enable_cvp(uint16_t session_id);
 int voc_set_route_flag(uint16_t session_id, uint8_t path_dir, uint8_t set);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index d528f4b..76091e3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1144,6 +1144,11 @@
 	struct snd_soc_codec *codec;
 	int i;
 
+	if (!card->instantiated) {
+		dev_dbg(card->dev, "uninsantiated card found card->name = %s\n",
+			card->name);
+		return 0;
+	}
 	/* If the initialization of this soc device failed, there is no codec
 	 * associated with it. Just bail out in this case.
 	 */
@@ -1397,6 +1402,11 @@
 	struct snd_soc_card *card = dev_get_drvdata(dev);
 	int i, ac97_control = 0;
 
+	if (!card->instantiated) {
+		dev_dbg(card->dev, "uninsantiated card found card->name = %s\n",
+			card->name);
+		return 0;
+	}
 	/* AC97 devices might have other drivers hanging off them so
 	 * need to resume immediately.  Other drivers don't have that
 	 * problem and may take a substantial amount of time to resume